DragonECS/src/EcsPipeline.Builder.cs

1193 lines
50 KiB
C#
Raw Normal View History

2024-06-25 22:02:39 +08:00
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.RunnersCore;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
2024-08-12 21:36:21 +08:00
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
2024-08-20 11:53:14 +08:00
using System.Runtime.Serialization;
2024-07-08 20:31:42 +08:00
using static DCFApixels.DragonECS.EcsConsts;
namespace DCFApixels.DragonECS
{
2024-08-12 21:36:21 +08:00
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "...")]
2024-10-12 14:48:13 +08:00
[MetaID("FC38597C9201C15D1A14D133237BD67F")]
2024-08-20 11:53:14 +08:00
public interface IEcsDefaultAddParams
2024-08-12 21:36:21 +08:00
{
AddParams AddParams { get; }
}
public sealed partial class EcsPipeline
{
public class Builder : IEcsModule
{
private SystemNode[] _systemNodes = new SystemNode[256];
private int _startIndex = -1;
private int _endIndex = -1;
private int _systemNodesCount = 0;
private int _freeIndex = -1;
private int _freeNodesCount = 0;
2024-06-25 22:02:39 +08:00
2024-07-08 20:31:42 +08:00
private readonly Dictionary<string, LayerSystemsList> _layerLists = new Dictionary<string, LayerSystemsList>(8);
private readonly List<InitDeclaredRunner> _initDeclaredRunners = new List<InitDeclaredRunner>(4);
2024-06-25 22:02:39 +08:00
public readonly LayerList Layers;
public readonly Injector.Builder Injector;
public readonly Configurator Configs;
2024-08-14 21:23:34 +08:00
private AddParams _defaultAddParams = new AddParams(BASIC_LAYER, 0, false);
2024-07-08 20:31:42 +08:00
2024-09-08 19:39:43 +08:00
private HashSet<Type> _uniqueSystemsSet = new HashSet<Type>();
2024-07-08 20:31:42 +08:00
#region Properties
//private ReadOnlySpan<SystemNode> SystemRecords
//{
// get { return new ReadOnlySpan<SystemNode>(_systemNodes, 0, _systemNodesCount); }
//}
2024-07-08 20:31:42 +08:00
#endregion
#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>();
2024-07-08 20:31:42 +08:00
Layers = new LayerList(this, PRE_BEGIN_LAYER, BEGIN_LAYER, BASIC_LAYER, END_LAYER, POST_END_LAYER);
}
#endregion
2024-08-14 20:39:55 +08:00
#region Add IEcsProcess
public Builder Add(IEcsProcess system, AddParams parameters)
{
return AddSystem_Internal(system, parameters);
}
private IEcsProcess _systemModule;
private bool _systemModuleAdded;
2024-08-14 20:39:55 +08:00
private Builder AddSystem_Internal(IEcsProcess system, AddParams settedAddParams)
{
AddParams prms = _defaultAddParams;
2024-08-20 11:53:14 +08:00
if (system is IEcsDefaultAddParams overrideInterface)
{
2024-08-14 20:39:55 +08:00
prms = prms.Overwrite(overrideInterface.AddParams);
}
2024-08-14 20:39:55 +08:00
prms = prms.Overwrite(settedAddParams);
// Если система одновременно явялется и системой и модулем то сначала будет вызван IEcsModule
// При этом дается возможность ручной установки порядка импорта системы вызовом Add(this)
2024-10-10 19:57:19 +08:00
if (_systemModule == system)
2024-10-09 01:55:30 +08:00
{
_systemModuleAdded = true;
}
else
{
if (system is IEcsModule module)
{
IEcsProcess systemModulePrev = _systemModule;
bool systemModuleAddedPrev = _systemModuleAdded;
_systemModule = system;
_systemModuleAdded = false;
int importHeadIndex = _endIndex;
AddModule_Internal(module, prms);
if (_systemModuleAdded == false)
{ //Если система не была добавлена вручную, то она будет добавлена перед тем что было импортировано через IEcsModule
InsertAfterNode_Internal(importHeadIndex, system, prms.layerName, prms.sortOrder, prms.isUnique);
}
2024-08-14 20:39:55 +08:00
2024-10-09 01:55:30 +08:00
_systemModule = systemModulePrev;
_systemModuleAdded = systemModuleAddedPrev;
return this;
}
}
AddNode_Internal(system, prms.layerName, prms.sortOrder, prms.isUnique);
return this;
}
private void AddNode_Internal(IEcsProcess system, string layer, int sortOrder, bool isUnique)
2024-06-25 22:02:39 +08:00
{
InsertAfterNode_Internal(_endIndex, system, layer, sortOrder, isUnique);
}
private void InsertAfterNode_Internal(int insertAfterIndex, IEcsProcess system, string layer, int sortOrder, bool isUnique)
{
2024-09-08 19:39:43 +08:00
//TODO нужно потестить
if (isUnique && _uniqueSystemsSet.Add(system.GetType()) == false)
{
2024-10-06 15:35:01 +08:00
//EcsDebug.PrintWarning($"The pipeline already contains a unique instance of {system.GetType().Name}");
return;
}
if (string.IsNullOrEmpty(layer))
{
layer = BASIC_LAYER;
2024-09-08 19:39:43 +08:00
}
SystemNode record = new SystemNode(system, layer, sortOrder, isUnique);
int newIndex;
if (_freeNodesCount <= 0)
{
if (_systemNodes.Length <= _systemNodesCount)
{
Array.Resize(ref _systemNodes, _systemNodes.Length << 1);
}
newIndex = _systemNodesCount;
_systemNodes[newIndex] = record;
}
else
{
_freeNodesCount--;
newIndex = _freeIndex;
_freeIndex = _systemNodes[_freeIndex].next;
}
_systemNodesCount++;
_systemNodes[newIndex] = record;
if (_systemNodesCount == 1)
{
_startIndex = newIndex;
}
else
{
_systemNodes[newIndex].next = _systemNodes[insertAfterIndex].next;
_systemNodes[insertAfterIndex].next = newIndex;
}
if (insertAfterIndex == _endIndex)
{
_endIndex = newIndex;
}
2024-06-25 23:35:51 +08:00
if (_layerLists.TryGetValue(layer, out LayerSystemsList list) == false)
2024-06-25 22:02:39 +08:00
{
list = new LayerSystemsList(layer);
_layerLists.Add(layer, list);
}
list.lasyInitSystemsCount++;
}
#endregion
2024-08-14 20:39:55 +08:00
#region AddModule IEcsModule
public Builder AddModule(IEcsModule module, AddParams parameters)
{
2024-10-19 00:02:56 +08:00
if (module is IEcsProcess system)
2024-10-13 15:15:17 +08:00
{
return AddSystem_Internal(system, parameters);
}
2024-08-14 20:39:55 +08:00
return AddModule_Internal(module, parameters);
}
private Builder AddModule_Internal(IEcsModule module, AddParams settedAddParams)
{
2024-09-07 22:17:08 +08:00
if (settedAddParams.flags.IsNoImport() == false)
{
2024-09-07 22:17:08 +08:00
AddParams prms = _defaultAddParams;
if (module is IEcsDefaultAddParams overrideInterface)
{
prms = prms.Overwrite(overrideInterface.AddParams);
}
var oldDefaultAddParams = _defaultAddParams;
_defaultAddParams = prms.Overwrite(settedAddParams);
module.Import(this);
_defaultAddParams = oldDefaultAddParams;
2024-07-08 20:31:42 +08:00
}
2024-09-08 19:39:43 +08:00
Injector.Inject(module);
2024-08-12 21:36:21 +08:00
return this;
}
#endregion
2024-08-14 20:39:55 +08:00
#region Add Raw
public Builder Add(object raw, AddParams parameters)
{
return AddRaw_Internal(raw, parameters);
}
private Builder AddRaw_Internal(object raw, AddParams settedAddParams)
{
switch (raw)
{
case IEcsProcess system: return AddSystem_Internal(system, settedAddParams);
case IEcsModule module: return AddModule_Internal(module, settedAddParams);
2025-03-10 13:00:30 +08:00
default: Throw.ArgumentException($"{raw.GetMeta().TypeName} Unsupported type"); return this;
2024-08-14 20:39:55 +08:00
}
}
2024-07-08 20:31:42 +08:00
#endregion
#region Add other
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 (ref readonly SystemNode otherRecord in new LinkedListIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex))
{
AddNode_Internal(otherRecord.system, otherRecord.layerName, otherRecord.sortOrder, otherRecord.isUnique);
}
}
#endregion
#region Remove
private void RemoveAt(int prevIndex, int removedNodeIndex)
2024-06-25 22:02:39 +08:00
{
ref var removedeNode = ref _systemNodes[removedNodeIndex];
_layerLists[removedeNode.layerName].lasyInitSystemsCount--;
_systemNodes[prevIndex].next = removedeNode.next;
removedeNode = default;
if (_endIndex == removedNodeIndex)
{
_endIndex = prevIndex;
}
if (_freeNodesCount > 0)
{
removedeNode.next = _freeIndex;
}
_freeIndex = removedNodeIndex;
_freeNodesCount++;
_systemNodesCount--;
2024-06-25 22:02:39 +08:00
}
public Builder Remove<TSystem>()
{
2024-09-08 19:39:43 +08:00
_uniqueSystemsSet.Remove(typeof(TSystem));
if (_systemNodesCount <= 1)
{
if (_systemNodesCount == 1 && _systemNodes[0].system is TSystem)
2024-06-25 22:02:39 +08:00
{
_systemNodesCount = 0;
2024-06-25 22:02:39 +08:00
}
return this;
}
int enumIndex = _startIndex;
for (int i = 1; i < _systemNodesCount; i++)
{
int nextIndex = _systemNodes[enumIndex].next;
if (_systemNodes[nextIndex].system is TSystem)
{
RemoveAt(enumIndex, nextIndex);
nextIndex = _systemNodes[enumIndex].next;
}
enumIndex = nextIndex;
}
return this;
}
#endregion
#region Build
2024-06-25 22:02:39 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2025-03-13 20:43:21 +08:00
private static EcsProfilerMarker _buildMarker = new EcsProfilerMarker("EcsPipeline.Build");
2024-06-25 22:02:39 +08:00
#endif
public EcsPipeline Build()
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2025-03-13 20:43:21 +08:00
_buildMarker.Begin();
#endif
var it = new LinkedListIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex);
2024-06-25 22:02:39 +08:00
LayerSystemsList basicLayerList;
if (_layerLists.TryGetValue(BASIC_LAYER, out basicLayerList) == false)
{
basicLayerList = new LayerSystemsList(BASIC_LAYER);
_layerLists.Add(BASIC_LAYER, basicLayerList);
}
int allSystemsLength = 0;
2024-06-25 22:02:39 +08:00
foreach (var item in _layerLists)
{
2024-06-25 22:02:39 +08:00
if (item.Key == BASIC_LAYER) { continue; }
if (Layers.Contains(item.Key))
{
item.Value.Init();
allSystemsLength += item.Value.lasyInitSystemsCount + 1;
}
else
{
basicLayerList.lasyInitSystemsCount += item.Value.lasyInitSystemsCount;
}
}
2024-06-25 22:02:39 +08:00
allSystemsLength += basicLayerList.lasyInitSystemsCount + 1;
basicLayerList.Init();
foreach (ref readonly SystemNode node in it)
2024-06-25 22:02:39 +08:00
{
var list = _layerLists[node.layerName];
2024-06-25 23:35:51 +08:00
if (list.IsInit == false)
2024-06-25 22:02:39 +08:00
{
list = basicLayerList;
}
2024-09-08 19:39:43 +08:00
list.Add(node.system, node.sortOrder, node.isUnique);
//if (node.isUnique == false || uniqueSystemsSet.Add(node.system.GetType()))
//{
// list.Add(node.system, node.sortOrder, node.isUnique);
//}
2024-06-25 22:02:39 +08:00
}
IEcsProcess[] allSystems = new IEcsProcess[allSystemsLength];
{
int i = 0;
foreach (var item in Layers)
{
2024-06-25 22:02:39 +08:00
if (_layerLists.TryGetValue(item, out var list) && list.IsInit)
{
2024-06-25 22:02:39 +08:00
list.Sort();
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
2025-03-13 20:43:21 +08:00
_buildMarker.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 Builder _source;
private List<string> _layers;
private string _basicLayerName;
2024-10-19 00:02:56 +08:00
private string _addLayerName;
2024-10-09 01:55:30 +08:00
#region Properties
public int Count { get { return _layers.Count; } }
public object this[int index] { get { return _layers[index]; } }
2024-10-09 01:55:30 +08:00
#endregion
2024-10-09 01:55:30 +08:00
#region Constructors
public LayerList(Builder source, string basicLayerName)
{
_source = source;
2024-10-19 00:02:56 +08:00
_layers = new List<string>(16) { basicLayerName };
_basicLayerName = basicLayerName;
2024-10-19 00:02:56 +08:00
_addLayerName = _basicLayerName;
}
2024-07-08 20:31:42 +08:00
public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer)
{
_source = source;
2024-10-19 00:02:56 +08:00
_layers = new List<string>(16) { preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer };
2024-07-08 20:31:42 +08:00
_basicLayerName = basicLayer;
2024-10-19 00:02:56 +08:00
_addLayerName = _basicLayerName;
2024-07-08 20:31:42 +08:00
}
2024-10-09 01:55:30 +08:00
#endregion
#region Edit
2024-10-09 01:55:30 +08:00
#region Single
2024-10-19 00:02:56 +08:00
public Builder Add(string newLayer)
{
InsertAfter(_addLayerName, newLayer);
_addLayerName = newLayer;
return _source;
}
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; }
int index = _layers.IndexOf(targetLayer);
if (index < 0)
{
throw new KeyNotFoundException($"Layer {targetLayer} not found");
}
2024-10-09 01:55:30 +08:00
_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)
{
_layers.Remove(movingLayer);
return InsertAfter(targetLayer, movingLayer);
}
2024-10-09 01:55:30 +08:00
#endregion
2024-10-09 01:55:30 +08:00
#region Range
2024-10-19 00:02:56 +08:00
public Builder Add(params string[] newLayers)
{
InsertAfter(_addLayerName, newLayers);
_addLayerName = newLayers[newLayers.Length - 1];
return _source;
}
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)
{
2024-10-09 01:55:30 +08:00
int index = _layers.IndexOf(targetLayer);
if (index < 0)
{
2024-10-09 01:55:30 +08:00
throw new KeyNotFoundException($"Layer {targetLayer} not found");
}
2024-10-09 01:55:30 +08:00
_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)
{
foreach (var movingLayer in movingLayers)
{
_layers.Remove(movingLayer);
}
return InsertAfter(targetLayer, movingLayers);
}
2024-10-09 01:55:30 +08:00
#endregion
#endregion
2024-09-08 19:39:43 +08:00
2024-10-09 01:55:30 +08:00
#region MergeWith
2024-11-05 15:53:00 +08:00
private static bool CheckOverlapsOrder(List<string> listA, IReadOnlyList<string> listB)
2024-09-08 19:39:43 +08:00
{
2024-11-05 15:50:18 +08:00
int lastIndexof = 0;
for (int i = 0; i < listB.Count; i++)
2024-09-08 19:39:43 +08:00
{
2024-11-05 15:50:18 +08:00
var a = listB[i];
int indexof = listA.IndexOf(a);
if (indexof < 0) { continue; }
if (indexof < lastIndexof)
2024-09-08 19:39:43 +08:00
{
2024-11-05 15:50:18 +08:00
return false;
2024-09-08 19:39:43 +08:00
}
2024-11-05 15:50:18 +08:00
lastIndexof = indexof;
2024-09-08 19:39:43 +08:00
}
2024-11-05 15:50:18 +08:00
return true;
2024-09-08 19:39:43 +08:00
}
2024-06-26 00:07:31 +08:00
public void MergeWith(IReadOnlyList<string> other)
{
List<string> listA = _layers;
2024-06-26 00:07:31 +08:00
IReadOnlyList<string> listB = other;
2024-11-05 15:53:00 +08:00
if (CheckOverlapsOrder(listA, listB) == false)
2024-09-08 19:39:43 +08:00
{
2024-11-05 15:50:18 +08:00
//Для слияния списков слоев, нужно чтобы в пересечении порядок записей совпадал
Throw.Exception("To merge layer lists, the names of the layers present in both lists must appear in the same order in both lists.");
2024-09-08 19:39:43 +08:00
}
HashSet<string> seen = new HashSet<string>();
List<string> result = new List<string>();
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;
}
2024-06-26 00:07:31 +08:00
public void MergeWith(LayerList other)
{
MergeWith(other._layers);
}
2024-10-09 01:55:30 +08:00
#endregion
2024-10-09 01:55:30 +08:00
#region Other
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(); }
2024-10-09 01:55:30 +08:00
#endregion
}
#endregion
#region SystemsList
2024-06-25 22:02:39 +08:00
private class LayerSystemsList
{
2024-06-25 22:02:39 +08:00
public int lasyInitSystemsCount = 0;
public Item[] records = null;
public int recordsCount = 0;
2024-06-25 20:24:11 +08:00
2024-08-07 10:40:31 +08:00
//отслеживание осортированности систем
private int _lastSortOrder;
2024-11-08 15:45:55 +08:00
//private int _lastAddOrder;
2024-06-25 22:02:39 +08:00
private bool _isSorted = true;
private string _layerName;
public bool IsInit { get { return records != null; } }
public bool IsSorted { get { return _isSorted; } }
public ReadOnlySpan<Item> Records { get { return new ReadOnlySpan<Item>(records, 1, recordsCount - 1); } }
public LayerSystemsList(string layerName) { _layerName = layerName; }
public void Init()
{
2024-06-25 22:02:39 +08:00
if (IsInit) { Throw.UndefinedException(); }
records = new Item[lasyInitSystemsCount + 1];
Add(new SystemsLayerMarkerSystem(_layerName), int.MinValue, false);
}
2024-06-25 22:02:39 +08:00
public void AddList(LayerSystemsList other)
{
for (int i = 1; i < other.recordsCount; i++)
{
var otherRecord = other.records[i];
2024-08-07 10:40:31 +08:00
AddItem_Internal(otherRecord);
}
}
public void Add(IEcsProcess system, int sortOrder, bool isUnique)
{
AddItem_Internal(new Item(system, sortOrder, isUnique));
2024-06-25 22:02:39 +08:00
}
2024-08-07 10:40:31 +08:00
private void AddItem_Internal(Item item)
2024-06-25 22:02:39 +08:00
{
if (_isSorted)
{
if (recordsCount <= 1)
{
_lastSortOrder = item.sortOrder;
2024-08-14 20:39:55 +08:00
}
else if (_lastSortOrder > item.sortOrder)
{
_isSorted = false;
}
2024-08-07 10:40:31 +08:00
else
{
2024-08-07 10:40:31 +08:00
_lastSortOrder = item.sortOrder;
}
}
if (records.Length <= recordsCount)
{
Array.Resize(ref records, recordsCount << 1);
}
2024-06-25 22:02:39 +08:00
records[recordsCount++] = item;
}
public void RemoveAll<T>()
{
2024-06-25 22:02:39 +08:00
for (int i = 0; i < recordsCount; i++)
{
2024-06-25 22:02:39 +08:00
if (records[i].system is T)
{
2024-06-25 22:02:39 +08:00
records[i] = records[--recordsCount];
}
}
2024-06-25 22:02:39 +08:00
_isSorted = false;
}
public void Sort()
{
2024-06-25 22:02:39 +08:00
if (_isSorted) { return; }
//Игнорирую первую систему, так как это чисто система с названием слоя
Array.Sort(records, 1, recordsCount - 1);
2024-06-25 22:02:39 +08:00
_isSorted = true;
2024-08-07 10:40:31 +08:00
_lastSortOrder = records[recordsCount - 1].sortOrder;
}
}
2024-06-25 22:02:39 +08:00
private readonly struct Item : IComparable<Item>
{
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;
public Item(IEcsProcess system, int sortOrder, bool isUnique)
{
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-25 22:02:39 +08:00
public int CompareTo(Item other)
2024-06-25 20:24:11 +08:00
{
return sortOrder - other.sortOrder;
2024-06-25 20:24:11 +08:00
}
}
#endregion
2024-06-25 22:02:39 +08:00
#region SerializableTemplate
public EcsPipelineTemplate GenerateSerializableTemplate()
{
var it = new LinkedListIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex);
EcsPipelineTemplate result = new EcsPipelineTemplate();
result.layers = new string[Layers.Count];
result.records = new EcsPipelineTemplate.Record[it.Count];
int i = 0;
foreach (ref readonly SystemNode node in it)
{
2024-09-14 18:34:13 +08:00
var prms = new AddParams(node.layerName, node.sortOrder, node.isUnique, AddParamsFlags.None.SetOverwriteAll(true).SetNoImport(true));
result.records[i++] = new EcsPipelineTemplate.Record(node.system, prms);
}
return result;
}
#endregion
2024-08-20 11:53:14 +08:00
#region SystemRecord
2024-08-14 20:39:55 +08:00
[StructLayout(LayoutKind.Auto)]
private struct SystemNode : ILinkedNext
2024-06-25 22:02:39 +08:00
{
public readonly IEcsProcess system;
2024-08-14 21:23:34 +08:00
public readonly string layerName;
2024-06-25 22:02:39 +08:00
public readonly int sortOrder;
public readonly bool isUnique;
public int next;
public int Next
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return next; }
}
public SystemNode(IEcsProcess system, string layerName, int sortOrder, bool isUnique, int next = -1)
2024-06-25 22:02:39 +08:00
{
this.system = system;
2024-08-14 21:23:34 +08:00
this.layerName = layerName;
2024-06-25 22:02:39 +08:00
this.sortOrder = sortOrder;
this.isUnique = isUnique;
this.next = next;
}
public override string ToString()
{
return this.AutoToString();
}
2024-06-25 22:02:39 +08:00
}
2024-08-20 11:53:14 +08:00
#endregion
}
}
2024-08-14 22:40:58 +08:00
public static partial class EcsPipelineBuilderExtensions
{
2024-10-19 00:03:02 +08:00
#region Simple Builders
public static EcsPipeline ToPipeline(this IEcsModule module)
{
return EcsPipeline.New().Add(module).Build();
}
public static EcsPipeline ToPipelineAndInit(this IEcsModule module)
{
return EcsPipeline.New().Add(module).BuildAndInit();
}
public static EcsPipeline ToPipeline(this IEnumerable<IEcsModule> modules)
{
var result = EcsPipeline.New();
foreach (var module in modules)
{
result.Add(module);
}
return result.Build();
}
public static EcsPipeline ToPipelineAndInit(this IEnumerable<IEcsModule> modules)
{
var result = modules.ToPipeline();
result.Init();
return result;
}
#endregion
2024-08-14 22:40:58 +08:00
#region Add IEcsProcess
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system)
{
return self.Add(system, AddParams.Default);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, string layerName)
{
return self.Add(system, new AddParams(layerName: layerName));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, int sortOrder)
{
return self.Add(system, new AddParams(sortOrder: sortOrder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, bool isUnique)
{
return self.Add(system, new AddParams(isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, string layerName, int sortOrder)
{
return self.Add(system, new AddParams(layerName: layerName, sortOrder: sortOrder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, string layerName, bool isUnique)
{
return self.Add(system, new AddParams(layerName: layerName, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, int sortOrder, bool isUnique)
{
return self.Add(system, new AddParams(sortOrder: sortOrder, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEcsProcess system, string layerName, int sortOrder, bool isUnique)
{
return self.Add(system, new AddParams(layerName: layerName, sortOrder: sortOrder, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-06 15:35:01 +08:00
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEcsProcess system)
{
return self.Add(system, new AddParams(isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-08-14 22:40:58 +08:00
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEcsProcess system, string layerName)
{
return self.Add(system, new AddParams(layerName: layerName, isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEcsProcess system, int sortOrder)
{
return self.Add(system, new AddParams(sortOrder: sortOrder, isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEcsProcess system, string layerName, int sortOrder)
{
return self.Add(system, new AddParams(layerName: layerName, sortOrder: sortOrder, isUnique: true));
}
#endregion
#region AddModule IEcsModule
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module)
{
return self.AddModule(module, AddParams.Default);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, string layerName)
{
return self.AddModule(module, new AddParams(layerName: layerName));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, int sortOrder)
{
return self.AddModule(module, new AddParams(sortOrder: sortOrder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, bool isUnique)
{
return self.AddModule(module, new AddParams(isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, string layerName, int sortOrder)
{
return self.AddModule(module, new AddParams(layerName: layerName, sortOrder: sortOrder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, string layerName, bool isUnique)
{
return self.AddModule(module, new AddParams(layerName: layerName, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, int sortOrder, bool isUnique)
{
return self.AddModule(module, new AddParams(sortOrder: sortOrder, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModule(this EcsPipeline.Builder self, IEcsModule module, string layerName, int sortOrder, bool isUnique)
{
return self.AddModule(module, new AddParams(layerName: layerName, sortOrder: sortOrder, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-06 15:35:01 +08:00
public static EcsPipeline.Builder AddModuleUnique(this EcsPipeline.Builder self, IEcsModule module)
{
return self.AddModule(module, new AddParams(isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-08-14 22:40:58 +08:00
public static EcsPipeline.Builder AddModuleUnique(this EcsPipeline.Builder self, IEcsModule module, string layerName)
{
return self.AddModule(module, new AddParams(layerName: layerName, isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModuleUnique(this EcsPipeline.Builder self, IEcsModule module, int sortOrder)
{
return self.AddModule(module, new AddParams(sortOrder: sortOrder, isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddModuleUnique(this EcsPipeline.Builder self, IEcsModule module, string layerName, int sortOrder)
{
return self.AddModule(module, new AddParams(layerName: layerName, sortOrder: sortOrder, isUnique: true));
}
#endregion
#region Add Raw
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw)
{
return self.Add(raw, AddParams.Default);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, string layerName)
{
return self.Add(raw, new AddParams(layerName: layerName));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, int sortOrder)
{
return self.Add(raw, new AddParams(sortOrder: sortOrder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, bool isUnique)
{
return self.Add(raw, new AddParams(isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, string layerName, int sortOrder)
{
return self.Add(raw, new AddParams(layerName: layerName, sortOrder: sortOrder));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, string layerName, bool isUnique)
{
return self.Add(raw, new AddParams(layerName: layerName, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, int sortOrder, bool isUnique)
{
return self.Add(raw, new AddParams(sortOrder: sortOrder, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, object raw, string layerName, int sortOrder, bool isUnique)
{
return self.Add(raw, new AddParams(layerName: layerName, sortOrder: sortOrder, isUnique: isUnique));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-10-06 15:35:01 +08:00
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, object raw)
{
return self.Add(raw, new AddParams(isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-08-14 22:40:58 +08:00
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, object raw, string layerName)
{
return self.Add(raw, new AddParams(layerName: layerName, isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, object raw, int sortOrder)
{
return self.Add(raw, new AddParams(sortOrder: sortOrder, isUnique: true));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, object raw, string layerName, int sortOrder)
{
return self.Add(raw, new AddParams(layerName: layerName, sortOrder: sortOrder, isUnique: true));
}
#endregion
}
#region AddParams
[Serializable]
[DataContract]
public struct AddParams : IEquatable<AddParams>
{
public static readonly AddParams Default = new AddParams();
[DataMember] public string layerName;
[DataMember] public int sortOrder;
[DataMember] public bool isUnique;
[DataMember] public AddParamsFlags flags;
#region Properties
public bool IsOverwriteLayerName
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return flags.IsOverwriteLayerName(); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set { flags = value ? flags | AddParamsFlags.OverwriteLayerName : flags & ~AddParamsFlags.OverwriteLayerName; }
}
public bool IsOverwriteSortOrder
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return flags.IsOverwriteSortOrder(); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set { flags = value ? flags | AddParamsFlags.OverwriteSortOrder : flags & ~AddParamsFlags.OverwriteSortOrder; }
}
public bool IsOverwriteIsUnique
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return flags.IsOverwriteIsUnique(); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set { flags = value ? flags | AddParamsFlags.OverwriteIsUnique : flags & ~AddParamsFlags.OverwriteIsUnique; }
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(string layerName)
{
this.layerName = layerName;
this.sortOrder = default;
this.isUnique = default;
flags = AddParamsFlags.OverwriteLayerName;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(int sortOrder)
{
this.layerName = default;
this.sortOrder = sortOrder;
this.isUnique = default;
flags = AddParamsFlags.OverwriteSortOrder;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(bool isUnique)
{
this.layerName = default;
this.sortOrder = default;
this.isUnique = isUnique;
flags = AddParamsFlags.OverwriteIsUnique;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(string layerName, int sortOrder)
{
this.layerName = layerName;
this.sortOrder = sortOrder;
this.isUnique = default;
flags = AddParamsFlags.OverwriteLayerName | AddParamsFlags.OverwriteSortOrder;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(string layerName, bool isUnique)
{
this.layerName = layerName;
this.sortOrder = default;
this.isUnique = isUnique;
flags = AddParamsFlags.OverwriteLayerName | AddParamsFlags.OverwriteIsUnique;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(int sortOrder, bool isUnique)
{
this.layerName = default;
this.sortOrder = sortOrder;
this.isUnique = isUnique;
flags = AddParamsFlags.OverwriteSortOrder | AddParamsFlags.OverwriteIsUnique;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(string layerName, int sortOrder, bool isUnique)
{
this.layerName = layerName;
this.sortOrder = sortOrder;
this.isUnique = isUnique;
2024-09-14 18:34:13 +08:00
flags = AddParamsFlags.None.SetOverwriteAll(true);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public AddParams(string layerName, int sortOrder, bool isUnique, AddParamsFlags overrideFlags)
{
this.layerName = layerName;
this.sortOrder = sortOrder;
this.isUnique = isUnique;
this.flags = overrideFlags;
}
#endregion
#region Overwrite
public AddParams Overwrite(AddParams other)
{
AddParams result = this;
if (other.flags.IsOverwriteLayerName())
{
result.layerName = other.layerName;
}
if (other.flags.IsOverwriteSortOrder())
{
result.sortOrder = other.sortOrder;
}
if (other.flags.IsOverwriteIsUnique())
{
result.isUnique = other.isUnique;
}
result.flags |= other.flags;
return result;
}
#endregion
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(AddParams other)
{
return sortOrder == other.sortOrder &&
layerName == other.layerName &&
isUnique == other.isUnique;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj)
{
return obj is AddParams && Equals((AddParams)obj);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return HashCode.Combine(sortOrder, layerName, isUnique);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString()
{
return (flags.IsOverwriteLayerName() ? $"{layerName}, " : "") +
(flags.IsOverwriteSortOrder() ? $"{sortOrder}, " : "") +
(flags.IsOverwriteIsUnique() ? $"{isUnique}, " : "");
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator AddParams(string a) { return new AddParams(a); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator AddParams(int a) { return new AddParams(a); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator AddParams(bool a) { return new AddParams(a); }
#endregion
}
[Flags]
public enum AddParamsFlags : byte
{
None = 0,
OverwriteLayerName = 1 << 0,
OverwriteSortOrder = 1 << 1,
OverwriteIsUnique = 1 << 2,
/// <summary>
/// Ignore call IEcsModule.Import(Builder b)
/// </summary>
NoImport = 1 << 7,
}
public static class AddParamsFlagsUtility
{
2024-09-14 18:34:13 +08:00
private const AddParamsFlags OverwriteAll = AddParamsFlags.OverwriteLayerName | AddParamsFlags.OverwriteSortOrder | AddParamsFlags.OverwriteIsUnique;
private const AddParamsFlags All = OverwriteAll | AddParamsFlags.NoImport;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-09-14 18:34:13 +08:00
public static AddParamsFlags Normalize(this AddParamsFlags flags) { return flags & All; }
2024-09-11 10:36:44 +08:00
2024-09-14 18:34:13 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOverwriteLayerName(this AddParamsFlags flags) { return (flags & AddParamsFlags.OverwriteLayerName) == AddParamsFlags.OverwriteLayerName; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOverwriteSortOrder(this AddParamsFlags flags) { return (flags & AddParamsFlags.OverwriteSortOrder) == AddParamsFlags.OverwriteSortOrder; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOverwriteIsUnique(this AddParamsFlags flags) { return (flags & AddParamsFlags.OverwriteIsUnique) == AddParamsFlags.OverwriteIsUnique; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-09-14 18:34:13 +08:00
public static bool IsOverwriteAll(this AddParamsFlags flags) { return (flags & OverwriteAll) == OverwriteAll; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNoImport(this AddParamsFlags flags) { return (flags & AddParamsFlags.NoImport) == AddParamsFlags.NoImport; }
2024-09-11 10:36:44 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AddParamsFlags SetOverwriteLayerName(this AddParamsFlags flags, bool flag) { return flag ? flags | AddParamsFlags.OverwriteLayerName : flags & ~AddParamsFlags.OverwriteLayerName; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AddParamsFlags SetOverwriteSortOrder(this AddParamsFlags flags, bool flag) { return flag ? flags | AddParamsFlags.OverwriteSortOrder : flags & ~AddParamsFlags.OverwriteSortOrder; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AddParamsFlags SetOverwriteIsUnique(this AddParamsFlags flags, bool flag) { return flag ? flags | AddParamsFlags.OverwriteIsUnique : flags & ~AddParamsFlags.OverwriteIsUnique; }
2024-09-14 18:34:13 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AddParamsFlags SetOverwriteAll(this AddParamsFlags flags, bool flag) { return flag ? flags | OverwriteAll : flags & ~OverwriteAll; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static AddParamsFlags SetNoImport(this AddParamsFlags flags, bool flag) { return flag ? flags | AddParamsFlags.NoImport : flags & ~AddParamsFlags.NoImport; }
}
#endregion
}