2024-02-14 03:04:05 +08:00
using DCFApixels.DragonECS.Internal ;
2023-05-26 06:18:09 +08:00
using System ;
2024-09-09 18:21:21 +08:00
using System.Collections.Concurrent ;
2023-03-27 17:34:12 +08:00
using System.Diagnostics ;
2023-03-27 17:58:51 +08:00
using System.Runtime.CompilerServices ;
2023-03-27 17:34:12 +08:00
namespace DCFApixels.DragonECS
{
2023-03-30 06:05:53 +08:00
public readonly struct EcsProfilerMarker
2023-03-30 06:03:05 +08:00
{
2023-03-30 06:05:53 +08:00
public readonly int id ;
2024-02-26 10:56:18 +08:00
internal EcsProfilerMarker ( int id ) { this . id = id ; }
public EcsProfilerMarker ( string name ) { id = DebugService . Instance . RegisterMark ( name ) ; }
2023-03-30 11:17:17 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-26 10:56:18 +08:00
public void Begin ( ) { DebugService . Instance . ProfilerMarkBegin ( id ) ; }
2023-03-30 11:17:17 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-26 10:56:18 +08:00
public void End ( ) { DebugService . Instance . ProfilerMarkEnd ( id ) ; }
2023-03-30 11:17:17 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-26 10:56:18 +08:00
public AutoScope Auto ( ) { return new AutoScope ( id ) ; }
2023-04-01 20:45:37 +08:00
public readonly ref struct AutoScope
2023-03-30 06:05:53 +08:00
{
2023-05-26 05:13:11 +08:00
private readonly int _id ;
2024-06-08 02:08:20 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-30 06:05:53 +08:00
public AutoScope ( int id )
2023-03-30 06:03:05 +08:00
{
2023-05-26 05:13:11 +08:00
_id = id ;
2023-06-12 20:30:44 +08:00
DebugService . Instance . ProfilerMarkBegin ( id ) ;
2023-03-30 06:05:53 +08:00
}
2024-06-08 02:08:20 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-26 10:56:18 +08:00
public void Dispose ( )
{
DebugService . Instance . ProfilerMarkEnd ( _id ) ;
}
2023-03-30 06:03:05 +08:00
}
2024-06-08 02:08:20 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator EcsProfilerMarker ( string markerName ) { return new EcsProfilerMarker ( markerName ) ; }
2023-03-30 06:03:05 +08:00
}
2023-03-30 06:05:53 +08:00
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.DEBUG_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, "Debugging utility. To modify or change the behavior, create a new class inherited from DebugService and set this service using DebugService.Set<T>().")]
2023-03-27 17:34:12 +08:00
public static class EcsDebug
{
2023-11-22 11:28:15 +08:00
public const string WARNING_TAG = EcsConsts . DEBUG_WARNING_TAG ;
public const string ERROR_TAG = EcsConsts . DEBUG_ERROR_TAG ;
2023-12-31 21:03:00 +08:00
public const string PASS_TAG = EcsConsts . DEBUG_PASS_TAG ;
2023-11-22 11:28:15 +08:00
2024-02-26 10:56:18 +08:00
public static void Set < T > ( ) where T : DebugService , new ( )
{
DebugService . Set < T > ( ) ;
}
public static void Set ( DebugService service )
{
DebugService . Set ( service ) ;
}
2023-03-27 17:34:12 +08:00
2023-03-27 17:58:51 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-26 10:56:18 +08:00
public static void PrintWarning ( object v )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-02-26 10:56:18 +08:00
DebugService . Instance . PrintWarning ( v ) ;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void PrintError ( object v )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-02-26 10:56:18 +08:00
DebugService . Instance . PrintError ( v ) ;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-03 01:12:53 +08:00
public static void PrintErrorAndBreak ( object v )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-02-26 10:56:18 +08:00
DebugService . Instance . PrintErrorAndBreak ( v ) ;
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void PrintPass ( object v )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-02-26 10:56:18 +08:00
DebugService . Instance . PrintPass ( v ) ;
#endif
2024-02-03 01:12:53 +08:00
}
2024-02-26 10:56:18 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-11-08 15:15:10 +08:00
public static void Print ( )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-02-26 10:56:18 +08:00
DebugService . Instance . Print ( ) ;
2023-11-08 15:15:10 +08:00
#endif
}
2024-02-26 10:56:18 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-27 15:59:46 +08:00
public static void Print ( object v )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2023-05-27 15:59:46 +08:00
DebugService . Instance . Print ( v ) ;
#endif
}
2023-03-27 17:58:51 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-27 17:34:12 +08:00
public static void Print ( string tag , object v )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2023-03-27 17:34:12 +08:00
DebugService . Instance . Print ( tag , v ) ;
#endif
}
2024-02-26 10:56:18 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-06-30 00:32:25 +08:00
public static void Break ( )
{
2024-04-27 17:55:44 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-02-26 10:56:18 +08:00
DebugService . Instance . Break ( ) ;
2023-06-30 00:32:25 +08:00
#endif
}
2023-03-27 17:34:12 +08:00
}
2023-03-30 06:03:05 +08:00
2023-03-27 17:34:12 +08:00
public abstract class DebugService
{
private static DebugService _instance ;
2024-09-09 18:21:21 +08:00
private static object _lock = new object ( ) ;
2023-06-12 20:46:51 +08:00
public static DebugService Instance
{
get
{
if ( _instance = = null )
2024-02-26 10:56:18 +08:00
{
2023-06-12 20:46:51 +08:00
_instance = new DefaultDebugService ( ) ;
2024-02-26 10:56:18 +08:00
}
2023-06-12 20:46:51 +08:00
return _instance ;
}
}
2023-03-27 17:34:12 +08:00
2024-02-26 10:56:18 +08:00
public static void Set < T > ( ) where T : DebugService , new ( )
{
Set ( new T ( ) ) ;
}
2023-03-27 17:34:12 +08:00
public static void Set ( DebugService service )
{
_instance = service ;
OnServiceChanged ( _instance ) ;
}
public static Action < DebugService > OnServiceChanged = delegate { } ;
2024-02-14 02:39:42 +08:00
private IdDispenser _idDispenser = new IdDispenser ( 4 , - 1 ) ;
2024-09-09 18:21:21 +08:00
private ConcurrentDictionary < string , int > _nameIdTable = new ConcurrentDictionary < string , int > ( ) ;
2023-03-27 17:34:12 +08:00
public abstract void Print ( string tag , object v ) ;
2023-06-30 00:31:17 +08:00
public abstract void Break ( ) ;
2023-03-27 17:34:12 +08:00
public int RegisterMark ( string name )
{
int id ;
2023-05-30 18:30:10 +08:00
if ( ! _nameIdTable . TryGetValue ( name , out id ) )
2023-03-27 17:34:12 +08:00
{
2024-09-09 18:21:21 +08:00
lock ( _lock )
{
id = _idDispenser . UseFree ( ) ;
_nameIdTable . TryAdd ( name , id ) ;
}
2023-03-27 17:34:12 +08:00
}
2023-06-12 20:30:44 +08:00
OnNewProfilerMark ( id , name ) ;
2023-03-27 17:34:12 +08:00
return id ;
}
public void DeleteMark ( string name )
{
int id = _nameIdTable [ name ] ;
2024-09-09 18:21:21 +08:00
//TODO кажется этот TryRemove не подходит
_nameIdTable . TryRemove ( name , out id ) ;
2023-03-27 17:34:12 +08:00
_idDispenser . Release ( id ) ;
2023-06-12 20:30:44 +08:00
OnDelProfilerMark ( id ) ;
2023-03-27 17:34:12 +08:00
}
2023-06-12 20:30:44 +08:00
protected abstract void OnNewProfilerMark ( int id , string name ) ;
protected abstract void OnDelProfilerMark ( int id ) ;
2023-03-27 17:34:12 +08:00
2023-06-12 20:30:44 +08:00
public abstract void ProfilerMarkBegin ( int id ) ;
public abstract void ProfilerMarkEnd ( int id ) ;
2023-03-27 17:34:12 +08:00
}
2024-02-26 10:56:18 +08:00
public static class DebugServiceExtensions
{
public static void PrintWarning ( this DebugService self , object v )
{
self . Print ( EcsConsts . DEBUG_WARNING_TAG , v ) ;
}
public static void PrintError ( this DebugService self , object v )
{
self . Print ( EcsConsts . DEBUG_ERROR_TAG , v ) ;
}
public static void PrintErrorAndBreak ( this DebugService self , object v )
{
self . Print ( EcsConsts . DEBUG_ERROR_TAG , v ) ;
self . Break ( ) ;
}
public static void PrintPass ( this DebugService self , object v )
{
self . Print ( EcsConsts . DEBUG_PASS_TAG , v ) ;
}
public static void Print ( this DebugService self , object v )
{
self . Print ( null , v ) ;
}
public static void Print ( this DebugService self )
{
self . Print ( "" ) ;
}
2024-09-08 19:39:43 +08:00
//TODO PrintJson возможно будет добавлено когда-то
2024-02-26 10:56:18 +08:00
}
2023-03-27 17:34:12 +08:00
public sealed class DefaultDebugService : DebugService
{
2024-04-27 17:55:44 +08:00
private const string PROFILER_MARKER = "ProfilerMark" ;
private struct MarkerData
{
public Stopwatch stopwatch ;
public string name ;
public MarkerData ( Stopwatch stopwatch , string name )
{
this . stopwatch = stopwatch ;
this . name = name ;
}
}
private MarkerData [ ] _stopwatchs ;
[ThreadStatic]
private static char [ ] _buffer ;
2023-03-27 17:34:12 +08:00
public DefaultDebugService ( )
{
2023-11-22 11:38:28 +08:00
Console . ForegroundColor = ConsoleColor . White ;
Console . BackgroundColor = ConsoleColor . Black ;
2024-05-01 16:32:03 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER
2024-04-27 17:55:44 +08:00
_stopwatchs = new MarkerData [ 64 ] ;
2023-03-27 17:34:12 +08:00
#endif
}
2023-11-22 11:38:28 +08:00
2023-03-27 17:34:12 +08:00
public override void Print ( string tag , object v )
{
2023-11-22 11:28:15 +08:00
if ( string . IsNullOrEmpty ( tag ) )
{
Console . WriteLine ( v ) ;
}
else
{
var color = Console . ForegroundColor ;
switch ( tag )
{
case EcsDebug . ERROR_TAG :
Console . ForegroundColor = ConsoleColor . Red ;
break ;
case EcsDebug . WARNING_TAG :
Console . ForegroundColor = ConsoleColor . Yellow ;
break ;
2023-12-31 21:03:00 +08:00
case EcsDebug . PASS_TAG :
Console . ForegroundColor = ConsoleColor . Green ;
break ;
2023-11-22 11:28:15 +08:00
}
Console . WriteLine ( $"[{tag}] {v}" ) ;
Console . ForegroundColor = color ;
}
2023-03-27 17:34:12 +08:00
}
2023-06-30 00:31:17 +08:00
public override void Break ( )
{
2023-11-22 11:28:15 +08:00
var color = Console . ForegroundColor ;
Console . ForegroundColor = ConsoleColor . Cyan ;
Console . WriteLine ( "Press Enter to с ontinue." ) ;
Console . ReadKey ( ) ;
Console . ForegroundColor = color ;
2023-06-30 00:31:17 +08:00
}
2024-04-27 17:55:44 +08:00
private const string PROFILER_MARKER_CACHE = "[" + PROFILER_MARKER + "] " ;
2023-06-12 20:30:44 +08:00
public override void ProfilerMarkBegin ( int id )
2023-03-27 17:34:12 +08:00
{
2024-05-01 16:32:03 +08:00
#if ( ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER ) & & ! UNITY_5_3_OR_NEWER
2024-01-29 01:10:05 +08:00
var color = Console . ForegroundColor ;
Console . ForegroundColor = ConsoleColor . DarkGray ;
2024-04-27 17:55:44 +08:00
_stopwatchs [ id ] . stopwatch . Start ( ) ;
Console . Write ( PROFILER_MARKER_CACHE ) ;
Console . Write ( _stopwatchs [ id ] . name ) ;
Console . WriteLine ( "> " ) ;
2024-01-29 01:10:05 +08:00
Console . ForegroundColor = color ;
2024-04-27 17:55:44 +08:00
#endif
2023-03-27 17:34:12 +08:00
}
2023-06-12 20:30:44 +08:00
public override void ProfilerMarkEnd ( int id )
2023-03-27 17:34:12 +08:00
{
2024-05-01 16:32:03 +08:00
#if ( ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_DEBUGGER ) & & ! UNITY_5_3_OR_NEWER
2023-11-22 11:28:15 +08:00
var color = Console . ForegroundColor ;
Console . ForegroundColor = ConsoleColor . DarkGray ;
2024-04-27 17:55:44 +08:00
_stopwatchs [ id ] . stopwatch . Stop ( ) ;
var time = _stopwatchs [ id ] . stopwatch . Elapsed ;
_stopwatchs [ id ] . stopwatch . Reset ( ) ;
Console . Write ( PROFILER_MARKER_CACHE ) ;
Console . Write ( "> " ) ;
Console . Write ( _stopwatchs [ id ] . name ) ;
Console . Write ( " s:" ) ;
int written = 0 ;
if ( _buffer = = null ) { _buffer = new char [ 128 ] ; }
ConvertDoubleToText ( time . TotalSeconds , _buffer , ref written ) ;
Console . WriteLine ( _buffer , 0 , written ) ;
2023-11-22 11:28:15 +08:00
Console . ForegroundColor = color ;
2024-04-27 17:55:44 +08:00
#endif
2023-03-27 17:34:12 +08:00
}
2024-04-27 17:55:44 +08:00
2023-06-12 20:30:44 +08:00
protected override void OnDelProfilerMark ( int id )
2023-03-27 17:34:12 +08:00
{
2024-04-27 17:55:44 +08:00
_stopwatchs [ id ] = default ;
2023-03-27 17:34:12 +08:00
}
2023-06-12 20:30:44 +08:00
protected override void OnNewProfilerMark ( int id , string name )
2023-03-27 17:34:12 +08:00
{
2023-03-30 16:39:16 +08:00
if ( id > = _stopwatchs . Length )
{
Array . Resize ( ref _stopwatchs , _stopwatchs . Length < < 1 ) ;
}
2024-04-27 17:55:44 +08:00
_stopwatchs [ id ] = new MarkerData ( new Stopwatch ( ) , name ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void ConvertDoubleToText ( double value , char [ ] stringBuffer , ref int written )
{
int bufferLength = stringBuffer . Length - 1 ;
decimal decimalValue = ( decimal ) value ;
int intValue = ( int ) decimalValue ;
decimal decimalPartValue = decimalValue - intValue ;
int index = written ;
if ( intValue = = 0 )
{
stringBuffer [ index + + ] = '0' ;
}
else
{
while ( intValue > 0 )
{
int digit = intValue % 10 ;
stringBuffer [ index + + ] = ( char ) ( '0' + digit ) ;
intValue / = 10 ;
}
Array . Reverse ( stringBuffer , 0 , index ) ;
}
if ( decimalPartValue ! = 0 )
{
stringBuffer [ index + + ] = '.' ;
}
int pathBufferLength = bufferLength - index ;
int zeroPartLength = 0 ;
for ( int i = 0 ; i < pathBufferLength ; i + + )
{
decimalPartValue = 10 * decimalPartValue ;
int digit = ( int ) decimalPartValue ;
if ( digit = = 0 )
{
zeroPartLength + + ;
}
else
{
zeroPartLength = 0 ;
}
stringBuffer [ index + + ] = ( char ) ( '0' + digit ) ;
decimalPartValue - = digit ;
}
written = bufferLength - zeroPartLength ;
2023-03-27 17:34:12 +08:00
}
}
}