remove Reflection except inside EcsHybridPool

This commit is contained in:
Mikhail 2024-02-23 18:34:40 +08:00
parent c14a513172
commit 4888ad82e4
11 changed files with 200 additions and 333 deletions

View File

@ -1,5 +1,4 @@
#pragma warning disable CS0162 // Обнаружен недостижимый код #pragma warning disable CS0162 // Обнаружен недостижимый код
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.RunnersCore; using DCFApixels.DragonECS.RunnersCore;
using System; using System;
@ -7,28 +6,24 @@ namespace DCFApixels.DragonECS
{ {
[MetaName(nameof(PreInit))] [MetaName(nameof(PreInit))]
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
[BindWithEcsRunner(typeof(EcsPreInitRunner))]
public interface IEcsPreInit : IEcsProcess public interface IEcsPreInit : IEcsProcess
{ {
void PreInit(); void PreInit();
} }
[MetaName(nameof(Init))] [MetaName(nameof(Init))]
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
[BindWithEcsRunner(typeof(EcsInitRunner))]
public interface IEcsInit : IEcsProcess public interface IEcsInit : IEcsProcess
{ {
void Init(); void Init();
} }
[MetaName(nameof(Run))] [MetaName(nameof(Run))]
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
[BindWithEcsRunner(typeof(EcsRunRunner))]
public interface IEcsRun : IEcsProcess public interface IEcsRun : IEcsProcess
{ {
void Run(); void Run();
} }
[MetaName(nameof(Destroy))] [MetaName(nameof(Destroy))]
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
[BindWithEcsRunner(typeof(EcsDestroyRunner))]
public interface IEcsDestroy : IEcsProcess public interface IEcsDestroy : IEcsProcess
{ {
void Destroy(); void Destroy();
@ -38,7 +33,7 @@ namespace DCFApixels.DragonECS
namespace DCFApixels.DragonECS.Internal namespace DCFApixels.DragonECS.Internal
{ {
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
public sealed class EcsPreInitRunner : EcsRunner<IEcsPreInit>, IEcsPreInit internal sealed class EcsPreInitRunner : EcsRunner<IEcsPreInit>, IEcsPreInit
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
private EcsProfilerMarker[] _markers; private EcsProfilerMarker[] _markers;
@ -73,7 +68,10 @@ namespace DCFApixels.DragonECS.Internal
#else #else
foreach (var item in Process) foreach (var item in Process)
{ {
try { item.PreInit(); } try
{
item.PreInit();
}
catch (Exception e) catch (Exception e)
{ {
#if DISABLE_CATH_EXCEPTIONS #if DISABLE_CATH_EXCEPTIONS
@ -86,7 +84,7 @@ namespace DCFApixels.DragonECS.Internal
} }
} }
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
public sealed class EcsInitRunner : EcsRunner<IEcsInit>, IEcsInit internal sealed class EcsInitRunner : EcsRunner<IEcsInit>, IEcsInit
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
private EcsProfilerMarker[] _markers; private EcsProfilerMarker[] _markers;
@ -134,7 +132,7 @@ namespace DCFApixels.DragonECS.Internal
} }
} }
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
public sealed class EcsRunRunner : EcsRunner<IEcsRun>, IEcsRun internal sealed class EcsRunRunner : EcsRunner<IEcsRun>, IEcsRun
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
private EcsProfilerMarker[] _markers; private EcsProfilerMarker[] _markers;
@ -182,7 +180,7 @@ namespace DCFApixels.DragonECS.Internal
} }
} }
[MetaColor(MetaColor.Orange)] [MetaColor(MetaColor.Orange)]
public sealed class EcsDestroyRunner : EcsRunner<IEcsDestroy>, IEcsDestroy internal sealed class EcsDestroyRunner : EcsRunner<IEcsDestroy>, IEcsDestroy
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
private EcsProfilerMarker[] _markers; private EcsProfilerMarker[] _markers;
@ -195,7 +193,7 @@ namespace DCFApixels.DragonECS.Internal
} }
} }
#endif #endif
void IEcsDestroy.Destroy() public void Destroy()
{ {
#if DEBUG && !DISABLE_DEBUG #if DEBUG && !DISABLE_DEBUG
for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++) for (int i = 0, n = Process.Length < _markers.Length ? Process.Length : _markers.Length; i < n; i++)

View File

@ -44,6 +44,15 @@
true; true;
#else #else
false; false;
#endif
public const bool DISABLE_CATH_EXCEPTIONS =
#if DISABLE_CATH_EXCEPTIONS
true;
#else
false;
#endif #endif
} }
} }
//#if UNITY_2020_3_OR_NEWER
// [UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve]
//#endif

View File

@ -49,8 +49,11 @@ namespace DCFApixels.DragonECS
} }
private static string AutoToString(object target, Type type, bool isWriteName) private static string AutoToString(object target, Type type, bool isWriteName)
{ {
#if !REFLECTION_DISABLED
//TODO сделать специальный вывод в виде названий констант для Enum-ов //TODO сделать специальный вывод в виде названий констант для Enum-ов
#pragma warning disable IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.
var fields = type.GetFields(RFL_FLAGS); var fields = type.GetFields(RFL_FLAGS);
#pragma warning restore IL2070
string[] values = new string[fields.Length]; string[] values = new string[fields.Length];
for (int i = 0; i < fields.Length; i++) for (int i = 0; i < fields.Length; i++)
values[i] = (fields[i].GetValue(target) ?? "NULL").ToString(); values[i] = (fields[i].GetValue(target) ?? "NULL").ToString();
@ -58,6 +61,9 @@ namespace DCFApixels.DragonECS
return $"{type.Name}({string.Join(", ", values)})"; return $"{type.Name}({string.Join(", ", values)})";
else else
return $"({string.Join(", ", values)})"; return $"({string.Join(", ", values)})";
#endif
EcsDebug.PrintWarning($"Reflection is not available, the {nameof(AutoToString)} method does not work.");
return string.Empty;
} }
#endregion #endregion

View File

@ -48,15 +48,20 @@ namespace DCFApixels.DragonECS
{ {
Builder builder = new Builder(world); Builder builder = new Builder(world);
Type aspectType = typeof(TAspect); Type aspectType = typeof(TAspect);
ConstructorInfo constructorInfo = aspectType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
EcsAspect newAspect; EcsAspect newAspect;
//TODO добавить оповещение что инициализация через конструктор не работает
#if !REFLECTION_DISABLED
ConstructorInfo constructorInfo = aspectType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
if (constructorInfo != null) if (constructorInfo != null)
{ {
newAspect = (EcsAspect)constructorInfo.Invoke(new object[] { builder }); newAspect = (EcsAspect)constructorInfo.Invoke(new object[] { builder });
} }
else else
#endif
{ {
newAspect = (EcsAspect)Activator.CreateInstance(typeof(TAspect)); #pragma warning disable IL2091 // Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The generic parameter of the source method or type does not have matching annotations.
newAspect = Activator.CreateInstance<TAspect>();
#pragma warning restore IL2091
newAspect.Init(builder); newAspect.Init(builder);
} }
newAspect._source = world; newAspect._source = world;
@ -92,13 +97,15 @@ namespace DCFApixels.DragonECS
#region Include/Exclude/Optional/Combine #region Include/Exclude/Optional/Combine
public TPool Include<TPool>() where TPool : IEcsPoolImplementation, new() public TPool Include<TPool>() where TPool : IEcsPoolImplementation, new()
{ {
IncludeImplicit(typeof(TPool).GetGenericArguments()[0]); var pool = _world.GetPool<TPool>();
return _world.GetPool<TPool>(); IncludeImplicit(pool.ComponentType);
return pool;
} }
public TPool Exclude<TPool>() where TPool : IEcsPoolImplementation, new() public TPool Exclude<TPool>() where TPool : IEcsPoolImplementation, new()
{ {
ExcludeImplicit(typeof(TPool).GetGenericArguments()[0]); var pool = _world.GetPool<TPool>();
return _world.GetPool<TPool>(); ExcludeImplicit(pool.ComponentType);
return pool;
} }
public TPool Optional<TPool>() where TPool : IEcsPoolImplementation, new() public TPool Optional<TPool>() where TPool : IEcsPoolImplementation, new()
{ {

View File

@ -21,12 +21,14 @@ namespace DCFApixels.DragonECS
private IEcsProcess[] _allSystems; private IEcsProcess[] _allSystems;
private Dictionary<Type, Array> _processes = new Dictionary<Type, Array>(); private Dictionary<Type, Array> _processes = new Dictionary<Type, Array>();
private Dictionary<Type, IEcsRunner> _runners = new Dictionary<Type, IEcsRunner>(); private Dictionary<Type, IEcsRunner> _runners = new Dictionary<Type, IEcsRunner>();
private IEcsRun _runRunnerCache; private EcsRunRunner _runRunnerCache;
private bool _isInit = false; private bool _isInit = false;
private bool _isDestoryed = false; private bool _isDestoryed = false;
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
private EcsProfilerMarker _initBarker = new EcsProfilerMarker("EcsPipeline.Init"); private EcsProfilerMarker _initBarker = new EcsProfilerMarker("EcsPipeline.Init");
#endif
#region Properties #region Properties
public IEcsPipelineConfig Config public IEcsPipelineConfig Config
@ -64,7 +66,7 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Get Process/Runner #region Get Process
public EcsProcess<T> GetProcess<T>() where T : IEcsProcess public EcsProcess<T> GetProcess<T>() where T : IEcsProcess
{ {
Type type = typeof(T); Type type = typeof(T);
@ -80,31 +82,43 @@ namespace DCFApixels.DragonECS
} }
return new EcsProcess<T>(result); return new EcsProcess<T>(result);
} }
#if !REFLECTION_DISABLED #endregion
#region Declare/Get Runner
public TRunner DeclareRunner<TRunner>() where TRunner : EcsRunner, IEcsRunner, new()
{
Type runnerType = typeof(TRunner);
if (_runners.TryGetValue(runnerType, out IEcsRunner result))
{
return (TRunner)result;
}
TRunner instance = new TRunner();
#if DEBUG
EcsRunner.CheckRunnerTypeIsValide(runnerType, instance.Interface);
#endif
instance.Init_Internal(this);
_runners.Add(runnerType, instance);
_runners.Add(instance.Interface, instance);
return instance;
}
public T GetRunner<T>() where T : IEcsProcess public T GetRunner<T>() where T : IEcsProcess
{ {
Type interfaceType = typeof(T); if (_runners.TryGetValue(typeof(T), out IEcsRunner result))
if (_runners.TryGetValue(interfaceType, out IEcsRunner result) == false)
{ {
result = (IEcsRunner)EcsRunner<T>.Instantiate(this); return (T)result;
_runners.Add(result.GetType(), result);
_runners.Add(interfaceType, result);
} }
return (T)result; Throw.UndefinedException();
return default;
} }
#endif public bool TryGetRunner<T>(out T runner) where T : IEcsProcess
public T GetRunnerInstance<T>() where T : IEcsRunner, new()
{ {
Type runnerType = typeof(T); if (_runners.TryGetValue(typeof(T), out IEcsRunner result))
if (_runners.TryGetValue(runnerType, out IEcsRunner result) == false)
{ {
result = new T(); runner = (T)result;
_runners.Add(runnerType, result); return true;
#if !REFLECTION_DISABLED
_runners.Add(result.Interface, result);
#endif
} }
return (T)result; runner = default;
return false;
} }
#endregion #endregion
@ -123,7 +137,9 @@ namespace DCFApixels.DragonECS
EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been initialized"); EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been initialized");
return; return;
} }
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
_initBarker.Begin(); _initBarker.Begin();
#endif
EcsProcess<IEcsPipelineMember> members = GetProcess<IEcsPipelineMember>(); EcsProcess<IEcsPipelineMember> members = GetProcess<IEcsPipelineMember>();
foreach (var member in members) foreach (var member in members)
{ {
@ -132,33 +148,31 @@ namespace DCFApixels.DragonECS
_injector = _injectorBuilder.Build(this); _injector = _injectorBuilder.Build(this);
_injectorBuilder = null; _injectorBuilder = null;
var preInitRunner = GetRunner<IEcsPreInit>(); DeclareRunner<EcsPreInitRunner>().PreInit();
preInitRunner.PreInit(); DeclareRunner<EcsInitRunner>().Init();
EcsRunner.Destroy(preInitRunner); _runRunnerCache = DeclareRunner<EcsRunRunner>();
var initRunner = GetRunner<IEcsInit>();
initRunner.Init();
EcsRunner.Destroy(initRunner);
_runRunnerCache = GetRunner<IEcsRun>();
_isInit = true; _isInit = true;
GC.Collect(); GC.Collect();
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
_initBarker.End(); _initBarker.End();
#endif
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run() public void Run()
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run)); if (!_isInit) { Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run)); }
if (_isDestoryed) Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run)); if (_isDestoryed) { Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run)); }
#endif #endif
_runRunnerCache.Run(); _runRunnerCache.Run();
} }
public void Destroy() public void Destroy()
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy)); if (!_isInit) { Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy)); }
#endif #endif
if (_isDestoryed) if (_isDestoryed)
{ {
@ -166,7 +180,7 @@ namespace DCFApixels.DragonECS
return; return;
} }
_isDestoryed = true; _isDestoryed = true;
GetRunner<IEcsDestroy>().Destroy(); DeclareRunner<EcsDestroyRunner>().Destroy();
} }
#endregion #endregion
@ -184,7 +198,10 @@ namespace DCFApixels.DragonECS
public readonly LayerList Layers; public readonly LayerList Layers;
private readonly IEcsPipelineConfigWriter _config; private readonly IEcsPipelineConfigWriter _config;
private readonly Injector.Builder _injector; private readonly Injector.Builder _injector;
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
private EcsProfilerMarker _buildBarker = new EcsProfilerMarker("EcsPipeline.Build"); private EcsProfilerMarker _buildBarker = new EcsProfilerMarker("EcsPipeline.Build");
#endif
private List<InitDeclaredRunner> _initDeclaredRunners = new List<InitDeclaredRunner>(4);
public IEcsPipelineConfigWriter Config public IEcsPipelineConfigWriter Config
{ {
@ -196,8 +213,9 @@ namespace DCFApixels.DragonECS
} }
public Builder(IEcsPipelineConfigWriter config = null) public Builder(IEcsPipelineConfigWriter config = null)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
_buildBarker.Begin(); _buildBarker.Begin();
#endif
if (config == null) { config = new EcsPipelineConfig(); } if (config == null) { config = new EcsPipelineConfig(); }
_config = config; _config = config;
@ -214,6 +232,11 @@ namespace DCFApixels.DragonECS
_uniqueTypes = new HashSet<Type>(); _uniqueTypes = new HashSet<Type>();
_systems = new Dictionary<string, List<IEcsProcess>>(KEYS_CAPACITY); _systems = new Dictionary<string, List<IEcsProcess>>(KEYS_CAPACITY);
} }
public Builder DeclareRunner<T>() where T : EcsRunner, IEcsRunner, new()
{
_initDeclaredRunners.Add(new InitDeclaredRunner<T>());
return this;
}
public Builder Add(IEcsProcess system, string layerName = null) public Builder Add(IEcsProcess system, string layerName = null)
{ {
AddInternal(system, layerName, false); AddInternal(system, layerName, false);
@ -268,10 +291,28 @@ namespace DCFApixels.DragonECS
if (_systems.TryGetValue(item, out var list)) if (_systems.TryGetValue(item, out var list))
result.AddRange(list); result.AddRange(list);
} }
EcsPipeline pipeline = new EcsPipeline(_config.GetPipelineConfig(), _injector, result.ToArray());
foreach (var item in _initDeclaredRunners)
{
item.Declare(pipeline);
}
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
_buildBarker.End(); _buildBarker.End();
return new EcsPipeline(_config.GetPipelineConfig(), _injector, result.ToArray()); #endif
return pipeline;
} }
private abstract class InitDeclaredRunner
{
public abstract void Declare(EcsPipeline pipeline);
}
private class InitDeclaredRunner<T> : InitDeclaredRunner where T : EcsRunner, IEcsRunner, new()
{
public override void Declare(EcsPipeline pipeline)
{
pipeline.DeclareRunner<T>();
}
}
public class LayerList : IEnumerable<string> public class LayerList : IEnumerable<string>
{ {
private const string ADD_LAYER = nameof(ADD_LAYER); // автоматический слой нужный только для метода Add private const string ADD_LAYER = nameof(ADD_LAYER); // автоматический слой нужный только для метода Add

View File

@ -1,4 +1,5 @@
using DCFApixels.DragonECS.RunnersCore; using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.RunnersCore;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -7,148 +8,66 @@ using static DCFApixels.DragonECS.EcsDebugUtility;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve]
#endif
[AttributeUsage(AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
public sealed class BindWithEcsRunnerAttribute : Attribute
{
private static readonly Type _baseType = typeof(EcsRunner<>);
public readonly Type runnerType;
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 IEcsProcess { }
namespace RunnersCore namespace RunnersCore
{ {
public interface IEcsRunner public abstract class EcsRunner
{
internal abstract void Init_Internal(EcsPipeline source);
#region CheckRunnerValide
public static void CheckRunnerTypeIsValide(Type runnerType, Type processInterfaceType)
{
#region DEBUG
#pragma warning disable IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.
Type targetInterface = processInterfaceType;
if (runnerType.IsAbstract || runnerType.IsInterface)
{
Throw.UndefinedException();
}
Type GetRunnerBaseType(Type inType)
{
if (inType.IsGenericType && inType.GetGenericTypeDefinition() == typeof(EcsRunner<>))
{
return inType;
}
if (inType.BaseType != null)
{
return GetRunnerBaseType(inType.BaseType);
}
return null;
}
Type baseType = GetRunnerBaseType(runnerType);
Type baseTypeArgument = baseType.GenericTypeArguments[0];
if (baseTypeArgument != targetInterface)
{
Throw.UndefinedException();
}
if (!runnerType.GetInterfaces().Any(o => o == targetInterface))
{
throw new EcsRunnerImplementationException($"Runner {GetGenericTypeFullName(runnerType, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}.");
}
#pragma warning restore IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.
#endregion
}
#endregion
}
public interface IEcsRunner : IEcsProcess
{ {
EcsPipeline Pipeline { get; } EcsPipeline Pipeline { get; }
Type Interface { get; } Type Interface { get; }
EcsProcessRaw ProcessRaw { get; } EcsProcessRaw ProcessRaw { get; }
bool IsDestroyed { get; }
bool IsEmpty { get; } bool IsEmpty { get; }
void Destroy();
} }
#if UNITY_2020_3_OR_NEWER public abstract class EcsRunner<TProcess> : EcsRunner, IEcsRunner, IEcsProcess
[UnityEngine.Scripting.RequireDerived, UnityEngine.Scripting.Preserve]
#endif
public abstract class EcsRunner<TProcess> : IEcsProcess, IEcsRunner
where TProcess : IEcsProcess where TProcess : IEcsProcess
{ {
#region Register
private static Type _runnerImplementationType;
internal static void Register(Type subclass)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_runnerImplementationType != null)
{
throw new EcsRunnerImplementationException($"The Runner<{typeof(TProcess).FullName}> can have only one implementing subclass");
}
Type interfaceType = typeof(TProcess);
var interfaces = interfaceType.GetInterfaces();
if (interfaceType.IsInterface == false)
{
throw new ArgumentException($"{typeof(TProcess).FullName} is not interface");
}
if (interfaces.Length != 1 || interfaces[0] != typeof(IEcsProcess))
{
throw new ArgumentException($"{typeof(TProcess).FullName} does not directly inherit the {nameof(IEcsProcess)} interface");
}
#endif
_runnerImplementationType = subclass;
}
#endregion
#region Instantiate
private static void CheckRunnerValide(Type type) //TODO доработать проверку валидности реалиазации ранера
{
Type targetInterface = typeof(TProcess);
if (type.IsAbstract)
{
throw new Exception();
}
Type GetRunnerBaseType(Type inType)
{
if (inType.IsGenericType && inType.GetGenericTypeDefinition() == typeof(EcsRunner<>))
return inType;
if (inType.BaseType != null)
return GetRunnerBaseType(inType.BaseType);
return null;
}
Type baseType = GetRunnerBaseType(type);
Type baseTypeArgument = baseType.GenericTypeArguments[0];
if (baseTypeArgument != targetInterface)
{
throw new Exception();
}
if (!type.GetInterfaces().Any(o => o == targetInterface))
{
throw new EcsRunnerImplementationException($"Runner {GetGenericTypeFullName(type, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}.");
}
}
public static TProcess Instantiate(EcsPipeline source)
{
EcsProcess<TProcess> process = source.GetProcess<TProcess>();
if (_runnerImplementationType == null)
{
Type interfaceType = typeof(TProcess);
if (interfaceType.TryGetCustomAttribute(out BindWithEcsRunnerAttribute atr))
{
Type runnerImplementationType = atr.runnerType;
if (interfaceType.IsGenericType)
{
Type[] genericTypes = interfaceType.GetGenericArguments();
runnerImplementationType = runnerImplementationType.MakeGenericType(genericTypes);
}
CheckRunnerValide(runnerImplementationType);
_runnerImplementationType = runnerImplementationType;
}
else
{
throw new EcsFrameworkException("Процесс не связан с раннером, используйте атрибуут BindWithEcsRunner(Type runnerType)");
}
}
var instance = (EcsRunner<TProcess>)Activator.CreateInstance(_runnerImplementationType);
return (TProcess)(IEcsProcess)instance.Set(source, process);
}
#endregion
private EcsPipeline _source; private EcsPipeline _source;
private EcsProcess<TProcess> _process; private EcsProcess<TProcess> _process;
private bool _isDestroyed; private bool _isInit = false;
#region Properties #region Properties
public EcsPipeline Pipeline public EcsPipeline Pipeline
@ -167,46 +86,32 @@ namespace DCFApixels.DragonECS
{ {
get { return _process; } get { return _process; }
} }
public bool IsDestroyed
{
get { return _isDestroyed; }
}
public bool IsEmpty public bool IsEmpty
{ {
get { return _process.IsNullOrEmpty; } get { return _process.IsNullOrEmpty; }
} }
#endregion #endregion
private EcsRunner<TProcess> Set(EcsPipeline source, EcsProcess<TProcess> process) #region Constructor Init OnSetup
public EcsRunner() { }
internal override sealed void Init_Internal(EcsPipeline source)
{ {
if (_isInit)
{
Throw.UndefinedException();
}
_isInit = true;
_source = source; _source = source;
this._process = process; _process = source.GetProcess<TProcess>();
OnSetup(); OnSetup();
return this;
} }
internal void Rebuild() protected virtual void OnSetup() { }
{ #endregion
Set(_source, _source.GetProcess<TProcess>());
}
public void Destroy()
{
_isDestroyed = true;
_source.OnRunnerDestroy_Internal(this);
_source = null;
_process = EcsProcess<TProcess>.Empty;
OnDestroy();
}
protected virtual void OnSetup() { } //TODO rename to OnInitialize
protected virtual void OnDestroy() { }
} }
} }
#region Extensions #region Extensions
public static class EcsRunner public static class IEcsProcessExtensions
{
public static void Destroy(IEcsProcess runner) => ((IEcsRunner)runner).Destroy();
}
public static class IEcsSystemExtensions
{ {
public static bool IsRunner(this IEcsProcess self) public static bool IsRunner(this IEcsProcess self)
{ {
@ -214,85 +119,4 @@ namespace DCFApixels.DragonECS
} }
} }
#endregion #endregion
public static class EcsProcessUtility
{
private struct ProcessInterface
{
public Type interfaceType;
public string processName;
public ProcessInterface(Type interfaceType, string processName)
{
this.interfaceType = interfaceType;
this.processName = processName;
}
}
private static Dictionary<Type, ProcessInterface> _processes = new Dictionary<Type, ProcessInterface>();
private static HashSet<Type> _systems = new HashSet<Type>();
static EcsProcessUtility()
{
Type processBasicInterface = typeof(IEcsProcess);
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.IsInterface)
{
string name = type.Name;
if (name[0] == 'I' && name.Length > 1 && char.IsUpper(name[1]))
name = name.Substring(1);
name = Regex.Replace(name, @"\bEcs|Process\b", "");
if (Regex.IsMatch(name, "`\\w{1,}$"))
{
var s = name.Split('`');
name = s[0] + $"<{s[1]}>";
}
_processes.Add(type, new ProcessInterface(type, name));
}
else
{
_systems.Add(type);
}
}
}
}
}
#region Systems
public static bool IsSystem(Type type) => _systems.Contains(type);
public static bool IsEcsSystem(this Type type) => _systems.Contains(type);
#endregion
#region Process
public static bool IsProcessInterface(Type type)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
return _processes.ContainsKey(type);
}
public static bool IsEcsProcessInterface(this Type type) => IsProcessInterface(type);
public static string GetProcessInterfaceName(Type type)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
return _processes[type].processName;
}
public static bool TryGetProcessInterfaceName(Type type, out string name)
{
if (type.IsGenericType) type = type.GetGenericTypeDefinition();
bool result = _processes.TryGetValue(type, out ProcessInterface data);
name = data.processName;
return result;
}
public static IEnumerable<Type> GetEcsProcessInterfaces(this Type self)
{
return self.GetInterfaces().Where(o => o.IsEcsProcessInterface());
}
#endregion
}
} }

View File

@ -1,5 +1,6 @@
using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.Internal;
using System; using System;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
@ -110,12 +111,16 @@ namespace DCFApixels.DragonECS
TPool newPool = new TPool(); TPool newPool = new TPool();
Type componentType = newPool.ComponentType; Type componentType = newPool.ComponentType;
//#if DEBUG //проверка соответсвия типов #if DEBUG //проверка соответсвия типов
// if(componentType != typeof(TPool).GetInterfaces().First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>)).GetGenericArguments()[0]) #pragma warning disable IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
// { if (componentType != typeof(TPool).GetInterfaces()
// Throw.UndefinedException(); .First(o => o.IsGenericType && o.GetGenericTypeDefinition() == typeof(IEcsPoolImplementation<>))
// } .GetGenericArguments()[0])
//#endif {
Throw.UndefinedException();
}
#pragma warning restore IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
#endif
int componentTypeCode = EcsTypeCode.Get(componentType); int componentTypeCode = EcsTypeCode.Get(componentType);
if (_componentTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID)) if (_componentTypeCode_2_CmpTypeIDs.TryGetValue(componentTypeCode, out int componentTypeID))
@ -136,11 +141,6 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _poolComponentCounts, _pools.Length); Array.Resize(ref _poolComponentCounts, _pools.Length);
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
//for (int i = 0; i < _entitiesCapacity; i++)
//{
// //Array.Resize(ref _entityComponentMasks[i], _pools.Length / 32 + 1);
//}
int newEntityComponentMaskLength = _pools.Length / COMPONENT_MATRIX_MASK_BITSIZE + 1; int newEntityComponentMaskLength = _pools.Length / COMPONENT_MATRIX_MASK_BITSIZE + 1;
int dif = newEntityComponentMaskLength - _entityComponentMaskLength; int dif = newEntityComponentMaskLength - _entityComponentMaskLength;
if (dif > 0) if (dif > 0)

View File

@ -124,7 +124,9 @@ namespace DCFApixels.DragonECS
return false; return false;
} }
InitNode(new InjectionNode<T>(type)); InitNode(new InjectionNode<T>(type));
#if !REFLECTION_DISABLED
if (IsCanInstantiated(type)) if (IsCanInstantiated(type))
#endif
{ {
InitBranch(new InjectionBranch(this, type, true)); InitBranch(new InjectionBranch(this, type, true));
} }
@ -184,3 +186,4 @@ namespace DCFApixels.DragonECS
#endregion #endregion
} }
} }

View File

@ -119,6 +119,15 @@ namespace DCFApixels.DragonECS.Internal
} }
internal static unsafe class UnmanagedArrayUtility internal static unsafe class UnmanagedArrayUtility
{ {
private static class MetaCache<T>
{
public readonly static int Size;
static MetaCache()
{
T def = default;
Size = Marshal.SizeOf(def);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* New<T>(int capacity) where T : unmanaged public static T* New<T>(int capacity) where T : unmanaged
{ {
@ -133,7 +142,7 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* NewAndInit<T>(int capacity) where T : unmanaged public static T* NewAndInit<T>(int capacity) where T : unmanaged
{ {
int newSize = Marshal.SizeOf(typeof(T)) * capacity; int newSize = MetaCache<T>.Size * capacity;
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer(); byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
for (int i = 0; i < newSize; i++) for (int i = 0; i < newSize; i++)
@ -144,7 +153,7 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
{ {
int newSize = Marshal.SizeOf(typeof(T)) * capacity; int newSize = MetaCache<T>.Size * capacity;
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer(); byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
for (int i = 0; i < newSize; i++) for (int i = 0; i < newSize; i++)
@ -182,7 +191,7 @@ namespace DCFApixels.DragonECS.Internal
{ {
return (T*)(Marshal.ReAllocHGlobal( return (T*)(Marshal.ReAllocHGlobal(
new IntPtr(oldPointer), new IntPtr(oldPointer),
new IntPtr(Marshal.SizeOf(typeof(T)) * newCount))).ToPointer(); new IntPtr(MetaCache<T>.Size * newCount))).ToPointer();
} }
} }

View File

@ -605,40 +605,6 @@ namespace DCFApixels.DragonECS.Internal
} }
} }
#endregion #endregion
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TEnum AllFlags<TEnum>() where TEnum : unmanaged, Enum
{
return EnumCache<TEnum>.allFlags;
}
private static class EnumCache<TEnum> where TEnum : unmanaged, Enum
{
public readonly static TEnum empty;
public readonly static TEnum allFlags;
public readonly static int valuesCount;
public readonly static int size;
static EnumCache()
{
Array values = Enum.GetValues(typeof(TEnum));
size = sizeof(TEnum);
long result = 0;
valuesCount = values.Length;
for (int i = 0; i < valuesCount; i++)
{
result |= (long)values.GetValue(i);
}
ulong emptyBits = 0;
allFlags = *(TEnum*)&result;
empty = *(TEnum*)&emptyBits;
return;
}
}
#endregion
} }
#region FindBitsResult removed #region FindBitsResult removed

View File

@ -21,17 +21,21 @@ namespace DCFApixels.DragonECS
private T _fakeComponent; private T _fakeComponent;
private EcsWorld.PoolsMediator _mediator; private EcsWorld.PoolsMediator _mediator;
#region Constructors #region CheckValide
#if DEBUG
private static bool _isInvalidType; private static bool _isInvalidType;
static EcsTagPool() static EcsTagPool()
{ {
#pragma warning disable IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
_isInvalidType = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length > 0; _isInvalidType = typeof(T).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).Length > 0;
#pragma warning restore IL2090
} }
public EcsTagPool() public EcsTagPool()
{ {
if (_isInvalidType) if (_isInvalidType)
throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data."); throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data.");
} }
#endif
#endregion #endregion
#region Properites #region Properites