mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 18:14:37 +08:00
rework System/Process/Runner logic. rework injections.
This commit is contained in:
parent
19b1ddbc7d
commit
92fa358c33
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
66
src/Builtin/InjectSystem/EcsPipelineExtensions.cs
Normal file
66
src/Builtin/InjectSystem/EcsPipelineExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
12
src/Builtin/InjectSystem/Exceptions.cs
Normal file
12
src/Builtin/InjectSystem/Exceptions.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace DCFApixels.DragonECS.DI.Internal
|
||||
{
|
||||
internal class Throw
|
||||
{
|
||||
public static void ArgumentNull()
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
}
|
||||
}
|
29
src/Builtin/InjectSystem/IInjectionBlock.cs
Normal file
29
src/Builtin/InjectSystem/IInjectionBlock.cs
Normal 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);
|
||||
}
|
||||
}
|
62
src/Builtin/InjectSystem/InitInjectionSystem.cs
Normal file
62
src/Builtin/InjectSystem/InitInjectionSystem.cs
Normal 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; }
|
||||
}
|
||||
}
|
75
src/Builtin/InjectSystem/InjectProcesses.cs
Normal file
75
src/Builtin/InjectSystem/InjectProcesses.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
65
src/Builtin/InjectSystem/InjectionBranch.cs
Normal file
65
src/Builtin/InjectSystem/InjectionBranch.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
src/Builtin/InjectSystem/InjectionGraph.cs
Normal file
124
src/Builtin/InjectSystem/InjectionGraph.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
35
src/Builtin/InjectSystem/InjectionNode.cs
Normal file
35
src/Builtin/InjectSystem/InjectionNode.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f3a2f2b184d60e43a2c2b019213d6c4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
90
src/Configs/EcsPipelineConfig.cs
Normal file
90
src/Configs/EcsPipelineConfig.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
}
|
@ -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
34
src/Configs/IConfig.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
184
src/EcsRunner.cs
184
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<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)
|
||||
{
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user