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 ;
using System.Collections.ObjectModel ;
2023-05-07 00:50:02 +08:00
using System.Linq ;
2023-03-26 11:19:03 +08:00
using System.Runtime.CompilerServices ;
namespace DCFApixels.DragonECS
{
2023-03-30 05:32:43 +08:00
public sealed class EcsPipeline
2023-03-26 11:19:03 +08:00
{
private IEcsSystem [ ] _allSystems ;
private Dictionary < Type , IEcsRunner > _runners ;
2023-05-07 00:50:02 +08:00
private IEcsRunProcess _runRunnerCache ;
2023-03-26 11:19:03 +08:00
private ReadOnlyCollection < IEcsSystem > _allSystemsSealed ;
private ReadOnlyDictionary < Type , IEcsRunner > _allRunnersSealed ;
2023-03-29 04:23:37 +08:00
private bool _isInit ;
2023-03-26 11:19:03 +08:00
private bool _isDestoryed ;
#region Properties
public ReadOnlyCollection < IEcsSystem > AllSystems = > _allSystemsSealed ;
public ReadOnlyDictionary < Type , IEcsRunner > AllRunners = > _allRunnersSealed ;
2023-04-01 20:45:37 +08:00
public bool IsInit = > _isInit ;
2023-03-26 11:19:03 +08:00
public bool IsDestoryed = > _isDestoryed ;
#endregion
#region Constructors
2023-03-30 05:32:43 +08:00
private EcsPipeline ( IEcsSystem [ ] systems )
2023-03-26 11:19:03 +08:00
{
_allSystems = systems ;
_runners = new Dictionary < Type , IEcsRunner > ( ) ;
_allSystemsSealed = new ReadOnlyCollection < IEcsSystem > ( _allSystems ) ;
_allRunnersSealed = new ReadOnlyDictionary < Type , IEcsRunner > ( _runners ) ;
2023-03-29 04:23:37 +08:00
_isInit = false ;
2023-03-26 11:19:03 +08:00
_isDestoryed = false ;
}
#endregion
#region Runners
public T GetRunner < T > ( ) where T : IEcsSystem
{
Type type = typeof ( T ) ;
if ( _runners . TryGetValue ( type , out IEcsRunner result ) )
return ( T ) result ;
2023-03-29 15:09:00 +08:00
result = ( IEcsRunner ) EcsRunner < T > . Instantiate ( this ) ;
2023-03-26 11:19:03 +08:00
_runners . Add ( type , result ) ;
return ( T ) result ;
}
2023-03-30 05:32:43 +08:00
internal void OnRunnerDestroy ( IEcsRunner runner )
{
_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-03-30 05:32:43 +08:00
EcsDebug . Print ( "[Warning]" , $"This {nameof(EcsPipeline)} has already been initialized" ) ;
2023-03-29 04:23:37 +08:00
return ;
}
_isInit = true ;
2023-03-30 11:17:17 +08:00
var ecsPipelineInjectRunner = GetRunner < IEcsInject < EcsPipeline > > ( ) ;
ecsPipelineInjectRunner . Inject ( this ) ;
EcsRunner . Destroy ( ecsPipelineInjectRunner ) ;
2023-05-07 00:50:02 +08:00
var preInitRunner = GetRunner < IEcsPreInitProcess > ( ) ;
2023-03-30 11:17:17 +08:00
preInitRunner . PreInit ( this ) ;
EcsRunner . Destroy ( preInitRunner ) ;
2023-05-07 00:50:02 +08:00
var initRunner = GetRunner < IEcsInitProcess > ( ) ;
2023-03-30 11:17:17 +08:00
initRunner . Init ( this ) ;
EcsRunner . Destroy ( initRunner ) ;
2023-03-29 04:23:37 +08:00
2023-05-07 00:50:02 +08:00
_runRunnerCache = GetRunner < IEcsRunProcess > ( ) ;
2023-03-29 04:23:37 +08:00
}
2023-03-26 11:19:03 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run ( )
{
2023-05-26 05:13:11 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DISABLE_DRAGONECS_ASSERT_CHEKS
2023-03-29 04:23:37 +08:00
CheckBeforeInitForMethod ( nameof ( Run ) ) ;
2023-03-26 11:19:03 +08:00
CheckAfterDestroyForMethod ( nameof ( Run ) ) ;
#endif
_runRunnerCache . Run ( this ) ;
}
public void Destroy ( )
{
2023-05-26 05:13:11 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DISABLE_DRAGONECS_ASSERT_CHEKS
2023-03-29 04:23:37 +08:00
CheckBeforeInitForMethod ( nameof ( Run ) ) ;
2023-03-26 11:19:03 +08:00
#endif
2023-03-29 04:23:37 +08:00
if ( _isDestoryed = = true )
{
2023-03-30 05:32:43 +08:00
EcsDebug . Print ( "[Warning]" , $"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 ;
2023-05-07 00:50:02 +08:00
GetRunner < IEcsDestroyProcess > ( ) . Destroy ( this ) ;
2023-03-26 11:19:03 +08:00
}
#endregion
#region StateChecks
2023-05-26 05:13:11 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DISABLE_DRAGONECS_ASSERT_CHEKS
2023-03-29 04:23:37 +08:00
private void CheckBeforeInitForMethod ( string methodName )
{
if ( ! _isInit )
2023-03-30 05:32:43 +08:00
throw new MethodAccessException ( $"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}" ) ;
2023-03-29 04:23:37 +08:00
}
private void CheckAfterInitForMethod ( string methodName )
{
if ( _isInit )
2023-03-30 05:32:43 +08:00
throw new MethodAccessException ( $"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}" ) ;
2023-03-29 04:23:37 +08:00
}
2023-03-26 11:19:03 +08:00
private void CheckAfterDestroyForMethod ( string methodName )
{
if ( _isDestoryed )
2023-03-30 05:32:43 +08:00
throw new MethodAccessException ( $"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}" ) ;
2023-03-26 11:19:03 +08:00
}
#endif
#endregion
#region Builder
2023-05-28 06:35:33 +08:00
public static Builder New ( ) = > new Builder ( ) ;
2023-03-26 11:19:03 +08:00
public class Builder
{
private const int KEYS_CAPACITY = 4 ;
2023-03-30 05:32:43 +08:00
private HashSet < Type > _uniqueTypes ;
2023-05-07 00:50:02 +08:00
private readonly Dictionary < string , List < IEcsSystem > > _systems ;
private readonly string _basicLayer ;
public readonly LayerList Layers ;
2023-03-26 11:19:03 +08:00
public Builder ( )
{
2023-05-07 00:50:02 +08:00
_basicLayer = EcsConsts . BASIC_LAYER ;
Layers = new LayerList ( this , _basicLayer ) ;
Layers . Insert ( EcsConsts . BASIC_LAYER , EcsConsts . PRE_BEGIN_LAYER , EcsConsts . BEGIN_LAYER ) ;
Layers . InsertAfter ( EcsConsts . BASIC_LAYER , EcsConsts . END_LAYER , EcsConsts . POST_END_LAYER ) ;
_uniqueTypes = new HashSet < Type > ( ) ;
_systems = new Dictionary < string , List < IEcsSystem > > ( KEYS_CAPACITY ) ;
2023-03-26 11:19:03 +08:00
}
2023-05-07 00:50:02 +08:00
public Builder Add ( IEcsSystem system , string layerName = null )
2023-03-30 05:32:43 +08:00
{
2023-05-07 00:50:02 +08:00
AddInternal ( system , layerName , false ) ;
2023-03-30 05:32:43 +08:00
return this ;
}
2023-05-07 00:50:02 +08:00
public Builder AddUnique ( IEcsSystem system , string layerName = null )
2023-03-30 05:32:43 +08:00
{
2023-05-07 00:50:02 +08:00
AddInternal ( system , layerName , true ) ;
2023-03-30 05:32:43 +08:00
return this ;
}
2023-05-23 01:47:28 +08:00
public Builder Remove < TSystem > ( )
{
_uniqueTypes . Remove ( typeof ( TSystem ) ) ;
foreach ( var list in _systems . Values )
list . RemoveAll ( o = > o is TSystem ) ;
return this ;
}
2023-05-07 00:50:02 +08:00
private void AddInternal ( IEcsSystem system , string layerName , bool isUnique )
2023-03-26 11:19:03 +08:00
{
2023-05-07 00:50:02 +08:00
if ( layerName = = null ) layerName = _basicLayer ;
2023-03-26 11:19:03 +08:00
List < IEcsSystem > list ;
2023-05-07 00:50:02 +08:00
if ( ! _systems . TryGetValue ( layerName , out list ) )
2023-03-26 11:19:03 +08:00
{
2023-05-28 05:53:08 +08:00
list = new List < IEcsSystem > { new SystemsLayerMarkerSystem ( layerName . ToString ( ) ) } ;
2023-05-07 00:50:02 +08:00
_systems . Add ( layerName , list ) ;
2023-03-26 11:19:03 +08:00
}
2023-03-30 05:32:43 +08:00
if ( ( _uniqueTypes . Add ( system . GetType ( ) ) = = false & & isUnique ) )
return ;
2023-03-26 11:19:03 +08:00
list . Add ( system ) ;
2023-05-07 00:50:02 +08:00
if ( system is IEcsModule module ) //если система одновременно явялется и системой и модулем то за один Add будет вызван Add и AddModule
AddModule ( module ) ;
2023-03-26 11:19:03 +08:00
}
2023-04-26 16:45:37 +08:00
public Builder AddModule ( IEcsModule module )
2023-03-26 11:19:03 +08:00
{
module . ImportSystems ( this ) ;
return this ;
}
2023-05-07 00:50:02 +08:00
public EcsPipeline Build ( )
2023-03-26 11:19:03 +08:00
{
2023-05-07 00:50:02 +08:00
Add ( new DeleteEmptyEntitesSystem ( ) , EcsConsts . POST_END_LAYER ) ;
List < IEcsSystem > result = new List < IEcsSystem > ( 32 ) ;
List < IEcsSystem > basicBlockList = _systems [ _basicLayer ] ;
foreach ( var item in _systems )
{
2023-05-30 00:13:05 +08:00
if ( ! Layers . Contains ( item . Key ) )
2023-05-07 00:50:02 +08:00
basicBlockList . AddRange ( item . Value ) ;
}
foreach ( var item in Layers )
2023-04-26 16:45:37 +08:00
{
2023-05-07 00:50:02 +08:00
if ( _systems . TryGetValue ( item , out var list ) )
result . AddRange ( list ) ;
2023-04-26 16:45:37 +08:00
}
2023-05-07 00:50:02 +08:00
return new EcsPipeline ( result . ToArray ( ) ) ;
2023-04-26 16:45:37 +08:00
}
2023-05-07 00:50:02 +08:00
public class LayerList : IEnumerable < string >
2023-03-26 11:19:03 +08:00
{
2023-05-07 00:50:02 +08:00
private const string ADD_LAYER = nameof ( ADD_LAYER ) ; // автоматический слой нужный только для метода Add
private Builder _source ;
private List < string > _layers ;
private string _basicLayerName ;
public LayerList ( Builder source , string basicLayerName )
2023-03-26 11:19:03 +08:00
{
2023-05-07 00:50:02 +08:00
_source = source ;
_layers = new List < string > ( 16 ) { basicLayerName , ADD_LAYER } ;
_basicLayerName = basicLayerName ;
2023-03-26 11:19:03 +08:00
}
2023-05-07 00:50:02 +08:00
public Builder Add ( string newLayer ) = > Insert ( ADD_LAYER , newLayer ) ;
public Builder Insert ( string targetLayer , string newLayer )
{
2023-05-30 00:13:05 +08:00
if ( Contains ( newLayer ) ) return _source ;
2023-03-26 11:19:03 +08:00
2023-05-07 00:50:02 +08:00
int index = _layers . IndexOf ( targetLayer ) ;
if ( index < 0 )
throw new KeyNotFoundException ( $"Layer {targetLayer} not found" ) ;
_layers . Insert ( index , newLayer ) ;
return _source ;
}
public Builder InsertAfter ( string targetLayer , string newLayer )
{
2023-05-30 00:13:05 +08:00
if ( Contains ( newLayer ) ) return _source ;
2023-03-26 11:19:03 +08:00
2023-05-07 00:50:02 +08:00
if ( targetLayer = = _basicLayerName ) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER ;
2023-03-26 11:19:03 +08:00
2023-05-07 00:50:02 +08:00
int index = _layers . IndexOf ( targetLayer ) ;
if ( index < 0 )
throw new KeyNotFoundException ( $"Layer {targetLayer} not found" ) ;
if ( + + index > = _layers . Count )
_layers . Add ( newLayer ) ;
else
_layers . Insert ( index , newLayer ) ;
return _source ;
}
public Builder Move ( string targetLayer , string movingLayer )
2023-03-26 11:19:03 +08:00
{
2023-05-07 00:50:02 +08:00
_layers . Remove ( movingLayer ) ;
return Insert ( targetLayer , movingLayer ) ;
2023-03-26 11:19:03 +08:00
}
2023-05-07 00:50:02 +08:00
public Builder MoveAfter ( string targetLayer , string movingLayer )
2023-03-26 11:19:03 +08:00
{
2023-05-07 00:50:02 +08:00
if ( targetLayer = = _basicLayerName ) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER ;
_layers . Remove ( movingLayer ) ;
return InsertAfter ( targetLayer , movingLayer ) ;
2023-03-26 11:19:03 +08:00
}
2023-05-07 00:50:02 +08:00
public Builder Add ( params string [ ] newLayers ) = > Insert ( ADD_LAYER , newLayers ) ;
public Builder Insert ( string targetLayer , params string [ ] newLayers )
{
int index = _layers . IndexOf ( targetLayer ) ;
if ( index < 0 )
throw new KeyNotFoundException ( $"Layer {targetLayer} not found" ) ;
2023-05-30 00:13:05 +08:00
_layers . InsertRange ( index , newLayers . Where ( o = > ! Contains ( o ) ) ) ;
2023-05-07 00:50:02 +08:00
return _source ;
}
public Builder InsertAfter ( string targetLayer , params string [ ] newLayers )
{
int index = _layers . IndexOf ( targetLayer ) ;
if ( index < 0 )
throw new KeyNotFoundException ( $"Layer {targetLayer} not found" ) ;
if ( targetLayer = = _basicLayerName ) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER ;
if ( + + index > = _layers . Count )
2023-05-30 00:13:05 +08:00
_layers . AddRange ( newLayers . Where ( o = > ! Contains ( o ) ) ) ;
2023-05-07 00:50:02 +08:00
else
2023-05-30 00:13:05 +08:00
_layers . InsertRange ( index , newLayers . Where ( o = > ! Contains ( o ) ) ) ;
2023-05-07 00:50:02 +08:00
return _source ;
}
public Builder Move ( string targetLayer , params string [ ] movingLayers )
{
foreach ( var movingLayer in movingLayers )
_layers . Remove ( movingLayer ) ;
return Insert ( targetLayer , movingLayers ) ;
}
public Builder MoveAfter ( string targetLayer , params string [ ] movingLayers )
{
if ( targetLayer = = _basicLayerName ) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER ;
foreach ( var movingLayer in movingLayers )
_layers . Remove ( movingLayer ) ;
return InsertAfter ( targetLayer , movingLayers ) ;
}
2023-05-30 00:13:05 +08:00
public bool Contains ( string layer ) = > _layers . Contains ( layer ) ;
2023-05-07 00:50:02 +08:00
public List < string > . Enumerator GetEnumerator ( ) = > _layers . GetEnumerator ( ) ;
IEnumerator < string > IEnumerable < string > . GetEnumerator ( ) = > _layers . GetEnumerator ( ) ;
IEnumerator IEnumerable . GetEnumerator ( ) = > _layers . GetEnumerator ( ) ;
2023-03-26 11:19:03 +08:00
}
}
#endregion
}
public interface IEcsModule
{
2023-05-26 00:24:38 +08:00
void ImportSystems ( EcsPipeline . Builder b ) ;
2023-03-26 11:19:03 +08:00
}
2023-03-30 05:32:43 +08:00
#region Extensions
2023-04-26 16:45:37 +08:00
public static class EcsPipelineExtensions
2023-03-26 11:19:03 +08:00
{
2023-05-26 00:24:38 +08:00
public static bool IsNullOrDestroyed ( this EcsPipeline self ) = > self = = null | | self . IsDestoryed ;
2023-05-07 00:50:02 +08:00
public static EcsPipeline . Builder Add ( this EcsPipeline . Builder self , IEnumerable < IEcsSystem > range , string layerName = null )
2023-03-26 11:19:03 +08:00
{
2023-05-26 00:24:38 +08:00
foreach ( var item in range ) self . Add ( item , layerName ) ;
2023-03-26 11:19:03 +08:00
return self ;
}
2023-05-07 00:50:02 +08:00
public static EcsPipeline . Builder AddUnique ( this EcsPipeline . Builder self , IEnumerable < IEcsSystem > range , string layerName = null )
2023-03-30 05:32:43 +08:00
{
2023-05-26 00:24:38 +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
2023-03-26 11:19:03 +08:00
}