mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 01:44:35 +08:00
update EcsPipeline.Builder
add system orders Split EcsPipeline.cs into EcsPipeline.cs and EcsPipeline.Builder.cs Add system orders to EcsPipeline.Builder Implement IEcsModule interface for EcsPipeline.Builder
This commit is contained in:
parent
e2feab383c
commit
469eea16bb
489
src/EcsPipeline.Builder.cs
Normal file
489
src/EcsPipeline.Builder.cs
Normal file
@ -0,0 +1,489 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
list.Add(system, order);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
selfList.AddList(otherPair.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO добавить проверку уникальных систем
|
||||||
|
//сливать множество уникальных нужно после слияния систем
|
||||||
|
_uniqueTypes.UnionWith(other._uniqueTypes);
|
||||||
|
|
||||||
|
}
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
Add(new SystemsLayerMarkerSystem(layerName), int.MinValue);
|
||||||
|
}
|
||||||
|
public void AddList(SystemsList other)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < other.recordsCount; i++)
|
||||||
|
{
|
||||||
|
var otherRecord = other.records[i];
|
||||||
|
Add(otherRecord.system, otherRecord.order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Add(IEcsProcess system, int order)
|
||||||
|
{
|
||||||
|
if (records.Length <= recordsCount)
|
||||||
|
{
|
||||||
|
Array.Resize(ref records, recordsCount << 1);
|
||||||
|
}
|
||||||
|
records[recordsCount++] = new SystemRecord(system, order);
|
||||||
|
}
|
||||||
|
public void RemoveAll<T>()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < recordsCount; i++)
|
||||||
|
{
|
||||||
|
if (records[i].system is T)
|
||||||
|
{
|
||||||
|
records[i] = records[--recordsCount];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Sort()
|
||||||
|
{
|
||||||
|
//Игнорирую первую систему, так как это чисто система с названием слоя
|
||||||
|
Array.Sort(records, 1, recordsCount - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private readonly struct SystemRecord : IComparable<SystemRecord>
|
||||||
|
{
|
||||||
|
public readonly IEcsProcess system;
|
||||||
|
public readonly int order;
|
||||||
|
public SystemRecord(IEcsProcess system, int order)
|
||||||
|
{
|
||||||
|
this.system = system;
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
public int CompareTo(SystemRecord other) { return order - other.order; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,8 +25,15 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
[MetaColor(MetaColor.DragonRose)]
|
[MetaColor(MetaColor.DragonRose)]
|
||||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
|
||||||
|
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||||
|
public interface IEcsSystemDefaultOrder : IEcsProcess
|
||||||
|
{
|
||||||
|
int Order { get; }
|
||||||
|
}
|
||||||
|
[MetaColor(MetaColor.DragonRose)]
|
||||||
|
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
|
||||||
[MetaDescription(EcsConsts.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.")]
|
[MetaDescription(EcsConsts.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.")]
|
||||||
public sealed class EcsPipeline
|
public sealed partial class EcsPipeline
|
||||||
{
|
{
|
||||||
private readonly IConfigContainer _configs;
|
private readonly IConfigContainer _configs;
|
||||||
private Injector.Builder _injectorBuilder;
|
private Injector.Builder _injectorBuilder;
|
||||||
@ -204,265 +211,6 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
return new Builder(config);
|
return new Builder(config);
|
||||||
}
|
}
|
||||||
public class Builder
|
|
||||||
{
|
|
||||||
private const int KEYS_CAPACITY = 4;
|
|
||||||
private HashSet<Type> _uniqueTypes;
|
|
||||||
private readonly Dictionary<string, List<IEcsProcess>> _systems;
|
|
||||||
private readonly string _basicLayer;
|
|
||||||
public readonly LayerList Layers;
|
|
||||||
private readonly Configurator _configurator;
|
|
||||||
private readonly Injector.Builder _injector;
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
private EcsProfilerMarker _buildBarker = new EcsProfilerMarker("EcsPipeline.Build");
|
|
||||||
#endif
|
|
||||||
private List<InitDeclaredRunner> _initDeclaredRunners = new List<InitDeclaredRunner>(4);
|
|
||||||
|
|
||||||
public Configurator Configs
|
|
||||||
{
|
|
||||||
get { return _configurator; }
|
|
||||||
}
|
|
||||||
public Injector.Builder Injector
|
|
||||||
{
|
|
||||||
get { return _injector; }
|
|
||||||
}
|
|
||||||
public Builder(IConfigContainerWriter config = null)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
_buildBarker.Begin();
|
|
||||||
#endif
|
|
||||||
if (config == null) { config = new ConfigContainer(); }
|
|
||||||
_configurator = new Configurator(config, this);
|
|
||||||
|
|
||||||
_injector = new Injector.Builder(this);
|
|
||||||
_injector.AddNode<object>();
|
|
||||||
_injector.AddNode<EcsWorld>();
|
|
||||||
_injector.AddNode<EcsAspect>();
|
|
||||||
_injector.AddNode<EcsPipeline>();
|
|
||||||
|
|
||||||
_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<IEcsProcess>>(KEYS_CAPACITY);
|
|
||||||
}
|
|
||||||
public Builder AddRunner<TRunner>() where TRunner : EcsRunner, IEcsRunner, new()
|
|
||||||
{
|
|
||||||
_initDeclaredRunners.Add(new InitDeclaredRunner<TRunner>());
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public Builder Add(IEcsProcess system, string layerName = null)
|
|
||||||
{
|
|
||||||
AddInternal(system, layerName, false);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public Builder AddUnique(IEcsProcess system, string layerName = null)
|
|
||||||
{
|
|
||||||
AddInternal(system, layerName, true);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public Builder Remove<TSystem>()
|
|
||||||
{
|
|
||||||
_uniqueTypes.Remove(typeof(TSystem));
|
|
||||||
foreach (var list in _systems.Values)
|
|
||||||
{
|
|
||||||
list.RemoveAll(o => o is TSystem);
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
private void AddInternal(IEcsProcess system, string layerName, bool isUnique)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(layerName))
|
|
||||||
{
|
|
||||||
layerName = system is IEcsSystemDefaultLayer defaultLayer ? defaultLayer.Layer : _basicLayer;
|
|
||||||
}
|
|
||||||
List<IEcsProcess> list;
|
|
||||||
if (!_systems.TryGetValue(layerName, out list))
|
|
||||||
{
|
|
||||||
list = new List<IEcsProcess> { new SystemsLayerMarkerSystem(layerName) };
|
|
||||||
_systems.Add(layerName, list);
|
|
||||||
}
|
|
||||||
if (_uniqueTypes.Add(system.GetType()) == false && isUnique)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
list.Add(system);
|
|
||||||
|
|
||||||
if (system is IEcsModule module)//если система одновременно явялется и системой и модулем то за один Add будет вызван Add и AddModule
|
|
||||||
{
|
|
||||||
AddModule(module);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public Builder AddModule(IEcsModule module)
|
|
||||||
{
|
|
||||||
module.Import(this);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
public EcsPipeline Build()
|
|
||||||
{
|
|
||||||
List<IEcsProcess> result = new List<IEcsProcess>(32);
|
|
||||||
List<IEcsProcess> basicBlockList;
|
|
||||||
if (_systems.TryGetValue(_basicLayer, out basicBlockList) == false)
|
|
||||||
{
|
|
||||||
basicBlockList = new List<IEcsProcess>();
|
|
||||||
}
|
|
||||||
foreach (var item in _systems)
|
|
||||||
{
|
|
||||||
if (!Layers.Contains(item.Key))
|
|
||||||
basicBlockList.AddRange(item.Value);
|
|
||||||
}
|
|
||||||
foreach (var item in Layers)
|
|
||||||
{
|
|
||||||
if (_systems.TryGetValue(item, out var list))
|
|
||||||
result.AddRange(list);
|
|
||||||
}
|
|
||||||
EcsPipeline pipeline = new EcsPipeline(_configurator.Instance.GetContainer(), _injector, result.ToArray());
|
|
||||||
foreach (var item in _initDeclaredRunners)
|
|
||||||
{
|
|
||||||
item.Declare(pipeline);
|
|
||||||
}
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
_buildBarker.End();
|
|
||||||
#endif
|
|
||||||
return pipeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
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>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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 LayerList(Builder source, string basicLayerName)
|
|
||||||
{
|
|
||||||
_source = source;
|
|
||||||
_layers = new List<string>(16) { basicLayerName, ADD_LAYER };
|
|
||||||
_basicLayerName = basicLayerName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder Add(string newLayer) => 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) => 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 bool Contains(string layer) => _layers.Contains(layer);
|
|
||||||
|
|
||||||
public List<string>.Enumerator GetEnumerator() => _layers.GetEnumerator();
|
|
||||||
IEnumerator<string> IEnumerable<string>.GetEnumerator() => _layers.GetEnumerator();
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => _layers.GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -511,7 +259,8 @@ namespace DCFApixels.DragonECS
|
|||||||
public class SystemsLayerMarkerSystem : IEcsProcess
|
public class SystemsLayerMarkerSystem : IEcsProcess
|
||||||
{
|
{
|
||||||
public readonly string name;
|
public readonly string name;
|
||||||
public SystemsLayerMarkerSystem(string name) => this.name = name;
|
public SystemsLayerMarkerSystem(string name) { this.name = name; }
|
||||||
|
public override string ToString() { return name; }
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -179,6 +179,13 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
|
public void Add(Builder other)
|
||||||
|
{
|
||||||
|
foreach (var item in other._initInjections)
|
||||||
|
{
|
||||||
|
_initInjections.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private abstract class InitInjectBase
|
private abstract class InitInjectBase
|
||||||
{
|
{
|
||||||
|
@ -10,20 +10,21 @@ namespace DCFApixels.DragonECS
|
|||||||
bool Has<T>();
|
bool Has<T>();
|
||||||
T Get<T>();
|
T Get<T>();
|
||||||
bool TryGet<T>(out T value);
|
bool TryGet<T>(out T value);
|
||||||
IEnumerable<object> GetAllConfigs();
|
IEnumerable<KeyValuePair<Type, object>> GetAllConfigs();
|
||||||
}
|
}
|
||||||
public interface IConfigContainerWriter
|
public interface IConfigContainerWriter
|
||||||
{
|
{
|
||||||
int Count { get; }
|
int Count { get; }
|
||||||
void Set<T>(T value);
|
void Set<T>(T value);
|
||||||
|
void Set(Type type, object value);
|
||||||
bool Has<T>();
|
bool Has<T>();
|
||||||
T Get<T>();
|
T Get<T>();
|
||||||
bool TryGet<T>(out T value);
|
bool TryGet<T>(out T value);
|
||||||
void Remove<T>();
|
void Remove<T>();
|
||||||
IEnumerable<object> GetAllConfigs();
|
IEnumerable<KeyValuePair<Type, object>> GetAllConfigs();
|
||||||
IConfigContainer GetContainer();
|
IConfigContainer GetContainer();
|
||||||
}
|
}
|
||||||
public sealed class ConfigContainer : IConfigContainer, IConfigContainerWriter, IEnumerable<object>
|
public sealed class ConfigContainer : IConfigContainer, IConfigContainerWriter, IEnumerable<KeyValuePair<Type, object>>
|
||||||
{
|
{
|
||||||
public static readonly ConfigContainer Empty = new ConfigContainer();
|
public static readonly ConfigContainer Empty = new ConfigContainer();
|
||||||
|
|
||||||
@ -66,6 +67,15 @@ namespace DCFApixels.DragonECS
|
|||||||
_storage[typeof(T)] = value;
|
_storage[typeof(T)] = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
public ConfigContainer Set(Type type, object value)
|
||||||
|
{
|
||||||
|
_storage[type] = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
void IConfigContainerWriter.Set(Type type, object value)
|
||||||
|
{
|
||||||
|
Set(type, value);
|
||||||
|
}
|
||||||
void IConfigContainerWriter.Set<T>(T value)
|
void IConfigContainerWriter.Set<T>(T value)
|
||||||
{
|
{
|
||||||
Set(value);
|
Set(value);
|
||||||
@ -76,17 +86,14 @@ namespace DCFApixels.DragonECS
|
|||||||
value = rawValue == null ? default : (T)rawValue;
|
value = rawValue == null ? default : (T)rawValue;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public IConfigContainer GetContainer()
|
public IConfigContainer GetContainer() { return this; }
|
||||||
|
public IEnumerable<KeyValuePair<Type, object>> GetAllConfigs()
|
||||||
{
|
{
|
||||||
return this;
|
return _storage;
|
||||||
}
|
}
|
||||||
public IEnumerable<object> GetAllConfigs()
|
public IEnumerator<KeyValuePair<Type, object>> GetEnumerator()
|
||||||
{
|
{
|
||||||
return _storage.Values;
|
return _storage.GetEnumerator();
|
||||||
}
|
|
||||||
public IEnumerator<object> GetEnumerator()
|
|
||||||
{
|
|
||||||
return _storage.Values.GetEnumerator();
|
|
||||||
}
|
}
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user