mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 18:14:37 +08:00
Merge branch 'dev' into test-pool
This commit is contained in:
commit
08021f25be
@ -10,7 +10,7 @@
|
||||
<RootNamespace>DCFApixels.DragonECS</RootNamespace>
|
||||
|
||||
<Title>DragonECS</Title>
|
||||
<Version>0.9.1</Version>
|
||||
<Version>0.9.9</Version>
|
||||
<Authors>DCFApixels</Authors>
|
||||
<Description>ECS Framework for Game Engines with C# and .Net Platform</Description>
|
||||
<Copyright>DCFApixels</Copyright>
|
||||
|
@ -8,7 +8,7 @@
|
||||
"displayName": "DragonECS",
|
||||
"description": "C# Entity Component System Framework",
|
||||
"unity": "2020.3",
|
||||
"version": "0.9.4",
|
||||
"version": "0.9.9",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/DCFApixels/DragonECS.git"
|
||||
|
@ -10,7 +10,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "The process to run when EcsPipeline.Init() is called. Before Init")]
|
||||
[MetaID("DE26527C92015AFDD4ECF4D81A4C946B")]
|
||||
[MetaID("DragonECS_DE26527C92015AFDD4ECF4D81A4C946B")]
|
||||
public interface IEcsPreInit : IEcsProcess
|
||||
{
|
||||
void PreInit();
|
||||
@ -19,7 +19,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "The process to run when EcsPipeline.Init() is called. After PreInit")]
|
||||
[MetaID("CC45527C9201DF82DCAAAEF33072F9EF")]
|
||||
[MetaID("DragonECS_CC45527C9201DF82DCAAAEF33072F9EF")]
|
||||
public interface IEcsInit : IEcsProcess
|
||||
{
|
||||
void Init();
|
||||
@ -28,7 +28,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "The process to run when EcsPipeline.Run() is called.")]
|
||||
[MetaID("9654527C9201BE75546322B9BB03C131")]
|
||||
[MetaID("DragonECS_9654527C9201BE75546322B9BB03C131")]
|
||||
public interface IEcsRun : IEcsProcess
|
||||
{
|
||||
void Run();
|
||||
@ -44,7 +44,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "The process to run when EcsPipeline.Destroy() is called.")]
|
||||
[MetaID("4661527C9201EE669C6EB61B19899AE5")]
|
||||
[MetaID("DragonECS_4661527C9201EE669C6EB61B19899AE5")]
|
||||
public interface IEcsDestroy : IEcsProcess
|
||||
{
|
||||
void Destroy();
|
||||
@ -62,7 +62,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("3273527C9201285BAA0A463F700A50FB")]
|
||||
[MetaID("DragonECS_3273527C9201285BAA0A463F700A50FB")]
|
||||
internal sealed class EcsPreInitRunner : EcsRunner<IEcsPreInit>, IEcsPreInit
|
||||
{
|
||||
private RunHelper _helper;
|
||||
@ -83,7 +83,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("ED85527C9201A391AB8EC0B734917859")]
|
||||
[MetaID("DragonECS_ED85527C9201A391AB8EC0B734917859")]
|
||||
internal sealed class EcsInitRunner : EcsRunner<IEcsInit>, IEcsInit
|
||||
{
|
||||
private RunHelper _helper;
|
||||
@ -104,7 +104,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("2098527C9201F260C840BFD50BC7E0BA")]
|
||||
[MetaID("DragonECS_2098527C9201F260C840BFD50BC7E0BA")]
|
||||
internal sealed class EcsRunRunner : EcsRunner<IEcsRun>, IEcsRun
|
||||
{
|
||||
private readonly struct Pair
|
||||
@ -150,9 +150,10 @@ namespace DCFApixels.DragonECS.Internal
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DRAGONECS_DISABLE_CATH_EXCEPTIONS
|
||||
throw;
|
||||
#endif
|
||||
throw e;
|
||||
#else
|
||||
EcsDebug.PrintError(e);
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -184,7 +185,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.PROCESSES_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("06A6527C92010430ACEB3DA520F272CC")]
|
||||
[MetaID("DragonECS_06A6527C92010430ACEB3DA520F272CC")]
|
||||
internal sealed class EcsDestroyRunner : EcsRunner<IEcsDestroy>, IEcsDestroy
|
||||
{
|
||||
private RunHelper _helper;
|
||||
|
@ -10,12 +10,13 @@ namespace DCFApixels.DragonECS
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.WORLDS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Inherits EcsWorld without extending its functionality and is used for specific injections. Can be used to store regular game entities, can also be used as a single world in the game for all entities.")]
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
[MetaID("4EE3527C92015BAB0299CB7B4E2663D1")]
|
||||
[MetaID("DragonECS_4EE3527C92015BAB0299CB7B4E2663D1")]
|
||||
public sealed class EcsDefaultWorld : EcsWorld, IInjectionUnit
|
||||
{
|
||||
public EcsDefaultWorld() : base() { }
|
||||
public EcsDefaultWorld(EcsWorldConfig config = null, string name = null, short worldID = -1) : base(config, name == null ? "Default" : name, worldID) { }
|
||||
public EcsDefaultWorld(IConfigContainer configs, string name = null, short worldID = -1) : base(configs, name == null ? "Default" : name, worldID) { }
|
||||
private const string DEFAULT_NAME = "Default";
|
||||
public EcsDefaultWorld() : base(default(EcsWorldConfig), DEFAULT_NAME) { }
|
||||
public EcsDefaultWorld(EcsWorldConfig config = null, string name = null, short worldID = -1) : base(config, name == null ? DEFAULT_NAME : name, worldID) { }
|
||||
public EcsDefaultWorld(IConfigContainer configs, string name = null, short worldID = -1) : base(configs, name == null ? DEFAULT_NAME : name, worldID) { }
|
||||
void IInjectionUnit.InitInjectionNode(InjectionGraph nodes) { nodes.AddNode(this); }
|
||||
}
|
||||
/// <summary> EcsWrold for store event entities. </summary>
|
||||
@ -23,12 +24,13 @@ namespace DCFApixels.DragonECS
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.WORLDS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Inherits EcsWorld without extending its functionality and is used for specific injections. Can be used to store event entities.")]
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
[MetaID("D7CE527C920160BCD765EFA72DBF8B89")]
|
||||
[MetaID("DragonECS_D7CE527C920160BCD765EFA72DBF8B89")]
|
||||
public sealed class EcsEventWorld : EcsWorld, IInjectionUnit
|
||||
{
|
||||
public EcsEventWorld() : base() { }
|
||||
public EcsEventWorld(EcsWorldConfig config = null, string name = null, short worldID = -1) : base(config, name == null ? "Events" : name, worldID) { }
|
||||
public EcsEventWorld(IConfigContainer configs, string name = null, short worldID = -1) : base(configs, name == null ? "Events" : name, worldID) { }
|
||||
private const string DEFAULT_NAME = "Events";
|
||||
public EcsEventWorld() : base(default(EcsWorldConfig), DEFAULT_NAME) { }
|
||||
public EcsEventWorld(EcsWorldConfig config = null, string name = null, short worldID = -1) : base(config, name == null ? DEFAULT_NAME : name, worldID) { }
|
||||
public EcsEventWorld(IConfigContainer configs, string name = null, short worldID = -1) : base(configs, name == null ? DEFAULT_NAME : name, worldID) { }
|
||||
void IInjectionUnit.InitInjectionNode(InjectionGraph nodes) { nodes.AddNode(this); }
|
||||
}
|
||||
}
|
||||
|
@ -400,7 +400,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (++_count >= _dense.Length)
|
||||
{
|
||||
Array.Resize(ref _dense, ArrayUtility.NormalizeSizeToPowerOfTwo(_count << 1));
|
||||
Array.Resize(ref _dense, ArrayUtility.NextPow2(_count << 1));
|
||||
}
|
||||
_dense[_count] = entityID;
|
||||
|
||||
@ -531,7 +531,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (minSize >= _dense.Length)
|
||||
{
|
||||
Array.Resize(ref _dense, ArrayUtility.NormalizeSizeToPowerOfTwo_ClampOverflow(minSize));
|
||||
Array.Resize(ref _dense, ArrayUtility.NextPow2_ClampOverflow(minSize));
|
||||
}
|
||||
}
|
||||
|
||||
@ -618,7 +618,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (dynamicBuffer.Length < _count)
|
||||
{
|
||||
Array.Resize(ref dynamicBuffer, ArrayUtility.NormalizeSizeToPowerOfTwo(_count));
|
||||
Array.Resize(ref dynamicBuffer, ArrayUtility.NextPow2(_count));
|
||||
}
|
||||
int i = 0;
|
||||
foreach (var e in this)
|
||||
|
@ -97,7 +97,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (dynamicBuffer.Length < _values.Length)
|
||||
{
|
||||
Array.Resize(ref dynamicBuffer, ArrayUtility.NormalizeSizeToPowerOfTwo(_values.Length));
|
||||
Array.Resize(ref dynamicBuffer, ArrayUtility.NextPow2(_values.Length));
|
||||
}
|
||||
int i = 0;
|
||||
foreach (var e in this)
|
||||
@ -246,7 +246,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (dynamicBuffer.Length < _source.Count)
|
||||
{
|
||||
Array.Resize(ref dynamicBuffer, ArrayUtility.NormalizeSizeToPowerOfTwo(_source.Count));
|
||||
Array.Resize(ref dynamicBuffer, ArrayUtility.NextPow2(_source.Count));
|
||||
}
|
||||
int i = 0;
|
||||
foreach (var e in this)
|
||||
|
@ -3,7 +3,7 @@
|
||||
#endif
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
namespace DCFApixels.DragonECS.Core
|
||||
{
|
||||
#region IEcsWorldComponent
|
||||
public interface IEcsWorldComponent<T>
|
||||
@ -44,11 +44,11 @@ namespace DCFApixels.DragonECS
|
||||
void Enable(ref T component);
|
||||
void Disable(ref T component);
|
||||
}
|
||||
public static class EcsComponentResetHandler<T>
|
||||
public static class EcsComponentLifecycleHandler<T>
|
||||
{
|
||||
public static readonly IEcsComponentLifecycle<T> instance;
|
||||
public static readonly bool isHasHandler;
|
||||
static EcsComponentResetHandler()
|
||||
static EcsComponentLifecycleHandler()
|
||||
{
|
||||
T def = default;
|
||||
if (def is IEcsComponentLifecycle<T> intrf)
|
||||
|
@ -1,16 +1,18 @@
|
||||
#if DISABLE_DEBUG
|
||||
#undef DEBUG
|
||||
#endif
|
||||
using DCFApixels.DragonECS.Core;
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static DCFApixels.DragonECS.EcsConsts;
|
||||
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
using static EcsConsts;
|
||||
#region EcsProfilerMarker
|
||||
public readonly struct EcsProfilerMarker
|
||||
{
|
||||
#if DEBUG || DRAGONECS_ENABLE_DEBUG_SERVICE
|
||||
@ -75,13 +77,15 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static explicit operator EcsProfilerMarker(string markerName) { return new EcsProfilerMarker(markerName); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(PACK_GROUP, DEBUG_GROUP)]
|
||||
[MetaDescription(AUTHOR, "Debugging utility. To modify or change the behavior, create a new class inherited from DebugService and set this service using DebugService.Set<T>().")]
|
||||
[MetaID("10A4587C92013B55820D8604D718A1C3")]
|
||||
[MetaID("DragonECS_10A4587C92013B55820D8604D718A1C3")]
|
||||
public static class EcsDebug
|
||||
{
|
||||
#region Set
|
||||
public static void Set<T>() where T : DebugService, new()
|
||||
{
|
||||
DebugService.Set<T>();
|
||||
@ -90,7 +94,12 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
DebugService.Set(service);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Print
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void PrintWarning(object v)
|
||||
{
|
||||
@ -99,6 +108,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.PrintWarning(v);
|
||||
#endif
|
||||
}
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void PrintError(object v)
|
||||
{
|
||||
@ -107,6 +119,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.PrintError(v);
|
||||
#endif
|
||||
}
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void PrintErrorAndBreak(object v)
|
||||
{
|
||||
@ -115,6 +130,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.PrintErrorAndBreak(v);
|
||||
#endif
|
||||
}
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void PrintPass(object v)
|
||||
{
|
||||
@ -123,6 +141,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.PrintPass(v);
|
||||
#endif
|
||||
}
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Print()
|
||||
{
|
||||
@ -131,6 +152,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.Print();
|
||||
#endif
|
||||
}
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Print(object v)
|
||||
{
|
||||
@ -139,6 +163,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.Print(v);
|
||||
#endif
|
||||
}
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
[UnityEngine.HideInCallstack]
|
||||
#endif
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Print(string tag, object v)
|
||||
{
|
||||
@ -147,6 +174,9 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.Print(tag, v);
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Break()
|
||||
{
|
||||
@ -154,9 +184,12 @@ namespace DCFApixels.DragonECS
|
||||
DebugService.CurrentThreadInstance.Break();
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
public static OnPrintHandler OnPrint = delegate { };
|
||||
public delegate void OnPrintHandler(string tag, object v);
|
||||
#endregion
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
@ -164,19 +197,23 @@ namespace DCFApixels.DragonECS
|
||||
public abstract class DebugService
|
||||
{
|
||||
private static DebugService _instance;
|
||||
private static object _lock = new object();
|
||||
private readonly static object _lock = new object();
|
||||
|
||||
private static HashSet<DebugService> _threadServiceClonesSet = new HashSet<DebugService>();
|
||||
private readonly static HashSet<DebugService> _threadServiceClonesSet = new HashSet<DebugService>();
|
||||
|
||||
[ThreadStatic]
|
||||
private static DebugService _currentThreadInstanceClone;
|
||||
[ThreadStatic]
|
||||
private static DebugService _currentThreadInstance; // для сравнения
|
||||
|
||||
private static IdDispenser _idDispenser = new IdDispenser(16, 0);
|
||||
private static Dictionary<string, int> _nameIdTable = new Dictionary<string, int>();
|
||||
private readonly static IdDispenser _idDispenser = new IdDispenser(16, 0);
|
||||
private readonly static Dictionary<string, int> _nameIdTable = new Dictionary<string, int>();
|
||||
|
||||
#region Properties
|
||||
public static bool IsNullOrDefault
|
||||
{
|
||||
get { return _instance == null || _instance is NullDebugService || _instance is DefaultDebugService; }
|
||||
}
|
||||
public static DebugService Instance
|
||||
{
|
||||
get { return _instance; }
|
||||
@ -207,10 +244,14 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
#region Static Constructor
|
||||
static DebugService()
|
||||
{
|
||||
#if !UNITY_5_3_OR_NEWER
|
||||
Set(new NullDebugService());
|
||||
#else
|
||||
Set(new DefaultDebugService());
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -241,15 +282,17 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
service.OnNewProfilerMark(record.Value, record.Key);
|
||||
}
|
||||
service.OnServiceSetup(oldService);
|
||||
oldService?.OnDisableBaseService(service);
|
||||
service.OnEnableBaseService(oldService);
|
||||
OnServiceChanged(service);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region OnServiceSetup/CreateThreadInstance
|
||||
protected virtual void OnServiceSetup(DebugService oldService) { }
|
||||
#region OnEnable/OnDisable/CreateThreadInstance
|
||||
protected virtual void OnEnableBaseService(DebugService prevService) { }
|
||||
protected virtual void OnDisableBaseService(DebugService nextService) { }
|
||||
protected abstract DebugService CreateThreadInstance();
|
||||
#endregion
|
||||
|
||||
@ -328,10 +371,17 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static OnServiceChangedHandler OnServiceChanged = delegate { };
|
||||
#region Events
|
||||
public static event OnServiceChangedHandler OnServiceChanged = delegate { };
|
||||
|
||||
public delegate void OnServiceChangedHandler(DebugService service);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
namespace DCFApixels.DragonECS.Core
|
||||
{
|
||||
#region DebugServiceExtensions
|
||||
public static class DebugServiceExtensions
|
||||
{
|
||||
public static void PrintWarning(this DebugService self, object v)
|
||||
@ -361,7 +411,9 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
//TODO PrintJson возможно будет добавлено когда-то
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DefaultServices
|
||||
//------------------------------------------------------------------------------------------------------------//
|
||||
|
||||
public sealed class NullDebugService : DebugService
|
||||
@ -379,7 +431,6 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
public sealed class DefaultDebugService : DebugService
|
||||
{
|
||||
#if !UNITY_5_3_OR_NEWER
|
||||
private const string PROFILER_MARKER = "ProfilerMark";
|
||||
private const string PROFILER_MARKER_CACHE = "[" + PROFILER_MARKER + "] ";
|
||||
|
||||
@ -548,14 +599,6 @@ namespace DCFApixels.DragonECS
|
||||
return this.AutoToString();
|
||||
}
|
||||
}
|
||||
#else
|
||||
protected sealed override DebugService CreateThreadInstance() { return this; }
|
||||
public sealed override void Break() { }
|
||||
public sealed override void Print(string tag, object v) { }
|
||||
public sealed override void ProfilerMarkBegin(int id) { }
|
||||
public sealed override void ProfilerMarkEnd(int id) { }
|
||||
protected sealed override void OnDelProfilerMark(int id) { }
|
||||
protected sealed override void OnNewProfilerMark(int id, string name) { }
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#if DISABLE_DEBUG
|
||||
#undef DEBUG
|
||||
#endif
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if DEBUG || !REFLECTION_DISABLED
|
||||
@ -312,6 +313,9 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
public static TypeMeta GetMeta(this object self)
|
||||
{
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
if (self is Type type) { Throw.DeepDebugException(); }
|
||||
#endif
|
||||
return EcsDebugUtility.GetTypeMeta(self);
|
||||
}
|
||||
public static TypeMeta ToMeta(this Type self)
|
||||
|
@ -28,6 +28,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
get { return string.IsNullOrEmpty(Author) == false; }
|
||||
}
|
||||
public MetaDescription(string text) : this(null, text) { }
|
||||
public MetaDescription(string author, string text)
|
||||
{
|
||||
if (author == null) { author = string.Empty; }
|
||||
|
@ -12,54 +12,67 @@ namespace DCFApixels.DragonECS
|
||||
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class MetaGroupAttribute : EcsMetaAttribute
|
||||
{
|
||||
public const char SEPARATOR = '/';
|
||||
public readonly MetaGroup Data;
|
||||
public const char SEPARATOR = MetaGroup.SEPARATOR;
|
||||
public readonly string Name = string.Empty;
|
||||
|
||||
[Obsolete(EcsMetaAttributeHalper.EMPTY_NO_SENSE_MESSAGE)]
|
||||
public MetaGroupAttribute() { Data = MetaGroup.Empty; }
|
||||
public MetaGroupAttribute(string name) { Data = new MetaGroup(name); }
|
||||
public MetaGroupAttribute(params string[] path) : this(string.Join(SEPARATOR, path)) { }
|
||||
public MetaGroupAttribute() { }
|
||||
public MetaGroupAttribute(string name) { Name = name; }
|
||||
public MetaGroupAttribute(params string[] path) { Name = string.Join(SEPARATOR, path); }
|
||||
}
|
||||
[DebuggerDisplay("{Name}")]
|
||||
public class MetaGroup
|
||||
{
|
||||
public const char SEPARATOR = MetaGroupAttribute.SEPARATOR;
|
||||
public const char SEPARATOR = '/';
|
||||
private const string SEPARATOR_STR = "/";
|
||||
public const string UNGROUPED = "<UNGROUPED>";
|
||||
private const string PATTERN = @"Module(?=/)";
|
||||
public static readonly MetaGroup Empty = new MetaGroup(UNGROUPED);
|
||||
|
||||
public readonly string Name;
|
||||
private string[] _path = null;
|
||||
private string[] _splited = null;
|
||||
public IReadOnlyCollection<string> Splited
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_path == null)
|
||||
if (_splited == null)
|
||||
{
|
||||
_path = EcsMetaAttributeHalper.Split(SEPARATOR, Name);
|
||||
_splited = EcsMetaAttributeHalper.Split(SEPARATOR, Name);
|
||||
}
|
||||
return _path;
|
||||
return _splited;
|
||||
}
|
||||
}
|
||||
public bool IsEmpty
|
||||
{
|
||||
get { return this == Empty; }
|
||||
}
|
||||
public MetaGroup(string name)
|
||||
private MetaGroup(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
Name = UNGROUPED;
|
||||
return;
|
||||
}
|
||||
name = name.Replace('\\', SEPARATOR);
|
||||
name = Regex.Replace(name, @"(\s*[\/\\]+\s*)+", SEPARATOR_STR).Trim();
|
||||
if (name[name.Length - 1] != SEPARATOR)
|
||||
{
|
||||
name += SEPARATOR;
|
||||
}
|
||||
if (name[0] == SEPARATOR)
|
||||
{
|
||||
name = name.Substring(1);
|
||||
}
|
||||
Name = Regex.Replace(name, PATTERN, "");
|
||||
Name = string.Intern(Name);
|
||||
}
|
||||
public static MetaGroup FromName(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return Empty;
|
||||
}
|
||||
return new MetaGroup(name);
|
||||
}
|
||||
public static MetaGroup FromNameSpace(Type type)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type.Namespace))
|
||||
|
@ -4,6 +4,10 @@
|
||||
using DCFApixels.DragonECS.Core;
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
@ -17,62 +21,384 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
Throw.ArgumentNull(nameof(id));
|
||||
EcsDebug.PrintError("The identifier cannot be empty or null");
|
||||
id = string.Empty;
|
||||
}
|
||||
if (MetaID.IsGenericID(id) == false)
|
||||
if (MetaID.IsValidID(id) == false)
|
||||
{
|
||||
Throw.ArgumentException($"Identifier {id} contains invalid characters: ,<>");
|
||||
EcsDebug.PrintError($"Identifier {id} contains invalid characters. Allowed charset: {MetaID.ALLOWED_CHARSET}");
|
||||
id = string.Empty;
|
||||
}
|
||||
id = string.Intern(id);
|
||||
ID = id;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MetaID
|
||||
public static unsafe class MetaID
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static Random _randon;
|
||||
[ThreadStatic]
|
||||
private static byte[] _buffer;
|
||||
[ThreadStatic]
|
||||
private static bool _isInit;
|
||||
public const string ALLOWED_CHARSET = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
//public static bool IsFixedNameType(Type type)
|
||||
//{
|
||||
// if (type.IsPrimitive)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// if(type == typeof(string))
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// return false;
|
||||
//}
|
||||
public static bool IsGenericID(string id)
|
||||
{
|
||||
return Regex.IsMatch(id, @"^[^,<>\s]*$");
|
||||
return id[id.Length - 1] == '>' || Regex.IsMatch(id, @"^[^,<>\s]*$");
|
||||
}
|
||||
public static bool IsValidID(string id)
|
||||
{
|
||||
return Regex.IsMatch(id, @"^[a-zA-Z0-9_]+$");
|
||||
}
|
||||
|
||||
public static unsafe string GenerateNewUniqueID()
|
||||
|
||||
[ThreadStatic]
|
||||
private static uint _randonState;
|
||||
public static string GenerateNewUniqueID()
|
||||
{
|
||||
if (_isInit == false)
|
||||
const int BYTES = 16;
|
||||
const int CHARS = BYTES * 2;
|
||||
const string CHARSET = "0123456789ABCDEF";
|
||||
|
||||
if (_randonState == 0)
|
||||
{
|
||||
IntPtr prt = Marshal.AllocHGlobal(1);
|
||||
long alloc = (long)prt;
|
||||
Marshal.Release(prt);
|
||||
_randon = new Random((int)alloc);
|
||||
_buffer = new byte[8];
|
||||
_isInit = true;
|
||||
Marshal.FreeHGlobal(prt);
|
||||
_randonState = (uint)alloc ^ (uint)DateTime.Now.Millisecond;
|
||||
}
|
||||
|
||||
byte* hibits = stackalloc byte[8];
|
||||
long* hibitsL = (long*)hibits;
|
||||
hibitsL[0] = DateTime.Now.Ticks;
|
||||
hibitsL[1] = _randon.Next();
|
||||
byte* bytes = stackalloc byte[BYTES];
|
||||
Span<byte> x = new Span<byte>(bytes, BYTES);
|
||||
long* bytesLong = (long*)bytes;
|
||||
uint* bytesUInt = (uint*)bytes;
|
||||
bytesLong[0] = DateTime.Now.Ticks;
|
||||
_randonState = BitsUtility.NextXorShiftState(_randonState);
|
||||
bytesUInt[2] = _randonState;
|
||||
_randonState = BitsUtility.NextXorShiftState(_randonState);
|
||||
bytesUInt[3] = _randonState;
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
||||
char* str = stackalloc char[CHARS];
|
||||
for (int i = 0, j = 0; i < BYTES; i++)
|
||||
{
|
||||
_buffer[i] = hibits[i];
|
||||
byte b = bytes[i];
|
||||
str[j++] = CHARSET[b & 0x0000_000F];
|
||||
str[j++] = CHARSET[(b >> 4) & 0x0000_000F];
|
||||
}
|
||||
|
||||
return BitConverter.ToString(_buffer).Replace("-", "");
|
||||
return new string(str, 0, CHARS);
|
||||
}
|
||||
public static string IDToAttribute(string id)
|
||||
{
|
||||
return $"[MetaID(\"id\")]";
|
||||
return $"[MetaID(\"{id}\")]";
|
||||
}
|
||||
public static string ConvertIDToTypeName(string id)
|
||||
{
|
||||
id = id.Replace("_1", "__");
|
||||
id = id.Replace("_2", "__");
|
||||
id = id.Replace("_3", "__");
|
||||
|
||||
id = id.Replace("<", "_1");
|
||||
id = id.Replace(">", "_2");
|
||||
id = id.Replace(",", "_3");
|
||||
return "_" + id;
|
||||
}
|
||||
public static string ParseIDFromTypeName(string name)
|
||||
{
|
||||
char* buffer = TempBuffer<char>.Get(name.Length);
|
||||
int count = 0;
|
||||
//skip name[0] char
|
||||
for (int i = 1, iMax = name.Length; i < iMax; i++)
|
||||
{
|
||||
char current = name[i];
|
||||
if (current == '_')
|
||||
{
|
||||
if (++i >= iMax) { break; }
|
||||
current = name[i];
|
||||
switch (current)
|
||||
{
|
||||
case '1': current = '<'; break;
|
||||
case '2': current = '>'; break;
|
||||
case '3': current = ','; break;
|
||||
}
|
||||
}
|
||||
buffer[count++] = current;
|
||||
}
|
||||
return new string(buffer, 0, count);
|
||||
}
|
||||
|
||||
public static string GenerateNewUniqueIDWithAttribute()
|
||||
{
|
||||
return IDToAttribute(GenerateNewUniqueID());
|
||||
}
|
||||
|
||||
|
||||
public static bool TryFindMetaIDCollisions(IEnumerable<TypeMeta> metas, out CollisionList collisions)
|
||||
{
|
||||
collisions = new CollisionList(metas);
|
||||
return collisions.IsHasAnyCollision;
|
||||
}
|
||||
public static CollisionList FindMetaIDCollisions(IEnumerable<TypeMeta> metas)
|
||||
{
|
||||
return new CollisionList(metas);
|
||||
}
|
||||
|
||||
#region CollisionList
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
[DebuggerDisplay("HasAnyCollision: {IsHasAnyCollision} ListsCount: {Count}")]
|
||||
public class CollisionList : IEnumerable<CollisionList.Collision>
|
||||
{
|
||||
private LinkedList[] _linkedLists;
|
||||
private Entry[] _entries;
|
||||
private int _collisionsCount;
|
||||
private int _listsCount;
|
||||
private HashSet<string> _collidingIDs;
|
||||
|
||||
public int CollisionsCount
|
||||
{
|
||||
get { return _collisionsCount; }
|
||||
}
|
||||
public int Count
|
||||
{
|
||||
get { return _listsCount; }
|
||||
}
|
||||
public bool IsHasAnyCollision
|
||||
{
|
||||
get { return _listsCount > 0; }
|
||||
}
|
||||
public Collision this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = _linkedLists[index];
|
||||
return new Collision(this, list.headNode, list.count);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsCollidingID(string id)
|
||||
{
|
||||
if(_collidingIDs== null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return _collidingIDs.Contains(id);
|
||||
}
|
||||
|
||||
public CollisionList(IEnumerable<TypeMeta> metas)
|
||||
{
|
||||
var metasCount = metas.Count();
|
||||
Dictionary<string, int> listIndexes = new Dictionary<string, int>(metasCount);
|
||||
_linkedLists = new LinkedList[metasCount];
|
||||
_entries = new Entry[metasCount];
|
||||
|
||||
bool hasCollision = false;
|
||||
|
||||
_listsCount = 0;
|
||||
foreach (var meta in metas)
|
||||
{
|
||||
if (meta.IsHasMetaID() == false) { continue; }
|
||||
if (listIndexes.TryGetValue(meta.MetaID, out int headIndex))
|
||||
{
|
||||
hasCollision = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
headIndex = _listsCount++;
|
||||
listIndexes.Add(meta.MetaID, headIndex);
|
||||
}
|
||||
int nodeIndex = _collisionsCount++;
|
||||
|
||||
ref var list = ref _linkedLists[headIndex];
|
||||
ref Entry entry = ref _entries[nodeIndex];
|
||||
if (list.count == 0)
|
||||
{
|
||||
entry.next = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.next = list.headNode;
|
||||
}
|
||||
entry.meta = meta;
|
||||
list.headNode = nodeIndex;
|
||||
listIndexes[meta.MetaID] = headIndex;
|
||||
list.count++;
|
||||
}
|
||||
|
||||
if (hasCollision)
|
||||
{
|
||||
_collidingIDs = new HashSet<string>();
|
||||
for (int i = 0; i < _listsCount; i++)
|
||||
{
|
||||
ref var list = ref _linkedLists[i];
|
||||
if (list.count <= 1)
|
||||
{
|
||||
_linkedLists[i--] = _linkedLists[--_listsCount];
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _listsCount; i++)
|
||||
{
|
||||
_collidingIDs.Add(this[i].MetaID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_listsCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerDisplay("Count: {count}")]
|
||||
private struct LinkedList
|
||||
{
|
||||
public int count;
|
||||
public int headNode;
|
||||
}
|
||||
[DebuggerDisplay("ID: {meta.MetaID} next: {next}")]
|
||||
public struct Entry
|
||||
{
|
||||
public TypeMeta meta;
|
||||
public int next;
|
||||
}
|
||||
|
||||
#region Enumerator
|
||||
public Enumerator GetEnumerator() { return new Enumerator(this, _listsCount); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator<Collision> IEnumerable<Collision>.GetEnumerator() { return GetEnumerator(); }
|
||||
public struct Enumerator : IEnumerator<Collision>
|
||||
{
|
||||
private readonly CollisionList _collisions;
|
||||
private readonly int _count;
|
||||
private int _index;
|
||||
public Collision Current
|
||||
{
|
||||
get
|
||||
{
|
||||
var list = _collisions._linkedLists[_index];
|
||||
return new Collision(_collisions, list.headNode, list.count);
|
||||
}
|
||||
}
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public Enumerator(CollisionList collisions, int count)
|
||||
{
|
||||
_collisions = collisions;
|
||||
_count = count;
|
||||
_index = -1;
|
||||
}
|
||||
public bool MoveNext() { return ++_index < _count; }
|
||||
public void Dispose() { }
|
||||
public void Reset() { _index = -1; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
[DebuggerDisplay("Count: {Count}")]
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
public readonly struct Collision : IEnumerable<TypeMeta>
|
||||
{
|
||||
private readonly CollisionList _collisions;
|
||||
private readonly string _metaID;
|
||||
private readonly int _head;
|
||||
private readonly int _count;
|
||||
public int Count
|
||||
{
|
||||
get { return _count; }
|
||||
}
|
||||
public string MetaID
|
||||
{
|
||||
get { return _metaID; }
|
||||
}
|
||||
internal Collision(CollisionList collisions, int head, int count)
|
||||
{
|
||||
_collisions = collisions;
|
||||
if (count == 0)
|
||||
{
|
||||
_head = 0;
|
||||
_metaID = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
_head = head;
|
||||
_metaID = collisions._entries[_head].meta.MetaID;
|
||||
}
|
||||
_head = head;
|
||||
_count = count;
|
||||
}
|
||||
|
||||
#region Enumerator
|
||||
public Enumerator GetEnumerator() { return new Enumerator(_collisions._entries, _head); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator<TypeMeta> IEnumerable<TypeMeta>.GetEnumerator() { return GetEnumerator(); }
|
||||
public struct Enumerator : IEnumerator<TypeMeta>
|
||||
{
|
||||
private readonly Entry[] _linkedEntries;
|
||||
private readonly int _head;
|
||||
private int _nextIndex;
|
||||
private int _index;
|
||||
public TypeMeta Current { get { return _linkedEntries[_index].meta; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public Enumerator(Entry[] linkedEntries, int head)
|
||||
{
|
||||
_linkedEntries = linkedEntries;
|
||||
_head = head;
|
||||
_nextIndex = _head;
|
||||
_index = -1;
|
||||
}
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_nextIndex < 0) { return false; }
|
||||
_index = _nextIndex;
|
||||
_nextIndex = _linkedEntries[_index].next;
|
||||
return true;
|
||||
}
|
||||
public void Dispose() { }
|
||||
public void Reset()
|
||||
{
|
||||
_nextIndex = _head;
|
||||
_index = -1;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region DebuggerProxy
|
||||
private class DebuggerProxy
|
||||
{
|
||||
public Type[] Types;
|
||||
public DebuggerProxy(Collision collision)
|
||||
{
|
||||
Types = collision.Select(o => o.Type).ToArray();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#region DebuggerProxy
|
||||
private class DebuggerProxy
|
||||
{
|
||||
public string[][] Lists;
|
||||
public DebuggerProxy(CollisionList collisions)
|
||||
{
|
||||
Lists = new string[collisions.Count][];
|
||||
int i = 0;
|
||||
foreach (var list in collisions)
|
||||
{
|
||||
int j = 0;
|
||||
Lists[i] = new string[list.Count];
|
||||
foreach (var typeMeta in list)
|
||||
{
|
||||
Lists[i][j] = typeMeta.MetaID;
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -3,8 +3,10 @@
|
||||
#endif
|
||||
using DCFApixels.DragonECS.Core;
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using DCFApixels.DragonECS.PoolsCore;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
#if DEBUG || !REFLECTION_DISABLED
|
||||
@ -36,14 +38,14 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.DEBUG_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Intended for extending meta information of types, for customization of type display in the editor. You can get it by using the object.GetMeta() or Type.ToMeta() extension method. Meta information is collected from meta attributes.")]
|
||||
[MetaID("248D587C9201EAEA881F27871B4D18A6")]
|
||||
[MetaID("DragonECS_248D587C9201EAEA881F27871B4D18A6")]
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
public sealed class TypeMeta : ITypeMeta
|
||||
{
|
||||
private const string NULL_NAME = "NULL";
|
||||
public static readonly TypeMeta NullTypeMeta;
|
||||
|
||||
private static object _lock = new object();
|
||||
private static readonly object _lock = new object();
|
||||
private static readonly Dictionary<Type, TypeMeta> _metaCache = new Dictionary<Type, TypeMeta>();
|
||||
private static int _increment = 1;
|
||||
|
||||
@ -65,6 +67,10 @@ namespace DCFApixels.DragonECS
|
||||
private string _metaID;
|
||||
private EcsTypeCode _typeCode;
|
||||
|
||||
private bool _isProcess;
|
||||
private bool _isComponent;
|
||||
private bool _isPool;
|
||||
|
||||
private InitFlag _initFlags = InitFlag.None;
|
||||
|
||||
#region Constructors
|
||||
@ -78,9 +84,9 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
_name = NULL_NAME,
|
||||
_typeName = NULL_NAME,
|
||||
_color = new MetaColor(MetaColor.Black),
|
||||
_color = MetaColor.Black,
|
||||
_description = new MetaDescription("", NULL_NAME),
|
||||
_group = new MetaGroup(""),
|
||||
_group = MetaGroup.Empty,
|
||||
_tags = Array.Empty<string>(),
|
||||
_metaID = string.Empty,
|
||||
_typeCode = EcsTypeCodeManager.Get(typeof(void)),
|
||||
@ -270,6 +276,7 @@ namespace DCFApixels.DragonECS
|
||||
return _metaID;
|
||||
}
|
||||
}
|
||||
public bool IsHasMetaID() { return string.IsNullOrEmpty(MetaID) == false; }
|
||||
#endregion
|
||||
|
||||
#region TypeCode
|
||||
@ -287,6 +294,45 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ReflectionInfo
|
||||
public bool IsComponent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initFlags.HasFlag(InitFlag.ReflectionInfo) == false)
|
||||
{
|
||||
MetaGenerator.GetReflectionInfo(this);
|
||||
_initFlags |= InitFlag.ReflectionInfo;
|
||||
}
|
||||
return _isComponent;
|
||||
}
|
||||
}
|
||||
public bool IsProcess
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initFlags.HasFlag(InitFlag.ReflectionInfo) == false)
|
||||
{
|
||||
MetaGenerator.GetReflectionInfo(this);
|
||||
_initFlags |= InitFlag.ReflectionInfo;
|
||||
}
|
||||
return _isProcess;
|
||||
}
|
||||
}
|
||||
public bool IsPool
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_initFlags.HasFlag(InitFlag.ReflectionInfo) == false)
|
||||
{
|
||||
MetaGenerator.GetReflectionInfo(this);
|
||||
_initFlags |= InitFlag.ReflectionInfo;
|
||||
}
|
||||
return _isPool;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region InitializeAll
|
||||
public TypeMeta InitializeAll()
|
||||
{
|
||||
@ -316,9 +362,10 @@ namespace DCFApixels.DragonECS
|
||||
Tags = 1 << 4,
|
||||
MetaID = 1 << 5,
|
||||
TypeCode = 1 << 6,
|
||||
//MemberType = 1 << 7,
|
||||
ReflectionInfo = 1 << 7,
|
||||
//MemberType = 1 << 8,
|
||||
|
||||
All = Name | Group | Color | Description | Tags | TypeCode | MetaID //| MemberType
|
||||
All = Name | Group | Color | Description | Tags | TypeCode | MetaID | ReflectionInfo //| MemberType
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -336,7 +383,17 @@ namespace DCFApixels.DragonECS
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
public static bool IsHasMeta(Type type)
|
||||
public static bool TryGetCustomMeta(Type type, out TypeMeta meta)
|
||||
{
|
||||
if (IsHasCustomMeta(type))
|
||||
{
|
||||
meta = type.ToMeta();
|
||||
return true;
|
||||
}
|
||||
meta = null;
|
||||
return false;
|
||||
}
|
||||
public static bool IsHasCustomMeta(Type type)
|
||||
{
|
||||
#if DEBUG || !REFLECTION_DISABLED
|
||||
return CheckEcsMemener(type) || Attribute.GetCustomAttributes(type, typeof(EcsMetaAttribute), false).Length > 0;
|
||||
@ -348,7 +405,7 @@ namespace DCFApixels.DragonECS
|
||||
public static bool IsHasMetaID(Type type)
|
||||
{
|
||||
#if DEBUG || !REFLECTION_DISABLED
|
||||
return type.HasAttribute<MetaIDAttribute>();
|
||||
return TryGetCustomMeta(type, out TypeMeta meta) && meta.IsHasMetaID();
|
||||
#else
|
||||
EcsDebug.PrintWarning($"Reflection is not available, the {nameof(TypeMeta)}.{nameof(IsHasMetaID)} method does not work.");
|
||||
return false;
|
||||
@ -404,6 +461,15 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Obsolete
|
||||
[Obsolete("Use TryGetCustomMeta(type)")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static bool IsHasMeta(Type type)
|
||||
{
|
||||
return IsHasCustomMeta(type);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MetaGenerator
|
||||
private static class MetaGenerator
|
||||
{
|
||||
@ -442,7 +508,6 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region GetColor
|
||||
|
||||
private static MetaColor AutoColor(TypeMeta meta)
|
||||
{
|
||||
int hash;
|
||||
@ -463,7 +528,7 @@ namespace DCFApixels.DragonECS
|
||||
return (isCustom ? atr.color : AutoColor(meta), isCustom);
|
||||
#else
|
||||
EcsDebug.PrintWarning($"Reflection is not available, the {nameof(MetaGenerator)}.{nameof(GetColor)} method does not work.");
|
||||
return (AutoColor(type), false);
|
||||
return (MetaColor.White, false);
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
@ -472,7 +537,14 @@ namespace DCFApixels.DragonECS
|
||||
public static MetaGroup GetGroup(Type type)
|
||||
{
|
||||
#if DEBUG || !REFLECTION_DISABLED //в дебажных утилитах REFLECTION_DISABLED только в релизном билде работает
|
||||
return type.TryGetAttribute(out MetaGroupAttribute atr) ? atr.Data : MetaGroup.FromNameSpace(type);
|
||||
if (type.TryGetAttribute(out MetaGroupAttribute atr))
|
||||
{
|
||||
return MetaGroup.FromName(atr.Name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MetaGroup.FromNameSpace(type);
|
||||
}
|
||||
#else
|
||||
EcsDebug.PrintWarning($"Reflection is not available, the {nameof(MetaGenerator)}.{nameof(GetGroup)} method does not work.");
|
||||
return MetaGroup.Empty;
|
||||
@ -507,9 +579,6 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
#region GetMetaID
|
||||
#if DEBUG || !REFLECTION_DISABLED //в дебажных утилитах REFLECTION_DISABLED только в релизном билде работает
|
||||
private static Dictionary<string, Type> _idTypePairs = new Dictionary<string, Type>();
|
||||
#endif
|
||||
public static string GetMetaID(Type type)
|
||||
{
|
||||
#if DEBUG || !REFLECTION_DISABLED //в дебажных утилитах REFLECTION_DISABLED только в релизном билде работает
|
||||
@ -524,22 +593,17 @@ namespace DCFApixels.DragonECS
|
||||
string id = atr.ID;
|
||||
if (type.IsGenericType && type.IsGenericTypeDefinition == false)
|
||||
{
|
||||
var metaIds = type.GetGenericArguments().Select(o => GetMetaID(o));
|
||||
if (metaIds.Any(o => string.IsNullOrEmpty(o)))
|
||||
var metaIDs = type.GetGenericArguments().Select(o => GetMetaID(o));
|
||||
if (metaIDs.Any(o => string.IsNullOrEmpty(o)))
|
||||
{
|
||||
id = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = $"{id}<{string.Join(", ", metaIds)}>";
|
||||
id = $"{id}<{string.Join(", ", metaIDs)}>";
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(id) == false &&
|
||||
_idTypePairs.TryGetValue(id, out Type otherType) && type != otherType)
|
||||
{
|
||||
Throw.Exception($"Types {type.ToMeta().TypeName} and {otherType.ToMeta().TypeName} have duplicate {atr.ID} MetaID.");
|
||||
}
|
||||
_idTypePairs[id] = type;
|
||||
id = string.Intern(id);
|
||||
return id;
|
||||
}
|
||||
#else
|
||||
@ -548,6 +612,15 @@ namespace DCFApixels.DragonECS
|
||||
#endif
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetReflectionInfo
|
||||
public static void GetReflectionInfo(TypeMeta meta)
|
||||
{
|
||||
meta._isComponent = typeof(IEcsComponentMember).IsAssignableFrom(meta.Type);
|
||||
meta._isProcess = typeof(IEcsProcess).IsAssignableFrom(meta.Type);
|
||||
meta._isPool = typeof(IEcsPoolImplementation).IsAssignableFrom(meta.Type);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ namespace DCFApixels.DragonECS
|
||||
#endregion
|
||||
|
||||
//Инициализация аспектов проходит в синхронизированном состоянии, поэтому использование _staticMaskCache потоко безопасно.
|
||||
private static Dictionary<Type, EcsStaticMask> _staticMaskCache = new Dictionary<Type, EcsStaticMask>();
|
||||
private readonly static Dictionary<Type, EcsStaticMask> _staticMaskCache = new Dictionary<Type, EcsStaticMask>();
|
||||
|
||||
internal EcsWorld _source;
|
||||
internal EcsMask _mask;
|
||||
@ -272,13 +272,13 @@ namespace DCFApixels.DragonECS
|
||||
public TPool IncludePool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||
{
|
||||
var pool = CachePool<TPool>();
|
||||
IncludeImplicit(pool.ComponentType);
|
||||
SetMaskInclude(pool.ComponentType);
|
||||
return pool;
|
||||
}
|
||||
public TPool ExcludePool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||
{
|
||||
var pool = CachePool<TPool>();
|
||||
ExcludeImplicit(pool.ComponentType);
|
||||
SetMaskExclude(pool.ComponentType);
|
||||
return pool;
|
||||
}
|
||||
public TPool OptionalPool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||
@ -291,14 +291,14 @@ namespace DCFApixels.DragonECS
|
||||
var pool = _world.GetPoolInstance<TPool>();
|
||||
return pool;
|
||||
}
|
||||
private void IncludeImplicit(Type type)
|
||||
public void SetMaskInclude(Type type)
|
||||
{
|
||||
if (_maskBuilder.IsNull == false)
|
||||
{
|
||||
_maskBuilder.Inc(type);
|
||||
}
|
||||
}
|
||||
private void ExcludeImplicit(Type type)
|
||||
public void SetMaskExclude(Type type)
|
||||
{
|
||||
if (_maskBuilder.IsNull == false)
|
||||
{
|
||||
@ -334,8 +334,8 @@ namespace DCFApixels.DragonECS
|
||||
IncludePool<TPool>();
|
||||
ExcludePool<TPool>();
|
||||
OptionalPool<TPool>();
|
||||
IncludeImplicit(null);
|
||||
ExcludeImplicit(null);
|
||||
SetMaskInclude(null);
|
||||
SetMaskExclude(null);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
@ -488,7 +488,7 @@ namespace DCFApixels.DragonECS
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
#endif
|
||||
public class EcsMaskIterator
|
||||
public class EcsMaskIterator : IDisposable
|
||||
{
|
||||
// TODO есть идея перенести эти ChunckBuffer-ы в стек,
|
||||
// для этого нужно проработать дизайн так чтобы память в стеке выделялась за пределами итератора и GetEnumerator,
|
||||
@ -555,6 +555,15 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
}
|
||||
unsafe ~EcsMaskIterator()
|
||||
{
|
||||
Cleanup(false);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Cleanup(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
private void Cleanup(bool disposing)
|
||||
{
|
||||
_sortIncBuffer.ReadonlyDispose();
|
||||
//_sortExcBuffer.ReadonlyDispose();// использует общую памяять с _sortIncBuffer;
|
||||
@ -563,7 +572,7 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SortConstraints
|
||||
#region SortConstraints/TryFindEntityStorage
|
||||
private unsafe int SortConstraints_Internal()
|
||||
{
|
||||
UnsafeArray<int> sortIncBuffer = _sortIncBuffer;
|
||||
@ -611,7 +620,7 @@ namespace DCFApixels.DragonECS
|
||||
// Поэтому исключающее ограничение игнорируется для maxEntites.
|
||||
return maxEntites;
|
||||
}
|
||||
private unsafe bool TryGetEntityStorage(out IEntityStorage storage)
|
||||
private unsafe bool TryFindEntityStorage(out IEntityStorage storage)
|
||||
{
|
||||
if (_isHasAnyEntityStorage)
|
||||
{
|
||||
@ -737,7 +746,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
return new Enumerator(_span.Slice(0, 0), _iterator);
|
||||
}
|
||||
if (_iterator.TryGetEntityStorage(out IEntityStorage storage))
|
||||
if (_iterator.TryFindEntityStorage(out IEntityStorage storage))
|
||||
{
|
||||
return new Enumerator(storage.ToSpan(), _iterator);
|
||||
}
|
||||
@ -811,6 +820,7 @@ namespace DCFApixels.DragonECS
|
||||
#region Iterate/Enumerable OnlyInc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public OnlyIncEnumerable IterateOnlyInc(EcsSpan span) { return new OnlyIncEnumerable(this, span); }
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
@ -952,29 +962,30 @@ namespace DCFApixels.DragonECS.Internal
|
||||
internal const int STACK_BUFFER_THRESHOLD = 100;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static void ConvertToChuncks(EcsMaskChunck* ptr, UnsafeArray<int> input, UnsafeArray<EcsMaskChunck> output)
|
||||
internal static void ConvertToChuncks(EcsMaskChunck* bufferPtr, UnsafeArray<int> input, UnsafeArray<EcsMaskChunck> output)
|
||||
{
|
||||
for (int i = 0; i < input.Length; i++)
|
||||
{
|
||||
ptr[i] = EcsMaskChunck.FromID(input.ptr[i]);
|
||||
bufferPtr[i] = EcsMaskChunck.FromID(input.ptr[i]);
|
||||
}
|
||||
|
||||
for (int inputI = 0, outputI = 0; outputI < output.Length; inputI++, ptr++)
|
||||
for (int inputI = 0, outputI = 0; outputI < output.Length; inputI++, bufferPtr++)
|
||||
{
|
||||
int maskX = ptr->mask;
|
||||
if (maskX == 0) { continue; }
|
||||
int chunkIndexX = ptr->chunkIndex;
|
||||
int stackingMask = bufferPtr->mask;
|
||||
if (stackingMask == 0) { continue; }
|
||||
int stackingChunkIndex = bufferPtr->chunkIndex;
|
||||
|
||||
EcsMaskChunck* subptr = ptr;
|
||||
for (int j = 1; j < input.Length - inputI; j++, subptr++)
|
||||
EcsMaskChunck* bufferSpanPtr = bufferPtr + 1;
|
||||
for (int j = 1; j < input.Length - inputI; j++, bufferSpanPtr++)
|
||||
{
|
||||
if (subptr->chunkIndex == chunkIndexX)
|
||||
if (bufferSpanPtr->chunkIndex == stackingChunkIndex)
|
||||
{
|
||||
maskX |= subptr->mask;
|
||||
*subptr = default;
|
||||
stackingMask |= bufferSpanPtr->mask;
|
||||
*bufferSpanPtr = default;
|
||||
}
|
||||
}
|
||||
output.ptr[outputI] = new EcsMaskChunck(chunkIndexX, maskX);
|
||||
|
||||
output.ptr[outputI] = new EcsMaskChunck(stackingChunkIndex, stackingMask);
|
||||
outputI++;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
|
||||
[MetaDescription(AUTHOR, "...")]
|
||||
[MetaID("FC38597C9201C15D1A14D133237BD67F")]
|
||||
[MetaID("DragonECS_FC38597C9201C15D1A14D133237BD67F")]
|
||||
public interface IEcsDefaultAddParams
|
||||
{
|
||||
AddParams AddParams { get; }
|
||||
@ -726,7 +726,7 @@ namespace DCFApixels.DragonECS
|
||||
#region SerializableTemplate
|
||||
public EcsPipelineTemplate GenerateSerializableTemplate()
|
||||
{
|
||||
var it = new LinkedListIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex);
|
||||
var it = new LinkedListCountIterator<SystemNode>(_systemNodes, _systemNodesCount, _startIndex);
|
||||
EcsPipelineTemplate result = new EcsPipelineTemplate();
|
||||
result.layers = new string[Layers.Count];
|
||||
result.records = new EcsPipelineTemplate.Record[it.Count];
|
||||
|
@ -14,6 +14,7 @@ using static DCFApixels.DragonECS.EcsConsts;
|
||||
namespace DCFApixels.DragonECS
|
||||
{
|
||||
public interface IEcsMember { }
|
||||
public interface IEcsComponentMember : IEcsMember { }
|
||||
public interface INamedMember
|
||||
{
|
||||
string Name { get; }
|
||||
@ -22,7 +23,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
|
||||
[MetaDescription(AUTHOR, "...")]
|
||||
[MetaID("F064557C92010419AB677453893D00AE")]
|
||||
[MetaID("DragonECS_F064557C92010419AB677453893D00AE")]
|
||||
public interface IEcsPipelineMember : IEcsProcess
|
||||
{
|
||||
EcsPipeline Pipeline { get; set; }
|
||||
@ -31,7 +32,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
|
||||
[MetaDescription(AUTHOR, "Container and engine for systems. Responsible for configuring the execution order of systems, providing a mechanism for messaging between systems, and a dependency injection mechanism.")]
|
||||
[MetaID("9F5A557C9201C5C3D9BCAC2FF1CC07D4")]
|
||||
[MetaID("DragonECS_9F5A557C9201C5C3D9BCAC2FF1CC07D4")]
|
||||
public sealed partial class EcsPipeline
|
||||
{
|
||||
private readonly IConfigContainer _configs;
|
||||
@ -113,20 +114,18 @@ namespace DCFApixels.DragonECS
|
||||
private static IEcsProcess[] _buffer;
|
||||
private T[] CreateProcess<T>() where T : IEcsProcess
|
||||
{
|
||||
if (_buffer == null || _buffer.Length < _allSystems.Length)
|
||||
{
|
||||
Array.Resize(ref _buffer, _allSystems.Length);
|
||||
}
|
||||
int l = 0;
|
||||
ArrayUtility.UpsizeWithoutCopy(ref _buffer, _allSystems.Length);
|
||||
int bufferLength = 0;
|
||||
for (int i = 0, iMax = _allSystems.Length; i < iMax; i++)
|
||||
{
|
||||
if (_allSystems[i] is T)
|
||||
{
|
||||
_buffer[l++] = _allSystems[i];
|
||||
_buffer[bufferLength++] = _allSystems[i];
|
||||
}
|
||||
}
|
||||
T[] result = new T[l];
|
||||
Array.Copy(_buffer, result, l);
|
||||
T[] result = new T[bufferLength];
|
||||
Array.Copy(_buffer, result, bufferLength);
|
||||
Array.Clear(_buffer, 0, bufferLength);
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
@ -288,7 +287,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.Black)]
|
||||
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
|
||||
[MetaDescription(AUTHOR, "An auxiliary type of system for dividing a pipeline into layers. This system is automatically added to the EcsPipeline.")]
|
||||
[MetaID("42596C7C9201D0B85D1335E6E4704B57")]
|
||||
[MetaID("DragonECS_42596C7C9201D0B85D1335E6E4704B57")]
|
||||
public class SystemsLayerMarkerSystem : IEcsProcess
|
||||
{
|
||||
public readonly string name;
|
||||
|
@ -14,7 +14,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("EF8A557C9201E6F04D4A76DC670BDE19")]
|
||||
[MetaID("DragonECS_EF8A557C9201E6F04D4A76DC670BDE19")]
|
||||
public interface IEcsProcess : IEcsMember { }
|
||||
|
||||
namespace RunnersCore
|
||||
@ -69,7 +69,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("E49B557C92010E46DF1602972BC988BC")]
|
||||
[MetaID("DragonECS_E49B557C92010E46DF1602972BC988BC")]
|
||||
public interface IEcsRunner : IEcsProcess
|
||||
{
|
||||
EcsPipeline Pipeline { get; }
|
||||
@ -84,7 +84,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.OTHER_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "...")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("7DB3557C9201F85E0E1C17D7B19D9CEE")]
|
||||
[MetaID("DragonECS_7DB3557C9201F85E0E1C17D7B19D9CEE")]
|
||||
public abstract class EcsRunner<TProcess> : EcsRunner, IEcsRunner, IEcsProcess
|
||||
where TProcess : IEcsProcess
|
||||
{
|
||||
@ -211,9 +211,10 @@ namespace DCFApixels.DragonECS
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DRAGONECS_DISABLE_CATH_EXCEPTIONS
|
||||
throw;
|
||||
#endif
|
||||
throw e;
|
||||
#else
|
||||
EcsDebug.PrintError(e);
|
||||
#endif
|
||||
}
|
||||
_markers[i].End();
|
||||
}
|
||||
@ -251,9 +252,10 @@ namespace DCFApixels.DragonECS
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DRAGONECS_DISABLE_CATH_EXCEPTIONS
|
||||
throw;
|
||||
#endif
|
||||
throw e;
|
||||
#else
|
||||
EcsDebug.PrintError(e);
|
||||
#endif
|
||||
}
|
||||
_markers[i].End();
|
||||
}
|
||||
@ -378,9 +380,10 @@ namespace DCFApixels.DragonECS
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DRAGONECS_DISABLE_CATH_EXCEPTIONS
|
||||
throw;
|
||||
#endif
|
||||
throw e;
|
||||
#else
|
||||
EcsDebug.PrintError(e);
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -433,9 +436,10 @@ namespace DCFApixels.DragonECS
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DRAGONECS_DISABLE_CATH_EXCEPTIONS
|
||||
throw;
|
||||
#endif
|
||||
throw e;
|
||||
#else
|
||||
EcsDebug.PrintError(e);
|
||||
#endif
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
146
src/EcsWorld.cs
146
src/EcsWorld.cs
@ -48,7 +48,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.WORLDS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Container for entities and components.")]
|
||||
[MetaID("AEF3557C92019C976FC48F90E95A9DA6")]
|
||||
[MetaID("DragonECS_AEF3557C92019C976FC48F90E95A9DA6")]
|
||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||
public partial class EcsWorld : IEntityStorage, IEcsMember, INamedMember
|
||||
{
|
||||
@ -65,6 +65,8 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
private int[] _delEntBuffer = Array.Empty<int>();
|
||||
private int _delEntBufferCount = 0;
|
||||
private int[] _emptyEntities = Array.Empty<int>();
|
||||
private int _emptyEntitiesCount = 0;
|
||||
private bool _isEnableAutoReleaseDelEntBuffer = true;
|
||||
|
||||
internal int _entityComponentMaskLength;
|
||||
@ -194,12 +196,12 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
_poolsMediator = new PoolsMediator(this);
|
||||
|
||||
int poolsCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.PoolsCapacity);
|
||||
int poolsCapacity = ArrayUtility.NextPow2(config.PoolsCapacity);
|
||||
_pools = new IEcsPoolImplementation[poolsCapacity];
|
||||
_poolSlots = new PoolSlot[poolsCapacity];
|
||||
ArrayUtility.Fill(_pools, _nullPool);
|
||||
|
||||
int entitiesCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.EntitiesCapacity);
|
||||
int entitiesCapacity = ArrayUtility.NextPow2(config.EntitiesCapacity);
|
||||
_entityDispenser = new IdDispenser(entitiesCapacity, 0, OnEntityDispenserResized);
|
||||
|
||||
_executorCoures = new Dictionary<(Type, object), IQueryExecutorImplementation>(config.PoolComponentsCapacity);
|
||||
@ -253,6 +255,38 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
return Get<AspectCache<TAspect>>().Instance;
|
||||
}
|
||||
public void GetAspects<TAspect0>(out TAspect0 a0)
|
||||
where TAspect0 : new()
|
||||
{
|
||||
a0 = GetAspect<TAspect0>();
|
||||
}
|
||||
public void GetAspects<TAspect0, TAspect1>(out TAspect0 a0, out TAspect1 a1)
|
||||
where TAspect0 : new()
|
||||
where TAspect1 : new()
|
||||
{
|
||||
a0 = GetAspect<TAspect0>();
|
||||
a1 = GetAspect<TAspect1>();
|
||||
}
|
||||
public void GetAspects<TAspect0, TAspect1, TAspect2>(out TAspect0 a0, out TAspect1 a1, out TAspect2 a2)
|
||||
where TAspect0 : new()
|
||||
where TAspect1 : new()
|
||||
where TAspect2 : new()
|
||||
{
|
||||
a0 = GetAspect<TAspect0>();
|
||||
a1 = GetAspect<TAspect1>();
|
||||
a2 = GetAspect<TAspect2>();
|
||||
}
|
||||
public void GetAspects<TAspect0, TAspect1, TAspect2, TAspect3>(out TAspect0 a0, out TAspect1 a1, out TAspect2 a2, out TAspect3 a3)
|
||||
where TAspect0 : new()
|
||||
where TAspect1 : new()
|
||||
where TAspect2 : new()
|
||||
where TAspect3 : new()
|
||||
{
|
||||
a0 = GetAspect<TAspect0>();
|
||||
a1 = GetAspect<TAspect1>();
|
||||
a2 = GetAspect<TAspect2>();
|
||||
a3 = GetAspect<TAspect3>();
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public TAspect GetAspect<TAspect>(out EcsMask mask) where TAspect : new()
|
||||
{
|
||||
@ -327,6 +361,7 @@ namespace DCFApixels.DragonECS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int NewEntity(int entityID)
|
||||
{
|
||||
_entityDispenser.Upsize(entityID + 1);
|
||||
#if DEBUG
|
||||
if (IsUsed(entityID)) { Throw.World_EntityIsAlreadyСontained(entityID); }
|
||||
#elif DRAGONECS_STABILITY_MODE
|
||||
@ -348,6 +383,7 @@ namespace DCFApixels.DragonECS
|
||||
slot.gen |= GEN_SLEEP_MASK;
|
||||
}
|
||||
_entityListeners.InvokeOnNewEntity(entityID);
|
||||
MoveToEmptyEntities(entityID);
|
||||
}
|
||||
|
||||
|
||||
@ -380,7 +416,7 @@ namespace DCFApixels.DragonECS
|
||||
public void DelEntity(int entityID)
|
||||
{
|
||||
#if DEBUG
|
||||
if (IsUsed(entityID) == false) { Throw.World_EntityIsAlreadyСontained(entityID); }
|
||||
if (IsUsed(entityID) == false) { Throw.World_EntityIsNotContained(entityID); }
|
||||
#elif DRAGONECS_STABILITY_MODE
|
||||
if (IsUsed(entityID) == false) { return; }
|
||||
#endif
|
||||
@ -390,6 +426,24 @@ namespace DCFApixels.DragonECS
|
||||
_entitiesCount--;
|
||||
_entityListeners.InvokeOnDelEntity(entityID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void MoveToEmptyEntities(int entityID)
|
||||
{
|
||||
_emptyEntities[_emptyEntitiesCount++] = entityID;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private bool RemoveFromEmptyEntities(int entityID)
|
||||
{
|
||||
for (int i = _emptyEntitiesCount - 1; i >= 0; i--)
|
||||
{
|
||||
if(_emptyEntities[i] == entityID)
|
||||
{
|
||||
_emptyEntities[i] = _emptyEntities[--_emptyEntitiesCount];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other
|
||||
@ -477,22 +531,62 @@ namespace DCFApixels.DragonECS
|
||||
#elif DRAGONECS_STABILITY_MODE
|
||||
if (mask.WorldID != ID) { return false; }
|
||||
#endif
|
||||
for (int i = 0, iMax = mask._incs.Length; i < iMax; i++)
|
||||
|
||||
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
bool IsMatchesMaskDeepDebug(EcsMask mask_, int entityID_)
|
||||
{
|
||||
if (!_pools[mask._incs[i]].Has(entityID))
|
||||
for (int i = 0, iMax = mask_._incs.Length; i < iMax; i++)
|
||||
{
|
||||
if (!_pools[mask_._incs[i]].Has(entityID_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0, iMax = mask._excs.Length; i < iMax; i++)
|
||||
for (int i = 0, iMax = mask_._excs.Length; i < iMax; i++)
|
||||
{
|
||||
if (_pools[mask._excs[i]].Has(entityID))
|
||||
if (_pools[mask_._excs[i]].Has(entityID_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool deepDebug = IsMatchesMaskDeepDebug(mask, entityID);
|
||||
#endif
|
||||
|
||||
var incChuncks = mask._incChunckMasks;
|
||||
var excChuncks = mask._excChunckMasks;
|
||||
var componentMaskStartIndex = entityID << _entityComponentMaskLengthBitShift;
|
||||
|
||||
for (int i = 0; i < incChuncks.Length; i++)
|
||||
{
|
||||
var bit = incChuncks[i];
|
||||
if ((_entityComponentMasks[componentMaskStartIndex + bit.chunkIndex] & bit.mask) != bit.mask)
|
||||
{
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
if (false != deepDebug) { Throw.DeepDebugException(); }
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < excChuncks.Length; i++)
|
||||
{
|
||||
var bit = excChuncks[i];
|
||||
if ((_entityComponentMasks[componentMaskStartIndex + bit.chunkIndex] & bit.mask) != 0)
|
||||
{
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
if (false != deepDebug) { Throw.DeepDebugException(); }
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
if (true != deepDebug) { Throw.DeepDebugException(); }
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Leaked
|
||||
@ -745,13 +839,24 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
public void ReleaseDelEntityBufferAll()
|
||||
{
|
||||
ReleaseDelEntityBuffer(_delEntBufferCount);
|
||||
ReleaseDelEntityBuffer(-1);
|
||||
}
|
||||
public unsafe void ReleaseDelEntityBuffer(int count)
|
||||
{
|
||||
if (_delEntBufferCount <= 0) { return; }
|
||||
if (_emptyEntitiesCount <= 0 && _delEntBufferCount <= 0) { return; }
|
||||
unchecked { _version++; }
|
||||
|
||||
for (int i = 0; i < _emptyEntitiesCount; i++)
|
||||
{
|
||||
TryDelEntity(_emptyEntities[i]);
|
||||
}
|
||||
_emptyEntitiesCount = 0;
|
||||
|
||||
if(count < 0)
|
||||
{
|
||||
count = _delEntBufferCount;
|
||||
}
|
||||
|
||||
count = Math.Max(0, Math.Min(count, _delEntBufferCount));
|
||||
_delEntBufferCount -= count;
|
||||
int slisedCount = count;
|
||||
@ -831,6 +936,7 @@ namespace DCFApixels.DragonECS
|
||||
SetEntityComponentMaskLength(CalcEntityComponentMaskLength()); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1;
|
||||
Array.Resize(ref _entities, newSize);
|
||||
Array.Resize(ref _delEntBuffer, newSize);
|
||||
Array.Resize(ref _emptyEntities, newSize);
|
||||
Array.Resize(ref _entityComponentMasks, newSize * _entityComponentMaskLength);
|
||||
|
||||
ArrayUtility.Fill(_entities, EntitySlot.Empty, _entitiesCapacity);
|
||||
@ -951,10 +1057,8 @@ namespace DCFApixels.DragonECS
|
||||
public ReadOnlySpan<object> GetComponentsFor(int entityID)
|
||||
{
|
||||
int count = GetComponentTypeIDsFor_Internal(entityID, ref _componentIDsBuffer);
|
||||
if (_componentsBuffer == null || _componentsBuffer.Length < count)
|
||||
{
|
||||
_componentsBuffer = new object[count];
|
||||
}
|
||||
ArrayUtility.UpsizeWithoutCopy(ref _componentIDsBuffer, count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_componentsBuffer[i] = _pools[_componentIDsBuffer[i]].GetRaw(entityID);
|
||||
@ -982,14 +1086,7 @@ namespace DCFApixels.DragonECS
|
||||
private unsafe int GetComponentTypeIDsFor_Internal(int entityID, ref int[] componentIDs)
|
||||
{
|
||||
var itemsCount = GetComponentsCount(entityID);
|
||||
if (componentIDs == null)
|
||||
{
|
||||
componentIDs = new int[itemsCount];
|
||||
}
|
||||
if (componentIDs.Length < itemsCount)
|
||||
{
|
||||
Array.Resize(ref componentIDs, itemsCount);
|
||||
}
|
||||
ArrayUtility.UpsizeWithoutCopy(ref componentIDs, itemsCount);
|
||||
|
||||
if (itemsCount <= 0) { return 0; }
|
||||
|
||||
@ -1150,22 +1247,27 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
private EcsWorld _world;
|
||||
private List<MaskQueryExecutor> _queries;
|
||||
public string Name { get { return _world.Name; } }
|
||||
public EntitySlotInfo[] Entities
|
||||
{
|
||||
get
|
||||
{
|
||||
EntitySlotInfo[] result = new EntitySlotInfo[_world.Count];
|
||||
int i = 0;
|
||||
using (_world.DisableAutoReleaseDelEntBuffer())
|
||||
{
|
||||
foreach (var e in _world.ToSpan())
|
||||
{
|
||||
result[i++] = _world.GetEntitySlotInfoDebug(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public long Version { get { return _world.Version; } }
|
||||
public IEcsPool[] Pools { get { return _world._pools; } }
|
||||
public short ID { get { return _world.ID; } }
|
||||
public bool IsDestroyed { get { return _world._isDestroyed; } }
|
||||
public List<MaskQueryExecutor> MaskQueries { get { return _queries; } }
|
||||
public DebuggerProxy(EcsWorld world)
|
||||
{
|
||||
|
@ -40,6 +40,17 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
return FindPoolInstance_Internal(GetComponentTypeID(componentType));
|
||||
}
|
||||
public bool TryFindPoolInstance(int componentTypeID, out IEcsPool pool)
|
||||
{
|
||||
pool = FindPoolInstance(componentTypeID);
|
||||
return pool.IsNullOrDummy() == false;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryFindPoolInstance(Type componentType, out IEcsPool pool)
|
||||
{
|
||||
pool = FindPoolInstance(componentType);
|
||||
return pool.IsNullOrDummy() == false;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private IEcsPool FindPoolInstance_Internal(int componentTypeID)
|
||||
{
|
||||
@ -267,7 +278,11 @@ namespace DCFApixels.DragonECS
|
||||
ref PoolSlot slot = ref _poolSlots[componentTypeID];
|
||||
slot.count++;
|
||||
slot.version++;
|
||||
_entities[entityID].componentsCount++;
|
||||
var count = _entities[entityID].componentsCount++;
|
||||
if (count == 0 && IsUsed(entityID))
|
||||
{
|
||||
RemoveFromEmptyEntities(entityID);
|
||||
}
|
||||
_entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chunkIndex] |= maskBit.mask;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -282,7 +297,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
if (count == 0 && IsUsed(entityID))
|
||||
{
|
||||
DelEntity(entityID);
|
||||
MoveToEmptyEntities(entityID);
|
||||
}
|
||||
CheckUnregisterValid(count, entityID);
|
||||
}
|
||||
@ -298,7 +313,11 @@ namespace DCFApixels.DragonECS
|
||||
ref PoolSlot slot = ref _poolSlots[componentTypeID];
|
||||
slot.count++;
|
||||
slot.version++;
|
||||
_entities[entityID].componentsCount++;
|
||||
var count = _entities[entityID].componentsCount++;
|
||||
if(count == 0 && IsUsed(entityID))
|
||||
{
|
||||
RemoveFromEmptyEntities(entityID);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -319,7 +338,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
if (count == 0 && IsUsed(entityID))
|
||||
{
|
||||
DelEntity(entityID);
|
||||
MoveToEmptyEntities(entityID);
|
||||
}
|
||||
CheckUnregisterValid(count, entityID);
|
||||
return true;
|
||||
|
@ -1,6 +1,7 @@
|
||||
#if DISABLE_DEBUG
|
||||
#undef DEBUG
|
||||
#endif
|
||||
using DCFApixels.DragonECS.Core;
|
||||
using DCFApixels.DragonECS.Internal;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -25,11 +26,11 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
private static EcsWorld[] _worlds = Array.Empty<EcsWorld>();
|
||||
private static readonly IdDispenser _worldIdDispenser = new IdDispenser(4, 0, n => Array.Resize(ref _worlds, n));
|
||||
|
||||
private static StructList<WorldComponentPoolAbstract> _allWorldComponentPools = new StructList<WorldComponentPoolAbstract>(64);
|
||||
private static readonly object _worldLock = new object();
|
||||
|
||||
private StructList<WorldComponentPoolAbstract> _worldComponentPools;
|
||||
private int _builtinWorldComponentsCount = 0;
|
||||
private static readonly object _worldLock = new object();
|
||||
|
||||
static EcsWorld()
|
||||
{
|
||||
@ -80,6 +81,7 @@ namespace DCFApixels.DragonECS
|
||||
|
||||
public static void ResetStaticState()
|
||||
{
|
||||
var nullworld = _worlds[0];
|
||||
for (int i = 1; i < _worlds.Length; i++)
|
||||
{
|
||||
var world = _worlds[i];
|
||||
@ -91,6 +93,8 @@ namespace DCFApixels.DragonECS
|
||||
}
|
||||
world = null;
|
||||
}
|
||||
_worlds = new EcsWorld[_worldIdDispenser.Capacity];
|
||||
_worlds[0] = nullworld;
|
||||
_worldIdDispenser.ReleaseAll();
|
||||
}
|
||||
|
||||
@ -136,8 +140,8 @@ namespace DCFApixels.DragonECS
|
||||
private static short _count;
|
||||
private static short[] _recycledItems = new short[4];
|
||||
private static short _recycledItemsCount;
|
||||
private static IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
|
||||
private static Abstract _controller = new Abstract();
|
||||
private static readonly IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
|
||||
private static readonly Abstract _controller = new Abstract();
|
||||
static WorldComponentPool()
|
||||
{
|
||||
_allWorldComponentPools.Add(_controller);
|
||||
|
@ -89,6 +89,28 @@ namespace DCFApixels.DragonECS.Internal
|
||||
public EcsSpan Execute()
|
||||
{
|
||||
Execute_Iternal();
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
var newSpan = new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount);
|
||||
using (EcsGroup group = EcsGroup.New(World))
|
||||
{
|
||||
foreach (var e in World.Entities)
|
||||
{
|
||||
if (World.IsMatchesMask(Mask, e))
|
||||
{
|
||||
group.Add(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (group.SetEquals(newSpan) == false)
|
||||
{
|
||||
int[] array = new int[_filteredAllEntities.Length];
|
||||
var count = _iterator.IterateTo(World.Entities, ref array);
|
||||
|
||||
EcsDebug.PrintError(newSpan.ToString() + "\r\n" + group.ToSpan().ToString());
|
||||
Throw.DeepDebugException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -99,6 +121,16 @@ namespace DCFApixels.DragonECS.Internal
|
||||
return Execute();
|
||||
}
|
||||
ExecuteFor_Iternal(span);
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
var newSpan = new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
|
||||
foreach (var e in newSpan)
|
||||
{
|
||||
if (World.IsMatchesMask(Mask, e) == false)
|
||||
{
|
||||
Throw.DeepDebugException();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
|
||||
}
|
||||
|
||||
|
@ -68,6 +68,24 @@ namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
_version++;
|
||||
_iterator.IterateTo(World.Entities, _filteredAllGroup);
|
||||
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
||||
if(_filteredGroup == null)
|
||||
{
|
||||
_filteredGroup = EcsGroup.New(World);
|
||||
}
|
||||
_filteredGroup.Clear();
|
||||
foreach (var e in World.Entities)
|
||||
{
|
||||
if(World.IsMatchesMask(Mask, e))
|
||||
{
|
||||
_filteredGroup.Add(e);
|
||||
}
|
||||
}
|
||||
if(_filteredAllGroup.SetEquals(_filteredGroup) == false)
|
||||
{
|
||||
throw new System.InvalidOperationException();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -125,6 +125,7 @@ namespace DCFApixels.DragonECS.Core
|
||||
_maskInc = mask._incs;
|
||||
_maskExc = mask._excs;
|
||||
_count = 1 + mask._incs.Length + mask._excs.Length;
|
||||
|
||||
_versions = UnmanagedArrayUtility.NewAndInit<long>(_count);
|
||||
}
|
||||
public bool Check()
|
||||
@ -158,17 +159,17 @@ namespace DCFApixels.DragonECS.Core
|
||||
{
|
||||
*_versions = _world.Version;
|
||||
|
||||
long* ptr = _versions;
|
||||
long* versionsPtr = _versions;
|
||||
var slots = _world._poolSlots;
|
||||
foreach (var slotIndex in _maskInc)
|
||||
{
|
||||
ptr++;
|
||||
*ptr = slots[slotIndex].version;
|
||||
versionsPtr++;
|
||||
*versionsPtr = slots[slotIndex].version;
|
||||
}
|
||||
foreach (var slotIndex in _maskExc)
|
||||
{
|
||||
ptr++;
|
||||
*ptr = slots[slotIndex].version;
|
||||
versionsPtr++;
|
||||
*versionsPtr = slots[slotIndex].version;
|
||||
}
|
||||
}
|
||||
public bool CheckAndNext()
|
||||
@ -179,25 +180,27 @@ namespace DCFApixels.DragonECS.Core
|
||||
}
|
||||
*_versions = _world.Version;
|
||||
|
||||
long* ptr = _versions;
|
||||
long* versionsPtr = _versions;
|
||||
var slots = _world._poolSlots;
|
||||
bool result = _count != 1;
|
||||
// Так как проверки EXC работают не правильно при отсутсвии INC,
|
||||
// то проверки без INC должны всегда возвращать false.
|
||||
bool result = _maskInc.Length > 0;
|
||||
foreach (var slotIndex in _maskInc)
|
||||
{
|
||||
ptr++;
|
||||
if (*ptr != slots[slotIndex].version)
|
||||
versionsPtr++;
|
||||
if (*versionsPtr != slots[slotIndex].version)
|
||||
{
|
||||
result = false;
|
||||
*ptr = slots[slotIndex].version;
|
||||
*versionsPtr = slots[slotIndex].version;
|
||||
}
|
||||
}
|
||||
foreach (var slotIndex in _maskExc)
|
||||
{
|
||||
ptr++;
|
||||
if (*ptr != slots[slotIndex].version)
|
||||
versionsPtr++;
|
||||
if (*versionsPtr != slots[slotIndex].version)
|
||||
{
|
||||
result = false;
|
||||
*ptr = slots[slotIndex].version;
|
||||
*versionsPtr = slots[slotIndex].version;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -9,7 +9,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.DI_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "The interface of the dependency injection process.")]
|
||||
[MetaID("4C86537C92019AA24383CBF53CBD456C")]
|
||||
[MetaID("DragonECS_4C86537C92019AA24383CBF53CBD456C")]
|
||||
public interface IEcsInject<T> : IEcsInjectProcess
|
||||
{
|
||||
void Inject(T obj);
|
||||
@ -22,7 +22,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.DI_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "The process interface that signals the completion of injection during pipeline initialization via the EcsPipeline.Init() method.")]
|
||||
[MetaID("05C3537C920155AFC044C900E4F17D90")]
|
||||
[MetaID("DragonECS_05C3537C920155AFC044C900E4F17D90")]
|
||||
public interface IOnInitInjectionComplete : IEcsProcess
|
||||
{
|
||||
void OnBeforeInitInjection();
|
||||
|
@ -14,13 +14,13 @@ namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
int Next { get; }
|
||||
}
|
||||
internal readonly struct LinkedListIterator<T> : IEnumerable<T>
|
||||
internal readonly struct LinkedListCountIterator<T> : IEnumerable<T>
|
||||
where T : ILinkedNext
|
||||
{
|
||||
public readonly T[] Array;
|
||||
public readonly int Count;
|
||||
public readonly int StartIndex;
|
||||
public LinkedListIterator(T[] array, int count, int startIndex)
|
||||
public LinkedListCountIterator(T[] array, int count, int startIndex)
|
||||
{
|
||||
Array = array;
|
||||
Count = count;
|
||||
@ -66,6 +66,58 @@ namespace DCFApixels.DragonECS.Internal
|
||||
void IEnumerator.Reset() { throw new NotSupportedException(); }
|
||||
}
|
||||
}
|
||||
internal readonly struct LinkedListIterator<T> : IEnumerable<T>
|
||||
where T : ILinkedNext
|
||||
{
|
||||
public readonly T[] Array;
|
||||
public readonly int EndIndex;
|
||||
public readonly int StartIndex;
|
||||
public LinkedListIterator(T[] array, int endIndex, int startIndex)
|
||||
{
|
||||
Array = array;
|
||||
EndIndex = endIndex;
|
||||
StartIndex = startIndex;
|
||||
}
|
||||
public Enumerator GetEnumerator()
|
||||
{
|
||||
return new Enumerator(Array, EndIndex, StartIndex);
|
||||
}
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); }
|
||||
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
||||
public struct Enumerator : IEnumerator<T>
|
||||
{
|
||||
private readonly T[] _array;
|
||||
private readonly int _endIndex;
|
||||
private readonly int _startIndex;
|
||||
private int _nextIndex;
|
||||
private int _index;
|
||||
public ref T Current { get { return ref _array[_index]; } }
|
||||
T IEnumerator<T>.Current { get { return Current; } }
|
||||
object IEnumerator.Current { get { return Current; } }
|
||||
public Enumerator(T[] array, int endIndex, int head)
|
||||
{
|
||||
_array = array;
|
||||
_startIndex = head;
|
||||
_nextIndex = _startIndex;
|
||||
_endIndex = endIndex;
|
||||
_index = _endIndex;
|
||||
}
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_nextIndex < 0) { return false; }
|
||||
_index = _nextIndex;
|
||||
_nextIndex = _array[_index].Next;
|
||||
return true;
|
||||
}
|
||||
public void Dispose() { }
|
||||
public void Reset()
|
||||
{
|
||||
_nextIndex = _startIndex;
|
||||
_index = _endIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal static class ArrayUtility
|
||||
{
|
||||
@ -92,58 +144,33 @@ namespace DCFApixels.DragonECS.Internal
|
||||
Array.Copy(array, array.Length - rightHeadLength, result, array.Length - rightHeadLength, rightHeadLength); // copy right head
|
||||
array = result;
|
||||
}
|
||||
private static int GetHighBitNumber(uint bits)
|
||||
{
|
||||
if (bits == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int bit = 0;
|
||||
if ((bits & 0xFFFF0000) != 0)
|
||||
{
|
||||
bits >>= 16;
|
||||
bit |= 16;
|
||||
}
|
||||
if ((bits & 0xFF00) != 0)
|
||||
{
|
||||
bits >>= 8;
|
||||
bit |= 8;
|
||||
}
|
||||
if ((bits & 0xF0) != 0)
|
||||
{
|
||||
bits >>= 4;
|
||||
bit |= 4;
|
||||
}
|
||||
if ((bits & 0xC) != 0)
|
||||
{
|
||||
bits >>= 2;
|
||||
bit |= 2;
|
||||
}
|
||||
if ((bits & 0x2) != 0)
|
||||
{
|
||||
bit |= 1;
|
||||
}
|
||||
return bit;
|
||||
}
|
||||
public static int NormalizeSizeToPowerOfTwo(int minSize)
|
||||
|
||||
public static int NextPow2(int v)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1);
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return ++v;
|
||||
}
|
||||
}
|
||||
public static int NormalizeSizeToPowerOfTwo_ClampOverflow(int minSize)
|
||||
public static int NextPow2_ClampOverflow(int v)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hibit = (GetHighBitNumber((uint)minSize - 1u) + 1);
|
||||
if (hibit >= 32)
|
||||
const int NO_SIGN_HIBIT = 0x40000000;
|
||||
if ((v & NO_SIGN_HIBIT) != 0)
|
||||
{
|
||||
return int.MaxValue;
|
||||
}
|
||||
return 1 << hibit;
|
||||
return NextPow2(v);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fill<T>(T[] array, T value, int startIndex = 0, int length = -1)
|
||||
{
|
||||
if (length < 0)
|
||||
@ -159,6 +186,39 @@ namespace DCFApixels.DragonECS.Internal
|
||||
array[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void UpsizeWithoutCopy<T>(ref T[] array, int minSize)
|
||||
{
|
||||
if (array == null || minSize > array.Length)
|
||||
{
|
||||
array = new T[minSize];
|
||||
}
|
||||
}
|
||||
public static void Upsize<T>(ref T[] array, int minSize)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
array = new T[minSize];
|
||||
}
|
||||
else if (minSize > array.Length)
|
||||
{
|
||||
Array.Resize(ref array, minSize);
|
||||
}
|
||||
}
|
||||
public static void UpsizeToNextPow2<T>(ref T[] array, int minSize)
|
||||
{
|
||||
if (array == null)
|
||||
{
|
||||
minSize = NextPow2(minSize);
|
||||
array = new T[minSize];
|
||||
}
|
||||
else if (minSize > array.Length)
|
||||
{
|
||||
minSize = NextPow2(minSize);
|
||||
Array.Resize(ref array, minSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal readonly struct EnumerableInt : IEnumerable<int>
|
||||
{
|
||||
|
@ -12,46 +12,6 @@ using Unity.IL2CPP.CompilerServices;
|
||||
|
||||
namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
#endif
|
||||
[DebuggerDisplay("{" + nameof(GetDebuggerDisplay) + "(),nq}")]
|
||||
internal readonly struct EcsTypeCodeKey : IEquatable<EcsTypeCodeKey>
|
||||
{
|
||||
public readonly Type Type;
|
||||
public readonly string NameKey;
|
||||
public EcsTypeCodeKey(Type type, string nameKey)
|
||||
{
|
||||
Type = type;
|
||||
NameKey = nameKey;
|
||||
}
|
||||
public bool Equals(EcsTypeCodeKey other)
|
||||
{
|
||||
return Type == other.Type && NameKey == other.NameKey;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is EcsTypeCodeKey other && Equals(other);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Type, NameKey);
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
if (string.IsNullOrEmpty(NameKey))
|
||||
{
|
||||
return Type.ToString();
|
||||
}
|
||||
return $"{Type} {NameKey}";
|
||||
}
|
||||
public static implicit operator EcsTypeCodeKey(Type type) { return new EcsTypeCodeKey(type, string.Empty); }
|
||||
private string GetDebuggerDisplay()
|
||||
{
|
||||
return ToString();
|
||||
}
|
||||
}
|
||||
//TODO разработать возможность ручного устанавливания ID типам.
|
||||
//это может быть полезно как детерминированность для сети
|
||||
#if ENABLE_IL2CPP
|
||||
@ -62,7 +22,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
private static readonly Dictionary<EcsTypeCodeKey, EcsTypeCode> _codes = new Dictionary<EcsTypeCodeKey, EcsTypeCode>();
|
||||
private static int _increment = 1;
|
||||
private static object _lock = new object();
|
||||
private static readonly object _lock = new object();
|
||||
public static int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@ -83,7 +43,6 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static EcsTypeCode Get<T>() { return EcsTypeCodeCache<T>.code; }
|
||||
public static bool Has(Type type) { return _codes.ContainsKey(type); }
|
||||
public static bool Has<T>() { return _codes.ContainsKey(typeof(T)); }
|
||||
public static EcsTypeCodeKey FindTypeOfCode(EcsTypeCode typeCode)
|
||||
{
|
||||
foreach (var item in _codes)
|
||||
@ -123,4 +82,40 @@ namespace DCFApixels.DragonECS.Internal
|
||||
return this.AutoToString(false);
|
||||
}
|
||||
}
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
#endif
|
||||
[DebuggerDisplay("{" + nameof(ToString) + "()}")]
|
||||
internal readonly struct EcsTypeCodeKey : IEquatable<EcsTypeCodeKey>
|
||||
{
|
||||
public readonly Type Type;
|
||||
public readonly string NameKey;
|
||||
public EcsTypeCodeKey(Type type, string nameKey)
|
||||
{
|
||||
Type = type;
|
||||
NameKey = nameKey;
|
||||
}
|
||||
public bool Equals(EcsTypeCodeKey other)
|
||||
{
|
||||
return Type == other.Type && NameKey == other.NameKey;
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is EcsTypeCodeKey other && Equals(other);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Type, NameKey);
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
if (string.IsNullOrEmpty(NameKey))
|
||||
{
|
||||
return Type.ToString();
|
||||
}
|
||||
return $"{Type} {NameKey}";
|
||||
}
|
||||
public static implicit operator EcsTypeCodeKey(Type type) { return new EcsTypeCodeKey(type, string.Empty); }
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _usedCount; }
|
||||
}
|
||||
public int Size
|
||||
public int Capacity
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _size; }
|
||||
@ -247,7 +247,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void Upsize_Internal(int minSize)
|
||||
{
|
||||
Resize(ArrayUtility.NormalizeSizeToPowerOfTwo_ClampOverflow(minSize));
|
||||
Resize(ArrayUtility.NextPow2_ClampOverflow(minSize));
|
||||
}
|
||||
private void Resize(int newSize)
|
||||
{
|
||||
@ -339,7 +339,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
get
|
||||
{
|
||||
Pair[] result = new Pair[_target.Size];
|
||||
Pair[] result = new Pair[_target.Capacity];
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
{
|
||||
result[i] = new Pair(
|
||||
@ -354,7 +354,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
{
|
||||
get
|
||||
{
|
||||
ID[] result = new ID[_target.Size];
|
||||
ID[] result = new ID[_target.Capacity];
|
||||
for (int i = 0; i < result.Length; i++)
|
||||
{
|
||||
int id = _target._dense[i];
|
||||
@ -365,7 +365,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
}
|
||||
public bool IsValid => _target.IsValid();
|
||||
public int Count => _target.Count;
|
||||
public int Size => _target.Size;
|
||||
public int Capacity => _target.Capacity;
|
||||
public int NullID => _target._nullID;
|
||||
internal readonly struct ID
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
set
|
||||
{
|
||||
if (value <= _items.Length) { return; }
|
||||
value = ArrayUtility.NormalizeSizeToPowerOfTwo(value);
|
||||
value = ArrayUtility.NextPow2(value);
|
||||
Array.Resize(ref _items, value);
|
||||
}
|
||||
}
|
||||
@ -53,7 +53,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public StructList(int capacity)
|
||||
{
|
||||
_items = new T[ArrayUtility.NormalizeSizeToPowerOfTwo(capacity)];
|
||||
_items = new T[ArrayUtility.NextPow2(capacity)];
|
||||
_count = 0;
|
||||
}
|
||||
|
||||
|
@ -44,6 +44,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||
|
@ -21,8 +21,8 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.POOLS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Standard component.")]
|
||||
[MetaID("84D2537C9201D6F6B92FEC1C8883A07A")]
|
||||
public interface IEcsComponent : IEcsMember { }
|
||||
[MetaID("DragonECS_84D2537C9201D6F6B92FEC1C8883A07A")]
|
||||
public interface IEcsComponent : IEcsComponentMember { }
|
||||
|
||||
/// <summary>Pool for IEcsComponent components</summary>
|
||||
#if ENABLE_IL2CPP
|
||||
@ -31,7 +31,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.POOLS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Pool for IEcsComponent components.")]
|
||||
[MetaID("C501547C9201A4B03FC25632E4FAAFD7")]
|
||||
[MetaID("DragonECS_C501547C9201A4B03FC25632E4FAAFD7")]
|
||||
[DebuggerDisplay("Count: {Count} Type: {ComponentType}")]
|
||||
public sealed class EcsPool<T> : IEcsPoolImplementation<T>, IEcsStructPool<T>, IEntityStorage, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
|
||||
where T : struct, IEcsComponent
|
||||
@ -51,8 +51,8 @@ namespace DCFApixels.DragonECS
|
||||
private bool _isDenseEntitiesDelayedValid = false;
|
||||
private int _recycledCount = 0;
|
||||
|
||||
private readonly IEcsComponentLifecycle<T> _componentLifecycleHandler = EcsComponentResetHandler<T>.instance;
|
||||
private readonly bool _isHasComponentLifecycleHandler = EcsComponentResetHandler<T>.isHasHandler;
|
||||
private readonly IEcsComponentLifecycle<T> _componentLifecycleHandler = EcsComponentLifecycleHandler<T>.instance;
|
||||
private readonly bool _isHasComponentLifecycleHandler = EcsComponentLifecycleHandler<T>.isHasHandler;
|
||||
private readonly IEcsComponentCopy<T> _componentCopyHandler = EcsComponentCopyHandler<T>.instance;
|
||||
private readonly bool _isHasComponentCopyHandler = EcsComponentCopyHandler<T>.isHasHandler;
|
||||
|
||||
@ -101,11 +101,12 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
ref int itemIndex = ref _mapping[entityID];
|
||||
#if DEBUG
|
||||
if (_source.IsUsed(entityID) == false) { Throw.Ent_ThrowIsNotAlive(_source, entityID); }
|
||||
if (itemIndex > 0) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); }
|
||||
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
|
||||
#elif DRAGONECS_STABILITY_MODE
|
||||
if (itemIndex > 0) { return ref Get(entityID); }
|
||||
if (_isLocked) { return ref _items[0]; }
|
||||
if (_isLocked | _source.IsUsed(entityID) == false) { return ref _items[0]; }
|
||||
#endif
|
||||
itemIndex = GetFreeItemIndex(entityID);
|
||||
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
|
||||
@ -279,15 +280,7 @@ namespace DCFApixels.DragonECS
|
||||
_maskBit = EcsMaskChunck.FromID(componentTypeID);
|
||||
|
||||
_mapping = new int[world.Capacity];
|
||||
Resize(ArrayUtility.NormalizeSizeToPowerOfTwo(world.Configs.GetWorldConfigOrDefault().PoolComponentsCapacity));
|
||||
//_capacity = ArrayUtility.NormalizeSizeToPowerOfTwo(world.Configs.GetWorldConfigOrDefault().PoolComponentsCapacity);
|
||||
//_items = new T[_capacity];
|
||||
//_sparseEntities = new int[_capacity];
|
||||
//_denseEntitiesDelayed = new int[_capacity];
|
||||
//for (int i = 0; i < _capacity; i++)
|
||||
//{// <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> free index-<2D> <20><><EFBFBD><EFBFBD> _denseEntitiesDelayed <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 0, <20><> free index <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
// _denseEntitiesDelayed[i] = i;
|
||||
//}
|
||||
Resize(ArrayUtility.NextPow2(world.Configs.GetWorldConfigOrDefault().PoolComponentsCapacity));
|
||||
}
|
||||
void IEcsPoolImplementation.OnWorldResize(int newSize)
|
||||
{
|
||||
@ -314,7 +307,7 @@ namespace DCFApixels.DragonECS
|
||||
{
|
||||
Add(entityID) = dataRaw == null ? default : (T)dataRaw;
|
||||
}
|
||||
object IEcsReadonlyPool.GetRaw(int entityID) { return Get(entityID); }
|
||||
object IEcsReadonlyPool.GetRaw(int entityID) { return Read(entityID); }
|
||||
void IEcsPool.SetRaw(int entityID, object dataRaw)
|
||||
{
|
||||
Get(entityID) = dataRaw == null ? default : (T)dataRaw;
|
||||
@ -515,13 +508,99 @@ namespace DCFApixels.DragonECS
|
||||
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
|
||||
#endregion
|
||||
|
||||
#region MarkersConverter
|
||||
#region Convertors
|
||||
public static implicit operator EcsPool<T>(IncludeMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
public static implicit operator EcsPool<T>(ExcludeMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
public static implicit operator EcsPool<T>(OptionalMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
public static implicit operator EcsPool<T>(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
#endregion
|
||||
|
||||
#region Apply
|
||||
public static void Apply(ref T component, int entityID, short worldID)
|
||||
{
|
||||
EcsWorld.GetPoolInstance<EcsPool<T>>(worldID).TryAddOrGet(entityID) = component;
|
||||
}
|
||||
public static void Apply(ref T component, int entityID, EcsPool<T> pool)
|
||||
{
|
||||
pool.TryAddOrGet(entityID) = component;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
#endif
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public readonly struct ReadonlyEcsPool<T> : IEcsReadonlyPool //IEnumerable<T> - IntelliSense hack
|
||||
where T : struct, IEcsComponent
|
||||
{
|
||||
private readonly EcsPool<T> _pool;
|
||||
|
||||
#region Properties
|
||||
public int ComponentTypeID
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.ComponentTypeID; }
|
||||
}
|
||||
public Type ComponentType
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.ComponentType; }
|
||||
}
|
||||
public EcsWorld World
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.World; }
|
||||
}
|
||||
public int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.Count; }
|
||||
}
|
||||
public bool IsReadOnly
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.IsReadOnly; }
|
||||
}
|
||||
public ref readonly T this[int entityID]
|
||||
{
|
||||
get { return ref _pool.Read(entityID); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
internal ReadonlyEcsPool(EcsPool<T> pool)
|
||||
{
|
||||
_pool = pool;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) { return _pool.Has(entityID); }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly T Get(int entityID) { return ref _pool.Read(entityID); }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref readonly T Read(int entityID) { return ref _pool.Read(entityID); }
|
||||
object IEcsReadonlyPool.GetRaw(int entityID) { return _pool.Read(entityID); }
|
||||
|
||||
#if !DRAGONECS_DISABLE_POOLS_EVENTS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddListener(IEcsPoolEventListener listener) { _pool.AddListener(listener); }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveListener(IEcsPoolEventListener listener) { _pool.AddListener(listener); }
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Convertors
|
||||
public static implicit operator ReadonlyEcsPool<T>(EcsPool<T> a) { return new ReadonlyEcsPool<T>(a); }
|
||||
public static implicit operator ReadonlyEcsPool<T>(IncludeMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
public static implicit operator ReadonlyEcsPool<T>(ExcludeMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
public static implicit operator ReadonlyEcsPool<T>(OptionalMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
public static implicit operator ReadonlyEcsPool<T>(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance<EcsPool<T>>(); }
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
public static class EcsPoolExtensions
|
||||
{
|
||||
|
@ -26,6 +26,13 @@ namespace DCFApixels.DragonECS.PoolsCore
|
||||
/// <typeparam name="T"> Component type. </typeparam>
|
||||
public interface IEcsPoolImplementation<T> : IEcsPoolImplementation { }
|
||||
|
||||
//TODO
|
||||
//public interface IEcsReadonlyPoolImplementation<TPool> : IEcsReadonlyPool
|
||||
// where TPool : IEcsReadonlyPoolImplementation<TPool>
|
||||
//{
|
||||
// void Init(ref TPool pool);
|
||||
//}
|
||||
|
||||
#region EcsPoolThrowHelper
|
||||
public static class EcsPoolThrowHelper
|
||||
{
|
||||
@ -74,7 +81,7 @@ namespace DCFApixels.DragonECS.Internal
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.POOLS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "A placeholder type, an instance of this type replaces the null ref.")]
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaID("460E547C9201227A4956AC297F67B484")]
|
||||
[MetaID("DragonECS_460E547C9201227A4956AC297F67B484")]
|
||||
[DebuggerDisplay("-")]
|
||||
public sealed class EcsNullPool : IEcsPoolImplementation<NullComponent>
|
||||
{
|
||||
@ -135,13 +142,13 @@ namespace DCFApixels.DragonECS.Internal
|
||||
throw new NullInstanceException();
|
||||
#endif
|
||||
}
|
||||
void IEcsReadonlyPool.Copy(int fromEntityID, int toEntityID)
|
||||
void IEcsPool.Copy(int fromEntityID, int toEntityID)
|
||||
{
|
||||
#if DEBUG
|
||||
throw new NullInstanceException();
|
||||
#endif
|
||||
}
|
||||
void IEcsReadonlyPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
void IEcsPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||
{
|
||||
#if DEBUG
|
||||
throw new NullInstanceException();
|
||||
@ -189,11 +196,10 @@ namespace DCFApixels.DragonECS
|
||||
#region Methods
|
||||
bool Has(int entityID);
|
||||
object GetRaw(int entityID);
|
||||
void Copy(int fromEntityID, int toEntityID);
|
||||
void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID);
|
||||
#endregion
|
||||
|
||||
#if !DRAGONECS_DISABLE_POOLS_EVENTS
|
||||
|
||||
#region Add/Remove Listeners
|
||||
void AddListener(IEcsPoolEventListener listener);
|
||||
void RemoveListener(IEcsPoolEventListener listener);
|
||||
@ -209,6 +215,8 @@ namespace DCFApixels.DragonECS
|
||||
void SetRaw(int entityID, object dataRaw);
|
||||
void Del(int entityID);
|
||||
void ClearAll();
|
||||
void Copy(int fromEntityID, int toEntityID);
|
||||
void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID);
|
||||
#endregion
|
||||
}
|
||||
|
||||
@ -261,6 +269,12 @@ namespace DCFApixels.DragonECS
|
||||
entityID = self.World.NewEntity();
|
||||
return ref self.Add(entityID);
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ref T NewEntityLong<T>(this IEcsStructPool<T> self, out entlong entity) where T : struct
|
||||
{
|
||||
entity = self.World.NewEntityLong();
|
||||
return ref self.Add(entity.GetIDUnchecked());
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
@ -20,8 +20,8 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.POOLS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Tag component or component without data.")]
|
||||
[MetaID("8D3E547C92013C6A2C2DFC8D2F1FA297")]
|
||||
public interface IEcsTagComponent : IEcsMember { }
|
||||
[MetaID("DragonECS_8D3E547C92013C6A2C2DFC8D2F1FA297")]
|
||||
public interface IEcsTagComponent : IEcsComponentMember { }
|
||||
|
||||
/// <summary> Pool for IEcsTagComponent components. </summary>
|
||||
#if ENABLE_IL2CPP
|
||||
@ -30,7 +30,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.POOLS_GROUP)]
|
||||
[MetaDescription(EcsConsts.AUTHOR, "Pool for IEcsTagComponent components. EcsTagPool is optimized for storing tag components or components without data.")]
|
||||
[MetaID("9D80547C9201E852E4F17324EAC1E15A")]
|
||||
[MetaID("DragonECS_9D80547C9201E852E4F17324EAC1E15A")]
|
||||
[DebuggerDisplay("Count: {Count} Type: {ComponentType}")]
|
||||
public sealed class EcsTagPool<T> : IEcsPoolImplementation<T>, IEcsStructPool<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
|
||||
where T : struct, IEcsTagComponent
|
||||
@ -104,10 +104,11 @@ namespace DCFApixels.DragonECS
|
||||
public void Add(int entityID)
|
||||
{
|
||||
#if DEBUG
|
||||
if (_source.IsUsed(entityID) == false) { Throw.Ent_ThrowIsNotAlive(_source, entityID); }
|
||||
if (Has(entityID)) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); }
|
||||
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
|
||||
#elif DRAGONECS_STABILITY_MODE
|
||||
if (Has(entityID) || _isLocked) { return; }
|
||||
if (Has(entityID) | _source.IsUsed(entityID) == false | _isLocked) { return; }
|
||||
#endif
|
||||
_count++;
|
||||
_mapping[entityID] = true;
|
||||
@ -311,12 +312,99 @@ namespace DCFApixels.DragonECS
|
||||
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
|
||||
#endregion
|
||||
|
||||
#region MarkersConverter
|
||||
#region Convertors
|
||||
public static implicit operator EcsTagPool<T>(IncludeMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
public static implicit operator EcsTagPool<T>(ExcludeMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
public static implicit operator EcsTagPool<T>(OptionalMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
public static implicit operator EcsTagPool<T>(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
#endregion
|
||||
|
||||
#region Apply
|
||||
public static void Apply(ref T component, int entityID, short worldID)
|
||||
{
|
||||
EcsWorld.GetPoolInstance<EcsTagPool<T>>(worldID).TryAdd(entityID);
|
||||
}
|
||||
public static void Apply(ref T component, int entityID, EcsTagPool<T> pool)
|
||||
{
|
||||
pool.TryAdd(entityID);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
#if ENABLE_IL2CPP
|
||||
[Il2CppSetOption(Option.NullChecks, false)]
|
||||
#endif
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public readonly struct ReadonlyEcsTagPool<T> : IEcsReadonlyPool //IEnumerable<T> - IntelliSense hack
|
||||
where T : struct, IEcsTagComponent
|
||||
{
|
||||
private readonly EcsTagPool<T> _pool;
|
||||
|
||||
#region Properties
|
||||
public int ComponentTypeID
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.ComponentTypeID; }
|
||||
}
|
||||
public Type ComponentType
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.ComponentType; }
|
||||
}
|
||||
public EcsWorld World
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.World; }
|
||||
}
|
||||
public int Count
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.Count; }
|
||||
}
|
||||
public bool IsReadOnly
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get { return _pool.IsReadOnly; }
|
||||
}
|
||||
public bool this[int entityID]
|
||||
{
|
||||
get { return _pool.Has(entityID); }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
internal ReadonlyEcsTagPool(EcsTagPool<T> pool)
|
||||
{
|
||||
_pool = pool;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Has(int entityID) { return _pool.Has(entityID); }
|
||||
object IEcsReadonlyPool.GetRaw(int entityID)
|
||||
{
|
||||
#if DEBUG
|
||||
if (Has(entityID) == false) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
|
||||
#endif
|
||||
return default;
|
||||
}
|
||||
|
||||
#if !DRAGONECS_DISABLE_POOLS_EVENTS
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void AddListener(IEcsPoolEventListener listener) { _pool.AddListener(listener); }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void RemoveListener(IEcsPoolEventListener listener) { _pool.AddListener(listener); }
|
||||
#endif
|
||||
#endregion
|
||||
|
||||
#region Convertors
|
||||
public static implicit operator ReadonlyEcsTagPool<T>(EcsTagPool<T> a) { return new ReadonlyEcsTagPool<T>(a); }
|
||||
public static implicit operator ReadonlyEcsTagPool<T>(IncludeMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
public static implicit operator ReadonlyEcsTagPool<T>(ExcludeMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
public static implicit operator ReadonlyEcsTagPool<T>(OptionalMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
public static implicit operator ReadonlyEcsTagPool<T>(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class EcsTagPoolExtensions
|
||||
|
@ -13,7 +13,7 @@ namespace DCFApixels.DragonECS
|
||||
[MetaTags(MetaTags.HIDDEN)]
|
||||
[MetaDescription(AUTHOR, "...")]
|
||||
[MetaGroup(PACK_GROUP, OTHER_GROUP)]
|
||||
[MetaID("128D547C9201EEAC49B05F89E4A253DF")]
|
||||
[MetaID("DragonECS_128D547C9201EEAC49B05F89E4A253DF")]
|
||||
[MetaColor(MetaColor.DragonRose)]
|
||||
public class EcsPipelineTemplate : IEcsModule
|
||||
{
|
||||
|
@ -118,6 +118,11 @@ namespace DCFApixels.DragonECS.Internal
|
||||
throw new InvalidOperationException($"The method {methodName} can only be executed before creating entities in the world.");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static void Ent_ThrowIsNotAlive(EcsWorld world, int entityID)
|
||||
{
|
||||
Ent_ThrowIsNotAlive((world, entityID));
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
internal static void Ent_ThrowIsNotAlive(entlong entity)
|
||||
{
|
||||
|
@ -20,6 +20,20 @@ namespace DCFApixels.DragonECS
|
||||
self.Apply(worldID, entityID);
|
||||
return (EcsWorld.GetWorld(worldID), entityID);
|
||||
}
|
||||
public static void Apply(this ITemplateNode self, EcsWorld world, int entityID)
|
||||
{
|
||||
self.Apply(world.ID, entityID);
|
||||
}
|
||||
public static int ApplyAndReturn(this ITemplateNode self, EcsWorld world, int entityID)
|
||||
{
|
||||
self.Apply(world.ID, entityID);
|
||||
return entityID;
|
||||
}
|
||||
public static entlong ApplyAndReturnLong(this ITemplateNode self, EcsWorld world, int entityID)
|
||||
{
|
||||
self.Apply(world.ID, entityID);
|
||||
return (world, entityID);
|
||||
}
|
||||
public static int NewEntity(this EcsWorld world, ITemplateNode template)
|
||||
{
|
||||
int e = world.NewEntity();
|
||||
|
@ -147,6 +147,20 @@ namespace DCFApixels.DragonECS
|
||||
return IsAlive;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Unpack(out int id)
|
||||
{
|
||||
#if DEBUG
|
||||
if (IsAlive == false) { Throw.Ent_ThrowIsNotAlive(this); }
|
||||
#elif DRAGONECS_STABILITY_MODE
|
||||
if (IsAlive == false)
|
||||
{
|
||||
id = EcsConsts.NULL_ENTITY_ID;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
id = _id;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Unpack(out int id, out EcsWorld world)
|
||||
{
|
||||
@ -216,6 +230,12 @@ namespace DCFApixels.DragonECS
|
||||
id = _id;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryUnpack(out int id)
|
||||
{
|
||||
id = _id;
|
||||
return IsAlive;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryUnpack(out int id, out EcsWorld world)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user