2024-06-24 22:06:02 +08:00
using DCFApixels.DragonECS.RunnersCore ;
using System ;
using System.Collections ;
using System.Collections.Generic ;
using System.Linq ;
namespace DCFApixels.DragonECS
{
public sealed partial class EcsPipeline
{
public class Builder : IEcsModule
{
private const int KEYS_CAPACITY = 4 ;
private const string BASIC_LAYER = EcsConsts . BASIC_LAYER ;
private readonly HashSet < Type > _uniqueTypes = new HashSet < Type > ( 32 ) ;
private readonly Dictionary < string , SystemsList > _systems = new Dictionary < string , SystemsList > ( KEYS_CAPACITY ) ;
private readonly List < InitDeclaredRunner > _initDeclaredRunners = new List < InitDeclaredRunner > ( 4 ) ;
public readonly LayerList Layers ;
public readonly Injector . Builder Injector ;
public readonly Configurator Configs ;
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
private EcsProfilerMarker _buildBarker = new EcsProfilerMarker ( "EcsPipeline.Build" ) ;
#endif
#region Constructors
public Builder ( IConfigContainerWriter config = null )
{
if ( config = = null ) { config = new ConfigContainer ( ) ; }
Configs = new Configurator ( config , this ) ;
Injector = new Injector . Builder ( this ) ;
Injector . AddNode < object > ( ) ;
Injector . AddNode < EcsWorld > ( ) ;
Injector . AddNode < EcsAspect > ( ) ;
Injector . AddNode < EcsPipeline > ( ) ;
Layers = new LayerList ( this , BASIC_LAYER ) ;
Layers . Insert ( EcsConsts . BASIC_LAYER , EcsConsts . PRE_BEGIN_LAYER , EcsConsts . BEGIN_LAYER ) ;
Layers . InsertAfter ( EcsConsts . BASIC_LAYER , EcsConsts . END_LAYER , EcsConsts . POST_END_LAYER ) ;
}
#endregion
#region Add
public Builder Add ( IEcsProcess system , int? order = null )
{
return AddInternal ( system , string . Empty , order , false ) ;
}
public Builder Add ( IEcsProcess system , string layerName , int? order = null )
{
return AddInternal ( system , layerName , order , false ) ;
}
public Builder AddUnique ( IEcsProcess system , int? order = null )
{
return AddInternal ( system , string . Empty , order , true ) ;
}
public Builder AddUnique ( IEcsProcess system , string layerName , int? order = null )
{
return AddInternal ( system , layerName , order , true ) ;
}
private Builder AddInternal ( IEcsProcess system , string layerName , int? settedOrder , bool isUnique )
{
int order ;
if ( settedOrder . HasValue )
{
order = settedOrder . Value ;
}
else
{
order = system is IEcsSystemDefaultOrder defaultOrder ? defaultOrder . Order : 0 ;
}
if ( string . IsNullOrEmpty ( layerName ) )
{
layerName = system is IEcsSystemDefaultLayer defaultLayer ? defaultLayer . Layer : BASIC_LAYER ;
}
if ( ! _systems . TryGetValue ( layerName , out SystemsList list ) )
{
list = new SystemsList ( layerName ) ;
_systems . Add ( layerName , list ) ;
}
if ( _uniqueTypes . Add ( system . GetType ( ) ) = = false & & isUnique )
{
return this ;
}
2024-06-25 15:31:25 +08:00
list . Add ( system , order , isUnique ) ;
2024-06-24 22:06:02 +08:00
if ( system is IEcsModule module ) //если система одновременно явялется и системой и модулем то за один Add будет вызван Add и AddModule
{
AddModule ( module ) ;
}
return this ;
}
#endregion
#region Add other
public Builder AddModule ( IEcsModule module )
{
module . Import ( this ) ;
return this ;
}
public Builder AddRunner < TRunner > ( ) where TRunner : EcsRunner , IEcsRunner , new ( )
{
_initDeclaredRunners . Add ( new InitDeclaredRunner < TRunner > ( ) ) ;
return this ;
}
void IEcsModule . Import ( Builder into )
{
into . MergeWith ( this ) ;
}
private void MergeWith ( Builder other )
{
Injector . Add ( other . Injector ) ;
foreach ( var declaredRunners in other . _initDeclaredRunners )
{
_initDeclaredRunners . Add ( declaredRunners ) ;
}
foreach ( var config in other . Configs . Instance . GetAllConfigs ( ) )
{
Configs . Instance . Set ( config . Key , config . Value ) ;
}
Layers . MergeWith ( other . Layers ) ;
foreach ( var otherPair in other . _systems )
{
if ( _systems . TryGetValue ( otherPair . Key , out SystemsList selfList ) = = false )
{
selfList = new SystemsList ( otherPair . Key ) ;
_systems . Add ( otherPair . Key , selfList ) ;
}
2024-06-25 15:31:25 +08:00
//selfList.AddList(otherPair.Value);
foreach ( var otherSystem in otherPair . Value . Records )
{
AddInternal ( otherSystem . system , otherPair . Key , otherSystem . order , otherSystem . isUnique ) ;
}
2024-06-24 22:06:02 +08:00
}
//TODO добавить проверку уникальных систем
//сливать множество уникальных нужно после слияния систем
2024-06-25 15:31:25 +08:00
//_uniqueTypes.UnionWith(other._uniqueTypes);
2024-06-24 22:06:02 +08:00
}
#endregion
#region Remove
public Builder Remove < TSystem > ( )
{
_uniqueTypes . Remove ( typeof ( TSystem ) ) ;
foreach ( var list in _systems . Values )
{
list . RemoveAll < TSystem > ( ) ;
}
return this ;
}
#endregion
#region Build
public EcsPipeline Build ( )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
_buildBarker . Begin ( ) ;
#endif
SystemsList basicBlockList ;
if ( _systems . TryGetValue ( BASIC_LAYER , out basicBlockList ) = = false )
{
basicBlockList = new SystemsList ( BASIC_LAYER ) ;
_systems . Add ( BASIC_LAYER , basicBlockList ) ;
}
int allSystemsLength = 0 ;
foreach ( var item in _systems )
{
if ( item . Key = = BASIC_LAYER )
{
continue ;
}
if ( ! Layers . Contains ( item . Key ) )
{
basicBlockList . AddList ( item . Value ) ;
}
else
{
allSystemsLength + = item . Value . recordsCount ;
}
item . Value . Sort ( ) ;
}
allSystemsLength + = basicBlockList . recordsCount ;
basicBlockList . Sort ( ) ;
IEcsProcess [ ] allSystems = new IEcsProcess [ allSystemsLength ] ;
{
int i = 0 ;
foreach ( var item in Layers )
{
if ( _systems . TryGetValue ( item , out var list ) )
{
for ( int j = 0 ; j < list . recordsCount ; j + + )
{
allSystems [ i + + ] = list . records [ j ] . system ;
}
}
}
}
EcsPipeline pipeline = new EcsPipeline ( Configs . Instance . GetContainer ( ) , Injector , allSystems ) ;
foreach ( var item in _initDeclaredRunners )
{
item . Declare ( pipeline ) ;
}
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
_buildBarker . End ( ) ;
#endif
return pipeline ;
}
#endregion
#region InitDeclaredRunner
private abstract class InitDeclaredRunner
{
public abstract void Declare ( EcsPipeline pipeline ) ;
}
private class InitDeclaredRunner < T > : InitDeclaredRunner where T : EcsRunner , IEcsRunner , new ( )
{
public override void Declare ( EcsPipeline pipeline )
{
pipeline . GetRunnerInstance < T > ( ) ;
}
}
#endregion
#region Configurator
public class Configurator
{
private readonly IConfigContainerWriter _configs ;
private readonly Builder _builder ;
public Configurator ( IConfigContainerWriter configs , Builder builder )
{
_configs = configs ;
_builder = builder ;
}
public IConfigContainerWriter Instance
{
get { return _configs ; }
}
public Builder Set < T > ( T value )
{
_configs . Set ( value ) ;
return _builder ;
}
}
#endregion
#region LayerList
public class LayerList : IEnumerable < string >
{
private const string ADD_LAYER = nameof ( ADD_LAYER ) ; // автоматический слой нужный только для метода Add
private Builder _source ;
private List < string > _layers ;
private string _basicLayerName ;
public int Count
{
get { return _layers . Count ; }
}
public LayerList ( Builder source , string basicLayerName )
{
_source = source ;
_layers = new List < string > ( 16 ) { basicLayerName , ADD_LAYER } ;
_basicLayerName = basicLayerName ;
}
public Builder Add ( string newLayer ) { return Insert ( ADD_LAYER , newLayer ) ; }
public Builder Insert ( string targetLayer , string newLayer )
{
if ( Contains ( newLayer ) ) { return _source ; }
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 )
{
if ( Contains ( newLayer ) ) { return _source ; }
if ( targetLayer = = _basicLayerName ) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
{
targetLayer = ADD_LAYER ;
}
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 )
{
_layers . Remove ( movingLayer ) ;
return Insert ( targetLayer , movingLayer ) ;
}
public Builder MoveAfter ( string targetLayer , string movingLayer )
{
if ( targetLayer = = _basicLayerName ) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
{
targetLayer = ADD_LAYER ;
}
_layers . Remove ( movingLayer ) ;
return InsertAfter ( targetLayer , movingLayer ) ;
}
public Builder Add ( params string [ ] newLayers ) { return 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" ) ;
}
_layers . InsertRange ( index , newLayers . Where ( o = > ! Contains ( o ) ) ) ;
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 )
{
_layers . AddRange ( newLayers . Where ( o = > ! Contains ( o ) ) ) ;
}
else
{
_layers . InsertRange ( index , newLayers . Where ( o = > ! Contains ( o ) ) ) ;
}
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 ) ;
}
public void MergeWith ( LayerList other )
{
HashSet < string > seen = new HashSet < string > ( ) ;
List < string > result = new List < string > ( ) ;
List < string > listA = _layers ;
List < string > listB = other . _layers ;
foreach ( string item in listA )
{
seen . Add ( item ) ;
}
foreach ( string item in listB )
{
if ( seen . Add ( item ) = = false )
{
seen . Remove ( item ) ;
}
}
int i = 0 , j = 0 ;
while ( i < listA . Count | | j < listB . Count )
{
while ( i < listA . Count & & seen . Contains ( listA [ i ] ) )
{
result . Add ( listA [ i ] ) ;
i + + ;
}
while ( j < listB . Count & & seen . Contains ( listB [ j ] ) )
{
result . Add ( listB [ j ] ) ;
j + + ;
}
if ( i < listA . Count ) { i + + ; }
if ( j < listB . Count )
{
result . Add ( listB [ j ] ) ;
j + + ;
}
}
_layers = result ;
}
public bool Contains ( string layer ) { return _layers . Contains ( layer ) ; }
public List < string > . Enumerator GetEnumerator ( ) { return _layers . GetEnumerator ( ) ; }
IEnumerator < string > IEnumerable < string > . GetEnumerator ( ) { return _layers . GetEnumerator ( ) ; }
IEnumerator IEnumerable . GetEnumerator ( ) { return _layers . GetEnumerator ( ) ; }
}
#endregion
#region SystemsList
private class SystemsList
{
public SystemRecord [ ] records = new SystemRecord [ 32 ] ;
public int recordsCount = 0 ;
public ReadOnlySpan < SystemRecord > Records { get { return new ReadOnlySpan < SystemRecord > ( records , 1 , recordsCount - 1 ) ; } }
public SystemsList ( string layerName )
{
2024-06-25 15:31:25 +08:00
Add ( new SystemsLayerMarkerSystem ( layerName ) , int . MinValue , false ) ;
2024-06-24 22:06:02 +08:00
}
public void AddList ( SystemsList other )
{
for ( int i = 1 ; i < other . recordsCount ; i + + )
{
var otherRecord = other . records [ i ] ;
2024-06-25 15:31:25 +08:00
Add ( otherRecord . system , otherRecord . order , otherRecord . isUnique ) ;
2024-06-24 22:06:02 +08:00
}
}
2024-06-25 15:31:25 +08:00
public void Add ( IEcsProcess system , int order , bool isUnique )
2024-06-24 22:06:02 +08:00
{
if ( records . Length < = recordsCount )
{
Array . Resize ( ref records , recordsCount < < 1 ) ;
}
2024-06-25 15:31:25 +08:00
records [ recordsCount + + ] = new SystemRecord ( system , order , isUnique ) ;
2024-06-24 22:06:02 +08:00
}
public void RemoveAll < T > ( )
{
2024-06-25 15:31:25 +08:00
//for (int i = 0; i < recordsCount; i++)
//{
// if (records[i].system is T)
// {
// records[i] = records[--recordsCount];
// }
//}
int freeIndex = 0 ;
while ( freeIndex < recordsCount & & ( records [ freeIndex ] . system is T ) = = false ) { freeIndex + + ; }
if ( freeIndex > = recordsCount ) { return ; }
int current = freeIndex + 1 ;
while ( current < recordsCount )
2024-06-24 22:06:02 +08:00
{
2024-06-25 15:31:25 +08:00
while ( current < recordsCount & & ( records [ current ] . system is T ) ) { current + + ; }
if ( current < recordsCount )
2024-06-24 22:06:02 +08:00
{
2024-06-25 15:31:25 +08:00
records [ freeIndex + + ] = records [ current + + ] ;
2024-06-24 22:06:02 +08:00
}
}
2024-06-25 15:31:25 +08:00
recordsCount = freeIndex ;
2024-06-24 22:06:02 +08:00
}
public void Sort ( )
{
//Игнорирую первую систему, так как это чисто система с названием слоя
Array . Sort ( records , 1 , recordsCount - 1 ) ;
}
}
private readonly struct SystemRecord : IComparable < SystemRecord >
{
public readonly IEcsProcess system ;
public readonly int order ;
2024-06-25 15:31:25 +08:00
public readonly bool isUnique ;
public SystemRecord ( IEcsProcess system , int order , bool isUnique )
2024-06-24 22:06:02 +08:00
{
this . system = system ;
this . order = order ;
2024-06-25 15:31:25 +08:00
this . isUnique = isUnique ;
2024-06-24 22:06:02 +08:00
}
public int CompareTo ( SystemRecord other ) { return order - other . order ; }
}
#endregion
}
}
}