DragonECS/src/EcsPipeline.cs

496 lines
16 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.Diagnostics;
using System.Linq;
2023-03-26 11:19:03 +08:00
using System.Runtime.CompilerServices;
2024-08-07 10:40:31 +08:00
using static DCFApixels.DragonECS.EcsConsts;
2023-03-26 11:19:03 +08:00
namespace DCFApixels.DragonECS
{
2024-08-14 20:39:55 +08:00
public interface IEcsMember { }
2024-12-03 16:59:32 +08:00
public interface INamedMember
{
string Name { get; }
}
2024-08-14 20:39:55 +08:00
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
2024-08-07 10:40:31 +08:00
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "...")]
2024-10-12 00:08:12 +08:00
[MetaID("F064557C92010419AB677453893D00AE")]
public interface IEcsPipelineMember : IEcsProcess
2024-02-17 00:10:38 +08:00
{
EcsPipeline Pipeline { get; set; }
2024-02-17 00:10:38 +08:00
}
2024-08-14 20:39:55 +08:00
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
2024-08-07 10:40:31 +08:00
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(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.")]
2024-10-12 00:08:12 +08:00
[MetaID("9F5A557C9201C5C3D9BCAC2FF1CC07D4")]
public sealed partial class EcsPipeline
2023-03-26 11:19:03 +08:00
{
2024-03-07 07:48:18 +08:00
private readonly IConfigContainer _configs;
2024-02-22 23:48:10 +08:00
private Injector _injector;
2023-03-26 11:19:03 +08:00
private IEcsProcess[] _allSystems;
private Dictionary<Type, Array> _processes = new Dictionary<Type, Array>();
private Dictionary<Type, IEcsRunner> _runners = new Dictionary<Type, IEcsRunner>();
private EcsRunRunner _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
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-10-31 14:46:21 +08:00
private static EcsProfilerMarker _initMarker = new EcsProfilerMarker("EcsPipeline.Init");
#endif
2024-02-22 23:48:10 +08:00
2023-03-26 11:19:03 +08:00
#region Properties
2024-03-07 07:48:18 +08:00
public IConfigContainer Configs
{
2024-03-07 07:48:18 +08:00
get { return _configs; }
}
public Injector Injector
{
get { return _injector; }
}
public EcsProcess<IEcsProcess> AllSystems
{
get { return new EcsProcess<IEcsProcess>(_allSystems); }
}
public IReadOnlyDictionary<Type, IEcsRunner> AllRunners
{
get { return _runners; }
}
2024-02-22 23:48:10 +08:00
public bool IsInit
{
get { return _isInit; }
}
2025-03-10 13:00:30 +08:00
public bool IsDestroyed
2024-02-22 23:48:10 +08:00
{
get { return _isDestoryed; }
}
2023-03-26 11:19:03 +08:00
#endregion
#region Constructors
2024-03-07 07:48:18 +08:00
private EcsPipeline(IConfigContainer configs, Injector.Builder injectorBuilder, IEcsProcess[] systems)
2023-03-26 11:19:03 +08:00
{
2024-03-07 07:48:18 +08:00
_configs = configs;
2023-03-26 11:19:03 +08:00
_allSystems = systems;
2025-03-13 20:46:51 +08:00
injectorBuilder.Inject(this);
var members = GetProcess<IEcsPipelineMember>();
for (int i = 0; i < members.Length; i++)
{
members[i].Pipeline = this;
}
_injector = injectorBuilder.Build(this);
2023-03-26 11:19:03 +08:00
}
#endregion
#region GetProcess
public EcsProcess<T> GetProcess<T>() where T : IEcsProcess
2024-02-17 00:10:27 +08:00
{
Type type = typeof(T);
T[] result;
2024-02-22 23:48:10 +08:00
if (_processes.TryGetValue(type, out Array array))
{
result = (T[])array;
}
else
{
2024-07-08 11:08:04 +08:00
result = CreateProcess<T>();
_processes.Add(type, result);
}
return new EcsProcess<T>(result);
2024-02-17 00:10:27 +08:00
}
2024-07-08 11:08:04 +08:00
[ThreadStatic]
private static IEcsProcess[] _buffer;
private T[] CreateProcess<T>() where T : IEcsProcess
{
2024-07-08 20:31:42 +08:00
if (_buffer == null || _buffer.Length < _allSystems.Length)
2024-07-08 11:08:04 +08:00
{
2024-07-08 20:31:42 +08:00
Array.Resize(ref _buffer, _allSystems.Length);
2024-07-08 11:08:04 +08:00
}
int l = 0;
for (int i = 0, iMax = _allSystems.Length; i < iMax; i++)
{
if (_allSystems[i] is T)
{
_buffer[l++] = _allSystems[i];
}
}
T[] result = new T[l];
Array.Copy(_buffer, result, l);
return result;
}
#endregion
#region GetRunner
public TRunner GetRunnerInstance<TRunner>() where TRunner : EcsRunner, IEcsRunner, new()
{
Type runnerType = typeof(TRunner);
if (_runners.TryGetValue(runnerType, out IEcsRunner result))
{
return (TRunner)result;
}
2025-03-13 20:46:51 +08:00
TRunner runnerInstance = new TRunner();
#if DEBUG && !DISABLE_DEBUG
EcsRunner.CheckRunnerTypeIsValide(runnerType, runnerInstance.Interface);
#endif
2025-03-13 20:46:51 +08:00
runnerInstance.Init_Internal(this);
_runners.Add(runnerType, runnerInstance);
_runners.Add(runnerInstance.Interface, runnerInstance);
Injector.ExtractAllTo(runnerInstance);
// init after.
Injector.Inject(runnerInstance);
return runnerInstance;
}
public T GetRunner<T>() where T : IEcsProcess
2024-01-26 02:26:17 +08:00
{
if (_runners.TryGetValue(typeof(T), out IEcsRunner result))
2024-02-17 00:10:27 +08:00
{
return (T)result;
2024-02-17 00:10:27 +08:00
}
2024-04-22 17:49:24 +08:00
Throw.Exception("No matching runner found.");
return default;
2024-01-26 02:26:17 +08:00
}
public bool TryGetRunner<T>(out T runner) where T : IEcsProcess
2023-03-26 11:19:03 +08:00
{
if (_runners.TryGetValue(typeof(T), out IEcsRunner result))
2024-01-26 02:26:17 +08:00
{
runner = (T)result;
return true;
2024-01-26 02:26:17 +08:00
}
runner = default;
return false;
2023-03-26 11:19:03 +08:00
}
#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;
}
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-25 18:33:17 +08:00
_initMarker.Begin();
#endif
2024-02-17 00:10:38 +08:00
GetRunnerInstance<EcsPreInitRunner>().PreInit();
GetRunnerInstance<EcsInitRunner>().Init();
_runRunnerCache = GetRunnerInstance<EcsRunRunner>();
2023-06-10 19:46:35 +08:00
_isInit = true;
GC.Collect();
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
2024-02-25 18:33:17 +08:00
_initMarker.End();
#endif
}
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
if (!_isInit) { Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run)); }
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
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;
GetRunnerInstance<EcsDestroyRunner>().Destroy();
2023-03-26 11:19:03 +08:00
}
#endregion
#region Builder
2024-03-07 07:48:18 +08:00
public static Builder New(IConfigContainerWriter config = null)
{
return new Builder(config);
}
2023-03-26 11:19:03 +08:00
#endregion
}
2024-09-08 19:39:43 +08:00
#region EcsModule
2023-03-26 11:19:03 +08:00
public interface IEcsModule
{
2023-05-30 17:56:53 +08:00
void Import(EcsPipeline.Builder b);
2023-03-26 11:19:03 +08:00
}
2024-10-19 00:03:02 +08:00
public abstract class EcsModule<T> : IEcsModule, IInjectionUnit, IEcsDefaultAddParams
2024-09-07 21:20:29 +08:00
{
2024-10-19 00:03:02 +08:00
AddParams IEcsDefaultAddParams.AddParams { get { return AddParams; } }
protected virtual AddParams AddParams { get { return default; } }
2024-09-07 21:20:29 +08:00
public abstract void Import(EcsPipeline.Builder b);
void IInjectionUnit.InitInjectionNode(InjectionGraph nodes) { nodes.AddNode<T>(); }
2024-09-07 21:20:29 +08:00
public EcsModule() { if (GetType() != typeof(T)) { Throw.UndefinedException(); } }
}
2024-09-08 19:39:43 +08:00
#endregion
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
{
2025-03-10 13:00:30 +08:00
return self == null || self.IsDestroyed;
}
public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable<IEcsProcess> 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<IEcsProcess> 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)]
2024-08-07 10:40:31 +08:00
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
[MetaDescription(AUTHOR, "An auxiliary type of system for dividing a pipeline into layers. This system is automatically added to the EcsPipeline.")]
2024-10-12 14:48:13 +08:00
[MetaID("42596C7C9201D0B85D1335E6E4704B57")]
public class SystemsLayerMarkerSystem : IEcsProcess
{
public readonly string name;
2024-06-25 22:15:54 +08:00
public readonly string layerNameSpace;
public readonly string layerName;
public SystemsLayerMarkerSystem(string name)
{
this.name = name;
int indexof = name.LastIndexOf('.');
2024-06-25 23:35:51 +08:00
if (indexof > 0)
2024-06-25 22:15:54 +08:00
{
layerNameSpace = name.Substring(0, indexof + 1);
layerName = name.Substring(indexof + 1);
}
else
{
layerNameSpace = string.Empty;
layerName = name;
}
}
public override string ToString() { return name; }
}
#endregion
#region EcsProcess
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2024-10-31 14:46:21 +08:00
public readonly struct EcsProcessRaw : IReadOnlyCollection<IEcsProcess>
{
2024-10-31 14:46:21 +08:00
public static readonly EcsProcessRaw Empty = new EcsProcessRaw(Array.Empty<IEcsProcess>());
private readonly Array _systems;
#region Properties
2024-10-31 14:46:21 +08:00
public bool IsNullOrEmpty
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems == null || _systems.Length <= 0; }
}
public int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems.Length; }
}
2024-10-31 14:46:21 +08:00
int IReadOnlyCollection<IEcsProcess>.Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _systems.Length; }
}
public IEcsProcess this[int index]
{
get { return (IEcsProcess)_systems.GetValue(index); }
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcessRaw(Array systems)
{
_systems = systems;
}
#endregion
#region Enumerator
2024-10-31 14:46:21 +08:00
IEnumerator<IEcsProcess> IEnumerable<IEcsProcess>.GetEnumerator()
{
return ((IEnumerable<IEcsProcess>)(EcsProcess<IEcsProcess>)this).GetEnumerator();
}
public IEnumerator GetEnumerator()
{
return _systems.GetEnumerator();
}
#endregion
#region Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal T[] GetSystems_Internal<T>()
{
return (T[])_systems;
}
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private EcsProcessRaw _process;
2024-05-01 13:38:08 +08:00
public IEnumerable<IEcsProcess> Systems
{
get
{
2024-05-01 13:38:08 +08:00
return _process._systems.Cast<IEcsProcess>().ToArray();
}
}
public int Count
{
get { return _process.Length; }
}
public DebuggerProxy(EcsProcessRaw process)
{
_process = process;
}
}
#endregion
}
[DebuggerTypeProxy(typeof(EcsProcess<>.DebuggerProxy))]
public readonly struct EcsProcess<TProcess> : IReadOnlyCollection<TProcess>
where TProcess : IEcsProcess
{
2024-10-31 14:46:21 +08:00
public static readonly EcsProcess<TProcess> Empty = new EcsProcess<TProcess>(Array.Empty<TProcess>());
private readonly TProcess[] _systems;
#region Properties
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]; }
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsProcess(TProcess[] systems)
{
_systems = systems;
}
#endregion
#region Converts
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);
}
#endregion
#region Enumerator
[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)]
2024-09-07 17:18:35 +08:00
void IDisposable.Dispose() { }
}
#endregion
#region DebuggerProxy
internal class DebuggerProxy
{
private EcsProcess<TProcess> _process;
2024-05-01 13:38:08 +08:00
public IEnumerable<IEcsProcess> Systems
{
get
{
2024-05-01 13:38:08 +08:00
return _process._systems.Cast<IEcsProcess>().ToArray();
}
}
public int Count
{
get { return _process.Length; }
}
public DebuggerProxy(EcsProcess<TProcess> process)
{
_process = process;
}
2024-04-29 21:59:33 +08:00
}
#endregion
}
#endregion
}