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
2024-06-25 20:24:11 +08:00
public Builder Add ( IEcsProcess system , int? sortingOrder = null )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
return AddInternal ( system , string . Empty , sortingOrder , false ) ;
2024-06-24 22:06:02 +08:00
}
2024-06-25 20:24:11 +08:00
public Builder Add ( IEcsProcess system , string layerName , int? sortingOrder = null )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
return AddInternal ( system , layerName , sortingOrder , false ) ;
2024-06-24 22:06:02 +08:00
}
2024-06-25 20:24:11 +08:00
public Builder AddUnique ( IEcsProcess system , int? sortingOrder = null )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
return AddInternal ( system , string . Empty , sortingOrder , true ) ;
2024-06-24 22:06:02 +08:00
}
2024-06-25 20:24:11 +08:00
public Builder AddUnique ( IEcsProcess system , string layerName , int? sortingOrder = null )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
return AddInternal ( system , layerName , sortingOrder , true ) ;
2024-06-24 22:06:02 +08:00
}
2024-06-25 20:24:11 +08:00
private Builder AddInternal ( IEcsProcess system , string layerName , int? settedSortingOrder , bool isUnique )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
int sortingOrder ;
if ( settedSortingOrder . HasValue )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
sortingOrder = settedSortingOrder . Value ;
2024-06-24 22:06:02 +08:00
}
else
{
2024-06-25 20:24:11 +08:00
sortingOrder = system is IEcsSystemDefaultSortingOrder defaultSortingOrder ? defaultSortingOrder . SortingOrder : 0 ;
2024-06-24 22:06:02 +08:00
}
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 20:24:11 +08:00
list . Add ( system , sortingOrder , 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 )
{
2024-06-25 20:24:11 +08:00
//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 )
{
2024-06-25 20:24:11 +08:00
AddInternal ( otherSystem . system , otherPair . Key , otherSystem . sortOrder , otherSystem . isUnique ) ;
2024-06-25 15:31:25 +08:00
}
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 ;
2024-06-25 20:24:11 +08:00
private int _lastSortingOrder ;
public bool isSorted = true ;
2024-06-24 22:06:02 +08:00
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 20:24:11 +08:00
Add ( otherRecord . system , otherRecord . sortOrder , otherRecord . isUnique ) ;
2024-06-24 22:06:02 +08:00
}
}
2024-06-25 20:24:11 +08:00
public void Add ( IEcsProcess system , int sortingOrder , bool isUnique )
2024-06-24 22:06:02 +08:00
{
2024-06-25 20:24:11 +08:00
if ( recordsCount < = 1 )
{
_lastSortingOrder = sortingOrder ;
}
else if ( _lastSortingOrder ! = sortingOrder )
{
isSorted = false ;
}
2024-06-24 22:06:02 +08:00
if ( records . Length < = recordsCount )
{
Array . Resize ( ref records , recordsCount < < 1 ) ;
}
2024-06-25 20:24:11 +08:00
records [ recordsCount + + ] = new SystemRecord ( system , sortingOrder , 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 ) ;
2024-06-25 20:24:11 +08:00
isSorted = true ;
2024-06-24 22:06:02 +08:00
}
}
private readonly struct SystemRecord : IComparable < SystemRecord >
{
public readonly IEcsProcess system ;
2024-06-25 20:24:11 +08:00
public readonly int sortOrder ;
2024-06-25 15:31:25 +08:00
public readonly bool isUnique ;
2024-06-25 20:24:11 +08:00
public SystemRecord ( IEcsProcess system , int sortOrder , bool isUnique )
2024-06-24 22:06:02 +08:00
{
this . system = system ;
2024-06-25 20:24:11 +08:00
this . sortOrder = sortOrder ;
2024-06-25 15:31:25 +08:00
this . isUnique = isUnique ;
2024-06-24 22:06:02 +08:00
}
2024-06-25 20:24:11 +08:00
public int CompareTo ( SystemRecord other )
{
int c = sortOrder - other . sortOrder ;
return c = = 0 ? 0 : c ;
}
2024-06-24 22:06:02 +08:00
}
#endregion
}
}
}