#if DISABLE_DEBUG #undef DEBUG #endif using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.RunnersCore; using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; using static DCFApixels.DragonECS.EcsConsts; namespace DCFApixels.DragonECS { public interface IEcsMember { } public interface INamedMember { string Name { get; } } [MetaColor(MetaColor.DragonRose)] [MetaGroup(PACK_GROUP, OTHER_GROUP)] [MetaDescription(AUTHOR, "...")] [MetaID("F064557C92010419AB677453893D00AE")] public interface IEcsPipelineMember : IEcsProcess { EcsPipeline Pipeline { get; set; } } [MetaColor(MetaColor.DragonRose)] [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.")] [MetaID("9F5A557C9201C5C3D9BCAC2FF1CC07D4")] public sealed partial class EcsPipeline { private readonly IConfigContainer _configs; private Injector _injector; private IEcsProcess[] _allSystems; private Dictionary _processes = new Dictionary(); private Dictionary _runners = new Dictionary(); private EcsRunRunner _runRunnerCache; private bool _isInit = false; private bool _isDestoryed = false; #if DEBUG private static EcsProfilerMarker _initMarker = new EcsProfilerMarker("EcsPipeline.Init"); #endif #region Properties public IConfigContainer Configs { get { return _configs; } } public Injector Injector { get { return _injector; } } public EcsProcess AllSystems { get { return new EcsProcess(_allSystems); } } public IReadOnlyDictionary AllRunners { get { return _runners; } } public bool IsInit { get { return _isInit; } } public bool IsDestroyed { get { return _isDestoryed; } } #endregion #region Constructors private EcsPipeline(IConfigContainer configs, Injector.Builder injectorBuilder, IEcsProcess[] systems) { _configs = configs; _allSystems = systems; injectorBuilder.Inject(this); var members = GetProcess(); for (int i = 0; i < members.Length; i++) { members[i].Pipeline = this; } _injector = injectorBuilder.Build(this); } #endregion #region GetProcess public EcsProcess GetProcess() where T : IEcsProcess { Type type = typeof(T); T[] result; if (_processes.TryGetValue(type, out Array array)) { result = (T[])array; } else { result = CreateProcess(); _processes.Add(type, result); } return new EcsProcess(result); } [ThreadStatic] private static IEcsProcess[] _buffer; private T[] CreateProcess() where T : IEcsProcess { if (_buffer == null || _buffer.Length < _allSystems.Length) { Array.Resize(ref _buffer, _allSystems.Length); } 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() where TRunner : EcsRunner, IEcsRunner, new() { Type runnerType = typeof(TRunner); if (_runners.TryGetValue(runnerType, out IEcsRunner result)) { return (TRunner)result; } TRunner runnerInstance = new TRunner(); #if DEBUG EcsRunner.CheckRunnerTypeIsValide(runnerType, runnerInstance.Interface); #endif 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() where T : IEcsProcess { if (_runners.TryGetValue(typeof(T), out IEcsRunner result)) { return (T)result; } Throw.Exception("No matching runner found."); return default; } public bool TryGetRunner(out T runner) where T : IEcsProcess { if (_runners.TryGetValue(typeof(T), out IEcsRunner result)) { runner = (T)result; return true; } runner = default; return false; } #endregion #region Internal internal void OnRunnerDestroy_Internal(IEcsRunner runner) { _runners.Remove(runner.Interface); } #endregion #region LifeCycle public void Init() { if (_isInit == true) { EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been initialized"); return; } #if DEBUG _initMarker.Begin(); #endif GetRunnerInstance().PreInit(); GetRunnerInstance().Init(); _runRunnerCache = GetRunnerInstance(); _isInit = true; GC.Collect(); #if DEBUG _initMarker.End(); #endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Run() { #if DEBUG || DRAGONECS_STABILITY_MODE if (!_isInit) { Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run)); } if (_isDestoryed) { Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run)); } #endif _runRunnerCache.Run(); } public void Destroy() { #if DEBUG || DRAGONECS_STABILITY_MODE if (!_isInit) { Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy)); } #endif if (_isDestoryed) { EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been destroyed"); return; } _isDestoryed = true; GetRunnerInstance().Destroy(); } #endregion #region Builder public static Builder New(IConfigContainerWriter config = null) { return new Builder(config); } #endregion } #region EcsModule public interface IEcsModule { void Import(EcsPipeline.Builder b); } public abstract class EcsModule : IEcsModule, IInjectionUnit, IEcsDefaultAddParams { AddParams IEcsDefaultAddParams.AddParams { get { return AddParams; } } protected virtual AddParams AddParams { get { return default; } } public abstract void Import(EcsPipeline.Builder b); void IInjectionUnit.InitInjectionNode(InjectionGraph nodes) { nodes.AddNode(); } public EcsModule() { if (GetType() != typeof(T)) { Throw.UndefinedException(); } } } #endregion #region Extensions public static partial class EcsPipelineExtensions { public static bool IsNullOrDestroyed(this EcsPipeline self) { return self == null || self.IsDestroyed; } public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable range, string layerName = null) { foreach (var item in range) { self.Add(item, layerName); } return self; } public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEnumerable range, string layerName = null) { foreach (var item in range) { self.AddUnique(item, layerName); } return self; } public static EcsPipeline BuildAndInit(this EcsPipeline.Builder self) { EcsPipeline result = self.Build(); result.Init(); return result; } } #endregion #region SystemsLayerMarkerSystem [MetaTags(MetaTags.HIDDEN)] [MetaColor(MetaColor.Black)] [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.")] [MetaID("42596C7C9201D0B85D1335E6E4704B57")] public class SystemsLayerMarkerSystem : IEcsProcess { public readonly string name; public readonly string layerNameSpace; public readonly string layerName; public SystemsLayerMarkerSystem(string name) { this.name = name; int indexof = name.LastIndexOf('.'); if (indexof > 0) { 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))] public readonly struct EcsProcessRaw : IReadOnlyCollection { public static readonly EcsProcessRaw Empty = new EcsProcessRaw(Array.Empty()); private readonly Array _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.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 IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)(EcsProcess)this).GetEnumerator(); } public IEnumerator GetEnumerator() { return _systems.GetEnumerator(); } #endregion #region Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] internal T[] GetSystems_Internal() { return (T[])_systems; } #endregion #region DebuggerProxy internal class DebuggerProxy { private EcsProcessRaw _process; public IEnumerable Systems { get { return _process._systems.Cast().ToArray(); } } public int Count { get { return _process.Length; } } public DebuggerProxy(EcsProcessRaw process) { _process = process; } } #endregion } [DebuggerTypeProxy(typeof(EcsProcess<>.DebuggerProxy))] public readonly struct EcsProcess : IReadOnlyCollection where TProcess : IEcsProcess { public static readonly EcsProcess Empty = new EcsProcess(Array.Empty()); 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.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(EcsProcessRaw raw) { return new EcsProcess(raw.GetSystems_Internal()); } public static implicit operator EcsProcessRaw(EcsProcess process) { return new EcsProcessRaw(process._systems); } #endregion #region Enumerator [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() { return new Enumerator(_systems); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public struct Enumerator : IEnumerator { 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)] void IDisposable.Dispose() { } } #endregion #region DebuggerProxy internal class DebuggerProxy { private EcsProcess _process; public IEnumerable Systems { get { return _process._systems.Cast().ToArray(); } } public int Count { get { return _process.Length; } } public DebuggerProxy(EcsProcess process) { _process = process; } } #endregion } #endregion }