DragonECS/src/EcsPipeline.cs

494 lines
19 KiB
C#
Raw Normal View History

2023-05-26 04:31:31 +08:00
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.RunnersCore;
2023-04-23 17:55:01 +08:00
using System;
using System.Collections;
2023-03-26 11:19:03 +08:00
using System.Collections.Generic;
using System.Linq;
2023-03-26 11:19:03 +08:00
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
public interface IEcsPipelineMember : IEcsSystem
2024-02-17 00:10:38 +08:00
{
public EcsPipeline Pipeline { get; set; }
}
2023-03-30 05:32:43 +08:00
public sealed class EcsPipeline
2023-03-26 11:19:03 +08:00
{
private readonly IEcsPipelineConfig _config;
2023-03-26 11:19:03 +08:00
private IEcsSystem[] _allSystems;
private Dictionary<Type, Array> _processes = new Dictionary<Type, Array>();
private Dictionary<Type, IEcsRunner> _runners = new Dictionary<Type, IEcsRunner>();
private IEcsRun _runRunnerCache;
2023-03-26 11:19:03 +08:00
2023-06-26 02:53:55 +08:00
private bool _isInit = false;
private bool _isDestoryed = false;
2023-03-26 11:19:03 +08:00
#region Properties
public IEcsPipelineConfig Config
{
get { return _config; }
}
public EcsProcess<IEcsSystem> AllSystems
{
get { return new EcsProcess<IEcsSystem>(_allSystems); }
}
public IReadOnlyDictionary<Type, IEcsRunner> AllRunners
{
get { return _runners; }
}
public bool IsInit
{
get { return _isInit; }
}
public bool IsDestoryed
{
get { return _isDestoryed; }
}
2023-03-26 11:19:03 +08:00
#endregion
#region Constructors
private EcsPipeline(IEcsPipelineConfig config, IEcsSystem[] systems)
2023-03-26 11:19:03 +08:00
{
_config = config;
2023-03-26 11:19:03 +08:00
_allSystems = systems;
}
#endregion
#region Get Process/Runner
public EcsProcess<T> GetProcess<T>() where T : IEcsSystem
2024-02-17 00:10:27 +08:00
{
Type type = typeof(T);
T[] result;
if(_processes.TryGetValue(type, out Array array))
{
result = (T[])array;
}
else
{
result = _allSystems.OfType<T>().ToArray();
_processes.Add(type, result);
}
return new EcsProcess<T>(result);
2024-02-17 00:10:27 +08:00
}
#if !REFLECTION_DISABLED
public T GetRunner<T>() where T : IEcsSystem
2024-01-26 02:26:17 +08:00
{
Type interfaceType = typeof(T);
if (_runners.TryGetValue(interfaceType, out IEcsRunner result) == false)
2024-02-17 00:10:27 +08:00
{
result = (IEcsRunner)EcsRunner<T>.Instantiate(this);
_runners.Add(result.GetType(), result);
_runners.Add(interfaceType, result);
2024-02-17 00:10:27 +08:00
}
return (T)result;
2024-01-26 02:26:17 +08:00
}
#endif
public T GetRunnerInstance<T>() where T : IEcsRunner, new()
2023-03-26 11:19:03 +08:00
{
Type runnerType = typeof(T);
if (_runners.TryGetValue(runnerType, out IEcsRunner result) == false)
2024-01-26 02:26:17 +08:00
{
result = new T();
_runners.Add(runnerType, result);
#if !REFLECTION_DISABLED
_runners.Add(result.Interface, result);
#endif
2024-01-26 02:26:17 +08:00
}
2023-03-26 11:19:03 +08:00
return (T)result;
}
#endregion
#region Internal
internal void OnRunnerDestroy_Internal(IEcsRunner runner)
2023-03-30 05:32:43 +08:00
{
_runners.Remove(runner.Interface);
}
2023-03-26 11:19:03 +08:00
#endregion
#region LifeCycle
public void Init()
{
2023-04-01 20:45:37 +08:00
if (_isInit == true)
{
2023-12-06 20:35:07 +08:00
EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been initialized");
return;
}
EcsProcess<IEcsPipelineMember> members = GetProcess<IEcsPipelineMember>();
2024-02-17 00:10:38 +08:00
foreach (var member in members)
{
member.Pipeline = this;
}
var preInitRunner = GetRunner<IEcsPreInit>();
preInitRunner.PreInit();
2023-03-30 11:17:17 +08:00
EcsRunner.Destroy(preInitRunner);
var initRunner = GetRunner<IEcsInit>();
initRunner.Init();
2023-03-30 11:17:17 +08:00
EcsRunner.Destroy(initRunner);
_runRunnerCache = GetRunner<IEcsRun>();
2023-06-10 19:46:35 +08:00
_isInit = true;
GC.Collect();
}
2023-03-26 11:19:03 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run()
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 02:53:55 +08:00
if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run));
2023-06-26 01:57:50 +08:00
if (_isDestoryed) Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run));
2023-03-26 11:19:03 +08:00
#endif
_runRunnerCache.Run();
2023-03-26 11:19:03 +08:00
}
public void Destroy()
{
2023-06-02 01:20:46 +08:00
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 02:53:55 +08:00
if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy));
2023-03-26 11:19:03 +08:00
#endif
2023-06-26 02:53:55 +08:00
if (_isDestoryed)
{
2023-06-26 01:57:50 +08:00
EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been destroyed");
return;
}
2023-03-26 11:19:03 +08:00
_isDestoryed = true;
GetRunner<IEcsDestroy>().Destroy();
2023-03-26 11:19:03 +08:00
}
#endregion
#region Builder
public static Builder New(IEcsPipelineConfigWriter config = null)
{
return new Builder(config);
}
2023-03-26 11:19:03 +08:00
public class Builder
{
private const int KEYS_CAPACITY = 4;
2023-03-30 05:32:43 +08:00
private HashSet<Type> _uniqueTypes;
private readonly Dictionary<string, List<IEcsSystem>> _systems;
private readonly string _basicLayer;
public readonly LayerList Layers;
private readonly IEcsPipelineConfigWriter _config;
public IEcsPipelineConfigWriter Config
{
get { return _config; }
}
public Builder(IEcsPipelineConfigWriter config = null)
2023-03-26 11:19:03 +08:00
{
if (config == null)
{
config = new EcsPipelineConfig();
}
_config = config;
_basicLayer = EcsConsts.BASIC_LAYER;
Layers = new LayerList(this, _basicLayer);
Layers.Insert(EcsConsts.BASIC_LAYER, EcsConsts.PRE_BEGIN_LAYER, EcsConsts.BEGIN_LAYER);
Layers.InsertAfter(EcsConsts.BASIC_LAYER, EcsConsts.END_LAYER, EcsConsts.POST_END_LAYER);
_uniqueTypes = new HashSet<Type>();
_systems = new Dictionary<string, List<IEcsSystem>>(KEYS_CAPACITY);
2023-03-26 11:19:03 +08:00
}
public Builder Add(IEcsSystem system, string layerName = null)
2023-03-30 05:32:43 +08:00
{
AddInternal(system, layerName, false);
2023-03-30 05:32:43 +08:00
return this;
}
public Builder AddUnique(IEcsSystem system, string layerName = null)
2023-03-30 05:32:43 +08:00
{
AddInternal(system, layerName, true);
2023-03-30 05:32:43 +08:00
return this;
}
2023-05-23 01:47:28 +08:00
public Builder Remove<TSystem>()
{
_uniqueTypes.Remove(typeof(TSystem));
foreach (var list in _systems.Values)
list.RemoveAll(o => o is TSystem);
return this;
}
private void AddInternal(IEcsSystem system, string layerName, bool isUnique)
2023-03-26 11:19:03 +08:00
{
if (layerName == null) layerName = _basicLayer;
List<IEcsSystem> list;
if (!_systems.TryGetValue(layerName, out list))
2023-03-26 11:19:03 +08:00
{
list = new List<IEcsSystem> { new SystemsLayerMarkerSystem(layerName.ToString()) };
_systems.Add(layerName, list);
2023-03-26 11:19:03 +08:00
}
2023-03-30 05:32:43 +08:00
if ((_uniqueTypes.Add(system.GetType()) == false && isUnique))
return;
2023-03-26 11:19:03 +08:00
list.Add(system);
if (system is IEcsModule module)//если система одновременно явялется и системой и модулем то за один Add будет вызван Add и AddModule
AddModule(module);
2023-03-26 11:19:03 +08:00
}
public Builder AddModule(IEcsModule module)
2023-03-26 11:19:03 +08:00
{
2023-05-30 17:56:53 +08:00
module.Import(this);
2023-03-26 11:19:03 +08:00
return this;
}
public EcsPipeline Build()
2023-03-26 11:19:03 +08:00
{
List<IEcsSystem> result = new List<IEcsSystem>(32);
List<IEcsSystem> basicBlockList = _systems[_basicLayer];
foreach (var item in _systems)
{
2023-05-30 00:13:05 +08:00
if (!Layers.Contains(item.Key))
basicBlockList.AddRange(item.Value);
}
foreach (var item in Layers)
{
2023-05-30 18:30:10 +08:00
if (_systems.TryGetValue(item, out var list))
result.AddRange(list);
}
return new EcsPipeline(_config.GetPipelineConfig(), result.ToArray());
}
public class LayerList : IEnumerable<string>
2023-03-26 11:19:03 +08:00
{
private const string ADD_LAYER = nameof(ADD_LAYER); // автоматический слой нужный только для метода Add
private Builder _source;
private List<string> _layers;
private string _basicLayerName;
public LayerList(Builder source, string basicLayerName)
2023-03-26 11:19:03 +08:00
{
_source = source;
_layers = new List<string>(16) { basicLayerName, ADD_LAYER };
2023-05-30 18:30:10 +08:00
_basicLayerName = basicLayerName;
2023-03-26 11:19:03 +08:00
}
public Builder Add(string newLayer) => Insert(ADD_LAYER, newLayer);
public Builder Insert(string targetLayer, string newLayer)
{
2023-05-30 00:13:05 +08:00
if (Contains(newLayer)) return _source;
2023-03-26 11:19:03 +08:00
int index = _layers.IndexOf(targetLayer);
if (index < 0)
throw new KeyNotFoundException($"Layer {targetLayer} not found");
_layers.Insert(index, newLayer);
return _source;
}
public Builder InsertAfter(string targetLayer, string newLayer)
{
2023-05-30 00:13:05 +08:00
if (Contains(newLayer)) return _source;
2023-03-26 11:19:03 +08:00
if (targetLayer == _basicLayerName) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER;
2023-03-26 11:19:03 +08:00
int index = _layers.IndexOf(targetLayer);
if (index < 0)
throw new KeyNotFoundException($"Layer {targetLayer} not found");
if (++index >= _layers.Count)
_layers.Add(newLayer);
else
_layers.Insert(index, newLayer);
return _source;
}
public Builder Move(string targetLayer, string movingLayer)
2023-03-26 11:19:03 +08:00
{
_layers.Remove(movingLayer);
return Insert(targetLayer, movingLayer);
2023-03-26 11:19:03 +08:00
}
public Builder MoveAfter(string targetLayer, string movingLayer)
2023-03-26 11:19:03 +08:00
{
if (targetLayer == _basicLayerName) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER;
_layers.Remove(movingLayer);
return InsertAfter(targetLayer, movingLayer);
2023-03-26 11:19:03 +08:00
}
public Builder Add(params string[] newLayers) => Insert(ADD_LAYER, newLayers);
public Builder Insert(string targetLayer, params string[] newLayers)
{
int index = _layers.IndexOf(targetLayer);
if (index < 0)
throw new KeyNotFoundException($"Layer {targetLayer} not found");
2023-05-30 00:13:05 +08:00
_layers.InsertRange(index, newLayers.Where(o => !Contains(o)));
return _source;
}
public Builder InsertAfter(string targetLayer, params string[] newLayers)
{
int index = _layers.IndexOf(targetLayer);
if (index < 0)
throw new KeyNotFoundException($"Layer {targetLayer} not found");
if (targetLayer == _basicLayerName) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER;
if (++index >= _layers.Count)
2023-05-30 00:13:05 +08:00
_layers.AddRange(newLayers.Where(o => !Contains(o)));
else
2023-05-30 00:13:05 +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)
{
if (targetLayer == _basicLayerName) // нужно чтобы метод Add работал правильно. _basicLayerName и ADD_LAYER считается одним слоем, поэтому Before = _basicLayerName After = ADD_LAYER
targetLayer = ADD_LAYER;
foreach (var movingLayer in movingLayers)
_layers.Remove(movingLayer);
return InsertAfter(targetLayer, movingLayers);
}
2023-05-30 00:13:05 +08:00
public bool Contains(string layer) => _layers.Contains(layer);
public List<string>.Enumerator GetEnumerator() => _layers.GetEnumerator();
IEnumerator<string> IEnumerable<string>.GetEnumerator() => _layers.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _layers.GetEnumerator();
2023-03-26 11:19:03 +08:00
}
}
#endregion
}
public interface IEcsModule
{
2023-05-30 17:56:53 +08:00
void Import(EcsPipeline.Builder b);
2023-03-26 11:19:03 +08:00
}
2023-03-30 05:32:43 +08:00
#region Extensions
2023-06-22 14:31:13 +08:00
public static partial class EcsPipelineExtensions
2023-03-26 11:19:03 +08:00
{
public static bool IsNullOrDestroyed(this EcsPipeline self)
2023-03-26 11:19:03 +08:00
{
return self == null || self.IsDestoryed;
}
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> range, string layerName = null)
{
foreach (var item in range)
{
self.Add(item, layerName);
}
2023-03-26 11:19:03 +08:00
return self;
}
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> range, string layerName = null)
2023-03-30 05:32:43 +08:00
{
foreach (var item in range)
{
self.AddUnique(item, layerName);
}
2023-03-30 05:32:43 +08:00
return self;
}
public static EcsPipeline BuildAndInit(this EcsPipeline.Builder self)
{
2023-03-30 05:32:43 +08:00
EcsPipeline result = self.Build();
result.Init();
return result;
}
2023-03-26 11:19:03 +08:00
}
2023-03-30 05:32:43 +08:00
#endregion
#region SystemsLayerMarkerSystem
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Black)]
public class SystemsLayerMarkerSystem : IEcsSystem
{
public readonly string name;
public SystemsLayerMarkerSystem(string name) => this.name = name;
}
#endregion
#region EcsProcess
public readonly struct EcsProcessRaw : IEnumerable
{
private readonly Array _systems;
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems.Length; }
}
public IEcsSystem this[int index]
{
get { return (IEcsSystem)_systems.GetValue(index); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcessRaw(Array systems)
{
_systems = systems;
}
public IEnumerator GetEnumerator()
{
return _systems.GetEnumerator();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal T[] GetSystems_Internal<T>()
{
return (T[])_systems;
}
}
public readonly struct EcsProcess<TProcess> : IReadOnlyCollection<TProcess>
where TProcess : IEcsSystem
{
public readonly static EcsProcess<TProcess> Empty = new EcsProcess<TProcess>(Array.Empty<TProcess>());
private readonly TProcess[] _systems;
public bool IsNullOrEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems == null || _systems.Length <= 0; }
}
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems.Length; }
}
int IReadOnlyCollection<TProcess>.Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems.Length; }
}
public TProcess this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems[index]; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcess(TProcess[] systems)
{
_systems = systems;
}
public static explicit operator EcsProcess<TProcess>(EcsProcessRaw raw)
{
return new EcsProcess<TProcess>(raw.GetSystems_Internal<TProcess>());
}
public static implicit operator EcsProcessRaw(EcsProcess<TProcess> process)
{
return new EcsProcessRaw(process._systems);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator() { return new Enumerator(_systems); }
IEnumerator<TProcess> IEnumerable<TProcess>.GetEnumerator() { return GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
public struct Enumerator : IEnumerator<TProcess>
{
private readonly TProcess[] _systems;
private int _index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator(TProcess[] systems)
{
_systems = systems;
_index = -1;
}
public TProcess Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems[_index]; }
}
object IEnumerator.Current { get { return Current; } }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() { return ++_index < _systems.Length; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset() { _index = -1; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() { }
}
}
#endregion
}