2023-05-26 04:31:31 +08:00
using DCFApixels.DragonECS.Internal ;
using DCFApixels.DragonECS.RunnersCore ;
2023-04-23 17:55:01 +08:00
using System ;
2023-05-07 00:50:02 +08:00
using System.Collections ;
2023-03-26 11:19:03 +08:00
using System.Collections.Generic ;
2024-03-09 23:09:01 +08:00
using System.Diagnostics ;
2023-05-07 00:50:02 +08:00
using System.Linq ;
2023-03-26 11:19:03 +08:00
using System.Runtime.CompilerServices ;
2024-08-07 10:40:31 +08:00
using static DCFApixels . DragonECS . EcsConsts ;
2023-03-26 11:19:03 +08:00
namespace DCFApixels.DragonECS
{
2024-08-14 20:39:55 +08:00
public interface IEcsMember { }
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
2024-08-07 10:40:31 +08:00
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "...")]
2024-10-12 00:08:12 +08:00
[MetaID("F064557C92010419AB677453893D00AE")]
2024-02-22 22:16:03 +08:00
public interface IEcsPipelineMember : IEcsProcess
2024-02-17 00:10:38 +08:00
{
2024-02-22 22:16:03 +08:00
EcsPipeline Pipeline { get ; set ; }
2024-02-17 00:10:38 +08:00
}
2024-08-14 20:39:55 +08:00
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
2024-08-07 10:40:31 +08:00
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "Container and engine for systems. Responsible for configuring the execution order of systems, providing a mechanism for messaging between systems, and a dependency injection mechanism.")]
2024-10-12 00:08:12 +08:00
[MetaID("9F5A557C9201C5C3D9BCAC2FF1CC07D4")]
2024-06-24 22:06:02 +08:00
public sealed partial class EcsPipeline
2023-03-26 11:19:03 +08:00
{
2024-03-07 07:48:18 +08:00
private readonly IConfigContainer _configs ;
2024-02-22 23:48:10 +08:00
private Injector . Builder _injectorBuilder ;
private Injector _injector ;
2023-03-26 11:19:03 +08:00
2024-02-22 22:16:03 +08:00
private IEcsProcess [ ] _allSystems ;
2024-02-22 15:39:37 +08:00
private Dictionary < Type , Array > _processes = new Dictionary < Type , Array > ( ) ;
private Dictionary < Type , IEcsRunner > _runners = new Dictionary < Type , IEcsRunner > ( ) ;
2024-02-23 18:34:40 +08:00
private EcsRunRunner _runRunnerCache ;
2023-03-26 11:19:03 +08:00
2023-06-26 02:53:55 +08:00
private bool _isInit = false ;
private bool _isDestoryed = false ;
2023-03-26 11:19:03 +08:00
2024-02-23 18:34:40 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-25 18:33:17 +08:00
private EcsProfilerMarker _initMarker = new EcsProfilerMarker ( "EcsPipeline.Init" ) ;
2024-02-23 18:34:40 +08:00
#endif
2024-02-22 23:48:10 +08:00
2023-03-26 11:19:03 +08:00
#region Properties
2024-03-07 07:48:18 +08:00
public IConfigContainer Configs
2024-02-22 15:39:37 +08:00
{
2024-03-07 07:48:18 +08:00
get { return _configs ; }
2024-02-22 15:39:37 +08:00
}
2024-02-22 22:16:03 +08:00
public Injector Injector
2024-02-22 15:39:37 +08:00
{
2024-02-22 22:16:03 +08:00
get { return _injector ; }
}
public EcsProcess < IEcsProcess > AllSystems
{
get { return new EcsProcess < IEcsProcess > ( _allSystems ) ; }
2024-02-22 15:39:37 +08:00
}
public IReadOnlyDictionary < Type , IEcsRunner > AllRunners
{
get { return _runners ; }
}
2024-02-22 23:48:10 +08:00
public bool IsInit
{
get { return _isInit ; }
2024-02-22 15:39:37 +08:00
}
2024-02-22 23:48:10 +08:00
public bool IsDestoryed
{
get { return _isDestoryed ; }
2024-02-22 15:39:37 +08:00
}
2023-03-26 11:19:03 +08:00
#endregion
#region Constructors
2024-03-07 07:48:18 +08:00
private EcsPipeline ( IConfigContainer configs , Injector . Builder injectorBuilder , IEcsProcess [ ] systems )
2023-03-26 11:19:03 +08:00
{
2024-03-07 07:48:18 +08:00
_configs = configs ;
2023-03-26 11:19:03 +08:00
_allSystems = systems ;
2024-02-22 23:48:10 +08:00
_injectorBuilder = injectorBuilder ;
2024-02-25 18:33:17 +08:00
_injectorBuilder . Inject ( this ) ;
2023-03-26 11:19:03 +08:00
}
#endregion
2024-02-26 08:31:35 +08:00
#region GetProcess
2024-02-22 22:16:03 +08:00
public EcsProcess < T > GetProcess < T > ( ) where T : IEcsProcess
2024-02-17 00:10:27 +08:00
{
2024-02-22 15:39:37 +08:00
Type type = typeof ( T ) ;
T [ ] result ;
2024-02-22 23:48:10 +08:00
if ( _processes . TryGetValue ( type , out Array array ) )
2024-02-22 15:39:37 +08:00
{
result = ( T [ ] ) array ;
}
else
{
2024-07-08 11:08:04 +08:00
result = CreateProcess < T > ( ) ;
2024-02-22 15:39:37 +08:00
_processes . Add ( type , result ) ;
}
return new EcsProcess < T > ( result ) ;
2024-02-17 00:10:27 +08:00
}
2024-07-08 11:08:04 +08:00
[ThreadStatic]
private static IEcsProcess [ ] _buffer ;
private T [ ] CreateProcess < T > ( ) where T : IEcsProcess
{
2024-07-08 20:31:42 +08:00
if ( _buffer = = null | | _buffer . Length < _allSystems . Length )
2024-07-08 11:08:04 +08:00
{
2024-07-08 20:31:42 +08:00
Array . Resize ( ref _buffer , _allSystems . Length ) ;
2024-07-08 11:08:04 +08:00
}
int l = 0 ;
for ( int i = 0 , iMax = _allSystems . Length ; i < iMax ; i + + )
{
if ( _allSystems [ i ] is T )
{
_buffer [ l + + ] = _allSystems [ i ] ;
}
}
T [ ] result = new T [ l ] ;
Array . Copy ( _buffer , result , l ) ;
return result ;
}
2024-02-23 18:34:40 +08:00
#endregion
2024-02-26 08:31:35 +08:00
#region GetRunner
public TRunner GetRunnerInstance < TRunner > ( ) where TRunner : EcsRunner , IEcsRunner , new ( )
2024-02-23 18:34:40 +08:00
{
Type runnerType = typeof ( TRunner ) ;
if ( _runners . TryGetValue ( runnerType , out IEcsRunner result ) )
{
return ( TRunner ) result ;
}
TRunner instance = new TRunner ( ) ;
#if DEBUG
EcsRunner . CheckRunnerTypeIsValide ( runnerType , instance . Interface ) ;
#endif
instance . Init_Internal ( this ) ;
_runners . Add ( runnerType , instance ) ;
_runners . Add ( instance . Interface , instance ) ;
return instance ;
}
2024-02-22 22:16:03 +08:00
public T GetRunner < T > ( ) where T : IEcsProcess
2024-01-26 02:26:17 +08:00
{
2024-02-23 18:34:40 +08:00
if ( _runners . TryGetValue ( typeof ( T ) , out IEcsRunner result ) )
2024-02-17 00:10:27 +08:00
{
2024-02-23 18:34:40 +08:00
return ( T ) result ;
2024-02-17 00:10:27 +08:00
}
2024-04-22 17:49:24 +08:00
Throw . Exception ( "No matching runner found." ) ;
2024-02-23 18:34:40 +08:00
return default ;
2024-01-26 02:26:17 +08:00
}
2024-02-23 18:34:40 +08:00
public bool TryGetRunner < T > ( out T runner ) where T : IEcsProcess
2023-03-26 11:19:03 +08:00
{
2024-02-23 18:34:40 +08:00
if ( _runners . TryGetValue ( typeof ( T ) , out IEcsRunner result ) )
2024-01-26 02:26:17 +08:00
{
2024-02-23 18:34:40 +08:00
runner = ( T ) result ;
return true ;
2024-01-26 02:26:17 +08:00
}
2024-02-23 18:34:40 +08:00
runner = default ;
return false ;
2023-03-26 11:19:03 +08:00
}
2024-02-22 15:39:37 +08:00
#endregion
#region Internal
internal void OnRunnerDestroy_Internal ( IEcsRunner runner )
2023-03-30 05:32:43 +08:00
{
_runners . Remove ( runner . Interface ) ;
}
2023-03-26 11:19:03 +08:00
#endregion
#region LifeCycle
2023-03-29 04:23:37 +08:00
public void Init ( )
{
2023-04-01 20:45:37 +08:00
if ( _isInit = = true )
2023-03-29 04:23:37 +08:00
{
2023-12-06 20:35:07 +08:00
EcsDebug . PrintWarning ( $"This {nameof(EcsPipeline)} has already been initialized" ) ;
2023-03-29 04:23:37 +08:00
return ;
}
2024-02-23 18:34:40 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-25 18:33:17 +08:00
_initMarker . Begin ( ) ;
2024-02-23 18:34:40 +08:00
#endif
2024-03-02 21:27:50 +08:00
var members = GetProcess < IEcsPipelineMember > ( ) ;
for ( int i = 0 ; i < members . Length ; i + + )
{
members [ i ] . Pipeline = this ;
}
2024-02-22 23:48:10 +08:00
_injector = _injectorBuilder . Build ( this ) ;
_injectorBuilder = null ;
2024-02-17 00:10:38 +08:00
2024-02-26 08:31:35 +08:00
GetRunnerInstance < EcsPreInitRunner > ( ) . PreInit ( ) ;
GetRunnerInstance < EcsInitRunner > ( ) . Init ( ) ;
_runRunnerCache = GetRunnerInstance < EcsRunRunner > ( ) ;
2023-03-29 04:23:37 +08:00
2023-06-10 19:46:35 +08:00
_isInit = true ;
2024-02-22 22:16:03 +08:00
2023-10-31 03:03:13 +08:00
GC . Collect ( ) ;
2024-02-23 18:34:40 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-25 18:33:17 +08:00
_initMarker . End ( ) ;
2024-02-23 18:34:40 +08:00
#endif
2023-03-29 04:23:37 +08:00
}
2023-03-26 11:19:03 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run ( )
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-23 18:34:40 +08:00
if ( ! _isInit ) { Throw . Pipeline_MethodCalledBeforeInitialisation ( nameof ( Run ) ) ; }
if ( _isDestoryed ) { Throw . Pipeline_MethodCalledAfterDestruction ( nameof ( Run ) ) ; }
2023-03-26 11:19:03 +08:00
#endif
2023-12-06 18:58:06 +08:00
_runRunnerCache . Run ( ) ;
2023-03-26 11:19:03 +08:00
}
public void Destroy ( )
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-23 18:34:40 +08:00
if ( ! _isInit ) { Throw . Pipeline_MethodCalledBeforeInitialisation ( nameof ( Destroy ) ) ; }
2023-03-26 11:19:03 +08:00
#endif
2023-06-26 02:53:55 +08:00
if ( _isDestoryed )
2023-03-29 04:23:37 +08:00
{
2023-06-26 01:57:50 +08:00
EcsDebug . PrintWarning ( $"This {nameof(EcsPipeline)} has already been destroyed" ) ;
2023-03-29 04:23:37 +08:00
return ;
}
2023-03-26 11:19:03 +08:00
_isDestoryed = true ;
2024-02-26 08:31:35 +08:00
GetRunnerInstance < EcsDestroyRunner > ( ) . Destroy ( ) ;
2023-03-26 11:19:03 +08:00
}
#endregion
#region Builder
2024-03-07 07:48:18 +08:00
public static Builder New ( IConfigContainerWriter config = null )
2024-02-22 15:39:37 +08:00
{
return new Builder ( config ) ;
}
2023-03-26 11:19:03 +08:00
#endregion
}
2024-09-08 19:39:43 +08:00
#region EcsModule
2023-03-26 11:19:03 +08:00
public interface IEcsModule
{
2023-05-30 17:56:53 +08:00
void Import ( EcsPipeline . Builder b ) ;
2023-03-26 11:19:03 +08:00
}
2024-09-07 21:20:29 +08:00
public abstract class EcsModule : IEcsModule
{
public abstract void Import ( EcsPipeline . Builder b ) ;
}
public abstract class EcsModule < T > : IInjectionUnit
{
2024-09-08 19:41:09 +08:00
void IInjectionUnit . InitInjectionNode ( InjectionGraph nodes ) { nodes . AddNode < T > ( ) ; }
2024-09-07 21:20:29 +08:00
public EcsModule ( ) { if ( GetType ( ) ! = typeof ( T ) ) { Throw . UndefinedException ( ) ; } }
}
2024-09-08 19:39:43 +08:00
#endregion
2023-03-26 11:19:03 +08:00
2023-03-30 05:32:43 +08:00
#region Extensions
2023-06-22 14:31:13 +08:00
public static partial class EcsPipelineExtensions
2023-03-26 11:19:03 +08:00
{
2024-02-22 15:39:37 +08:00
public static bool IsNullOrDestroyed ( this EcsPipeline self )
2023-03-26 11:19:03 +08:00
{
2024-02-22 15:39:37 +08:00
return self = = null | | self . IsDestoryed ;
}
2024-02-22 22:16:03 +08:00
public static EcsPipeline . Builder Add ( this EcsPipeline . Builder self , IEnumerable < IEcsProcess > range , string layerName = null )
2024-02-22 15:39:37 +08:00
{
foreach ( var item in range )
{
self . Add ( item , layerName ) ;
}
2023-03-26 11:19:03 +08:00
return self ;
}
2024-02-22 22:16:03 +08:00
public static EcsPipeline . Builder AddUnique ( this EcsPipeline . Builder self , IEnumerable < IEcsProcess > range , string layerName = null )
2023-03-30 05:32:43 +08:00
{
2024-02-22 15:39:37 +08:00
foreach ( var item in range )
{
self . AddUnique ( item , layerName ) ;
}
2023-03-30 05:32:43 +08:00
return self ;
}
public static EcsPipeline BuildAndInit ( this EcsPipeline . Builder self )
2023-03-29 04:23:37 +08:00
{
2023-03-30 05:32:43 +08:00
EcsPipeline result = self . Build ( ) ;
2023-03-29 04:23:37 +08:00
result . Init ( ) ;
return result ;
}
2023-03-26 11:19:03 +08:00
}
2023-03-30 05:32:43 +08:00
#endregion
2024-02-22 15:39:37 +08:00
#region SystemsLayerMarkerSystem
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Black)]
2024-08-07 10:40:31 +08:00
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "An auxiliary type of system for dividing a pipeline into layers. This system is automatically added to the EcsPipeline.")]
2024-02-22 22:16:03 +08:00
public class SystemsLayerMarkerSystem : IEcsProcess
2024-02-22 15:39:37 +08:00
{
public readonly string name ;
2024-06-25 22:15:54 +08:00
public readonly string layerNameSpace ;
public readonly string layerName ;
public SystemsLayerMarkerSystem ( string name )
{
this . name = name ;
int indexof = name . LastIndexOf ( '.' ) ;
2024-06-25 23:35:51 +08:00
if ( indexof > 0 )
2024-06-25 22:15:54 +08:00
{
layerNameSpace = name . Substring ( 0 , indexof + 1 ) ;
layerName = name . Substring ( indexof + 1 ) ;
}
else
{
layerNameSpace = string . Empty ;
layerName = name ;
}
}
2024-06-24 22:06:02 +08:00
public override string ToString ( ) { return name ; }
2024-02-22 15:39:37 +08:00
}
#endregion
#region EcsProcess
2024-03-09 23:09:01 +08:00
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2024-02-22 15:39:37 +08:00
public readonly struct EcsProcessRaw : IEnumerable
{
private readonly Array _systems ;
2024-03-09 23:09:01 +08:00
#region Properties
2024-02-22 15:39:37 +08:00
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems . Length ; }
}
2024-02-22 22:16:03 +08:00
public IEcsProcess this [ int index ]
2024-02-22 15:39:37 +08:00
{
2024-02-22 22:16:03 +08:00
get { return ( IEcsProcess ) _systems . GetValue ( index ) ; }
2024-02-22 15:39:37 +08:00
}
2024-03-09 23:09:01 +08:00
#endregion
#region Constructors
2024-02-22 15:39:37 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcessRaw ( Array systems )
{
_systems = systems ;
}
2024-03-09 23:09:01 +08:00
#endregion
#region Enumerator
2024-02-22 15:39:37 +08:00
public IEnumerator GetEnumerator ( )
{
return _systems . GetEnumerator ( ) ;
}
2024-03-09 23:09:01 +08:00
#endregion
#region Internal
2024-02-22 15:39:37 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal T [ ] GetSystems_Internal < T > ( )
{
return ( T [ ] ) _systems ;
}
2024-03-09 23:09:01 +08:00
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private EcsProcessRaw _process ;
2024-05-01 13:38:08 +08:00
public IEnumerable < IEcsProcess > Systems
2024-03-09 23:09:01 +08:00
{
get
{
2024-05-01 13:38:08 +08:00
return _process . _systems . Cast < IEcsProcess > ( ) . ToArray ( ) ;
2024-03-09 23:09:01 +08:00
}
}
public int Count
{
get { return _process . Length ; }
}
public DebuggerProxy ( EcsProcessRaw process )
{
_process = process ;
}
}
#endregion
2024-02-22 15:39:37 +08:00
}
2024-03-09 23:09:01 +08:00
[DebuggerTypeProxy(typeof(EcsProcess<>.DebuggerProxy))]
2024-02-22 15:39:37 +08:00
public readonly struct EcsProcess < TProcess > : IReadOnlyCollection < TProcess >
2024-02-22 22:16:03 +08:00
where TProcess : IEcsProcess
2024-02-22 15:39:37 +08:00
{
public readonly static EcsProcess < TProcess > Empty = new EcsProcess < TProcess > ( Array . Empty < TProcess > ( ) ) ;
private readonly TProcess [ ] _systems ;
2024-03-09 23:09:01 +08:00
#region Properties
2024-02-22 15:39:37 +08:00
public bool IsNullOrEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems = = null | | _systems . Length < = 0 ; }
}
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems . Length ; }
}
int IReadOnlyCollection < TProcess > . Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems . Length ; }
}
public TProcess this [ int index ]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems [ index ] ; }
}
2024-03-09 23:09:01 +08:00
#endregion
#region Constructors
2024-02-22 15:39:37 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcess ( TProcess [ ] systems )
{
_systems = systems ;
}
2024-03-09 23:09:01 +08:00
#endregion
#region Converts
2024-02-22 15:39:37 +08:00
public static explicit operator EcsProcess < TProcess > ( EcsProcessRaw raw )
{
return new EcsProcess < TProcess > ( raw . GetSystems_Internal < TProcess > ( ) ) ;
}
public static implicit operator EcsProcessRaw ( EcsProcess < TProcess > process )
{
return new EcsProcessRaw ( process . _systems ) ;
}
2024-03-09 23:09:01 +08:00
#endregion
#region Enumerator
2024-02-22 15:39:37 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator ( ) { return new Enumerator ( _systems ) ; }
IEnumerator < TProcess > IEnumerable < TProcess > . GetEnumerator ( ) { return GetEnumerator ( ) ; }
IEnumerator IEnumerable . GetEnumerator ( ) { return GetEnumerator ( ) ; }
public struct Enumerator : IEnumerator < TProcess >
{
private readonly TProcess [ ] _systems ;
private int _index ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator ( TProcess [ ] systems )
{
_systems = systems ;
_index = - 1 ;
}
public TProcess Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems [ _index ] ; }
}
object IEnumerator . Current { get { return Current ; } }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext ( ) { return + + _index < _systems . Length ; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset ( ) { _index = - 1 ; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-09-07 17:18:35 +08:00
void IDisposable . Dispose ( ) { }
2024-02-22 15:39:37 +08:00
}
2024-03-09 23:09:01 +08:00
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private EcsProcess < TProcess > _process ;
2024-05-01 13:38:08 +08:00
public IEnumerable < IEcsProcess > Systems
2024-03-09 23:09:01 +08:00
{
get
{
2024-05-01 13:38:08 +08:00
return _process . _systems . Cast < IEcsProcess > ( ) . ToArray ( ) ;
2024-03-09 23:09:01 +08:00
}
}
public int Count
{
get { return _process . Length ; }
}
public DebuggerProxy ( EcsProcess < TProcess > process )
{
_process = process ;
}
2024-04-29 21:59:33 +08:00
2024-03-09 23:09:01 +08:00
}
#endregion
2024-02-22 15:39:37 +08:00
}
#endregion
}