rework System/Process/Runner logic. rework injections.

This commit is contained in:
Mikhail 2024-02-22 15:39:37 +08:00
parent 19b1ddbc7d
commit 92fa358c33
27 changed files with 1062 additions and 699 deletions

View File

@ -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>, IEcsPreInit
{
[MetaColor(MetaColor.Orange)]
public sealed class EcsPreInitProcessRunner : EcsRunner<IEcsPreInitProcess>, 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>, 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>, 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>, 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>, 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>, 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>, 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
}
}
}

View File

@ -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>(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<T> : 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<InitInjectSystemBase>();
}
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>, 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<T> : EcsRunner<IEcsInject<T>>, IEcsInject<T>
{
private EcsBaseTypeInjectRunner _baseTypeInjectRunner;
void IEcsInject<T>.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<T> : EcsBaseTypeInjectRunner
{
private IEcsInject<T> _runner;
public EcsBaseTypeInjectRunner(EcsPipeline pipeline) => _runner = pipeline.GetRunner<IEcsInject<T>>();
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<IEcsPreInject>();
public sealed override void Inject(object obj) => _runner.PreInject(obj);
}
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public sealed class EcsPreInitInjectProcessRunner : EcsRunner<IEcsPreInitInjectProcess>, 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<T> : InitInjectSystemBase, IEcsPipelineMember, IEcsInject<InitInjectController>, IEcsPreInitInjectProcess
{
private EcsPipeline _pipeline;
public EcsPipeline Pipeline
{
get { return Pipeline; }
set
{
_pipeline = value;
if (_injectedData == null)
{
return;
}
if (_injectController == null)
{
var injectPipelineRunner = _pipeline.GetRunner<IEcsInject<EcsPipeline>>();
injectPipelineRunner.Inject(_pipeline);
EcsRunner.Destroy(injectPipelineRunner);
_injectController = new InitInjectController(_pipeline);
var injectMapRunner = _pipeline.GetRunner<IEcsInject<InitInjectController>>();
_pipeline.GetRunner<IEcsPreInitInjectProcess>().OnPreInitInjectionBefore();
injectMapRunner.Inject(_injectController);
EcsRunner.Destroy(injectMapRunner);
}
var injectRunnerGeneric = _pipeline.GetRunner<IEcsInject<T>>();
injectRunnerGeneric.Inject(_injectedData);
if (_injectController.OnInject())
{
_injectController.Destroy();
var injectCallbacksRunner = _pipeline.GetRunner<IEcsPreInitInjectProcess>();
injectCallbacksRunner.OnPreInitInjectionAfter();
EcsRunner.Destroy(injectCallbacksRunner);
}
_injectedData = default;
}
}
private InitInjectController _injectController;
void IEcsInject<InitInjectController>.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<T>(this EcsPipeline self, T data)
{
self.GetRunner<IEcsInject<T>>().Inject(data);
}
}
public static partial class EcsPipelineBuilderExtensions
{
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
{
if (data == null) Throw.ArgumentNull();
self.Add(new InitInjectSystem<T>(data));
if (data is IEcsModule module)
self.AddModule(module);
return self;
}
public static EcsPipeline.Builder Inject<T0, T1>(this EcsPipeline.Builder self, T0 d0, T1 d1)
{
return self.Inject(d0).Inject(d1);
}
public static EcsPipeline.Builder Inject<T0, T1, T2>(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2)
{
return self.Inject(d0).Inject(d1).Inject(d2);
}
public static EcsPipeline.Builder Inject<T0, T1, T2, T3>(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<T0, T1, T2, T3, T4>(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<T0, T1, T2, T3, T4, T5>(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<T0, T1, T2, T3, T4, T5, T6>(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<T0, T1, T2, T3, T4, T5, T6, T7>(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);
}
}
}

View File

@ -0,0 +1,66 @@
using DCFApixels.DragonECS.DI.Internal;
namespace DCFApixels.DragonECS
{
public static partial class EcsPipelineExtensions
{
public static void Inject<T>(this EcsPipeline self, T data)
{
self.GetRunner<IEcsInject<T>>().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>(InjectionGraph.CONFIG_NAME);
return self;
}
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
{
if (data == null)
{
Throw.ArgumentNull();
}
self.Add(new InitInjectionSystem<T>(data));
if (data is IEcsModule module)
{
self.AddModule(module);
}
return self;
}
public static EcsPipeline.Builder Inject<T0, T1>(this EcsPipeline.Builder self, T0 d0, T1 d1)
{
return self.Inject(d0).Inject(d1);
}
public static EcsPipeline.Builder Inject<T0, T1, T2>(this EcsPipeline.Builder self, T0 d0, T1 d1, T2 d2)
{
return self.Inject(d0).Inject(d1).Inject(d2);
}
public static EcsPipeline.Builder Inject<T0, T1, T2, T3>(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<T0, T1, T2, T3, T4>(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<T0, T1, T2, T3, T4, T5>(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<T0, T1, T2, T3, T4, T5, T6>(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<T0, T1, T2, T3, T4, T5, T6, T7>(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);
}
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace DCFApixels.DragonECS.DI.Internal
{
internal class Throw
{
public static void ArgumentNull()
{
throw new ArgumentNullException();
}
}
}

View File

@ -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>(T obj)
{
_injectionGraph.Inject(obj);
}
public void InjectNoBoxing<T>(T data)
{
_injectionGraph.InjectNoBoxing(data);
}
#if !REFLECTION_DISABLED
public void InjectRaw(object obj)
{
_injectionGraph.InjectRaw(obj);
}
#endif
}
public interface IInjectionBlock
{
void InjectTo(Injector i);
}
}

View File

@ -0,0 +1,62 @@
namespace DCFApixels.DragonECS.DI.Internal
{
public abstract class InitInjectSystemBase : IEcsSystem { }
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public class InitInjectionSystem<T> : InitInjectSystemBase, IEcsPipelineMember, IEcsInject<InitInjectController>, IEcsPreInitInjectProcess
{
private EcsPipeline _pipeline;
public EcsPipeline Pipeline
{
get { return Pipeline; }
set
{
_pipeline = value;
if (_injectedData == null)
{
return;
}
if (_injectController == null)
{
_pipeline.Config.Get<InjectionGraph>(InjectionGraph.CONFIG_NAME).Init(_pipeline);
var injectPipelineRunner = _pipeline.GetRunner<IEcsInject<EcsPipeline>>();
injectPipelineRunner.Inject(_pipeline);
EcsRunner.Destroy(injectPipelineRunner);
_injectController = new InitInjectController(_pipeline);
var injectMapRunner = _pipeline.GetRunner<IEcsInject<InitInjectController>>();
_pipeline.GetRunner<IEcsPreInitInjectProcess>().OnPreInitInjectionBefore(_pipeline);
injectMapRunner.Inject(_injectController);
EcsRunner.Destroy(injectMapRunner);
}
var injectRunnerGeneric = _pipeline.GetRunner<IEcsInject<T>>();
injectRunnerGeneric.Inject(_injectedData);
if (_injectController.OnInject())
{
_injectController.Destroy();
var injectCallbacksRunner = _pipeline.GetRunner<IEcsPreInitInjectProcess>();
injectCallbacksRunner.OnPreInitInjectionAfter();
EcsRunner.Destroy(injectCallbacksRunner);
}
_injectedData = default;
}
}
private InitInjectController _injectController;
void IEcsInject<InitInjectController>.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; }
}
}

View File

@ -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<T> : 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<InitInjectSystemBase> _injectSystems;
private int _injectCount;
public bool IsInjectionEnd
{
get { return _injectCount >= _injectSystems.Length; }
}
public InitInjectController(EcsPipeline source)
{
_injectCount = 0;
_source = source;
_injectSystems = _source.GetProcess<InitInjectSystemBase>();
}
public bool OnInject()
{
_injectCount++;
return IsInjectionEnd;
}
public void Destroy()
{
_source = null;
_injectSystems = EcsProcess<InitInjectSystemBase>.Empty;
}
}
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public sealed class EcsInjectRunner<T> : EcsRunner<IEcsInject<T>>, IEcsInject<T>
{
private InjectionGraph _injectionGraph;
void IEcsInject<T>.Inject(T obj)
{
_injectionGraph.Inject(obj);
}
protected override void OnSetup()
{
_injectionGraph = Pipeline.Config.Get<InjectionGraph>(InjectionGraph.CONFIG_NAME);
}
}
[MetaTags(MetaTags.HIDDEN)]
[MetaColor(MetaColor.Gray)]
public sealed class EcsInitInjectProcessRunner : EcsRunner<IEcsPreInitInjectProcess>, IEcsPreInitInjectProcess
{
public void OnPreInitInjectionAfter()
{
foreach (var item in Process) item.OnPreInitInjectionAfter();
}
public void OnPreInitInjectionBefore(EcsPipeline pipeline)
{
foreach (var item in Process) item.OnPreInitInjectionBefore(pipeline);
}
}
}

View File

@ -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<InjectionNodeBase>();
return;
}
InjectionNodeBase[] newNodes = new InjectionNodeBase[_nodesCount];
for (int i = 0; i < newNodes.Length; i++)
{
newNodes[i] = _nodes[i];
}
}
}
}

View File

@ -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<Type, InjectionBranch> _branches = new Dictionary<Type, InjectionBranch>(32);
private Dictionary<Type, InjectionNodeBase> _nodes = new Dictionary<Type, InjectionNodeBase>(32);
private bool _isInit = false;
public InjectionGraph()
{
Declare<object>();
Declare<EcsWorld>();
}
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<T>()
{
Type type = typeof(T);
if (_nodes.ContainsKey(type))
{
return false;
}
InitNode(new InjectionNode<T>(type));
if (IsCanInstantiated(type))
{
InitBranch(new InjectionBranch(this, type, true));
}
return true;
}
public void Declare<T>()
{
if (TryDeclare<T>() == false)
{
throw new Exception();
}
}
public void InjectNoBoxing<T>(T data)
{
_pipeline.GetRunner<IEcsInject<T>>().Inject(data);
}
public void Inject<T>(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<T>(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;
}
}
}

View File

@ -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<T> : InjectionNodeBase
{
private EcsProcess<IEcsInject<T>> _process;
public InjectionNode(Type type) : base(type) { }
public override void Init(EcsPipeline pipeline)
{
_process = pipeline.GetProcess<IEcsInject<T>>();
}
public override void Inject(object obj)
{
for (int i = 0; i < _process.Length; i++)
{
_process[i].Inject((T)obj);
}
}
}
}

View File

@ -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<EcsWorld>
{
private readonly List<EcsWorld> _worlds = new List<EcsWorld>();
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<TComponent> : IEcsRunProcess, IEcsInject<EcsWorld>
where TComponent : struct, IEcsComponent
{
public EcsPipeline pipeline { get; set; }
private sealed class Aspect : EcsAspect
{
public EcsPool<TComponent> pool;
public Aspect(Builder b) => pool = b.Include<TComponent>();
}
private readonly List<EcsWorld> _worlds = new List<EcsWorld>();
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<TComponent>())
{
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<TComponent>(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<TComponent>(), layerName);
return b;
}
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 5f3a2f2b184d60e43a2c2b019213d6c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<KeyValuePair<string, object>>
{
public static readonly IEcsWorldConfig Empty = new EmptyConfig();
private Dictionary<string, object> _storage = new Dictionary<string, object>();
public EcsPipelineConfig() { }
public EcsPipelineConfig(IEnumerable<KeyValuePair<string, object>> range)
{
_storage = new Dictionary<string, object>(range);
}
public EcsPipelineConfig(params KeyValuePair<string, object>[] range)
{
_storage = new Dictionary<string, object>(range);
}
public int Count
{
get { return _storage.Count; }
}
public T Get<T>(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<T>(string valueName, T value)
{
_storage[valueName] = value;
}
public void Add(string key, object value)
{
_storage.Add(key, value);
}
public void Add(KeyValuePair<string, object> pair)
{
_storage.Add(pair.Key, pair.Value);
}
public bool TryGet<T>(string valueName, out T value)
{
bool result = _storage.TryGetValue(valueName, out object rawValue);
value = rawValue == null ? default : (T)rawValue;
return result;
}
public IEnumerable<KeyValuePair<string, object>> GetAllConfigs()
{
return _storage;
}
public IEnumerator<KeyValuePair<string, object>> 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<T>(string valueName) { return default; }
public IEnumerable<KeyValuePair<string, object>> GetAllConfigs() { return Array.Empty<KeyValuePair<string, object>>(); }
public bool Has(string valueName) { return false; }
public bool TryGet<T>(string valueName, out T value) { value = default; return false; }
}
}
}

View File

@ -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<T>(string valueName);
bool TryGet<T>(string valueName, out T value);
IEnumerable<KeyValuePair<string, object>> GetAllConfigs();
}
public interface IEcsWorldConfigWriter
{
int Count { get; }
void Set<T>(string valueName, T value);
bool Has(string valueName);
T Get<T>(string valueName);
bool TryGet<T>(string valueName, out T value);
void Remove(string valueName);
IEnumerable<KeyValuePair<string, object>> GetAllConfigs();
IEcsWorldConfig GetWorldConfig();
}
[Serializable]
public class EcsWorldConfig : IEcsWorldConfigWriter, IEcsWorldConfig, IEnumerable<KeyValuePair<string, object>>
@ -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; } }

34
src/Configs/IConfig.cs Normal file
View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
namespace DCFApixels.DragonECS
{
public interface IConfig
{
int Count { get; }
bool Has(string valueName);
T Get<T>(string valueName);
bool TryGet<T>(string valueName, out T value);
IEnumerable<KeyValuePair<string, object>> GetAllConfigs();
}
public interface IConfigWriter
{
int Count { get; }
void Set<T>(string valueName, T value);
bool Has(string valueName);
T Get<T>(string valueName);
bool TryGet<T>(string valueName, out T value);
void Remove(string valueName);
IEnumerable<KeyValuePair<string, object>> GetAllConfigs();
}
public static class ConfigExtensions
{
public static T GetOrDefault<T>(this IConfig self, string valueName, T defaultValue)
{
if (self.TryGet(valueName, out T value))
{
return value;
}
return defaultValue;
}
}
}

View File

@ -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<Type, IEcsRunner> _runners = new Dictionary<Type, IEcsRunner>();
private IEcsRunProcess _runRunnerCache;
private readonly IEcsPipelineConfig _config;
private ReadOnlyCollection<IEcsProcess> _allSystemsSealed;
private ReadOnlyDictionary<Type, IEcsRunner> _allRunnersSealed;
private IEcsSystem[] _allSystems;
private Dictionary<Type, Array> _processes = new Dictionary<Type, Array>();
private Dictionary<Type, IEcsRunner> _runners = new Dictionary<Type, IEcsRunner>();
private IEcsRun _runRunnerCache;
private bool _isInit = false;
private bool _isDestoryed = false;
#region Properties
public ReadOnlyCollection<IEcsProcess> AllSystems => _allSystemsSealed;
public ReadOnlyDictionary<Type, IEcsRunner> AllRunners => _allRunnersSealed;
public bool IsInit => _isInit;
public bool IsDestoryed => _isDestoryed;
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; }
}
#endregion
#region Constructors
private EcsPipeline(IEcsProcess[] systems)
private EcsPipeline(IEcsPipelineConfig config, IEcsSystem[] systems)
{
_config = config;
_allSystems = systems;
_allSystemsSealed = new ReadOnlyCollection<IEcsProcess>(_allSystems);
_allRunnersSealed = new ReadOnlyDictionary<Type, IEcsRunner>(_runners);
}
#endregion
#region GetSystems
public T[] GetSystems<T>()
{
return _allSystems.OfType<T>().ToArray();
}
public int GetSystemsNoAllock<T>(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<T>() where T : IEcsProcess
#region Get Process/Runner
public EcsProcess<T> GetProcess<T>() 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<T>().ToArray();
_processes.Add(type, result);
}
return new EcsProcess<T>(result);
}
#if !REFLECTION_DISABLED
public T GetRunner<T>() where T : IEcsSystem
{
Type interfaceType = typeof(T);
if (_runners.TryGetValue(interfaceType, out IEcsRunner result) == false)
{
result = (IEcsRunner)EcsRunner<T>.Instantiate(this);
_runners.Add(result.GetType(), result);
_runners.Add(interfaceType, result);
}
result = (IEcsRunner)EcsRunner<T>.Instantiate(this);
_runners.Add(type, result);
return (T)result;
}
internal void OnRunnerDestroy(IEcsRunner runner)
#endif
public T GetRunnerInstance<T>() 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<IEcsPipelineMember>();
EcsProcess<IEcsPipelineMember> members = GetProcess<IEcsPipelineMember>();
foreach (var member in members)
{
member.Pipeline = this;
}
var preInitRunner = GetRunner<IEcsPreInitProcess>();
var preInitRunner = GetRunner<IEcsPreInit>();
preInitRunner.PreInit();
EcsRunner.Destroy(preInitRunner);
var initRunner = GetRunner<IEcsInitProcess>();
var initRunner = GetRunner<IEcsInit>();
initRunner.Init();
EcsRunner.Destroy(initRunner);
_runRunnerCache = GetRunner<IEcsRunProcess>();
_runRunnerCache = GetRunner<IEcsRun>();
_isInit = true;
GC.Collect();
}
@ -129,34 +153,47 @@ namespace DCFApixels.DragonECS
return;
}
_isDestoryed = true;
GetRunner<IEcsDestroyProcess>().Destroy();
GetRunner<IEcsDestroy>().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<Type> _uniqueTypes;
private readonly Dictionary<string, List<IEcsProcess>> _systems;
private readonly Dictionary<string, List<IEcsSystem>> _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<Type>();
_systems = new Dictionary<string, List<IEcsProcess>>(KEYS_CAPACITY);
_systems = new Dictionary<string, List<IEcsSystem>>(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<IEcsProcess> list;
List<IEcsSystem> list;
if (!_systems.TryGetValue(layerName, out list))
{
list = new List<IEcsProcess> { new SystemsLayerMarkerSystem(layerName.ToString()) };
list = new List<IEcsSystem> { 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<IEcsProcess> result = new List<IEcsProcess>(32);
List<IEcsProcess> basicBlockList = _systems[_basicLayer];
List<IEcsSystem> result = new List<IEcsSystem>(32);
List<IEcsSystem> 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<string>
{
@ -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<IEcsProcess> 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<IEcsSystem> 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<IEcsProcess> range, string layerName = null)
public static EcsPipeline.Builder AddUnique(this EcsPipeline.Builder self, IEnumerable<IEcsSystem> 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<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
}

View File

@ -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<TInterface> : IEcsProcess, IEcsRunner
where TInterface : IEcsProcess
public abstract class EcsRunner<TProcess> : 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<IEcsProcess> targets)
{
return targets.Where(o => o is TInterface).Select(o => (TInterface)o).ToArray();
}
private static TInterface[] FilterSystems(IEnumerable<IEcsProcess> targets, object filter)
{
Type interfaceType = typeof(TInterface);
IEnumerable<IEcsProcess> newTargets;
if (filter != null)
{
newTargets = targets.Where(o =>
{
if (o is TInterface == false) return false;
var atr = o.GetType().GetCustomAttribute<EcsRunnerFilterAttribute>();
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<EcsRunnerFilterAttribute>();
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<TProcess> process = source.GetProcess<TProcess>();
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<TInterface>)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<TProcess>)Activator.CreateInstance(_runnerImplementationType);
return (TProcess)(IEcsSystem)instance.Set(source, process);
}
#endregion
private EcsPipeline _source;
protected TInterface[] targets;
private ReadOnlyCollection<TInterface> _targetsSealed;
private object _filter;
private bool _isHasFilter;
private EcsProcess<TProcess> _process;
private bool _isDestroyed;
#region Properties
public EcsPipeline Pipeline => _source;
public Type Interface => typeof(TInterface);
public IList TargetsRaw => _targetsSealed;
public ReadOnlySpan<TInterface> 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<TProcess> Process
{
get { return _process; }
}
public bool IsDestroyed
{
get { return _isDestroyed; }
}
public bool IsEmpty
{
get { return _process.IsNullOrEmpty;}
}
#endregion
private EcsRunner<TInterface> Set(EcsPipeline source, TInterface[] targets, bool isHasFilter, object filter)
private EcsRunner<TProcess> Set(EcsPipeline source, EcsProcess<TProcess> process)
{
_source = source;
this.targets = targets;
_targetsSealed = new ReadOnlyCollection<TInterface>(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<TProcess>());
}
public void Destroy()
{
_isDestroyed = true;
_source.OnRunnerDestroy(this);
_source.OnRunnerDestroy_Internal(this);
_source = null;
targets = null;
_targetsSealed = null;
_filter = null;
_process = EcsProcess<TProcess>.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)
{

View File

@ -1,6 +1,6 @@
namespace DCFApixels.DragonECS
{
public abstract partial class EcsWorld
public partial class EcsWorld
{
internal readonly struct PoolCache<T> : IEcsWorldComponent<PoolCache<T>>
where T : IEcsPoolImplementation, new()

View File

@ -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;

View File

@ -4,7 +4,7 @@ using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
public abstract partial class EcsWorld
public partial class EcsWorld
{
private SparseArray<int> _poolTypeCode_2_CmpTypeIDs = new SparseArray<int>();
private SparseArray<int> _componentTypeCode_2_CmpTypeIDs = new SparseArray<int>();
@ -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))

View File

@ -14,7 +14,7 @@ namespace DCFApixels.DragonECS
public EcsWorld World => EcsWorld.GetWorld(_worldID);
public ref T Value => ref EcsWorld.GetData<T>(_worldID);
}
public abstract partial class EcsWorld
public partial class EcsWorld
{
private const short GEN_MASK = 0x7fff;
private const short DEATH_GEN_BIT = short.MinValue;

View File

@ -5,7 +5,7 @@ using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS.Internal
{
public static class EcsTypeCode
internal static class EcsTypeCode
{
private static readonly Dictionary<Type, int> _codes = new Dictionary<Type, int>();
private static int _increment = 1;
@ -29,11 +29,11 @@ namespace DCFApixels.DragonECS.Internal
public static bool Has<T>() { return _codes.ContainsKey(typeof(T)); }
public static IEnumerable<TypeCodeInfo> GetDeclaredTypes() { return _codes.Select(o => new TypeCodeInfo(o.Key, o.Value)); }
}
public static class EcsTypeCodeCache<T>
internal static class EcsTypeCodeCache<T>
{
public static readonly int code = EcsTypeCode.Get(typeof(T));
}
public struct TypeCodeInfo
internal struct TypeCodeInfo
{
public Type type;
public int code;

View File

@ -299,7 +299,7 @@ namespace DCFApixels.DragonECS
}
}
public abstract partial class EcsWorld
public partial class EcsWorld
{
private Dictionary<Type, HybridMapping> _hybridMapping = new Dictionary<Type, HybridMapping>();
internal HybridMapping GetHybridMapping(Type type)