diff --git a/src/Builtin/BaseProcesses.cs b/src/Builtin/BaseProcesses.cs index 8697b95..8cc945f 100644 --- a/src/Builtin/BaseProcesses.cs +++ b/src/Builtin/BaseProcesses.cs @@ -5,231 +5,228 @@ using System; namespace DCFApixels.DragonECS { - #region Interfaces [MetaName(nameof(PreInit))] [MetaColor(MetaColor.Orange)] - [BindWithEcsRunner(typeof(EcsPreInitProcessRunner))] - public interface IEcsPreInitProcess : IEcsProcess + [BindWithEcsRunner(typeof(EcsPreInitRunner))] + public interface IEcsPreInit : IEcsSystem { void PreInit(); } [MetaName(nameof(Init))] [MetaColor(MetaColor.Orange)] - [BindWithEcsRunner(typeof(EcsInitProcessRunner))] - public interface IEcsInitProcess : IEcsProcess + [BindWithEcsRunner(typeof(EcsInitRunner))] + public interface IEcsInit : IEcsSystem { void Init(); } [MetaName(nameof(Run))] [MetaColor(MetaColor.Orange)] - [BindWithEcsRunner(typeof(EcsRunProcessRunner))] - public interface IEcsRunProcess : IEcsProcess + [BindWithEcsRunner(typeof(EcsRunRunner))] + public interface IEcsRun : IEcsSystem { void Run(); } [MetaName(nameof(Destroy))] [MetaColor(MetaColor.Orange)] - [BindWithEcsRunner(typeof(EcsDestroyProcessRunner))] - public interface IEcsDestroyProcess : IEcsProcess + [BindWithEcsRunner(typeof(EcsDestroyRunner))] + public interface IEcsDestroy : IEcsSystem { void Destroy(); } +} - #endregion - - namespace Internal +namespace DCFApixels.DragonECS.Internal +{ + [MetaColor(MetaColor.Orange)] + public sealed class EcsPreInitRunner : EcsRunner, IEcsPreInit { - [MetaColor(MetaColor.Orange)] - public sealed class EcsPreInitProcessRunner : EcsRunner, IEcsPreInitProcess +#if DEBUG && !DISABLE_DEBUG + private EcsProfilerMarker[] _markers; + protected override void OnSetup() { -#if DEBUG && !DISABLE_DEBUG - private EcsProfilerMarker[] _markers; - protected override void OnSetup() + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) { - _markers = new EcsProfilerMarker[targets.Length]; - for (int i = 0; i < targets.Length; i++) - { - _markers[i] = new EcsProfilerMarker($"{targets[i].GetType().Name}.{nameof(PreInit)}"); - } - } -#endif - public void PreInit() - { -#if DEBUG && !DISABLE_DEBUG - for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) - { - _markers[i].Begin(); - try - { - targets[i].PreInit(); - } - catch (Exception e) - { -#if DISABLE_CATH_EXCEPTIONS - throw e; -#endif - EcsDebug.PrintError(e); - } - _markers[i].End(); - } -#else - foreach (var item in targets) - { - try { item.PreInit(); } - catch (Exception e) - { -#if DISABLE_CATH_EXCEPTIONS - throw e; -#endif - EcsDebug.PrintError(e); - } - } -#endif + _markers[i] = new EcsProfilerMarker($"{Process[i].GetType().Name}.{nameof(PreInit)}"); } } - [MetaColor(MetaColor.Orange)] - public sealed class EcsInitProcessRunner : EcsRunner, IEcsInitProcess +#endif + public void PreInit() { #if DEBUG && !DISABLE_DEBUG - private EcsProfilerMarker[] _markers; - protected override void OnSetup() + for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++) { - _markers = new EcsProfilerMarker[targets.Length]; - for (int i = 0; i < targets.Length; i++) + _markers[i].Begin(); + try { - _markers[i] = new EcsProfilerMarker($"{targets[i].GetType().Name}.{nameof(Init)}"); + Process[i].PreInit(); + } + catch (Exception e) + { +#if DISABLE_CATH_EXCEPTIONS + throw; +#endif + EcsDebug.PrintError(e); + } + _markers[i].End(); + } +#else + foreach (var item in Process) + { + try { item.PreInit(); } + catch (Exception e) + { +#if DISABLE_CATH_EXCEPTIONS + throw; +#endif + EcsDebug.PrintError(e); } } #endif - public void Init() - { + } + } + [MetaColor(MetaColor.Orange)] + public sealed class EcsInitRunner : EcsRunner, IEcsInit + { #if DEBUG && !DISABLE_DEBUG - for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) - { - _markers[i].Begin(); - try - { - targets[i].Init(); - } - catch (Exception e) - { -#if DISABLE_CATH_EXCEPTIONS - throw e; -#endif - EcsDebug.PrintError(e); - } - _markers[i].End(); - } -#else - foreach (var item in targets) - { - try { item.Init(); } - catch (Exception e) - { -#if DISABLE_CATH_EXCEPTIONS - throw e; -#endif - EcsDebug.PrintError(e); - } - } -#endif + private EcsProfilerMarker[] _markers; + protected override void OnSetup() + { + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) + { + _markers[i] = new EcsProfilerMarker($"{Process[i].GetType().Name}.{nameof(Init)}"); } } - [MetaColor(MetaColor.Orange)] - public sealed class EcsRunProcessRunner : EcsRunner, IEcsRunProcess +#endif + public void Init() { #if DEBUG && !DISABLE_DEBUG - private EcsProfilerMarker[] _markers; - protected override void OnSetup() + for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++) { - _markers = new EcsProfilerMarker[targets.Length]; - for (int i = 0; i < targets.Length; i++) + _markers[i].Begin(); + try { - _markers[i] = new EcsProfilerMarker($"{targets[i].GetType().Name}.{nameof(Run)}"); + Process[i].Init(); + } + catch (Exception e) + { +#if DISABLE_CATH_EXCEPTIONS + throw; +#endif + EcsDebug.PrintError(e); + } + _markers[i].End(); + } +#else + foreach (var item in Process) + { + try { item.Init(); } + catch (Exception e) + { +#if DISABLE_CATH_EXCEPTIONS + throw; +#endif + EcsDebug.PrintError(e); } } #endif - public void Run() - { + } + } + [MetaColor(MetaColor.Orange)] + public sealed class EcsRunRunner : EcsRunner, IEcsRun + { #if DEBUG && !DISABLE_DEBUG - for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) - { - _markers[i].Begin(); - try - { - targets[i].Run(); - } - catch (Exception e) - { -#if DISABLE_CATH_EXCEPTIONS - throw e; -#endif - EcsDebug.PrintError(e); - } - _markers[i].End(); - } -#else - foreach (var item in targets) - { - try { item.Run(); } - catch (Exception e) - { -#if DISABLE_CATH_EXCEPTIONS - throw e; -#endif - EcsDebug.PrintError(e); - } - } -#endif + private EcsProfilerMarker[] _markers; + protected override void OnSetup() + { + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) + { + _markers[i] = new EcsProfilerMarker($"{Process[i].GetType().Name}.{nameof(Run)}"); } } - [MetaColor(MetaColor.Orange)] - public sealed class EcsDestroyProcessRunner : EcsRunner, IEcsDestroyProcess +#endif + public void Run() { #if DEBUG && !DISABLE_DEBUG - private EcsProfilerMarker[] _markers; - protected override void OnSetup() + for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++) { - _markers = new EcsProfilerMarker[targets.Length]; - for (int i = 0; i < targets.Length; i++) + _markers[i].Begin(); + try { - _markers[i] = new EcsProfilerMarker($"{targets[i].GetType().Name}.{nameof(IEcsDestroyProcess.Destroy)}"); + Process[i].Run(); } - } -#endif - void IEcsDestroyProcess.Destroy() - { -#if DEBUG && !DISABLE_DEBUG - for (int i = 0; i < targets.Length && targets.Length <= _markers.Length; i++) + catch (Exception e) { - _markers[i].Begin(); - try - { - targets[i].Destroy(); - } - catch (Exception e) - { #if DISABLE_CATH_EXCEPTIONS - throw e; + throw; #endif - EcsDebug.PrintError(e); - } - _markers[i].End(); + EcsDebug.PrintError(e); } + _markers[i].End(); + } #else - foreach (var item in targets) + foreach (var item in Process) + { + try { item.Run(); } + catch (Exception e) { - try { item.Destroy(); } - catch (Exception e) - { #if DISABLE_CATH_EXCEPTIONS - throw e; + throw; #endif - EcsDebug.PrintError(e); - } + EcsDebug.PrintError(e); } -#endif } +#endif + } + } + [MetaColor(MetaColor.Orange)] + public sealed class EcsDestroyRunner : EcsRunner, IEcsDestroy + { +#if DEBUG && !DISABLE_DEBUG + private EcsProfilerMarker[] _markers; + protected override void OnSetup() + { + _markers = new EcsProfilerMarker[Process.Length]; + for (int i = 0; i < Process.Length; i++) + { + _markers[i] = new EcsProfilerMarker($"{Process[i].GetType().Name}.{nameof(IEcsDestroy.Destroy)}"); + } + } +#endif + void IEcsDestroy.Destroy() + { +#if DEBUG && !DISABLE_DEBUG + for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++) + { + _markers[i].Begin(); + try + { + Process[i].Destroy(); + } + catch (Exception e) + { +#if DISABLE_CATH_EXCEPTIONS + throw; +#endif + EcsDebug.PrintError(e); + } + _markers[i].End(); + } +#else + foreach (var item in Process) + { + try { item.Destroy(); } + catch (Exception e) + { +#if DISABLE_CATH_EXCEPTIONS + throw; +#endif + EcsDebug.PrintError(e); + } + } +#endif } } } diff --git a/src/Builtin/InjectSystem.cs b/src/Builtin/InjectSystem.cs deleted file mode 100644 index fdb4f5e..0000000 --- a/src/Builtin/InjectSystem.cs +++ /dev/null @@ -1,241 +0,0 @@ -using DCFApixels.DragonECS.Internal; -using DCFApixels.DragonECS.RunnersCore; -using System; - -namespace DCFApixels.DragonECS -{ - public readonly struct Injector - { - private readonly EcsPipeline _pipeline; - public Injector(EcsPipeline pipeline) - { - _pipeline = pipeline; - } - public void Inject(T data) - { - _pipeline.Inject(data); - } - } - public interface IInjectionBlock - { - void InjectTo(Injector i); - } - - [MetaName(nameof(PreInject))] - [BindWithEcsRunner(typeof(EcsPreInjectRunner))] - public interface IEcsPreInject : IEcsProcess - { - void PreInject(object obj); - } - [MetaName(nameof(Inject))] - [BindWithEcsRunner(typeof(EcsInjectRunner<>))] - public interface IEcsInject : IEcsProcess - { - void Inject(T obj); - } - [MetaName("PreInitInject")] - [BindWithEcsRunner(typeof(EcsPreInitInjectProcessRunner))] - public interface IEcsPreInitInjectProcess : IEcsProcess - { - void OnPreInitInjectionBefore(); - void OnPreInitInjectionAfter(); - } - - namespace Internal - { - internal class InitInjectController - { - private EcsPipeline _source; - private InitInjectSystemBase[] _injectSystems; - private int _injectCount; - public bool IsInjectionEnd - { - get { return _injectCount >= _injectSystems.Length; } - } - public InitInjectController(EcsPipeline source) - { - _injectCount = 0; - _source = source; - _injectSystems = _source.GetSystems(); - } - public bool OnInject() - { - _injectCount++; - return IsInjectionEnd; - } - public void Destroy() - { - _source = null; - _injectSystems = null; - } - } - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Gray)] - public sealed class EcsPreInjectRunner : EcsRunner, IEcsPreInject - { - void IEcsPreInject.PreInject(object obj) - { - if (obj is IInjectionBlock container) - { - container.InjectTo(new Injector(Pipeline)); - } - foreach (var item in targets) - { - item.PreInject(obj); - } - } - } - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Gray)] - public sealed class EcsInjectRunner : EcsRunner>, IEcsInject - { - private EcsBaseTypeInjectRunner _baseTypeInjectRunner; - void IEcsInject.Inject(T obj) - { - if (obj == null) Throw.ArgumentNull(); - _baseTypeInjectRunner.Inject(obj); - foreach (var item in targets) item.Inject(obj); - } - protected override void OnSetup() - { - Type baseType = typeof(T).BaseType; - if (baseType != typeof(object) && baseType != typeof(ValueType) && baseType != null) - _baseTypeInjectRunner = (EcsBaseTypeInjectRunner)Activator.CreateInstance(typeof(EcsBaseTypeInjectRunner<>).MakeGenericType(baseType), Pipeline); - else - _baseTypeInjectRunner = new EcsObjectTypePreInjectRunner(Pipeline); - } - } - internal abstract class EcsBaseTypeInjectRunner - { - public abstract void Inject(object obj); - } - internal sealed class EcsBaseTypeInjectRunner : EcsBaseTypeInjectRunner - { - private IEcsInject _runner; - public EcsBaseTypeInjectRunner(EcsPipeline pipeline) => _runner = pipeline.GetRunner>(); - public sealed override void Inject(object obj) => _runner.Inject((T)obj); - } - internal sealed class EcsObjectTypePreInjectRunner : EcsBaseTypeInjectRunner - { - private IEcsPreInject _runner; - public EcsObjectTypePreInjectRunner(EcsPipeline pipeline) => _runner = pipeline.GetRunner(); - public sealed override void Inject(object obj) => _runner.PreInject(obj); - } - - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Gray)] - public sealed class EcsPreInitInjectProcessRunner : EcsRunner, IEcsPreInitInjectProcess - { - public void OnPreInitInjectionAfter() - { - foreach (var item in targets) item.OnPreInitInjectionAfter(); - } - public void OnPreInitInjectionBefore() - { - foreach (var item in targets) item.OnPreInitInjectionBefore(); - } - } - public abstract class InitInjectSystemBase { } - - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Gray)] - public class InitInjectSystem : InitInjectSystemBase, IEcsPipelineMember, IEcsInject, IEcsPreInitInjectProcess - { - private EcsPipeline _pipeline; - public EcsPipeline Pipeline - { - get { return Pipeline; } - set - { - _pipeline = value; - - if (_injectedData == null) - { - return; - } - if (_injectController == null) - { - var injectPipelineRunner = _pipeline.GetRunner>(); - injectPipelineRunner.Inject(_pipeline); - EcsRunner.Destroy(injectPipelineRunner); - - _injectController = new InitInjectController(_pipeline); - var injectMapRunner = _pipeline.GetRunner>(); - _pipeline.GetRunner().OnPreInitInjectionBefore(); - injectMapRunner.Inject(_injectController); - EcsRunner.Destroy(injectMapRunner); - } - var injectRunnerGeneric = _pipeline.GetRunner>(); - injectRunnerGeneric.Inject(_injectedData); - if (_injectController.OnInject()) - { - _injectController.Destroy(); - var injectCallbacksRunner = _pipeline.GetRunner(); - injectCallbacksRunner.OnPreInitInjectionAfter(); - EcsRunner.Destroy(injectCallbacksRunner); - } - _injectedData = default; - } - } - - private InitInjectController _injectController; - void IEcsInject.Inject(InitInjectController obj) { _injectController = obj; } - - private T _injectedData; - internal InitInjectSystem(T injectedData) - { - if (injectedData == null) Throw.ArgumentNull(); - _injectedData = injectedData; - } - void IEcsPreInitInjectProcess.OnPreInitInjectionBefore() { } - void IEcsPreInitInjectProcess.OnPreInitInjectionAfter() { _injectController = null; } - } - } - - public static partial class EcsPipelineExtensions - { - public static void Inject(this EcsPipeline self, T data) - { - self.GetRunner>().Inject(data); - } - } - public static partial class EcsPipelineBuilderExtensions - { - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T data) - { - if (data == null) Throw.ArgumentNull(); - self.Add(new InitInjectSystem(data)); - if (data is IEcsModule module) - self.AddModule(module); - return self; - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1) - { - return self.Inject(d0).Inject(d1); - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2) - { - return self.Inject(d0).Inject(d1).Inject(d2); - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3) - { - return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3); - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4) - { - return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4); - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f) - { - return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f); - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f, T6 d6) - { - return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f).Inject(d6); - } - public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f, T6 d6, T7 d7) - { - return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f).Inject(d6).Inject(d7); - } - } -} diff --git a/src/Builtin/InjectSystem/EcsPipelineExtensions.cs b/src/Builtin/InjectSystem/EcsPipelineExtensions.cs new file mode 100644 index 0000000..2ea31c2 --- /dev/null +++ b/src/Builtin/InjectSystem/EcsPipelineExtensions.cs @@ -0,0 +1,66 @@ +using DCFApixels.DragonECS.DI.Internal; + +namespace DCFApixels.DragonECS +{ + public static partial class EcsPipelineExtensions + { + public static void Inject(this EcsPipeline self, T data) + { + self.GetRunner>().Inject(data); + } + } + public static partial class EcsPipelineBuilderExtensions + { + public static EcsPipeline.Builder AddInjectionGraph(this EcsPipeline.Builder self, InjectionGraph graph) + { + self.Config.Set(InjectionGraph.CONFIG_NAME, graph); + return self; + } + public static EcsPipeline.Builder GetInjectionGraph(this EcsPipeline.Builder self, out InjectionGraph graph) + { + graph = self.Config.Get(InjectionGraph.CONFIG_NAME); + return self; + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T data) + { + if (data == null) + { + Throw.ArgumentNull(); + } + self.Add(new InitInjectionSystem(data)); + if (data is IEcsModule module) + { + self.AddModule(module); + } + return self; + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1) + { + return self.Inject(d0).Inject(d1); + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2) + { + return self.Inject(d0).Inject(d1).Inject(d2); + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3) + { + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3); + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4) + { + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4); + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f) + { + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f); + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f, T6 d6) + { + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f).Inject(d6); + } + public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2, T3 d3, T4 d4, T5 f, T6 d6, T7 d7) + { + return self.Inject(d0).Inject(d1).Inject(d2).Inject(d3).Inject(d4).Inject(f).Inject(d6).Inject(d7); + } + } +} \ No newline at end of file diff --git a/src/Builtin/InjectSystem/Exceptions.cs b/src/Builtin/InjectSystem/Exceptions.cs new file mode 100644 index 0000000..c48f0d9 --- /dev/null +++ b/src/Builtin/InjectSystem/Exceptions.cs @@ -0,0 +1,12 @@ +using System; + +namespace DCFApixels.DragonECS.DI.Internal +{ + internal class Throw + { + public static void ArgumentNull() + { + throw new ArgumentNullException(); + } + } +} diff --git a/src/Builtin/InjectSystem/IInjectionBlock.cs b/src/Builtin/InjectSystem/IInjectionBlock.cs new file mode 100644 index 0000000..68a9782 --- /dev/null +++ b/src/Builtin/InjectSystem/IInjectionBlock.cs @@ -0,0 +1,29 @@ +namespace DCFApixels.DragonECS +{ + public readonly struct Injector + { + private readonly InjectionGraph _injectionGraph; + public Injector(InjectionGraph injectionGraph) + { + _injectionGraph = injectionGraph; + } + public void Inject(T obj) + { + _injectionGraph.Inject(obj); + } + public void InjectNoBoxing(T data) + { + _injectionGraph.InjectNoBoxing(data); + } +#if !REFLECTION_DISABLED + public void InjectRaw(object obj) + { + _injectionGraph.InjectRaw(obj); + } +#endif + } + public interface IInjectionBlock + { + void InjectTo(Injector i); + } +} diff --git a/src/Builtin/InjectSystem/InitInjectionSystem.cs b/src/Builtin/InjectSystem/InitInjectionSystem.cs new file mode 100644 index 0000000..8537b0a --- /dev/null +++ b/src/Builtin/InjectSystem/InitInjectionSystem.cs @@ -0,0 +1,62 @@ +namespace DCFApixels.DragonECS.DI.Internal +{ + public abstract class InitInjectSystemBase : IEcsSystem { } + + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + public class InitInjectionSystem : InitInjectSystemBase, IEcsPipelineMember, IEcsInject, IEcsPreInitInjectProcess + { + private EcsPipeline _pipeline; + public EcsPipeline Pipeline + { + get { return Pipeline; } + set + { + _pipeline = value; + + if (_injectedData == null) + { + return; + } + if (_injectController == null) + { + _pipeline.Config.Get(InjectionGraph.CONFIG_NAME).Init(_pipeline); + var injectPipelineRunner = _pipeline.GetRunner>(); + injectPipelineRunner.Inject(_pipeline); + EcsRunner.Destroy(injectPipelineRunner); + + _injectController = new InitInjectController(_pipeline); + var injectMapRunner = _pipeline.GetRunner>(); + _pipeline.GetRunner().OnPreInitInjectionBefore(_pipeline); + injectMapRunner.Inject(_injectController); + EcsRunner.Destroy(injectMapRunner); + } + var injectRunnerGeneric = _pipeline.GetRunner>(); + injectRunnerGeneric.Inject(_injectedData); + if (_injectController.OnInject()) + { + _injectController.Destroy(); + var injectCallbacksRunner = _pipeline.GetRunner(); + injectCallbacksRunner.OnPreInitInjectionAfter(); + EcsRunner.Destroy(injectCallbacksRunner); + } + _injectedData = default; + } + } + + private InitInjectController _injectController; + void IEcsInject.Inject(InitInjectController obj) { _injectController = obj; } + + private T _injectedData; + internal InitInjectionSystem(T injectedData) + { + if (injectedData == null) + { + Throw.ArgumentNull(); + } + _injectedData = injectedData; + } + void IEcsPreInitInjectProcess.OnPreInitInjectionBefore(EcsPipeline pipeline) { } + void IEcsPreInitInjectProcess.OnPreInitInjectionAfter() { _injectController = null; } + } +} diff --git a/src/Builtin/InjectSystem/InjectProcesses.cs b/src/Builtin/InjectSystem/InjectProcesses.cs new file mode 100644 index 0000000..54b429d --- /dev/null +++ b/src/Builtin/InjectSystem/InjectProcesses.cs @@ -0,0 +1,75 @@ +using DCFApixels.DragonECS.DI.Internal; +using DCFApixels.DragonECS.RunnersCore; + +namespace DCFApixels.DragonECS +{ + [MetaName(nameof(Inject))] + [BindWithEcsRunner(typeof(EcsInjectRunner<>))] + public interface IEcsInject : IEcsSystem + { + void Inject(T obj); + } + [MetaName("PreInitInject")] + [BindWithEcsRunner(typeof(EcsInitInjectProcessRunner))] + public interface IEcsPreInitInjectProcess : IEcsSystem + { + void OnPreInitInjectionBefore(EcsPipeline pipeline); + void OnPreInitInjectionAfter(); + } +} +namespace DCFApixels.DragonECS.DI.Internal +{ + internal class InitInjectController + { + private EcsPipeline _source; + private EcsProcess _injectSystems; + private int _injectCount; + public bool IsInjectionEnd + { + get { return _injectCount >= _injectSystems.Length; } + } + public InitInjectController(EcsPipeline source) + { + _injectCount = 0; + _source = source; + _injectSystems = _source.GetProcess(); + } + public bool OnInject() + { + _injectCount++; + return IsInjectionEnd; + } + public void Destroy() + { + _source = null; + _injectSystems = EcsProcess.Empty; + } + } + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + public sealed class EcsInjectRunner : EcsRunner>, IEcsInject + { + private InjectionGraph _injectionGraph; + void IEcsInject.Inject(T obj) + { + _injectionGraph.Inject(obj); + } + protected override void OnSetup() + { + _injectionGraph = Pipeline.Config.Get(InjectionGraph.CONFIG_NAME); + } + } + [MetaTags(MetaTags.HIDDEN)] + [MetaColor(MetaColor.Gray)] + public sealed class EcsInitInjectProcessRunner : EcsRunner, IEcsPreInitInjectProcess + { + public void OnPreInitInjectionAfter() + { + foreach (var item in Process) item.OnPreInitInjectionAfter(); + } + public void OnPreInitInjectionBefore(EcsPipeline pipeline) + { + foreach (var item in Process) item.OnPreInitInjectionBefore(pipeline); + } + } +} diff --git a/src/Builtin/InjectSystem.cs.meta b/src/Builtin/InjectSystem/InjectSystem.cs.meta similarity index 100% rename from src/Builtin/InjectSystem.cs.meta rename to src/Builtin/InjectSystem/InjectSystem.cs.meta diff --git a/src/Builtin/InjectSystem/InjectionBranch.cs b/src/Builtin/InjectSystem/InjectionBranch.cs new file mode 100644 index 0000000..fcffe76 --- /dev/null +++ b/src/Builtin/InjectSystem/InjectionBranch.cs @@ -0,0 +1,65 @@ +using System; + +namespace DCFApixels.DragonECS +{ + public class InjectionBranch + { + private InjectionGraph _source; + private Type _type; + private InjectionNodeBase[] _nodes = new InjectionNodeBase[2]; + private int _nodesCount = 0; + private bool _isDeclared = false; + + public Type Type + { + get { return _type; } + } + public bool IsDeclared + { + get { return _isDeclared; } + } + public InjectionBranch(InjectionGraph source, Type type, bool isDeclared) + { + _source = source; + _isDeclared = isDeclared; + _type = type; + } + public void SetDeclaredTrue() + { + _isDeclared = true; + } + public void Inject(object obj) + { + for (int i = 0; i < _nodesCount; i++) + { + _nodes[i].Inject(obj); + } + if (obj is IInjectionBlock container) + { + container.InjectTo(new Injector(_source)); + } + } + public void AddNode(InjectionNodeBase node) + { + if (_nodesCount >= _nodes.Length) + { + Array.Resize(ref _nodes, (_nodes.Length << 1) + 1); + } + _nodes[_nodesCount++] = node; + } + public void Trim() + { + if (_nodesCount <= 0) + { + _nodes = Array.Empty(); + return; + } + + InjectionNodeBase[] newNodes = new InjectionNodeBase[_nodesCount]; + for (int i = 0; i < newNodes.Length; i++) + { + newNodes[i] = _nodes[i]; + } + } + } +} diff --git a/src/Builtin/InjectSystem/InjectionGraph.cs b/src/Builtin/InjectSystem/InjectionGraph.cs new file mode 100644 index 0000000..b8e9519 --- /dev/null +++ b/src/Builtin/InjectSystem/InjectionGraph.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; + +namespace DCFApixels.DragonECS +{ + public class InjectionGraph + { + internal const string CONFIG_NAME = "DCFApixels.DragonECS.DI:" + nameof(InjectionGraph); + + private EcsPipeline _pipeline; + private Dictionary _branches = new Dictionary(32); + private Dictionary _nodes = new Dictionary(32); + private bool _isInit = false; + + public InjectionGraph() + { + Declare(); + Declare(); + } + public void Init(EcsPipeline pipeline) + { + if (_isInit) + { + throw new Exception("Already initialized"); + } + _pipeline = pipeline; + foreach (var node in _nodes.Values) + { + node.Init(pipeline); + } + _isInit = true; + } + public bool TryDeclare() + { + Type type = typeof(T); + if (_nodes.ContainsKey(type)) + { + return false; + } + InitNode(new InjectionNode(type)); + if (IsCanInstantiated(type)) + { + InitBranch(new InjectionBranch(this, type, true)); + } + return true; + } + public void Declare() + { + if (TryDeclare() == false) + { + throw new Exception(); + } + } + public void InjectNoBoxing(T data) + { + _pipeline.GetRunner>().Inject(data); + } + public void Inject(T obj) + { + Type type = typeof(T); +#if DEBUG + if (obj.GetType() != type) + { + throw new ArgumentException(); + } + if (IsCanInstantiated(type) == false) + { + throw new Exception(); + } +#endif + if (_branches.TryGetValue(type, out InjectionBranch branch) == false) + { + InitNode(new InjectionNode(type)); + branch = new InjectionBranch(this, type, true); + InitBranch(branch); + } + branch.Inject(obj); + } + +#if !REFLECTION_DISABLED + public void InjectRaw(object obj) + { + Type type = obj.GetType(); + if (_branches.TryGetValue(type, out InjectionBranch branch) == false) + { + branch = new InjectionBranch(this, type, false); + InitBranch(branch); + } + branch.Inject(obj); + } +#endif + + private void InitBranch(InjectionBranch branch) + { + _branches.Add(branch.Type, branch); + foreach (var (type, node) in _nodes) + { + if (branch.Type.IsAssignableTo(type)) + { + branch.AddNode(node); + } + } + } + private void InitNode(InjectionNodeBase node) + { + if (_pipeline != null) + { + node.Init(_pipeline); + } + _nodes.Add(node.Type, node); + foreach (var (type, branch) in _branches) + { + if (branch.Type.IsAssignableTo(type)) + { + branch.AddNode(node); + } + } + } + private bool IsCanInstantiated(Type type) + { + return !type.IsAbstract && !type.IsInterface; + } + } +} diff --git a/src/Builtin/InjectSystem/InjectionNode.cs b/src/Builtin/InjectSystem/InjectionNode.cs new file mode 100644 index 0000000..a5efc97 --- /dev/null +++ b/src/Builtin/InjectSystem/InjectionNode.cs @@ -0,0 +1,35 @@ +using System; + +namespace DCFApixels.DragonECS +{ + public abstract class InjectionNodeBase + { + private readonly Type _type; + public Type Type + { + get { return _type; } + } + protected InjectionNodeBase(Type type) + { + _type = type; + } + public abstract void Inject(object obj); + public abstract void Init(EcsPipeline pipeline); + } + public class InjectionNode : InjectionNodeBase + { + private EcsProcess> _process; + public InjectionNode(Type type) : base(type) { } + public override void Init(EcsPipeline pipeline) + { + _process = pipeline.GetProcess>(); + } + public override void Inject(object obj) + { + for (int i = 0; i < _process.Length; i++) + { + _process[i].Inject((T)obj); + } + } + } +} diff --git a/src/Builtin/Worlds.cs b/src/Builtin/InjectSystem/Worlds.cs similarity index 100% rename from src/Builtin/Worlds.cs rename to src/Builtin/InjectSystem/Worlds.cs diff --git a/src/Builtin/Worlds.cs.meta b/src/Builtin/InjectSystem/Worlds.cs.meta similarity index 100% rename from src/Builtin/Worlds.cs.meta rename to src/Builtin/InjectSystem/Worlds.cs.meta diff --git a/src/Builtin/Systems.cs b/src/Builtin/Systems.cs deleted file mode 100644 index 5428395..0000000 --- a/src/Builtin/Systems.cs +++ /dev/null @@ -1,69 +0,0 @@ -using DCFApixels.DragonECS.Internal; -using System.Collections.Generic; - -namespace DCFApixels.DragonECS -{ - namespace Internal - { - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Black)] - public class SystemsLayerMarkerSystem : IEcsProcess - { - public readonly string name; - public SystemsLayerMarkerSystem(string name) => this.name = name; - } - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Grey)] - public class EndFrameSystem : IEcsRunProcess, IEcsInject - { - private readonly List _worlds = new List(); - public void Inject(EcsWorld obj) => _worlds.Add(obj); - public void Run() - { - foreach (var world in _worlds) - { - world.DeleteEmptyEntites(); - world.ReleaseDelEntityBufferAll(); - } - } - } - [MetaTags(MetaTags.HIDDEN)] - [MetaColor(MetaColor.Grey)] - public class DeleteOneFrameComponentSystem : IEcsRunProcess, IEcsInject - where TComponent : struct, IEcsComponent - { - public EcsPipeline pipeline { get; set; } - private sealed class Aspect : EcsAspect - { - public EcsPool pool; - public Aspect(Builder b) => pool = b.Include(); - } - private readonly List _worlds = new List(); - public void Inject(EcsWorld obj) => _worlds.Add(obj); - public void Run() - { - for (int i = 0, iMax = _worlds.Count; i < iMax; i++) - { - EcsWorld world = _worlds[i]; - if (world.IsComponentTypeDeclared()) - { - foreach (var e in world.WhereToGroup(out Aspect a)) - a.pool.Del(e); - } - } - } - } - } - public static class DeleteOneFrameComponentSystemExtensions - { - private const string AUTO_DEL_LAYER = nameof(AUTO_DEL_LAYER); - public static EcsPipeline.Builder AutoDel(this EcsPipeline.Builder b, string layerName = AUTO_DEL_LAYER) - where TComponent : struct, IEcsComponent - { - if (AUTO_DEL_LAYER == layerName) - b.Layers.InsertAfter(EcsConsts.POST_END_LAYER, AUTO_DEL_LAYER); - b.AddUnique(new DeleteOneFrameComponentSystem(), layerName); - return b; - } - } -} diff --git a/src/Builtin/Systems.cs.meta b/src/Builtin/Systems.cs.meta deleted file mode 100644 index b99b817..0000000 --- a/src/Builtin/Systems.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 5f3a2f2b184d60e43a2c2b019213d6c4 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/Configs/EcsPipelineConfig.cs b/src/Configs/EcsPipelineConfig.cs new file mode 100644 index 0000000..46af458 --- /dev/null +++ b/src/Configs/EcsPipelineConfig.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace DCFApixels.DragonECS +{ + public interface IEcsPipelineConfig : IConfig { } + public interface IEcsPipelineConfigWriter : IConfigWriter + { + IEcsPipelineConfig GetPipelineConfig(); + } + [Serializable] + public class EcsPipelineConfig : IEcsPipelineConfigWriter, IEcsPipelineConfig, IEnumerable> + { + public static readonly IEcsWorldConfig Empty = new EmptyConfig(); + + private Dictionary _storage = new Dictionary(); + + public EcsPipelineConfig() { } + public EcsPipelineConfig(IEnumerable> range) + { + _storage = new Dictionary(range); + } + public EcsPipelineConfig(params KeyValuePair[] range) + { + _storage = new Dictionary(range); + } + + public int Count + { + get { return _storage.Count; } + } + public T Get(string valueName) + { + return (T)_storage[valueName]; + } + public bool Has(string valueName) + { + return _storage.ContainsKey(valueName); + } + public void Remove(string valueName) + { + _storage.Remove(valueName); + } + public void Set(string valueName, T value) + { + _storage[valueName] = value; + } + public void Add(string key, object value) + { + _storage.Add(key, value); + } + public void Add(KeyValuePair pair) + { + _storage.Add(pair.Key, pair.Value); + } + public bool TryGet(string valueName, out T value) + { + bool result = _storage.TryGetValue(valueName, out object rawValue); + value = rawValue == null ? default : (T)rawValue; + return result; + } + public IEnumerable> GetAllConfigs() + { + return _storage; + } + public IEnumerator> GetEnumerator() + { + return GetAllConfigs().GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() + { + return GetAllConfigs().GetEnumerator(); + } + + public IEcsPipelineConfig GetPipelineConfig() + { + return this; + } + + private class EmptyConfig : IEcsWorldConfig + { + public int Count { get { return 0; } } + public T Get(string valueName) { return default; } + public IEnumerable> GetAllConfigs() { return Array.Empty>(); } + public bool Has(string valueName) { return false; } + public bool TryGet(string valueName, out T value) { value = default; return false; } + } + } +} diff --git a/src/EcsWorldConfig.cs b/src/Configs/EcsWorldConfig.cs similarity index 90% rename from src/EcsWorldConfig.cs rename to src/Configs/EcsWorldConfig.cs index 8cfaca7..7945574 100644 --- a/src/EcsWorldConfig.cs +++ b/src/Configs/EcsWorldConfig.cs @@ -4,23 +4,10 @@ using System.Collections.Generic; namespace DCFApixels.DragonECS { - public interface IEcsWorldConfig + public interface IEcsWorldConfig : IConfig { } + public interface IEcsWorldConfigWriter : IConfigWriter { - int Count { get; } - bool Has(string valueName); - T Get(string valueName); - bool TryGet(string valueName, out T value); - IEnumerable> GetAllConfigs(); - } - public interface IEcsWorldConfigWriter - { - int Count { get; } - void Set(string valueName, T value); - bool Has(string valueName); - T Get(string valueName); - bool TryGet(string valueName, out T value); - void Remove(string valueName); - IEnumerable> GetAllConfigs(); + IEcsWorldConfig GetWorldConfig(); } [Serializable] public class EcsWorldConfig : IEcsWorldConfigWriter, IEcsWorldConfig, IEnumerable> @@ -86,6 +73,11 @@ namespace DCFApixels.DragonECS return GetAllConfigs().GetEnumerator(); } + public IEcsWorldConfig GetWorldConfig() + { + return this; + } + private class EmptyConfig : IEcsWorldConfig { public int Count { get { return 0; } } diff --git a/src/EcsWorldConfig.cs.meta b/src/Configs/EcsWorldConfig.cs.meta similarity index 100% rename from src/EcsWorldConfig.cs.meta rename to src/Configs/EcsWorldConfig.cs.meta diff --git a/src/Configs/IConfig.cs b/src/Configs/IConfig.cs new file mode 100644 index 0000000..4ed43b9 --- /dev/null +++ b/src/Configs/IConfig.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace DCFApixels.DragonECS +{ + public interface IConfig + { + int Count { get; } + bool Has(string valueName); + T Get(string valueName); + bool TryGet(string valueName, out T value); + IEnumerable> GetAllConfigs(); + } + public interface IConfigWriter + { + int Count { get; } + void Set(string valueName, T value); + bool Has(string valueName); + T Get(string valueName); + bool TryGet(string valueName, out T value); + void Remove(string valueName); + IEnumerable> GetAllConfigs(); + } + public static class ConfigExtensions + { + public static T GetOrDefault(this IConfig self, string valueName, T defaultValue) + { + if (self.TryGet(valueName, out T value)) + { + return value; + } + return defaultValue; + } + } +} diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs index af23482..13bf6b9 100644 --- a/src/EcsPipeline.cs +++ b/src/EcsPipeline.cs @@ -3,80 +3,104 @@ using DCFApixels.DragonECS.RunnersCore; using System; using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public interface IEcsPipelineMember + public interface IEcsPipelineMember : IEcsSystem { public EcsPipeline Pipeline { get; set; } } public sealed class EcsPipeline { - private IEcsProcess[] _allSystems; - private Dictionary _runners = new Dictionary(); - private IEcsRunProcess _runRunnerCache; + private readonly IEcsPipelineConfig _config; - private ReadOnlyCollection _allSystemsSealed; - private ReadOnlyDictionary _allRunnersSealed; + private IEcsSystem[] _allSystems; + private Dictionary _processes = new Dictionary(); + private Dictionary _runners = new Dictionary(); + private IEcsRun _runRunnerCache; private bool _isInit = false; private bool _isDestoryed = false; #region Properties - public ReadOnlyCollection AllSystems => _allSystemsSealed; - public ReadOnlyDictionary AllRunners => _allRunnersSealed; - public bool IsInit => _isInit; - public bool IsDestoryed => _isDestoryed; + public IEcsPipelineConfig Config + { + get { return _config; } + } + public EcsProcess AllSystems + { + get { return new EcsProcess(_allSystems); } + } + public IReadOnlyDictionary AllRunners + { + get { return _runners; } + } + public bool IsInit + { + get { return _isInit; } + } + public bool IsDestoryed + { + get { return _isDestoryed; } + } #endregion #region Constructors - private EcsPipeline(IEcsProcess[] systems) + private EcsPipeline(IEcsPipelineConfig config, IEcsSystem[] systems) { + _config = config; _allSystems = systems; - _allSystemsSealed = new ReadOnlyCollection(_allSystems); - _allRunnersSealed = new ReadOnlyDictionary(_runners); } #endregion - #region GetSystems - public T[] GetSystems() - { - return _allSystems.OfType().ToArray(); - } - public int GetSystemsNoAllock(ref T[] array) - { - int count = 0; - for (int i = 0; i < _allSystems.Length; i++) - { - if (_allSystems is T targetSystem) - { - if (array.Length <= count) - { - Array.Resize(ref array, array.Length << 1); - } - array[count++] = targetSystem; - } - } - return count; - } - #endregion - - #region Runners - public T GetRunner() where T : IEcsProcess + #region Get Process/Runner + public EcsProcess GetProcess() where T : IEcsSystem { Type type = typeof(T); - if (_runners.TryGetValue(type, out IEcsRunner result)) + T[] result; + if(_processes.TryGetValue(type, out Array array)) { - return (T)result; + result = (T[])array; + } + else + { + result = _allSystems.OfType().ToArray(); + _processes.Add(type, result); + } + return new EcsProcess(result); + } +#if !REFLECTION_DISABLED + public T GetRunner() where T : IEcsSystem + { + Type interfaceType = typeof(T); + if (_runners.TryGetValue(interfaceType, out IEcsRunner result) == false) + { + result = (IEcsRunner)EcsRunner.Instantiate(this); + _runners.Add(result.GetType(), result); + _runners.Add(interfaceType, result); } - result = (IEcsRunner)EcsRunner.Instantiate(this); - _runners.Add(type, result); return (T)result; } - internal void OnRunnerDestroy(IEcsRunner runner) +#endif + public T GetRunnerInstance() where T : IEcsRunner, new() + { + Type runnerType = typeof(T); + if (_runners.TryGetValue(runnerType, out IEcsRunner result) == false) + { + result = new T(); + _runners.Add(runnerType, result); +#if !REFLECTION_DISABLED + _runners.Add(result.Interface, result); +#endif + } + return (T)result; + } + #endregion + + #region Internal + internal void OnRunnerDestroy_Internal(IEcsRunner runner) { _runners.Remove(runner.Interface); } @@ -91,20 +115,20 @@ namespace DCFApixels.DragonECS return; } - IEcsPipelineMember[] members = GetSystems(); + EcsProcess members = GetProcess(); foreach (var member in members) { member.Pipeline = this; } - var preInitRunner = GetRunner(); + var preInitRunner = GetRunner(); preInitRunner.PreInit(); EcsRunner.Destroy(preInitRunner); - var initRunner = GetRunner(); + var initRunner = GetRunner(); initRunner.Init(); EcsRunner.Destroy(initRunner); - _runRunnerCache = GetRunner(); + _runRunnerCache = GetRunner(); _isInit = true; GC.Collect(); } @@ -129,34 +153,47 @@ namespace DCFApixels.DragonECS return; } _isDestoryed = true; - GetRunner().Destroy(); + GetRunner().Destroy(); } #endregion #region Builder - public static Builder New() => new Builder(); + public static Builder New(IEcsPipelineConfigWriter config = null) + { + return new Builder(config); + } public class Builder { private const int KEYS_CAPACITY = 4; private HashSet _uniqueTypes; - private readonly Dictionary> _systems; + private readonly Dictionary> _systems; private readonly string _basicLayer; public readonly LayerList Layers; - public Builder() + private readonly IEcsPipelineConfigWriter _config; + public IEcsPipelineConfigWriter Config { + get { return _config; } + } + public Builder(IEcsPipelineConfigWriter config = null) + { + 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(); - _systems = new Dictionary>(KEYS_CAPACITY); + _systems = new Dictionary>(KEYS_CAPACITY); } - public Builder Add(IEcsProcess system, string layerName = null) + public Builder Add(IEcsSystem system, string layerName = null) { AddInternal(system, layerName, false); return this; } - public Builder AddUnique(IEcsProcess system, string layerName = null) + public Builder AddUnique(IEcsSystem system, string layerName = null) { AddInternal(system, layerName, true); return this; @@ -168,13 +205,13 @@ namespace DCFApixels.DragonECS list.RemoveAll(o => o is TSystem); return this; } - private void AddInternal(IEcsProcess system, string layerName, bool isUnique) + private void AddInternal(IEcsSystem system, string layerName, bool isUnique) { if (layerName == null) layerName = _basicLayer; - List list; + List list; if (!_systems.TryGetValue(layerName, out list)) { - list = new List { new SystemsLayerMarkerSystem(layerName.ToString()) }; + list = new List { new SystemsLayerMarkerSystem(layerName.ToString()) }; _systems.Add(layerName, list); } if ((_uniqueTypes.Add(system.GetType()) == false && isUnique)) @@ -191,9 +228,8 @@ namespace DCFApixels.DragonECS } public EcsPipeline Build() { - Add(new EndFrameSystem(), EcsConsts.POST_END_LAYER); - List result = new List(32); - List basicBlockList = _systems[_basicLayer]; + List result = new List(32); + List basicBlockList = _systems[_basicLayer]; foreach (var item in _systems) { if (!Layers.Contains(item.Key)) @@ -204,7 +240,7 @@ namespace DCFApixels.DragonECS if (_systems.TryGetValue(item, out var list)) result.AddRange(list); } - return new EcsPipeline(result.ToArray()); + return new EcsPipeline(_config.GetPipelineConfig(), result.ToArray()); } public class LayerList : IEnumerable { @@ -321,15 +357,24 @@ namespace DCFApixels.DragonECS #region Extensions public static partial class EcsPipelineExtensions { - public static bool IsNullOrDestroyed(this EcsPipeline self) => self == null || self.IsDestoryed; - public static EcsPipeline.Builder Add(this EcsPipeline.Builder self, IEnumerable range, string layerName = null) + public static bool IsNullOrDestroyed(this EcsPipeline self) { - foreach (var item in range) self.Add(item, layerName); + return self == null || self.IsDestoryed; + } + 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) + public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEnumerable range, string layerName = null) { - foreach (var item in range) self.AddUnique(item, layerName); + foreach (var item in range) + { + self.AddUnique(item, layerName); + } return self; } public static EcsPipeline BuildAndInit(this EcsPipeline.Builder self) @@ -340,4 +385,110 @@ namespace DCFApixels.DragonECS } } #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() + { + return (T[])_systems; + } + } + public readonly struct EcsProcess : IReadOnlyCollection + where TProcess : IEcsSystem + { + public readonly static EcsProcess Empty = new EcsProcess(Array.Empty()); + 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.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(EcsProcessRaw raw) + { + return new EcsProcess(raw.GetSystems_Internal()); + } + public static implicit operator EcsProcessRaw(EcsProcess process) + { + return new EcsProcessRaw(process._systems); + } + [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)] + public void Dispose() { } + } + } + #endregion +} \ No newline at end of file diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs index 9a0dd8c..eab554c 100644 --- a/src/EcsRunner.cs +++ b/src/EcsRunner.cs @@ -1,29 +1,14 @@ using DCFApixels.DragonECS.RunnersCore; using System; -using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; -using System.Reflection; using System.Text.RegularExpressions; using static DCFApixels.DragonECS.EcsDebugUtility; namespace DCFApixels.DragonECS { - [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)] - sealed class EcsRunnerFilterAttribute : Attribute - { - public readonly Type interfaceType; - public readonly object filter; - public EcsRunnerFilterAttribute(Type interfaceType, object filter) - { - this.interfaceType = interfaceType; - this.filter = filter; - } - public EcsRunnerFilterAttribute(object filter) : this(null, filter) { } - } #if UNITY_2020_3_OR_NEWER - [UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve] + [UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve] #endif [AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)] public sealed class BindWithEcsRunnerAttribute : Attribute @@ -33,22 +18,30 @@ namespace DCFApixels.DragonECS public BindWithEcsRunnerAttribute(Type runnerType) { if (runnerType == null) + { throw new ArgumentNullException(); + } if (!CheckSubclass(runnerType)) + { throw new ArgumentException(); + } this.runnerType = runnerType; } private bool CheckSubclass(Type type) { if (type.IsGenericType && type.GetGenericTypeDefinition() == _baseType) + { return true; + } if (type.BaseType != null) + { return CheckSubclass(type.BaseType); + } return false; } } - public interface IEcsProcess { } + public interface IEcsSystem { } namespace RunnersCore { @@ -56,9 +49,7 @@ namespace DCFApixels.DragonECS { EcsPipeline Pipeline { get; } Type Interface { get; } - IList TargetsRaw { get; } - object Filter { get; } - bool IsHasFilter { get; } + EcsProcessRaw ProcessRaw { get; } bool IsDestroyed { get; } bool IsEmpty { get; } void Destroy(); @@ -67,72 +58,39 @@ namespace DCFApixels.DragonECS #if UNITY_2020_3_OR_NEWER [UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve] #endif - public abstract class EcsRunner : IEcsProcess, IEcsRunner - where TInterface : IEcsProcess + public abstract class EcsRunner : IEcsSystem, IEcsRunner + where TProcess : IEcsSystem { #region Register - private static Type _subclass; + private static Type _runnerImplementationType; internal static void Register(Type subclass) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (_subclass != null) + if (_runnerImplementationType != null) { - throw new EcsRunnerImplementationException($"The Runner<{typeof(TInterface).FullName}> can have only one implementing subclass"); + throw new EcsRunnerImplementationException($"The Runner<{typeof(TProcess).FullName}> can have only one implementing subclass"); } - Type interfaceType = typeof(TInterface); + Type interfaceType = typeof(TProcess); var interfaces = interfaceType.GetInterfaces(); if (interfaceType.IsInterface == false) { - throw new ArgumentException($"{typeof(TInterface).FullName} is not interface"); + throw new ArgumentException($"{typeof(TProcess).FullName} is not interface"); } - if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsProcess)) + if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsSystem)) { - throw new ArgumentException($"{typeof(TInterface).FullName} does not directly inherit the {nameof(IEcsProcess)} interface"); + throw new ArgumentException($"{typeof(TProcess).FullName} does not directly inherit the {nameof(IEcsSystem)} interface"); } #endif - _subclass = subclass; - } - #endregion - - #region FilterSystems - private static TInterface[] FilterSystems(IEnumerable targets) - { - return targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray(); - } - private static TInterface[] FilterSystems(IEnumerable targets, object filter) - { - Type interfaceType = typeof(TInterface); - - IEnumerable newTargets; - - if (filter != null) - { - newTargets = targets.Where(o => - { - if (o is TInterface == false) return false; - var atr = o.GetType().GetCustomAttribute(); - return atr != null && atr.interfaceType == interfaceType && atr.filter.Equals(filter); - }); - } - else - { - newTargets = targets.Where(o => - { - if (o is TInterface == false) return false; - var atr = o.GetType().GetCustomAttribute(); - return atr == null || atr.interfaceType == interfaceType && atr.filter == null; - }); - } - return newTargets.Select(o => (TInterface)o).ToArray(); + _runnerImplementationType = subclass; } #endregion #region Instantiate private static void CheckRunnerValide(Type type) //TODO доработать проверку валидности реалиазации ранера { - Type targetInterface = typeof(TInterface); + Type targetInterface = typeof(TProcess); if (type.IsAbstract) { throw new Exception(); @@ -160,91 +118,85 @@ namespace DCFApixels.DragonECS } } - private static TInterface Instantiate(EcsPipeline source, TInterface[] targets, bool isHasFilter, object filter) + + public static TProcess Instantiate(EcsPipeline source) { - if (_subclass == null) + EcsProcess process = source.GetProcess(); + if (_runnerImplementationType == null) { - Type interfaceType = typeof(TInterface); + Type interfaceType = typeof(TProcess); if (interfaceType.TryGetCustomAttribute(out BindWithEcsRunnerAttribute atr)) { - Type runnerType = atr.runnerType; + Type runnerImplementationType = atr.runnerType; if (interfaceType.IsGenericType) { Type[] genericTypes = interfaceType.GetGenericArguments(); - runnerType = runnerType.MakeGenericType(genericTypes); + runnerImplementationType = runnerImplementationType.MakeGenericType(genericTypes); } - CheckRunnerValide(runnerType); - _subclass = runnerType; + CheckRunnerValide(runnerImplementationType); + _runnerImplementationType = runnerImplementationType; } else { throw new EcsFrameworkException("Процесс не связан с раннером, используйте атрибуут BindWithEcsRunner(Type runnerType)"); } } - - var instance = (EcsRunner)Activator.CreateInstance(_subclass); - return (TInterface)(IEcsProcess)instance.Set(source, targets, isHasFilter, filter); - } - public static TInterface Instantiate(EcsPipeline source) - { - return Instantiate(source, FilterSystems(source.AllSystems), false, null); - } - public static TInterface Instantiate(EcsPipeline source, object filter) - { - return Instantiate(source, FilterSystems(source.AllSystems, filter), true, filter); + var instance = (EcsRunner)Activator.CreateInstance(_runnerImplementationType); + return (TProcess)(IEcsSystem)instance.Set(source, process); } #endregion private EcsPipeline _source; - protected TInterface[] targets; - private ReadOnlyCollection _targetsSealed; - private object _filter; - private bool _isHasFilter; + private EcsProcess _process; private bool _isDestroyed; #region Properties - public EcsPipeline Pipeline => _source; - public Type Interface => typeof(TInterface); - public IList TargetsRaw => _targetsSealed; - public ReadOnlySpan Targets => targets; - public object Filter => _filter; - public bool IsHasFilter => _isHasFilter; - public bool IsDestroyed => _isDestroyed; - public bool IsEmpty => targets == null || targets.Length <= 0; + public EcsPipeline Pipeline + { + get { return _source; } + } + public Type Interface + { + get { return typeof(TProcess); } + } + public EcsProcessRaw ProcessRaw + { + get { return _process; } + } + public EcsProcess Process + { + get { return _process; } + } + public bool IsDestroyed + { + get { return _isDestroyed; } + } + public bool IsEmpty + { + get { return _process.IsNullOrEmpty;} + } #endregion - private EcsRunner Set(EcsPipeline source, TInterface[] targets, bool isHasFilter, object filter) + private EcsRunner Set(EcsPipeline source, EcsProcess process) { _source = source; - this.targets = targets; - _targetsSealed = new ReadOnlyCollection(targets); - _filter = filter; - _isHasFilter = isHasFilter; + this._process = process; OnSetup(); return this; } internal void Rebuild() { - if (_isHasFilter) - { - Set(_source, FilterSystems(_source.AllSystems), _isHasFilter, _filter); - } - else - { - Set(_source, FilterSystems(_source.AllSystems, _filter), _isHasFilter, _filter); - } + Set(_source, _source.GetProcess()); } public void Destroy() { _isDestroyed = true; - _source.OnRunnerDestroy(this); + _source.OnRunnerDestroy_Internal(this); _source = null; - targets = null; - _targetsSealed = null; - _filter = null; + _process = EcsProcess.Empty; OnDestroy(); } - protected virtual void OnSetup() { } //rename to OnInitialize + protected virtual void OnSetup() { } //TODO rename to OnInitialize protected virtual void OnDestroy() { } } } @@ -252,11 +204,11 @@ namespace DCFApixels.DragonECS #region Extensions public static class EcsRunner { - public static void Destroy(IEcsProcess runner) => ((IEcsRunner)runner).Destroy(); + public static void Destroy(IEcsSystem runner) => ((IEcsRunner)runner).Destroy(); } public static class IEcsSystemExtensions { - public static bool IsRunner(this IEcsProcess self) + public static bool IsRunner(this IEcsSystem self) { return self is IEcsRunner; } @@ -280,13 +232,13 @@ namespace DCFApixels.DragonECS static EcsProcessUtility() { - Type processBasicInterface = typeof(IEcsProcess); + Type processBasicInterface = typeof(IEcsSystem); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { var types = assembly.GetTypes(); foreach (var type in types) { - if (type.GetInterface(nameof(IEcsProcess)) != null || type == processBasicInterface) + if (type.GetInterface(nameof(IEcsSystem)) != null || type == processBasicInterface) { if (type.IsInterface) { diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs index a964ce5..1238410 100644 --- a/src/EcsWorld.cache.cs +++ b/src/EcsWorld.cache.cs @@ -1,6 +1,6 @@ namespace DCFApixels.DragonECS { - public abstract partial class EcsWorld + public partial class EcsWorld { internal readonly struct PoolCache : IEcsWorldComponent> where T : IEcsPoolImplementation, new() diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 17891ec..0dbb9b8 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public abstract partial class EcsWorld : IEntityStorage + public partial class EcsWorld : IEntityStorage { public readonly short id; private IEcsWorldConfig _config; diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 29eb598..0df9e46 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -4,7 +4,7 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public abstract partial class EcsWorld + public partial class EcsWorld { private SparseArray _poolTypeCode_2_CmpTypeIDs = new SparseArray(); private SparseArray _componentTypeCode_2_CmpTypeIDs = new SparseArray(); @@ -110,12 +110,12 @@ namespace DCFApixels.DragonECS TPool newPool = new TPool(); Type componentType = newPool.ComponentType; -//#if DEBUG //проверка соответсвия типов -// if(componentType != typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)).GetGenericArguments()[0]) -// { -// Throw.UndefinedException(); -// } -//#endif + //#if DEBUG //проверка соответсвия типов + // if(componentType != typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)).GetGenericArguments()[0]) + // { + // Throw.UndefinedException(); + // } + //#endif int componentTypeCode = EcsTypeCode.Get(componentType); if (_componentTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID)) diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index baa3a89..9a1a9f6 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -14,7 +14,7 @@ namespace DCFApixels.DragonECS public EcsWorld World => EcsWorld.GetWorld(_worldID); public ref T Value => ref EcsWorld.GetData(_worldID); } - public abstract partial class EcsWorld + public partial class EcsWorld { private const short GEN_MASK = 0x7fff; private const short DEATH_GEN_BIT = short.MinValue; diff --git a/src/Internal/EcsTypeCode.cs b/src/Internal/EcsTypeCode.cs index 2d53f00..eab9457 100644 --- a/src/Internal/EcsTypeCode.cs +++ b/src/Internal/EcsTypeCode.cs @@ -5,7 +5,7 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS.Internal { - public static class EcsTypeCode + internal static class EcsTypeCode { private static readonly Dictionary _codes = new Dictionary(); private static int _increment = 1; @@ -29,11 +29,11 @@ namespace DCFApixels.DragonECS.Internal public static bool Has() { return _codes.ContainsKey(typeof(T)); } public static IEnumerable GetDeclaredTypes() { return _codes.Select(o => new TypeCodeInfo(o.Key, o.Value)); } } - public static class EcsTypeCodeCache + internal static class EcsTypeCodeCache { public static readonly int code = EcsTypeCode.Get(typeof(T)); } - public struct TypeCodeInfo + internal struct TypeCodeInfo { public Type type; public int code; diff --git a/src/Pools/EcsHybridPool.cs b/src/Pools/EcsHybridPool.cs index e75b73c..0314a2f 100644 --- a/src/Pools/EcsHybridPool.cs +++ b/src/Pools/EcsHybridPool.cs @@ -299,7 +299,7 @@ namespace DCFApixels.DragonECS } } - public abstract partial class EcsWorld + public partial class EcsWorld { private Dictionary _hybridMapping = new Dictionary(); internal HybridMapping GetHybridMapping(Type type)