diff --git a/DragonECS.csproj b/DragonECS.csproj
index f0b44cf..41358e5 100644
--- a/DragonECS.csproj
+++ b/DragonECS.csproj
@@ -10,7 +10,7 @@
DCFApixels.DragonECS
DragonECS
- 0.9.1
+ 0.9.9
DCFApixels
ECS Framework for Game Engines with C# and .Net Platform
DCFApixels
diff --git a/package.json b/package.json
index ace3df9..fcffa56 100644
--- a/package.json
+++ b/package.json
@@ -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"
diff --git a/src/Builtin/BaseProcesses.cs b/src/Builtin/BaseProcesses.cs
index e1cfd1c..52344b5 100644
--- a/src/Builtin/BaseProcesses.cs
+++ b/src/Builtin/BaseProcesses.cs
@@ -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
{
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
{
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
{
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
{
private RunHelper _helper;
diff --git a/src/Builtin/Worlds.cs b/src/Builtin/Worlds.cs
index e7697be..75e5e4d 100644
--- a/src/Builtin/Worlds.cs
+++ b/src/Builtin/Worlds.cs
@@ -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); }
}
/// EcsWrold for store event entities.
@@ -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); }
}
}
diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs
index 7334897..5d70cfe 100644
--- a/src/Collections/EcsGroup.cs
+++ b/src/Collections/EcsGroup.cs
@@ -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)
diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs
index 58bc198..48c26c4 100644
--- a/src/Collections/EcsSpan.cs
+++ b/src/Collections/EcsSpan.cs
@@ -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)
diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs
index c2ce421..3a46db5 100644
--- a/src/DataInterfaces.cs
+++ b/src/DataInterfaces.cs
@@ -3,7 +3,7 @@
#endif
using System.Runtime.CompilerServices;
-namespace DCFApixels.DragonECS
+namespace DCFApixels.DragonECS.Core
{
#region IEcsWorldComponent
public interface IEcsWorldComponent
@@ -44,11 +44,11 @@ namespace DCFApixels.DragonECS
void Enable(ref T component);
void Disable(ref T component);
}
- public static class EcsComponentResetHandler
+ public static class EcsComponentLifecycleHandler
{
public static readonly IEcsComponentLifecycle instance;
public static readonly bool isHasHandler;
- static EcsComponentResetHandler()
+ static EcsComponentLifecycleHandler()
{
T def = default;
if (def is IEcsComponentLifecycle intrf)
diff --git a/src/DebugUtils/EcsDebug.cs b/src/DebugUtils/EcsDebug.cs
index 3eac63d..0f5608e 100644
--- a/src/DebugUtils/EcsDebug.cs
+++ b/src/DebugUtils/EcsDebug.cs
@@ -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().")]
- [MetaID("10A4587C92013B55820D8604D718A1C3")]
+ [MetaID("DragonECS_10A4587C92013B55820D8604D718A1C3")]
public static class EcsDebug
{
+ #region Set
public static void Set() where T : DebugService, new()
{
DebugService.Set();
@@ -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 _threadServiceClonesSet = new HashSet();
+ private readonly static HashSet _threadServiceClonesSet = new HashSet();
[ThreadStatic]
private static DebugService _currentThreadInstanceClone;
[ThreadStatic]
private static DebugService _currentThreadInstance; // для сравнения
- private static IdDispenser _idDispenser = new IdDispenser(16, 0);
- private static Dictionary _nameIdTable = new Dictionary();
+ private readonly static IdDispenser _idDispenser = new IdDispenser(16, 0);
+ private readonly static Dictionary _nameIdTable = new Dictionary();
#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
}
\ No newline at end of file
diff --git a/src/DebugUtils/EcsDebugUtility.cs b/src/DebugUtils/EcsDebugUtility.cs
index 9d9e3ed..f7303dd 100644
--- a/src/DebugUtils/EcsDebugUtility.cs
+++ b/src/DebugUtils/EcsDebugUtility.cs
@@ -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)
diff --git a/src/DebugUtils/MetaAttributes/MetaDescriptionAttribute.cs b/src/DebugUtils/MetaAttributes/MetaDescriptionAttribute.cs
index 4119212..6b5352a 100644
--- a/src/DebugUtils/MetaAttributes/MetaDescriptionAttribute.cs
+++ b/src/DebugUtils/MetaAttributes/MetaDescriptionAttribute.cs
@@ -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; }
diff --git a/src/DebugUtils/MetaAttributes/MetaGroupAttribute.cs b/src/DebugUtils/MetaAttributes/MetaGroupAttribute.cs
index f2545d7..832c3da 100644
--- a/src/DebugUtils/MetaAttributes/MetaGroupAttribute.cs
+++ b/src/DebugUtils/MetaAttributes/MetaGroupAttribute.cs
@@ -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 = "";
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 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))
diff --git a/src/DebugUtils/MetaAttributes/MetaIDAttribute.cs b/src/DebugUtils/MetaAttributes/MetaIDAttribute.cs
index 55f4b71..c42f9bf 100644
--- a/src/DebugUtils/MetaAttributes/MetaIDAttribute.cs
+++ b/src/DebugUtils/MetaAttributes/MetaIDAttribute.cs
@@ -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 x = new Span(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.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 metas, out CollisionList collisions)
+ {
+ collisions = new CollisionList(metas);
+ return collisions.IsHasAnyCollision;
+ }
+ public static CollisionList FindMetaIDCollisions(IEnumerable metas)
+ {
+ return new CollisionList(metas);
+ }
+
+ #region CollisionList
+ [DebuggerTypeProxy(typeof(DebuggerProxy))]
+ [DebuggerDisplay("HasAnyCollision: {IsHasAnyCollision} ListsCount: {Count}")]
+ public class CollisionList : IEnumerable
+ {
+ private LinkedList[] _linkedLists;
+ private Entry[] _entries;
+ private int _collisionsCount;
+ private int _listsCount;
+ private HashSet _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 metas)
+ {
+ var metasCount = metas.Count();
+ Dictionary listIndexes = new Dictionary(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();
+ 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 IEnumerable.GetEnumerator() { return GetEnumerator(); }
+ public struct Enumerator : IEnumerator
+ {
+ 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
+ {
+ 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 IEnumerable.GetEnumerator() { return GetEnumerator(); }
+ public struct Enumerator : IEnumerator
+ {
+ 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
}
}
\ No newline at end of file
diff --git a/src/DebugUtils/TypeMeta.cs b/src/DebugUtils/TypeMeta.cs
index 1a822ba..8eceb19 100644
--- a/src/DebugUtils/TypeMeta.cs
+++ b/src/DebugUtils/TypeMeta.cs
@@ -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 _metaCache = new Dictionary();
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(),
_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();
+ 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 _idTypePairs = new Dictionary();
-#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
}
diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs
index 1f56e26..c1dc6e1 100644
--- a/src/EcsAspect.cs
+++ b/src/EcsAspect.cs
@@ -125,7 +125,7 @@ namespace DCFApixels.DragonECS
#endregion
//Инициализация аспектов проходит в синхронизированном состоянии, поэтому использование _staticMaskCache потоко безопасно.
- private static Dictionary _staticMaskCache = new Dictionary();
+ private readonly static Dictionary _staticMaskCache = new Dictionary();
internal EcsWorld _source;
internal EcsMask _mask;
@@ -272,13 +272,13 @@ namespace DCFApixels.DragonECS
public TPool IncludePool() where TPool : IEcsPoolImplementation, new()
{
var pool = CachePool();
- IncludeImplicit(pool.ComponentType);
+ SetMaskInclude(pool.ComponentType);
return pool;
}
public TPool ExcludePool() where TPool : IEcsPoolImplementation, new()
{
var pool = CachePool();
- ExcludeImplicit(pool.ComponentType);
+ SetMaskExclude(pool.ComponentType);
return pool;
}
public TPool OptionalPool() where TPool : IEcsPoolImplementation, new()
@@ -291,14 +291,14 @@ namespace DCFApixels.DragonECS
var pool = _world.GetPoolInstance();
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();
ExcludePool();
OptionalPool();
- IncludeImplicit(null);
- ExcludeImplicit(null);
+ SetMaskInclude(null);
+ SetMaskExclude(null);
}
#endregion
}
diff --git a/src/EcsMask.cs b/src/EcsMask.cs
index d6b843b..56c42b3 100644
--- a/src/EcsMask.cs
+++ b/src/EcsMask.cs
@@ -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 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 input, UnsafeArray output)
+ internal static void ConvertToChuncks(EcsMaskChunck* bufferPtr, UnsafeArray input, UnsafeArray 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++;
}
}
diff --git a/src/EcsPipeline.Builder.cs b/src/EcsPipeline.Builder.cs
index d66f6d3..f81533b 100644
--- a/src/EcsPipeline.Builder.cs
+++ b/src/EcsPipeline.Builder.cs
@@ -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(_systemNodes, _systemNodesCount, _startIndex);
+ var it = new LinkedListCountIterator(_systemNodes, _systemNodesCount, _startIndex);
EcsPipelineTemplate result = new EcsPipelineTemplate();
result.layers = new string[Layers.Count];
result.records = new EcsPipelineTemplate.Record[it.Count];
diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs
index 6ad2331..0bebeec 100644
--- a/src/EcsPipeline.cs
+++ b/src/EcsPipeline.cs
@@ -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() 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;
diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs
index 1b457ae..227a53a 100644
--- a/src/EcsRunner.cs
+++ b/src/EcsRunner.cs
@@ -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 : 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
{
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index c0674d8..71cf329 100644
--- a/src/EcsWorld.cs
+++ b/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();
private int _delEntBufferCount = 0;
+ private int[] _emptyEntities = Array.Empty();
+ 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>().Instance;
}
+ public void GetAspects(out TAspect0 a0)
+ where TAspect0 : new()
+ {
+ a0 = GetAspect();
+ }
+ public void GetAspects(out TAspect0 a0, out TAspect1 a1)
+ where TAspect0 : new()
+ where TAspect1 : new()
+ {
+ a0 = GetAspect();
+ a1 = GetAspect();
+ }
+ public void GetAspects(out TAspect0 a0, out TAspect1 a1, out TAspect2 a2)
+ where TAspect0 : new()
+ where TAspect1 : new()
+ where TAspect2 : new()
+ {
+ a0 = GetAspect();
+ a1 = GetAspect();
+ a2 = GetAspect();
+ }
+ public void GetAspects(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();
+ a1 = GetAspect();
+ a2 = GetAspect();
+ a3 = GetAspect();
+ }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TAspect GetAspect(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,20 +531,60 @@ 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++)
+ {
+ 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, iMax = mask._excs.Length; i < iMax; i++)
+ for (int i = 0; i < excChuncks.Length; i++)
{
- if (_pools[mask._excs[i]].Has(entityID))
+ 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
@@ -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