From 29dc82568542a5e05bdbd10fe994da5064218bac Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Sun, 25 Jun 2023 23:13:51 +0800
Subject: [PATCH 001/104] simple refactoring
---
src/EcsAspect.cs | 6 +++---
src/Pools/EcsPool.cs | 23 +++++++++--------------
src/Pools/EcsPoolBase.cs | 7 ++++++-
src/Pools/EcsTagPool.cs | 18 ++++++++----------
src/entlong.cs | 2 +-
5 files changed, 27 insertions(+), 29 deletions(-)
diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs
index 3c47c0b..6a6a2fc 100644
--- a/src/EcsAspect.cs
+++ b/src/EcsAspect.cs
@@ -179,10 +179,10 @@ namespace DCFApixels.DragonECS
}
#endregion
- private struct Combined
+ private readonly struct Combined
{
- public EcsAspect aspect;
- public int order;
+ public readonly EcsAspect aspect;
+ public readonly int order;
public Combined(EcsAspect aspect, int order)
{
this.aspect = aspect;
diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs
index cc1cb6d..131b2ff 100644
--- a/src/Pools/EcsPool.cs
+++ b/src/Pools/EcsPool.cs
@@ -7,11 +7,11 @@ using static DCFApixels.DragonECS.EcsPoolThrowHalper;
namespace DCFApixels.DragonECS
{
/// Pool for IEcsComponent components
- public sealed class EcsPool : IEcsPoolImplementation, IEcsStructsPool, IEnumerable //IEnumerable - IntelliSense hack
+ public sealed class EcsPool : IEcsPoolImplementation, IEcsStructPool, IEnumerable //IEnumerable - IntelliSense hack
where T : struct, IEcsComponent
{
private EcsWorld _source;
- private int _id;
+ private int _componentID;
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
private T[] _items; //dense
@@ -19,15 +19,15 @@ namespace DCFApixels.DragonECS
private int[] _recycledItems;
private int _recycledItemsCount;
- private IEcsComponentReset _componentResetHandler;
- private IEcsComponentCopy _componentCopyHandler;
+ private IEcsComponentReset _componentResetHandler = EcsComponentResetHandler.instance;
+ private IEcsComponentCopy _componentCopyHandler = EcsComponentCopyHandler.instance;
- private List _listeners;
+ private List _listeners = new List();
#region Properites
public int Count => _itemsCount;
public int Capacity => _items.Length;
- public int ComponentID => _id;
+ public int ComponentID => _componentID;
public Type ComponentType => typeof(T);
public EcsWorld World => _source;
#endregion
@@ -36,7 +36,7 @@ namespace DCFApixels.DragonECS
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
- _id = componentID;
+ _componentID = componentID;
const int capacity = 512;
@@ -45,11 +45,6 @@ namespace DCFApixels.DragonECS
_recycledItemsCount = 0;
_items = new T[capacity];
_itemsCount = 0;
-
- _listeners = new List();
-
- _componentResetHandler = EcsComponentResetHandler.instance;
- _componentCopyHandler = EcsComponentCopyHandler.instance;
}
#endregion
@@ -171,8 +166,8 @@ namespace DCFApixels.DragonECS
void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID) = (T)dataRaw;
object IEcsPool.GetRaw(int entityID) => Read(entityID);
void IEcsPool.SetRaw(int entityID, object dataRaw) => Get(entityID) = (T)dataRaw;
- ref readonly T IEcsStructsPool.Read(int entityID) => ref Read(entityID);
- ref T IEcsStructsPool.Get(int entityID) => ref Get(entityID);
+ ref readonly T IEcsStructPool.Read(int entityID) => ref Read(entityID);
+ ref T IEcsStructPool.Get(int entityID) => ref Get(entityID);
#endregion
#region Listeners
diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs
index bb4d4cd..f07681f 100644
--- a/src/Pools/EcsPoolBase.cs
+++ b/src/Pools/EcsPoolBase.cs
@@ -30,12 +30,17 @@ namespace DCFApixels.DragonECS
void RemoveListener(IEcsPoolEventListener listener);
#endregion
}
- public interface IEcsStructsPool
+ public interface IEcsStructPool : IEcsPool
{
ref T Add(int entityID);
ref readonly T Read(int entityID);
ref T Get(int entityID);
}
+ public interface IEcsClassPool : IEcsPool
+ {
+ T Add(int entityID);
+ T Get(int entityID);
+ }
/// Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool.
public interface IEcsPoolImplementation : IEcsPool
{
diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs
index 01c958f..a435a19 100644
--- a/src/Pools/EcsTagPool.cs
+++ b/src/Pools/EcsTagPool.cs
@@ -6,23 +6,23 @@ using static DCFApixels.DragonECS.EcsPoolThrowHalper;
namespace DCFApixels.DragonECS
{
- public sealed class EcsTagPool : IEcsPoolImplementation, IEcsStructsPool, IEnumerable //IEnumerable - IntelliSense hack
+ public sealed class EcsTagPool : IEcsPoolImplementation, IEcsStructPool, IEnumerable //IEnumerable - IntelliSense hack
where T : struct, IEcsTagComponent
{
private EcsWorld _source;
- private int _id;
+ private int _componentID;
private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
private int _count;
- private List _listeners;
+ private List _listeners = new List();
private T _fakeComponent;
#region Properites
public int Count => _count;
int IEcsPool.Capacity => -1;
- public int ComponentID => _id;
+ public int ComponentID => _componentID;
public Type ComponentType => typeof(T);
public EcsWorld World => _source;
#endregion
@@ -31,12 +31,10 @@ namespace DCFApixels.DragonECS
void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID)
{
_source = world;
- _id = componentID;
+ _componentID = componentID;
_mapping = new bool[world.Capacity];
_count = 0;
-
- _listeners = new List();
}
#endregion
@@ -131,19 +129,19 @@ namespace DCFApixels.DragonECS
#endregion
#region Other
- ref T IEcsStructsPool.Add(int entityID)
+ ref T IEcsStructPool.Add(int entityID)
{
Add(entityID);
return ref _fakeComponent;
}
- ref readonly T IEcsStructsPool.Read(int entityID)
+ ref readonly T IEcsStructPool.Read(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) ThrowNotHaveComponent(entityID);
#endif
return ref _fakeComponent;
}
- ref T IEcsStructsPool.Get(int entityID)
+ ref T IEcsStructPool.Get(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) ThrowNotHaveComponent(entityID);
diff --git a/src/entlong.cs b/src/entlong.cs
index 904db21..2a4430a 100644
--- a/src/entlong.cs
+++ b/src/entlong.cs
@@ -33,7 +33,7 @@ namespace DCFApixels.DragonECS
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => this == NULL;
+ get => full == 0l;
}
public int ID
{
From 4b7649e80c00bdb19f4d94fe1c7367f1fe04f25c Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Sun, 25 Jun 2023 23:22:01 +0800
Subject: [PATCH 002/104] split EcsWorld
---
src/EcsWorld.cs | 92 ---------------------------------
src/EcsWorld.static.cs | 100 ++++++++++++++++++++++++++++++++++++
src/EcsWorld.static.cs.meta | 11 ++++
3 files changed, 111 insertions(+), 92 deletions(-)
create mode 100644 src/EcsWorld.static.cs
create mode 100644 src/EcsWorld.static.cs.meta
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 4d3b758..7ab71dc 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -3,101 +3,9 @@ using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS
{
- [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 4)]
- public struct EcsWorldCmp where T : struct
- {
- private int _worldID;
- public EcsWorldCmp(int worldID) => _worldID = worldID;
- public EcsWorld World => EcsWorld.GetWorld(_worldID);
- public ref T Value => ref EcsWorld.GetData(_worldID);
- }
- public abstract partial class EcsWorld
- {
- private const short GEN_BITS = 0x7fff;
- private const short DEATH_GEN_BIT = short.MinValue;
- private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2;
-
- private static EcsWorld[] Worlds = new EcsWorld[4];
- private static IntDispenser _worldIdDispenser = new IntDispenser(0);
-
- private static List _dataReleaseres = new List();
-
- static EcsWorld()
- {
- Worlds[0] = new EcsNullWorld();
- }
- private static void ReleaseData(int worldID)
- {
- for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++)
- _dataReleaseres[i].Release(worldID);
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static EcsWorld GetWorld(int worldID) => Worlds[worldID];
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref T GetData(int worldID) => ref WorldComponentPool.GetForWorld(worldID);
-
- private abstract class DataReleaser
- {
- public abstract void Release(int worldID);
- }
- private static class WorldComponentPool
- {
- private static T[] _items = new T[4];
- private static int[] _mapping = new int[4];
- private static int _count;
- private static int[] _recycledItems = new int[4];
- private static int _recycledItemsCount;
- private static IEcsWorldComponent _interface = EcsWorldComponentHandler.instance;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref T Get(int itemIndex) => ref _items[itemIndex];
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ref T GetForWorld(int worldID) => ref _items[GetItemIndex(worldID)];
- public static int GetItemIndex(int worldID)
- {
- if (_mapping.Length < Worlds.Length)
- Array.Resize(ref _mapping, Worlds.Length);
-
- ref int itemIndex = ref _mapping[worldID];
- if (itemIndex <= 0)
- {
- if (_recycledItemsCount > 0)
- {
- _count++;
- itemIndex = _recycledItems[--_recycledItemsCount];
- }
- else
- {
- itemIndex = ++_count;
- }
- _interface.Init(ref _items[itemIndex], Worlds[worldID]);
- _dataReleaseres.Add(new Releaser());
- }
- return itemIndex;
- }
- private static void Release(int worldID)
- {
- ref int itemIndex = ref _mapping[worldID];
- if (itemIndex != 0)
- {
- _interface.OnDestroy(ref _items[itemIndex], Worlds[worldID]);
- _recycledItems[_recycledItemsCount++] = itemIndex;
- }
- }
- private sealed class Releaser : DataReleaser
- {
- public sealed override void Release(int worldID)
- {
- WorldComponentPool.Release(worldID);
- }
- }
- }
- }
public abstract partial class EcsWorld
{
public readonly short id;
diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs
new file mode 100644
index 0000000..d5e69af
--- /dev/null
+++ b/src/EcsWorld.static.cs
@@ -0,0 +1,100 @@
+using DCFApixels.DragonECS.Utils;
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace DCFApixels.DragonECS
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 4)]
+ public struct EcsWorldCmp where T : struct
+ {
+ private int _worldID;
+ public EcsWorldCmp(int worldID) => _worldID = worldID;
+ public EcsWorld World => EcsWorld.GetWorld(_worldID);
+ public ref T Value => ref EcsWorld.GetData(_worldID);
+ }
+ public abstract partial class EcsWorld
+ {
+ private const short GEN_BITS = 0x7fff;
+ private const short DEATH_GEN_BIT = short.MinValue;
+ private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2;
+
+ private static EcsWorld[] Worlds = new EcsWorld[4];
+ private static IntDispenser _worldIdDispenser = new IntDispenser(0);
+
+ private static List _dataReleaseres = new List();
+
+ static EcsWorld()
+ {
+ Worlds[0] = new EcsNullWorld();
+ }
+ private static void ReleaseData(int worldID)
+ {
+ for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++)
+ _dataReleaseres[i].Release(worldID);
+ }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static EcsWorld GetWorld(int worldID) => Worlds[worldID];
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetData(int worldID) => ref WorldComponentPool.GetForWorld(worldID);
+
+ private abstract class DataReleaser
+ {
+ public abstract void Release(int worldID);
+ }
+ private static class WorldComponentPool
+ {
+ private static T[] _items = new T[4];
+ private static int[] _mapping = new int[4];
+ private static int _count;
+ private static int[] _recycledItems = new int[4];
+ private static int _recycledItemsCount;
+ private static IEcsWorldComponent _interface = EcsWorldComponentHandler.instance;
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T Get(int itemIndex) => ref _items[itemIndex];
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ref T GetForWorld(int worldID) => ref _items[GetItemIndex(worldID)];
+ public static int GetItemIndex(int worldID)
+ {
+ if (_mapping.Length < Worlds.Length)
+ Array.Resize(ref _mapping, Worlds.Length);
+
+ ref int itemIndex = ref _mapping[worldID];
+ if (itemIndex <= 0)
+ {
+ if (_recycledItemsCount > 0)
+ {
+ _count++;
+ itemIndex = _recycledItems[--_recycledItemsCount];
+ }
+ else
+ {
+ itemIndex = ++_count;
+ }
+ _interface.Init(ref _items[itemIndex], Worlds[worldID]);
+ _dataReleaseres.Add(new Releaser());
+ }
+ return itemIndex;
+ }
+ private static void Release(int worldID)
+ {
+ ref int itemIndex = ref _mapping[worldID];
+ if (itemIndex != 0)
+ {
+ _interface.OnDestroy(ref _items[itemIndex], Worlds[worldID]);
+ _recycledItems[_recycledItemsCount++] = itemIndex;
+ }
+ }
+ private sealed class Releaser : DataReleaser
+ {
+ public sealed override void Release(int worldID)
+ {
+ WorldComponentPool.Release(worldID);
+ }
+ }
+ }
+ }
+}
diff --git a/src/EcsWorld.static.cs.meta b/src/EcsWorld.static.cs.meta
new file mode 100644
index 0000000..d99ff4b
--- /dev/null
+++ b/src/EcsWorld.static.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 30c8fd4d7c5aeae4486e16024b4f50cc
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
From f07a489d96e88d9ef03292984d4d92da5cb00758 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Mon, 26 Jun 2023 01:57:50 +0800
Subject: [PATCH 003/104] update exceptions
---
src/Builtin/InjectSystem.cs | 10 ++--
src/EcsAspect.cs | 15 ++----
src/EcsGroup.cs | 44 +++++------------
src/EcsPipeline.cs | 29 ++---------
src/EcsRunner.cs | 3 +-
src/EcsWorld.cs | 8 ++--
src/EcsWorld.static.cs | 1 +
src/Utils/Exceptions.cs | 96 +++++++++++++++++++++++++++++++++++++
src/entlong.cs | 26 +++-------
9 files changed, 132 insertions(+), 100 deletions(-)
diff --git a/src/Builtin/InjectSystem.cs b/src/Builtin/InjectSystem.cs
index e618f57..03c6a7c 100644
--- a/src/Builtin/InjectSystem.cs
+++ b/src/Builtin/InjectSystem.cs
@@ -2,7 +2,7 @@
using DCFApixels.DragonECS.RunnersCore;
using System;
using System.Linq;
-using System.Runtime.CompilerServices;
+using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
@@ -59,12 +59,10 @@ namespace DCFApixels.DragonECS
private EcsBaseTypeInjectRunner _baseTypeInjectRunner;
void IEcsInject.Inject(T obj)
{
- if (obj == null) ThrowArgumentNullException();
+ if (obj == null) Throw.ArgumentNull();
_baseTypeInjectRunner.Inject(obj);
foreach (var item in targets) item.Inject(obj);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void ThrowArgumentNullException() => throw new ArgumentNullException();
protected override void OnSetup()
{
Type baseType = typeof(T).BaseType;
@@ -112,7 +110,7 @@ namespace DCFApixels.DragonECS
void IEcsInject.Inject(PreInitInjectController obj) => _injectController = obj;
public InjectSystem(T injectedData)
{
- if (injectedData == null) throw new ArgumentNullException();
+ if (injectedData == null) Throw.ArgumentNull();
_injectedData = injectedData;
}
public void PreInit(EcsPipeline pipeline)
@@ -149,7 +147,7 @@ namespace DCFApixels.DragonECS
{
public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T data)
{
- if (data == null) throw new ArgumentNullException();
+ if (data == null) Throw.ArgumentNull();
return self.Add(new InjectSystem(data));
}
public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b)
diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs
index 6a6a2fc..0ff7038 100644
--- a/src/EcsAspect.cs
+++ b/src/EcsAspect.cs
@@ -6,14 +6,13 @@ using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
+using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
public abstract class EcsAspect
{
- [EditorBrowsable(EditorBrowsableState.Always)]
internal EcsWorld source;
- [EditorBrowsable(EditorBrowsableState.Always)]
internal EcsMask mask;
private bool _isInit;
@@ -85,7 +84,7 @@ namespace DCFApixels.DragonECS
{
int id = _world.GetComponentID(type);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_inc.Contains(id) || _exc.Contains(id)) throw new EcsFrameworkException($"{type.Name} already in constraints list.");
+ if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
#endif
_inc.Add(id);
}
@@ -93,7 +92,7 @@ namespace DCFApixels.DragonECS
{
int id = _world.GetComponentID(type);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_inc.Contains(id) || _exc.Contains(id)) throw new EcsFrameworkException($"{type.Name} already in constraints list.");
+ if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
#endif
_exc.Add(id);
}
@@ -279,14 +278,6 @@ namespace DCFApixels.DragonECS
public override string ToString() => CreateLogString(worldTypeID, included, excluded);
}
#endregion
-
- #region ThrowHelper
- internal static class ThrowHelper
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowArgumentDifferentWorldsException() => throw new ArgumentException("The groups belong to different worlds.");
- }
- #endregion
}
#endregion
diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs
index 7ec7c8c..5886d20 100644
--- a/src/EcsGroup.cs
+++ b/src/EcsGroup.cs
@@ -6,7 +6,7 @@ using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
-using static DCFApixels.DragonECS.EcsGroup.ThrowHelper;
+using static DCFApixels.DragonECS.EcsThrowHalper;
#endif
namespace DCFApixels.DragonECS
@@ -151,7 +151,7 @@ namespace DCFApixels.DragonECS
get
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (index < 0 || index >= Count) ThrowArgumentOutOfRange();
+ if (index < 0 || index >= Count) Throw.ArgumentOutOfRange();
#endif
return _dense[++index];
}
@@ -200,7 +200,7 @@ namespace DCFApixels.DragonECS
internal void AddInternal(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (Has(entityID)) ThrowAlreadyContains(entityID);
+ if (Has(entityID)) Throw.Group_AlreadyContains(entityID);
#endif
if (++_count >= _dense.Length)
Array.Resize(ref _dense, _dense.Length << 1);
@@ -218,7 +218,7 @@ namespace DCFApixels.DragonECS
internal void RemoveInternal(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowDoesNotContain(entityID);
+ if (!Has(entityID)) Throw.Group_DoesNotContain(entityID);
#endif
_dense[_sparse[entityID]] = _dense[_count];
_sparse[_dense[_count--]] = _sparse[entityID];
@@ -287,7 +287,7 @@ namespace DCFApixels.DragonECS
public ReadOnlySpan ToSpan(int start, int length)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (start + length > _count) ThrowArgumentOutOfRangeException();
+ if (start + length > _count) Throw.ArgumentOutOfRange();
#endif
return new ReadOnlySpan(_dense, start, length);
}
@@ -301,7 +301,7 @@ namespace DCFApixels.DragonECS
public void UnionWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_source != group.World) ThrowArgumentDifferentWorldsException();
+ if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
foreach (var item in group)
if (!Has(item))
@@ -315,7 +315,7 @@ namespace DCFApixels.DragonECS
public void ExceptWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_source != group.World) ThrowArgumentDifferentWorldsException();
+ if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
foreach (var item in this)
if (group.Has(item))
@@ -329,7 +329,7 @@ namespace DCFApixels.DragonECS
public void IntersectWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (World != group.World) ThrowArgumentDifferentWorldsException();
+ if (World != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
foreach (var item in this)
if (!group.Has(item))
@@ -343,7 +343,7 @@ namespace DCFApixels.DragonECS
public void SymmetricExceptWith(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_source != group.World) ThrowArgumentDifferentWorldsException();
+ if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
#endif
foreach (var item in group)
if (Has(item))
@@ -367,7 +367,7 @@ namespace DCFApixels.DragonECS
public static EcsGroup Union(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (a._source != b._source) ThrowArgumentDifferentWorldsException();
+ if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
#endif
EcsGroup result = a._source.GetFreeGroup();
foreach (var item in a)
@@ -381,7 +381,7 @@ namespace DCFApixels.DragonECS
public static EcsGroup Except(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (a._source != b._source) ThrowArgumentDifferentWorldsException();
+ if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
#endif
EcsGroup result = a._source.GetFreeGroup();
foreach (var item in a)
@@ -394,7 +394,7 @@ namespace DCFApixels.DragonECS
public static EcsGroup Intersect(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (a._source != b._source) ThrowArgumentDifferentWorldsException();
+ if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
#endif
EcsGroup result = a._source.GetFreeGroup();
foreach (var item in a)
@@ -408,7 +408,7 @@ namespace DCFApixels.DragonECS
public static EcsGroup SymmetricExcept(EcsGroup a, EcsGroup b)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (a._source != b._source) ThrowArgumentDifferentWorldsException();
+ if (a._source != b._source) Throw.Group_ArgumentDifferentWorldsException();
#endif
EcsGroup result = a._source.GetFreeGroup();
foreach (var item in a)
@@ -519,24 +519,6 @@ namespace DCFApixels.DragonECS
}
#endregion
- #region ThrowHalper
-#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- internal static class ThrowHelper
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowAlreadyContains(int entityID) => throw new EcsFrameworkException($"This group already contains entity {entityID}.");
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowArgumentOutOfRange() => throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count.");
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowDoesNotContain(int entityID) => throw new EcsFrameworkException($"This group does not contain entity {entityID}.");
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException();
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowArgumentDifferentWorldsException() => throw new ArgumentException("The groups belong to different worlds.");
- }
-#endif
- #endregion
-
#region DebuggerProxy
internal class DebuggerProxy
{
diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs
index 5f915df..a06e1c5 100644
--- a/src/EcsPipeline.cs
+++ b/src/EcsPipeline.cs
@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
+using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
@@ -86,19 +87,19 @@ namespace DCFApixels.DragonECS
public void Run()
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- CheckBeforeInitForMethod(nameof(Run));
- CheckAfterDestroyForMethod(nameof(Run));
+ if (_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run));
+ if (_isDestoryed) Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run));
#endif
_runRunnerCache.Run(this);
}
public void Destroy()
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- CheckBeforeInitForMethod(nameof(Run));
+ if (_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy));
#endif
if (_isDestoryed == true)
{
- EcsDebug.Print("[Warning]", $"This {nameof(EcsPipeline)} has already been destroyed");
+ EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been destroyed");
return;
}
_isDestoryed = true;
@@ -106,26 +107,6 @@ namespace DCFApixels.DragonECS
}
#endregion
- #region StateChecks
-#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- private void CheckBeforeInitForMethod(string methodName)
- {
- if (!_isInit)
- throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}");
- }
- private void CheckAfterInitForMethod(string methodName)
- {
- if (_isInit)
- throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}");
- }
- private void CheckAfterDestroyForMethod(string methodName)
- {
- if (_isDestoryed)
- throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}");
- }
-#endif
- #endregion
-
#region Builder
public static Builder New() => new Builder();
public class Builder
diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs
index a86185a..7e30725 100644
--- a/src/EcsRunner.cs
+++ b/src/EcsRunner.cs
@@ -73,8 +73,7 @@ namespace DCFApixels.DragonECS
}
if (delayedExceptions.Count > 0)
{
- foreach (var item in delayedExceptions) EcsDebug.Print(EcsConsts.DEBUG_ERROR_TAG, item.Message);
- throw delayedExceptions[0];
+ throw new AggregateException(delayedExceptions);
}
}
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 7ab71dc..e062288 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -3,6 +3,7 @@ using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
@@ -301,7 +302,7 @@ namespace DCFApixels.DragonECS
var count = --_componentCounts[entityID];
if (count == 0 && _allEntites.Has(entityID)) DelEntity(entityID);
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
- if (count < 0) throw new EcsFrameworkException("нарушен баланс инкремента/декремента компонентов");
+ if (count < 0) Throw.World_InvalidIncrementComponentsBalance();
#endif
}
#endregion
@@ -322,8 +323,7 @@ namespace DCFApixels.DragonECS
internal void ReleaseGroup(EcsGroup group)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
- if (group.World != this)
- throw new ArgumentException("groupFilter.WorldIndex != this");
+ if (group.World != this) Throw.World_GroupDoesNotBelongWorld();
#endif
group._isReleased = true;
group.Clear();
@@ -365,8 +365,6 @@ namespace DCFApixels.DragonECS
#endregion
}
- internal sealed class EcsNullWorld : EcsWorld { }
-
#region Callbacks Interface
public interface IEcsWorldEventListener
{
diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs
index d5e69af..cf61e9f 100644
--- a/src/EcsWorld.static.cs
+++ b/src/EcsWorld.static.cs
@@ -97,4 +97,5 @@ namespace DCFApixels.DragonECS
}
}
}
+ internal sealed class EcsNullWorld : EcsWorld { }
}
diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs
index a965542..7cd999d 100644
--- a/src/Utils/Exceptions.cs
+++ b/src/Utils/Exceptions.cs
@@ -1,8 +1,104 @@
using System;
+using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
namespace DCFApixels.DragonECS
{
+ public class EcsThrowHalper
+ {
+ public static readonly EcsThrowHalper Throw = new EcsThrowHalper();
+ private EcsThrowHalper() { }
+ }
+
+ public static class EcsThrowHalper_Core
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void Pool_AlreadyHasComponent(this EcsThrowHalper _, int entityID)
+ {
+ throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName()}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void Pool_NotHaveComponent(this EcsThrowHalper _, int entityID)
+ {
+ throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName()}.");
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ArgumentNull(this EcsThrowHalper _)
+ {
+ throw new ArgumentNullException();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ConstraintIsAlreadyContainedInMask(this EcsThrowHalper _, Type type)
+ {
+ throw new EcsFrameworkException($"The {EcsDebugUtility.GetGenericTypeName(type)} constraint is already contained in the mask.");
+ }
+
+ //[MethodImpl(MethodImplOptions.NoInlining)]
+ //public static void ArgumentDifferentWorldsException()
+ //{
+ // throw new ArgumentException("The groups belong to different worlds.");
+ //}
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ArgumentOutOfRange(this EcsThrowHalper _)
+ {
+ throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count.");
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Group_AlreadyContains(this EcsThrowHalper _, int entityID)
+ {
+ throw new EcsFrameworkException($"This group already contains entity {entityID}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Group_DoesNotContain(this EcsThrowHalper _, int entityID)
+ {
+ throw new EcsFrameworkException($"This group does not contain entity {entityID}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Group_ArgumentDifferentWorldsException(this EcsThrowHalper _)
+ {
+ throw new ArgumentException("The groups belong to different worlds.");
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Pipeline_MethodCalledAfterInitialisation(this EcsThrowHalper _, string methodName)
+ {
+ throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Pipeline_MethodCalledBeforeInitialisation(this EcsThrowHalper _, string methodName)
+ {
+ throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Pipeline_MethodCalledAfterDestruction(this EcsThrowHalper _, string methodName)
+ {
+ throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}.");
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void World_InvalidIncrementComponentsBalance(this EcsThrowHalper _)
+ {
+ throw new MethodAccessException("Invalid increment components balance.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void World_GroupDoesNotBelongWorld(this EcsThrowHalper _)
+ {
+ throw new MethodAccessException("The Group does not belong in this world.");
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Ent_ThrowIsNotAlive(this EcsThrowHalper _, entlong entity)
+ {
+ if (entity.IsNull)
+ throw new EcsFrameworkException($"The {entity} is null.");
+ else
+ throw new EcsFrameworkException($"The {entity} is not alive.");
+ }
+ }
+
[Serializable]
public class EcsFrameworkException : Exception
{
diff --git a/src/entlong.cs b/src/entlong.cs
index 2a4430a..ff49d76 100644
--- a/src/entlong.cs
+++ b/src/entlong.cs
@@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using static DCFApixels.DragonECS.entlong.ThrowHalper;
+using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
@@ -33,7 +33,7 @@ namespace DCFApixels.DragonECS
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => full == 0l;
+ get => full == 0L;
}
public int ID
{
@@ -41,7 +41,7 @@ namespace DCFApixels.DragonECS
get
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!IsAlive) ThrowIsNotAlive(this);
+ if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
return id;
}
@@ -52,7 +52,7 @@ namespace DCFApixels.DragonECS
get
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!IsAlive) ThrowIsNotAlive(this);
+ if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
return gen;
}
@@ -63,7 +63,7 @@ namespace DCFApixels.DragonECS
get
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!IsAlive) ThrowIsNotAlive(this);
+ if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
return EcsWorld.GetWorld(world);
}
@@ -74,7 +74,7 @@ namespace DCFApixels.DragonECS
get
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!IsAlive) ThrowIsNotAlive(this);
+ if (!IsAlive) Throw.Ent_ThrowIsNotAlive(this);
#endif
return world;
}
@@ -143,20 +143,6 @@ namespace DCFApixels.DragonECS
public static explicit operator entlong(in long a) => new entlong(a);
#endregion
- #region ThrowHalper
- internal static class ThrowHalper
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void ThrowIsNotAlive(entlong entity)
- {
- if (entity.IsNull)
- throw new EcsFrameworkException($"The {entity} is null.");
- else
- throw new EcsFrameworkException($"The {entity} is not alive.");
- }
- }
- #endregion
-
#region DebuggerProxy
internal class DebuggerProxy
{
From 9a6010efdbbec549fabc1699d415d18d4ff6a900 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Mon, 26 Jun 2023 02:53:55 +0800
Subject: [PATCH 004/104] update exceptions
---
src/Builtin/InjectSystem.cs | 1 -
src/EcsAspect.cs | 5 +-
src/EcsGroup.cs | 8 +-
src/EcsPipeline.cs | 18 ++---
src/EcsWorld.cs | 1 -
src/Pools/EcsPool.cs | 13 ++-
src/Pools/EcsPoolBase.cs | 5 +-
src/Pools/EcsTagPool.cs | 17 ++--
src/Utils/Exceptions.cs | 156 ++++++++++++++++--------------------
src/entlong.cs | 2 +-
10 files changed, 100 insertions(+), 126 deletions(-)
diff --git a/src/Builtin/InjectSystem.cs b/src/Builtin/InjectSystem.cs
index 03c6a7c..fdac12e 100644
--- a/src/Builtin/InjectSystem.cs
+++ b/src/Builtin/InjectSystem.cs
@@ -2,7 +2,6 @@
using DCFApixels.DragonECS.RunnersCore;
using System;
using System.Linq;
-using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs
index 0ff7038..adb37b3 100644
--- a/src/EcsAspect.cs
+++ b/src/EcsAspect.cs
@@ -1,12 +1,11 @@
-using System;
+using DCFApixels.DragonECS.Internal;
+using System;
using System.Collections.Generic;
-using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
-using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs
index 5886d20..cd8e834 100644
--- a/src/EcsGroup.cs
+++ b/src/EcsGroup.cs
@@ -1,13 +1,11 @@
-using System;
-using System.Linq;
+using DCFApixels.DragonECS.Internal;
+using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
-using static DCFApixels.DragonECS.EcsThrowHalper;
-#endif
namespace DCFApixels.DragonECS
{
diff --git a/src/EcsPipeline.cs b/src/EcsPipeline.cs
index a06e1c5..6c39ded 100644
--- a/src/EcsPipeline.cs
+++ b/src/EcsPipeline.cs
@@ -6,21 +6,20 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
-using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
public sealed class EcsPipeline
{
private IEcsProcess[] _allSystems;
- private Dictionary _runners;
+ private Dictionary _runners = new Dictionary();
private IEcsRunProcess _runRunnerCache;
private ReadOnlyCollection _allSystemsSealed;
private ReadOnlyDictionary _allRunnersSealed;
- private bool _isInit;
- private bool _isDestoryed;
+ private bool _isInit = false;
+ private bool _isDestoryed = false;
#region Properties
public ReadOnlyCollection AllSystems => _allSystemsSealed;
@@ -33,13 +32,8 @@ namespace DCFApixels.DragonECS
private EcsPipeline(IEcsProcess[] systems)
{
_allSystems = systems;
- _runners = new Dictionary();
-
_allSystemsSealed = new ReadOnlyCollection(_allSystems);
_allRunnersSealed = new ReadOnlyDictionary(_runners);
-
- _isInit = false;
- _isDestoryed = false;
}
#endregion
@@ -87,7 +81,7 @@ namespace DCFApixels.DragonECS
public void Run()
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run));
+ if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Run));
if (_isDestoryed) Throw.Pipeline_MethodCalledAfterDestruction(nameof(Run));
#endif
_runRunnerCache.Run(this);
@@ -95,9 +89,9 @@ namespace DCFApixels.DragonECS
public void Destroy()
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy));
+ if (!_isInit) Throw.Pipeline_MethodCalledBeforeInitialisation(nameof(Destroy));
#endif
- if (_isDestoryed == true)
+ if (_isDestoryed)
{
EcsDebug.PrintWarning($"This {nameof(EcsPipeline)} has already been destroyed");
return;
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index e062288..dc9f5d6 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -3,7 +3,6 @@ using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs
index 131b2ff..ac14c63 100644
--- a/src/Pools/EcsPool.cs
+++ b/src/Pools/EcsPool.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using static DCFApixels.DragonECS.EcsPoolThrowHalper;
namespace DCFApixels.DragonECS
{
@@ -53,7 +52,7 @@ namespace DCFApixels.DragonECS
{
ref int itemIndex = ref _mapping[entityID];
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (itemIndex > 0) ThrowAlreadyHasComponent(entityID);
+ if (itemIndex > 0) EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID);
#endif
if (_recycledItemsCount > 0)
{
@@ -74,7 +73,7 @@ namespace DCFApixels.DragonECS
public ref T Get(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
_listeners.InvokeOnGet(entityID);
return ref _items[_mapping[entityID]];
@@ -83,7 +82,7 @@ namespace DCFApixels.DragonECS
public ref readonly T Read(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
return ref _items[_mapping[entityID]];
}
@@ -117,7 +116,7 @@ namespace DCFApixels.DragonECS
public void Del(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
ref int itemIndex = ref _mapping[entityID];
_componentResetHandler.Reset(ref _items[itemIndex]);
@@ -136,14 +135,14 @@ namespace DCFApixels.DragonECS
public void Copy(int fromEntityID, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(fromEntityID)) ThrowNotHaveComponent(fromEntityID);
+ if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID);
#endif
_componentCopyHandler.Copy(ref Get(fromEntityID), ref TryAddOrGet(toEntityID));
}
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(fromEntityID)) ThrowNotHaveComponent(fromEntityID);
+ if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID);
#endif
_componentCopyHandler.Copy(ref Get(fromEntityID), ref toWorld.GetPool().TryAddOrGet(toEntityID));
}
diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs
index f07681f..6237eda 100644
--- a/src/Pools/EcsPoolBase.cs
+++ b/src/Pools/EcsPoolBase.cs
@@ -1,4 +1,5 @@
using DCFApixels.DragonECS.Internal;
+using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
@@ -57,11 +58,11 @@ namespace DCFApixels.DragonECS
{
public static void ThrowAlreadyHasComponent(int entityID)
{
- throw new EcsFrameworkException($"Entity({entityID}) already has component {typeof(T).Name}.");
+ throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName()}.");
}
public static void ThrowNotHaveComponent(int entityID)
{
- throw new EcsFrameworkException($"Entity({entityID}) has no component {typeof(T).Name}.");
+ throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName()}.");
}
}
public static class IEcsPoolImplementationExtensions
diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs
index a435a19..69f45a2 100644
--- a/src/Pools/EcsTagPool.cs
+++ b/src/Pools/EcsTagPool.cs
@@ -2,7 +2,6 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using static DCFApixels.DragonECS.EcsPoolThrowHalper;
namespace DCFApixels.DragonECS
{
@@ -42,7 +41,7 @@ namespace DCFApixels.DragonECS
public void Add(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (Has(entityID)) ThrowAlreadyHasComponent(entityID);
+ if (Has(entityID)) EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID);
#endif
_count++;
_mapping[entityID] = true;
@@ -67,7 +66,7 @@ namespace DCFApixels.DragonECS
public void Del(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
_mapping[entityID] = false;
_count--;
@@ -81,14 +80,14 @@ namespace DCFApixels.DragonECS
public void Copy(int fromEntityID, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(fromEntityID)) ThrowNotHaveComponent(fromEntityID);
+ if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID);
#endif
TryAdd(toEntityID);
}
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(fromEntityID)) ThrowNotHaveComponent(fromEntityID);
+ if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID);
#endif
toWorld.GetPool().TryAdd(toEntityID);
}
@@ -137,14 +136,14 @@ namespace DCFApixels.DragonECS
ref readonly T IEcsStructPool.Read(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
return ref _fakeComponent;
}
ref T IEcsStructPool.Get(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
return ref _fakeComponent;
}
@@ -152,14 +151,14 @@ namespace DCFApixels.DragonECS
object IEcsPool.GetRaw(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
return _fakeComponent;
}
void IEcsPool.SetRaw(int entityID, object dataRaw)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
- if (!Has(entityID)) ThrowNotHaveComponent(entityID);
+ if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID);
#endif
}
#endregion
diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs
index 7cd999d..ed4e955 100644
--- a/src/Utils/Exceptions.cs
+++ b/src/Utils/Exceptions.cs
@@ -4,98 +4,84 @@ using System.Runtime.Serialization;
namespace DCFApixels.DragonECS
{
- public class EcsThrowHalper
+ namespace Internal
{
- public static readonly EcsThrowHalper Throw = new EcsThrowHalper();
- private EcsThrowHalper() { }
- }
+ internal static class Throw
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ArgumentNull()
+ {
+ throw new ArgumentNullException();
+ }
- public static class EcsThrowHalper_Core
- {
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void Pool_AlreadyHasComponent(this EcsThrowHalper _, int entityID)
- {
- throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName()}.");
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- public static void Pool_NotHaveComponent(this EcsThrowHalper _, int entityID)
- {
- throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName()}.");
- }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ConstraintIsAlreadyContainedInMask(Type type)
+ {
+ throw new EcsFrameworkException($"The {EcsDebugUtility.GetGenericTypeName(type)} constraint is already contained in the mask.");
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void ArgumentNull(this EcsThrowHalper _)
- {
- throw new ArgumentNullException();
- }
+ //[MethodImpl(MethodImplOptions.NoInlining)]
+ //public static void ArgumentDifferentWorldsException()
+ //{
+ // throw new ArgumentException("The groups belong to different worlds.");
+ //}
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void ArgumentOutOfRange()
+ {
+ throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count.");
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void ConstraintIsAlreadyContainedInMask(this EcsThrowHalper _, Type type)
- {
- throw new EcsFrameworkException($"The {EcsDebugUtility.GetGenericTypeName(type)} constraint is already contained in the mask.");
- }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Group_AlreadyContains(int entityID)
+ {
+ throw new EcsFrameworkException($"This group already contains entity {entityID}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Group_DoesNotContain(int entityID)
+ {
+ throw new EcsFrameworkException($"This group does not contain entity {entityID}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Group_ArgumentDifferentWorldsException()
+ {
+ throw new ArgumentException("The groups belong to different worlds.");
+ }
- //[MethodImpl(MethodImplOptions.NoInlining)]
- //public static void ArgumentDifferentWorldsException()
- //{
- // throw new ArgumentException("The groups belong to different worlds.");
- //}
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void ArgumentOutOfRange(this EcsThrowHalper _)
- {
- throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count.");
- }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Pipeline_MethodCalledAfterInitialisation(string methodName)
+ {
+ throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Pipeline_MethodCalledBeforeInitialisation(string methodName)
+ {
+ throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Pipeline_MethodCalledAfterDestruction(string methodName)
+ {
+ throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}.");
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Group_AlreadyContains(this EcsThrowHalper _, int entityID)
- {
- throw new EcsFrameworkException($"This group already contains entity {entityID}.");
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Group_DoesNotContain(this EcsThrowHalper _, int entityID)
- {
- throw new EcsFrameworkException($"This group does not contain entity {entityID}.");
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Group_ArgumentDifferentWorldsException(this EcsThrowHalper _)
- {
- throw new ArgumentException("The groups belong to different worlds.");
- }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void World_InvalidIncrementComponentsBalance()
+ {
+ throw new MethodAccessException("Invalid increment components balance.");
+ }
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void World_GroupDoesNotBelongWorld()
+ {
+ throw new MethodAccessException("The Group does not belong in this world.");
+ }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Pipeline_MethodCalledAfterInitialisation(this EcsThrowHalper _, string methodName)
- {
- throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}.");
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Pipeline_MethodCalledBeforeInitialisation(this EcsThrowHalper _, string methodName)
- {
- throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}.");
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Pipeline_MethodCalledAfterDestruction(this EcsThrowHalper _, string methodName)
- {
- throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}.");
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void World_InvalidIncrementComponentsBalance(this EcsThrowHalper _)
- {
- throw new MethodAccessException("Invalid increment components balance.");
- }
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void World_GroupDoesNotBelongWorld(this EcsThrowHalper _)
- {
- throw new MethodAccessException("The Group does not belong in this world.");
- }
-
- [MethodImpl(MethodImplOptions.NoInlining)]
- internal static void Ent_ThrowIsNotAlive(this EcsThrowHalper _, entlong entity)
- {
- if (entity.IsNull)
- throw new EcsFrameworkException($"The {entity} is null.");
- else
- throw new EcsFrameworkException($"The {entity} is not alive.");
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void Ent_ThrowIsNotAlive(entlong entity)
+ {
+ if (entity.IsNull)
+ throw new EcsFrameworkException($"The {entity} is null.");
+ else
+ throw new EcsFrameworkException($"The {entity} is not alive.");
+ }
}
}
diff --git a/src/entlong.cs b/src/entlong.cs
index ff49d76..8f54c97 100644
--- a/src/entlong.cs
+++ b/src/entlong.cs
@@ -1,10 +1,10 @@
#pragma warning disable IDE1006
+using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using static DCFApixels.DragonECS.EcsThrowHalper;
namespace DCFApixels.DragonECS
{
From f7a0495c874a1a726e3b067883b002e840b076cc Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Mon, 26 Jun 2023 04:04:00 +0800
Subject: [PATCH 005/104] remove useless
---
src/Utils/WorldMetaStorage.cs | 50 -----------------------------------
1 file changed, 50 deletions(-)
diff --git a/src/Utils/WorldMetaStorage.cs b/src/Utils/WorldMetaStorage.cs
index da3b563..49e13a5 100644
--- a/src/Utils/WorldMetaStorage.cs
+++ b/src/Utils/WorldMetaStorage.cs
@@ -52,10 +52,6 @@ namespace DCFApixels.DragonECS
public static int GetAspectID(int worldID) => Aspect.Get(worldID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetExecutorID(int worldID) => Executor.Get(worldID);
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int GetWorldComponentID(int worldID) => WorldComponent.Get(worldID);
- public static int GetWorldComponentID(Type type, int worldID) => _metas[worldID].GetWorldComponentID(type);
-
private abstract class ResizerBase
{
@@ -219,36 +215,6 @@ namespace DCFApixels.DragonECS
}
}
}
- private static class WorldComponent
- {
- public static int[] ids;
- static WorldComponent()
- {
- ids = new int[_tokenCount];
- for (int i = 0; i < ids.Length; i++)
- ids[i] = -1;
- _resizers.Add(new Resizer());
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Get(int token)
- {
- ref int id = ref ids[token];
- if (id < 0)
- id = _metas[token].GetWorldComponentID(typeof(T));
- return id;
- }
- private sealed class Resizer : ResizerBase
- {
- public override Type Type => typeof(T);
- public override int[] IDS => ids;
- public override void Resize(int size)
- {
- int oldSize = ids.Length;
- Array.Resize(ref ids, size);
- ArrayUtility.Fill(ids, -1, oldSize, size);
- }
- }
- }
#endregion
private class WorldTypeMeta
{
@@ -260,7 +226,6 @@ namespace DCFApixels.DragonECS
public int worldComponentCount;
private Type[] _types = new Type[10];
private Dictionary _declaredComponentTypes = new Dictionary();
- private Dictionary _declaredWorldComponentTypes = new Dictionary();
public WorldTypeMeta(Type worldType)
{
@@ -279,21 +244,6 @@ namespace DCFApixels.DragonECS
public bool IsDeclaredComponentType(Type type) => _declaredComponentTypes.ContainsKey(type);
public Type GetComponentType(int componentID) => _types[componentID];
public int GetComponentID(Type type) => PoolComponentIdArrays.GetComponentID(type, id);
-
-
- public int DeclareWorldComponentType(Type type)
- {
- int id = worldComponentCount++;
- _declaredWorldComponentTypes.Add(type, id);
- return id;
- }
- public bool IsDeclaredWorldComponentType(Type type) => _declaredWorldComponentTypes.ContainsKey(type);
- public int GetWorldComponentID(Type type)
- {
- if (!_declaredWorldComponentTypes.TryGetValue(type, out int id))
- id = DeclareWorldComponentType(type);
- return id;
- }
}
}
}
From f3b7841ffe9b436230144cd8523b4d4e2979435b Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 01:21:52 +0800
Subject: [PATCH 006/104] hot fix
---
src/DataInterfaces.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs
index 474bffe..f64125c 100644
--- a/src/DataInterfaces.cs
+++ b/src/DataInterfaces.cs
@@ -20,7 +20,7 @@ namespace DCFApixels.DragonECS
isHasHandler = targetType.GetInterfaces().Contains(typeof(IEcsWorldComponent<>).MakeGenericType(targetType));
if (isHasHandler)
{
- instance = (IEcsWorldComponent)Activator.CreateInstance(typeof(ComponentResetHandler<>).MakeGenericType(targetType));
+ instance = (IEcsWorldComponent)Activator.CreateInstance(typeof(WorldComponentHandler<>).MakeGenericType(targetType));
}
else
{
From 35d71245bc1de44a694f385fda24f4bce60b45ec Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 01:23:01 +0800
Subject: [PATCH 007/104] replace int with short for indexing world components
---
src/EcsWorld.cs | 2 ++
src/EcsWorld.static.cs | 13 +++++++------
2 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index dc9f5d6..6e8e334 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -142,6 +142,8 @@ namespace DCFApixels.DragonECS
}
return (TExecutor)result;
}
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Get() where T : struct => ref WorldComponentPool.GetForWorld(id);
#endregion
diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs
index cf61e9f..c131c80 100644
--- a/src/EcsWorld.static.cs
+++ b/src/EcsWorld.static.cs
@@ -47,10 +47,10 @@ namespace DCFApixels.DragonECS
private static class WorldComponentPool
{
private static T[] _items = new T[4];
- private static int[] _mapping = new int[4];
- private static int _count;
- private static int[] _recycledItems = new int[4];
- private static int _recycledItemsCount;
+ private static short[] _mapping = new short[4];
+ private static short _count;
+ private static short[] _recycledItems = new short[4];
+ private static short _recycledItemsCount;
private static IEcsWorldComponent _interface = EcsWorldComponentHandler.instance;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -62,7 +62,7 @@ namespace DCFApixels.DragonECS
if (_mapping.Length < Worlds.Length)
Array.Resize(ref _mapping, Worlds.Length);
- ref int itemIndex = ref _mapping[worldID];
+ ref short itemIndex = ref _mapping[worldID];
if (itemIndex <= 0)
{
if (_recycledItemsCount > 0)
@@ -79,9 +79,10 @@ namespace DCFApixels.DragonECS
}
return itemIndex;
}
+
private static void Release(int worldID)
{
- ref int itemIndex = ref _mapping[worldID];
+ ref short itemIndex = ref _mapping[worldID];
if (itemIndex != 0)
{
_interface.OnDestroy(ref _items[itemIndex], Worlds[worldID]);
From 1b693863078b27ab1917214adbb058a780770888 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 02:51:51 +0800
Subject: [PATCH 008/104] Update README-RU.md
---
README-RU.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README-RU.md b/README-RU.md
index 6395b63..6c2493a 100644
--- a/README-RU.md
+++ b/README-RU.md
@@ -14,7 +14,7 @@
| :--- | :--- | :--- |
Данный [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Фреймворк нацелен на максимальную удобность, модульность, расширяемость и производительность динамического изменения сущностей. Без генерации кода и зависимостей.
-> **NOTICE:** Проект в стадии разработки. API может меняться.
+> **Warning**: Проект в стадии разработки. API может меняться.
> Readme еще не завершен
## Оглавление
From 9ebf7bc023219b61cf27bd964d9fdc1cca5c2f03 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 02:52:11 +0800
Subject: [PATCH 009/104] Update README.md
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index dc8f4f2..fc32f17 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
| :--- | :--- | :--- |
The [ECS](https://en.wikipedia.org/wiki/Entity_component_system) Framework aims to maximize usability, modularity, extensibility and performance of dynamic entity changes. Without code generation and dependencies
-> **NOTICE:** The project is a work in progress, API may change.
+> **Warning**: The project is a work in progress, API may change.
> While the English version of the README is incomplete, you can view the [Russian version](https://github.com/DCFApixels/DragonECS/blob/main/README-RU.md).
# Versioning
From 51b409d5d65fd0b450304982a2f224ccc05164ff Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 05:09:41 +0800
Subject: [PATCH 010/104] GetPool optimisation
GetPool almost 2x faster.
---
src/EcsAspect.cs | 49 +++++++++++++++++------------------
src/EcsWorld.cache.cs | 40 ++++++++++++++++++++++++++++
src/EcsWorld.cs | 27 ++++++-------------
src/Utils/EcsTypeCodeCache.cs | 28 ++++++++++++++++++++
4 files changed, 100 insertions(+), 44 deletions(-)
create mode 100644 src/EcsWorld.cache.cs
create mode 100644 src/Utils/EcsTypeCodeCache.cs
diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs
index adb37b3..a65d555 100644
--- a/src/EcsAspect.cs
+++ b/src/EcsAspect.cs
@@ -123,10 +123,10 @@ namespace DCFApixels.DragonECS
foreach (var item in _combined)
{
EcsMask submask = item.aspect.mask;
- maskInc.ExceptWith(submask._exc);//удаляю конфликтующие ограничения
- maskExc.ExceptWith(submask._inc);//удаляю конфликтующие ограничения
- maskInc.UnionWith(submask._inc);
- maskExc.UnionWith(submask._exc);
+ maskInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения
+ maskExc.ExceptWith(submask.inc);//удаляю конфликтующие ограничения
+ maskInc.UnionWith(submask.inc);
+ maskExc.UnionWith(submask.exc);
}
maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
@@ -144,7 +144,7 @@ namespace DCFApixels.DragonECS
var exc = maskExc.ToArray();
Array.Sort(exc);
- mask = new EcsMask(_world.WorldTypeID, inc, exc);
+ mask = new EcsMask(_world.id, inc, exc);
_world = null;
_inc = null;
_exc = null;
@@ -202,24 +202,23 @@ namespace DCFApixels.DragonECS
[DebuggerTypeProxy(typeof(DebuggerProxy))]
public sealed class EcsMask
{
- internal readonly int _worldTypeID;
+ internal readonly int worldID;
/// Including constraints
- internal readonly int[] _inc;
+ internal readonly int[] inc;
/// Excluding constraints
- internal readonly int[] _exc;
- internal EcsMask(int worldTypeID, int[] inc, int[] exc)
+ internal readonly int[] exc;
+ internal EcsMask(int worldID, int[] inc, int[] exc)
{
#if DEBUG
- if (worldTypeID == 0) throw new ArgumentException();
CheckConstraints(inc, exc);
#endif
- _worldTypeID = worldTypeID;
- _inc = inc;
- _exc = exc;
+ this.worldID = worldID;
+ this.inc = inc;
+ this.exc = exc;
}
#region Object
- public override string ToString() => CreateLogString(_worldTypeID, _inc, _exc);
+ public override string ToString() => CreateLogString(worldID, inc, exc);
#endregion
#region Debug utils
@@ -247,10 +246,10 @@ namespace DCFApixels.DragonECS
return false;
}
#endif
- private static string CreateLogString(int worldTypeID, int[] inc, int[] exc)
+ private static string CreateLogString(int worldID, int[] inc, int[] exc)
{
#if (DEBUG && !DISABLE_DEBUG)
- string converter(int o) => EcsDebugUtility.GetGenericTypeName(WorldMetaStorage.GetComponentType(worldTypeID, o), 1);
+ string converter(int o) => EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1);
return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})";
#else
return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization
@@ -259,22 +258,22 @@ namespace DCFApixels.DragonECS
internal class DebuggerProxy
{
public readonly Type worldType;
- public readonly int worldTypeID;
+ public readonly int worldID;
public readonly int[] included;
public readonly int[] excluded;
public readonly Type[] includedTypes;
public readonly Type[] excludedTypes;
public DebuggerProxy(EcsMask mask)
{
- worldType = WorldMetaStorage.GetWorldType(mask._worldTypeID);
- worldTypeID = mask._worldTypeID;
- included = mask._inc;
- excluded = mask._exc;
- Type converter(int o) => WorldMetaStorage.GetComponentType(worldTypeID, o);
+ worldType = WorldMetaStorage.GetWorldType(mask.worldID);
+ worldID = mask.worldID;
+ included = mask.inc;
+ excluded = mask.exc;
+ Type converter(int o) => WorldMetaStorage.GetComponentType(worldID, o);
includedTypes = included.Select(converter).ToArray();
excludedTypes = excluded.Select(converter).ToArray();
}
- public override string ToString() => CreateLogString(worldTypeID, included, excluded);
+ public override string ToString() => CreateLogString(worldID, included, excluded);
}
#endregion
}
@@ -338,8 +337,8 @@ namespace DCFApixels.DragonECS
public Enumerator(EcsReadonlyGroup sourceGroup, EcsMask mask)
{
_sourceGroup = sourceGroup.GetEnumerator();
- _inc = mask._inc;
- _exc = mask._exc;
+ _inc = mask.inc;
+ _exc = mask.exc;
_pools = sourceGroup.World._pools;
}
public int Current
diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs
new file mode 100644
index 0000000..56ae21c
--- /dev/null
+++ b/src/EcsWorld.cache.cs
@@ -0,0 +1,40 @@
+using DCFApixels.DragonECS.Utils;
+using System;
+
+namespace DCFApixels.DragonECS
+{
+ public partial class EcsWorld
+ {
+ internal readonly struct PoolCache : IEcsWorldComponent>
+ where TPool : IEcsPoolImplementation, new()
+ {
+ public readonly TPool instance;
+ public PoolCache(TPool instance) => this.instance = instance;
+ void IEcsWorldComponent>.Init(ref PoolCache component, EcsWorld world)
+ {
+ component = new PoolCache(world.CreatePool());
+ }
+ void IEcsWorldComponent>.OnDestroy(ref PoolCache component, EcsWorld world)
+ {
+ component = default;
+ }
+ }
+ private TPool CreatePool() where TPool : IEcsPoolImplementation, new()
+ {
+ int index = WorldMetaStorage.GetPoolID(_worldTypeID);
+ if (index >= _pools.Length)
+ {
+ int oldCapacity = _pools.Length;
+ Array.Resize(ref _pools, _pools.Length << 1);
+ ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
+ }
+ if (_pools[index] == _nullPool)
+ {
+ var pool = new TPool();
+ _pools[index] = pool;
+ pool.OnInit(this, index);
+ }
+ return (TPool)_pools[index];
+ }
+ }
+}
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 6e8e334..d3f2c21 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -3,6 +3,7 @@ using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using typecode = System.Int32;
namespace DCFApixels.DragonECS
{
@@ -102,22 +103,10 @@ namespace DCFApixels.DragonECS
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TPool GetPool() where TPool : IEcsPoolImplementation, new()
{
- int index = WorldMetaStorage.GetPoolID(_worldTypeID);
- if (index >= _pools.Length)
- {
- int oldCapacity = _pools.Length;
- Array.Resize(ref _pools, _pools.Length << 1);
- ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
- }
- if (_pools[index] == _nullPool)
- {
- var pool = new TPool();
- _pools[index] = pool;
- pool.OnInit(this, index);
- }
- return (TPool)_pools[index];
+ return Get>().instance;
}
public TAspect GetAspect() where TAspect : EcsAspect
{
@@ -236,17 +225,17 @@ namespace DCFApixels.DragonECS
public bool IsMatchesMask(EcsMask mask, int entityID)
{
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
- if (mask._worldTypeID != _worldTypeID)
+ if (mask.worldID != id)
throw new EcsFrameworkException("The types of the target world of the mask and this world are different.");
#endif
- for (int i = 0, iMax = mask._inc.Length; i < iMax; i++)
+ for (int i = 0, iMax = mask.inc.Length; i < iMax; i++)
{
- if (!_pools[mask._inc[i]].Has(entityID))
+ if (!_pools[mask.inc[i]].Has(entityID))
return false;
}
- for (int i = 0, iMax = mask._exc.Length; i < iMax; i++)
+ for (int i = 0, iMax = mask.exc.Length; i < iMax; i++)
{
- if (_pools[mask._exc[i]].Has(entityID))
+ if (_pools[mask.exc[i]].Has(entityID))
return false;
}
return true;
diff --git a/src/Utils/EcsTypeCodeCache.cs b/src/Utils/EcsTypeCodeCache.cs
new file mode 100644
index 0000000..c60c241
--- /dev/null
+++ b/src/Utils/EcsTypeCodeCache.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+
+namespace DCFApixels.DragonECS
+{
+ namespace Internal
+ {
+ internal static class EcsTypeCode
+ {
+ private static readonly Dictionary _codes = new Dictionary();
+ private static int _incremetn = 1;
+ public static int GetCode(Type type)
+ {
+ if (!_codes.TryGetValue(type, out int code))
+ {
+ code = _incremetn++;
+ _codes.Add(type, code);
+ }
+ return code;
+ }
+ public static int Count => _codes.Count;
+ }
+ internal static class EcsTypeCodeCache
+ {
+ public static readonly int code = EcsTypeCode.GetCode(typeof(T));
+ }
+ }
+}
From cd1da0253a71d2958c06e049970f1f952e286a30 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 05:30:45 +0800
Subject: [PATCH 011/104] optimisation
---
src/EcsWorld.cache.cs | 45 +++++++++++++++++++++++++++++++++-------
src/EcsWorld.cs | 29 ++++----------------------
src/Pools/EcsPoolBase.cs | 1 -
3 files changed, 42 insertions(+), 33 deletions(-)
diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs
index 56ae21c..6862d0b 100644
--- a/src/EcsWorld.cache.cs
+++ b/src/EcsWorld.cache.cs
@@ -1,20 +1,21 @@
using DCFApixels.DragonECS.Utils;
using System;
+using System.Reflection;
namespace DCFApixels.DragonECS
{
public partial class EcsWorld
{
- internal readonly struct PoolCache : IEcsWorldComponent>
- where TPool : IEcsPoolImplementation, new()
+ internal readonly struct PoolCache : IEcsWorldComponent>
+ where T : IEcsPoolImplementation, new()
{
- public readonly TPool instance;
- public PoolCache(TPool instance) => this.instance = instance;
- void IEcsWorldComponent>.Init(ref PoolCache component, EcsWorld world)
+ public readonly T instance;
+ public PoolCache(T instance) => this.instance = instance;
+ void IEcsWorldComponent>.Init(ref PoolCache component, EcsWorld world)
{
- component = new PoolCache(world.CreatePool());
+ component = new PoolCache(world.CreatePool());
}
- void IEcsWorldComponent>.OnDestroy(ref PoolCache component, EcsWorld world)
+ void IEcsWorldComponent>.OnDestroy(ref PoolCache component, EcsWorld world)
{
component = default;
}
@@ -36,5 +37,35 @@ namespace DCFApixels.DragonECS
}
return (TPool)_pools[index];
}
+ internal readonly struct AspectCache : IEcsWorldComponent>
+ where T : EcsAspect
+ {
+ public readonly T instance;
+ public AspectCache(T instance) => this.instance = instance;
+ void IEcsWorldComponent>.Init(ref AspectCache component, EcsWorld world)
+ {
+ component = new AspectCache(EcsAspect.Builder.Build(world));
+ }
+ void IEcsWorldComponent>.OnDestroy(ref AspectCache component, EcsWorld world)
+ {
+ component = default;
+ }
+ }
+ internal readonly struct ExcecutorCache : IEcsWorldComponent>
+ where T : EcsQueryExecutor, new()
+ {
+ public readonly T instance;
+ public ExcecutorCache(T instance) => this.instance = instance;
+ void IEcsWorldComponent>.Init(ref ExcecutorCache component, EcsWorld world)
+ {
+ T instance = new T();
+ instance.Initialize(world);
+ component = new ExcecutorCache(instance);
+ }
+ void IEcsWorldComponent>.OnDestroy(ref ExcecutorCache component, EcsWorld world)
+ {
+ component = default;
+ }
+ }
}
}
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index d3f2c21..797abdb 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -27,9 +27,6 @@ namespace DCFApixels.DragonECS
internal IEcsPoolImplementation[] _pools;
private EcsNullPool _nullPool = EcsNullPool.instance;
- private EcsAspect[] _aspects;
- private EcsQueryExecutor[] _executors;
-
private List> _groups = new List>();
private Stack _groupsPool = new Stack(64);
@@ -73,9 +70,6 @@ namespace DCFApixels.DragonECS
_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET];
_allEntites = GetFreeGroup();
-
- _aspects = new EcsAspect[128];
- _executors = new EcsQueryExecutor[128];
}
public void Destroy()
{
@@ -83,8 +77,6 @@ namespace DCFApixels.DragonECS
_gens = null;
_pools = null;
_nullPool = null;
- _aspects = null;
- _executors = null;
Worlds[id] = null;
ReleaseData(id);
_worldIdDispenser.Release(id);
@@ -108,28 +100,15 @@ namespace DCFApixels.DragonECS
{
return Get>().instance;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TAspect GetAspect() where TAspect : EcsAspect
{
- int index = WorldMetaStorage.GetAspectID(_worldTypeID);
- if (index >= _aspects.Length)
- Array.Resize(ref _aspects, _aspects.Length << 1);
- if (_aspects[index] == null)
- _aspects[index] = EcsAspect.Builder.Build(this);
- return (TAspect)_aspects[index];
+ return Get>().instance;
}
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TExecutor GetExecutor() where TExecutor : EcsQueryExecutor, new()
{
- int index = WorldMetaStorage.GetExecutorID(_worldTypeID);
- if (index >= _executors.Length)
- Array.Resize(ref _executors, _executors.Length << 1);
- var result = _executors[index];
- if (result == null)
- {
- result = new TExecutor();
- _executors[index] = result;
- result.Initialize(this);
- }
- return (TExecutor)result;
+ return Get>().instance;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs
index 6237eda..459c01f 100644
--- a/src/Pools/EcsPoolBase.cs
+++ b/src/Pools/EcsPoolBase.cs
@@ -1,5 +1,4 @@
using DCFApixels.DragonECS.Internal;
-using DCFApixels.DragonECS.Internal;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
From 09ce34223973afbb4ccb2f357aa640ef17064295 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 05:33:53 +0800
Subject: [PATCH 012/104] remove useless
---
src/Utils/WorldMetaStorage.cs | 67 +----------------------------------
1 file changed, 1 insertion(+), 66 deletions(-)
diff --git a/src/Utils/WorldMetaStorage.cs b/src/Utils/WorldMetaStorage.cs
index 49e13a5..85dd1a2 100644
--- a/src/Utils/WorldMetaStorage.cs
+++ b/src/Utils/WorldMetaStorage.cs
@@ -48,10 +48,6 @@ namespace DCFApixels.DragonECS
public static Type GetComponentType(int worldID, int componentID) => _metas[worldID].GetComponentType(componentID);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetPoolID(int worldID) => Pool.Get(worldID);
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int GetAspectID(int worldID) => Aspect.Get(worldID);
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int GetExecutorID(int worldID) => Executor.Get(worldID);
private abstract class ResizerBase
{
@@ -155,74 +151,13 @@ namespace DCFApixels.DragonECS
}
}
}
- private static class Aspect
- {
- public static int[] ids;
- static Aspect()
- {
- ids = new int[_tokenCount];
- for (int i = 0; i < ids.Length; i++)
- ids[i] = -1;
- _resizers.Add(new Resizer());
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Get(int token)
- {
- ref int id = ref ids[token];
- if (id < 0)
- id = _metas[token].aspectsCount++;
- return id;
- }
- private sealed class Resizer : ResizerBase
- {
- public override Type Type => typeof(T);
- public override int[] IDS => ids;
- public override void Resize(int size)
- {
- int oldSize = ids.Length;
- Array.Resize(ref ids, size);
- ArrayUtility.Fill(ids, -1, oldSize, size);
- }
- }
- }
- private static class Executor
- {
- public static int[] ids;
- static Executor()
- {
- ids = new int[_tokenCount];
- for (int i = 0; i < ids.Length; i++)
- ids[i] = -1;
- _resizers.Add(new Resizer());
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int Get(int token)
- {
- ref int id = ref ids[token];
- if (id < 0)
- id = _metas[token].executorsCount++;
- return id;
- }
- private sealed class Resizer : ResizerBase
- {
- public override Type Type => typeof(T);
- public override int[] IDS => ids;
- public override void Resize(int size)
- {
- int oldSize = ids.Length;
- Array.Resize(ref ids, size);
- ArrayUtility.Fill(ids, -1, oldSize, size);
- }
- }
- }
#endregion
+
private class WorldTypeMeta
{
public readonly Type worldType;
public int id;
public int componentCount;
- public int aspectsCount;
- public int executorsCount;
public int worldComponentCount;
private Type[] _types = new Type[10];
private Dictionary _declaredComponentTypes = new Dictionary();
From 709ecf9cf8773964ef2e21eea3c1bb97ec5dedf7 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Tue, 27 Jun 2023 06:01:30 +0800
Subject: [PATCH 013/104] add meta
---
src/EcsWorld.cache.cs.meta | 11 +++++++++++
src/Utils/EcsTypeCodeCache.cs.meta | 11 +++++++++++
2 files changed, 22 insertions(+)
create mode 100644 src/EcsWorld.cache.cs.meta
create mode 100644 src/Utils/EcsTypeCodeCache.cs.meta
diff --git a/src/EcsWorld.cache.cs.meta b/src/EcsWorld.cache.cs.meta
new file mode 100644
index 0000000..63d2a9d
--- /dev/null
+++ b/src/EcsWorld.cache.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5cae52accc835594f95c8d972e40c57e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/Utils/EcsTypeCodeCache.cs.meta b/src/Utils/EcsTypeCodeCache.cs.meta
new file mode 100644
index 0000000..8f99598
--- /dev/null
+++ b/src/Utils/EcsTypeCodeCache.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: be4c15a212b2a6941bdbe78f18b038b3
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
From 7a5aa6477d22c6a311b6cbd9e8e1061b7f2230ec Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Thu, 29 Jun 2023 00:56:26 +0800
Subject: [PATCH 014/104] update entity copying/EcsTypeCode Api/add
IdDispenser/import module with inject
---
src/Builtin/InjectSystem.cs | 5 +-
src/EcsWorld.cache.cs | 3 +-
src/EcsWorld.cs | 23 +-
.../{EcsTypeCodeCache.cs => EcsTypeCode.cs} | 8 +-
...eCodeCache.cs.meta => EcsTypeCode.cs.meta} | 0
src/Utils/IdDispenser.cs | 415 ++++++++++++++++++
src/Utils/IdDispenser.cs.meta | 11 +
7 files changed, 456 insertions(+), 9 deletions(-)
rename src/Utils/{EcsTypeCodeCache.cs => EcsTypeCode.cs} (81%)
rename src/Utils/{EcsTypeCodeCache.cs.meta => EcsTypeCode.cs.meta} (100%)
create mode 100644 src/Utils/IdDispenser.cs
create mode 100644 src/Utils/IdDispenser.cs.meta
diff --git a/src/Builtin/InjectSystem.cs b/src/Builtin/InjectSystem.cs
index fdac12e..47b8b50 100644
--- a/src/Builtin/InjectSystem.cs
+++ b/src/Builtin/InjectSystem.cs
@@ -147,7 +147,10 @@ namespace DCFApixels.DragonECS
public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, T data)
{
if (data == null) Throw.ArgumentNull();
- return self.Add(new InjectSystem(data));
+ self.Add(new InjectSystem(data));
+ if (data is IEcsModule module)
+ self.AddModule(module);
+ return self;
}
public static EcsPipeline.Builder Inject(this EcsPipeline.Builder self, A a, B b)
{
diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs
index 6862d0b..2ba0f22 100644
--- a/src/EcsWorld.cache.cs
+++ b/src/EcsWorld.cache.cs
@@ -1,10 +1,9 @@
using DCFApixels.DragonECS.Utils;
using System;
-using System.Reflection;
namespace DCFApixels.DragonECS
{
- public partial class EcsWorld
+ public abstract partial class EcsWorld
{
internal readonly struct PoolCache : IEcsWorldComponent>
where T : IEcsPoolImplementation, new()
diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs
index 797abdb..f64521a 100644
--- a/src/EcsWorld.cs
+++ b/src/EcsWorld.cs
@@ -3,7 +3,6 @@ using DCFApixels.DragonECS.Utils;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using typecode = System.Int32;
namespace DCFApixels.DragonECS
{
@@ -14,6 +13,8 @@ namespace DCFApixels.DragonECS
private Type _worldType;
private int _worldTypeID;
+ private bool _isDestroyed;
+
private IntDispenser _entityDispenser;
private int _entitiesCount;
private int _entitesCapacity;
@@ -34,6 +35,7 @@ namespace DCFApixels.DragonECS
private List _entityListeners = new List();
#region Properties
+ public bool IsDestroyed => _isDestroyed;
public int WorldTypeID => _worldTypeID;
public int Count => _entitiesCount;
public int Capacity => _entitesCapacity; //_denseEntities.Length;
@@ -80,6 +82,7 @@ namespace DCFApixels.DragonECS
Worlds[id] = null;
ReleaseData(id);
_worldIdDispenser.Release(id);
+ _isDestroyed = true;
}
#endregion
@@ -242,7 +245,16 @@ namespace DCFApixels.DragonECS
{
foreach (var pool in _pools)
{
- if (pool.Has(fromEntityID)) pool.Copy(fromEntityID, toEntityID);
+ if (pool.Has(fromEntityID))
+ pool.Copy(fromEntityID, toEntityID);
+ }
+ }
+ public void CopyEntity(int fromEntityID, EcsWorld toWorld, int toEntityID)
+ {
+ foreach (var pool in _pools)
+ {
+ if (pool.Has(fromEntityID))
+ pool.Copy(fromEntityID, toWorld, toEntityID);
}
}
public int CloneEntity(int fromEntityID)
@@ -251,6 +263,12 @@ namespace DCFApixels.DragonECS
CopyEntity(fromEntityID, newEntity);
return newEntity;
}
+ public int CloneEntity(int fromEntityID, EcsWorld toWorld)
+ {
+ int newEntity = NewEmptyEntity();
+ CopyEntity(fromEntityID, toWorld, newEntity);
+ return newEntity;
+ }
public void CloneEntity(int fromEntityID, int toEntityID)
{
CopyEntity(fromEntityID, toEntityID);
@@ -260,6 +278,7 @@ namespace DCFApixels.DragonECS
pool.Del(toEntityID);
}
}
+ //public void CloneEntity(int fromEntityID, EcsWorld toWorld, int toEntityID)
#endregion
#region Components Increment
diff --git a/src/Utils/EcsTypeCodeCache.cs b/src/Utils/EcsTypeCode.cs
similarity index 81%
rename from src/Utils/EcsTypeCodeCache.cs
rename to src/Utils/EcsTypeCode.cs
index c60c241..77d26f2 100644
--- a/src/Utils/EcsTypeCodeCache.cs
+++ b/src/Utils/EcsTypeCode.cs
@@ -19,10 +19,10 @@ namespace DCFApixels.DragonECS
return code;
}
public static int Count => _codes.Count;
- }
- internal static class EcsTypeCodeCache
- {
- public static readonly int code = EcsTypeCode.GetCode(typeof(T));
+ internal static class Cache
+ {
+ public static readonly int code = EcsTypeCode.GetCode(typeof(T));
+ }
}
}
}
diff --git a/src/Utils/EcsTypeCodeCache.cs.meta b/src/Utils/EcsTypeCode.cs.meta
similarity index 100%
rename from src/Utils/EcsTypeCodeCache.cs.meta
rename to src/Utils/EcsTypeCode.cs.meta
diff --git a/src/Utils/IdDispenser.cs b/src/Utils/IdDispenser.cs
new file mode 100644
index 0000000..beaf822
--- /dev/null
+++ b/src/Utils/IdDispenser.cs
@@ -0,0 +1,415 @@
+// Sparse Set based ID dispenser, with the ability to reserve IDs.
+// Warning! Release version omits error exceptions, incorrect use may lead to unstable state.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace DCFApixels
+{
+ [Serializable]
+ [DebuggerTypeProxy(typeof(DebuggerProxy))]
+ public class IdDispenser : IEnumerable, IReadOnlyCollection
+ {
+ private const int MIN_SIZE = 4;
+
+ private int[] _dense = Array.Empty();
+ private int[] _sparse = Array.Empty();
+ private IDState[] _sparseState = Array.Empty();
+
+ private int _usedCount; //[ |uuuu| ]
+ private int _reservedCount; //[rrr| | ]
+ private int _size; //[rrr|uuuu|ffffff]
+
+ private int _nullID;
+
+ #region Properties
+ /// Used Count
+ public int Count => _usedCount;
+ public int ReservedCount => _reservedCount;
+ public int Size => _size;
+ public int NullID => _nullID;
+ #endregion
+
+ public IdDispenser(int capacity, int nullID = 0)
+ {
+ if (capacity % MIN_SIZE > 0)
+ capacity += MIN_SIZE;
+ Resize(capacity);
+ SetNullID(nullID);
+
+ Reserved = new ReservedSpan(this);
+ Used = new UsedSpan(this);
+ }
+
+ #region Use/Reserve/Release
+ /// Marks as used and returns next free id.
+ public int UseFree()
+ {
+ int count = _usedCount + _reservedCount;
+ CheckOrResize(count + 1);
+ int id = _dense[count];
+ Add(id);
+ _sparseState[id] = IDState.Used;
+ return id;
+ }
+ public void UseFreeRange(ref int[] array, int range)
+ {
+ if (array.Length < range)
+ Array.Resize(ref array, range);
+ for (int i = 0; i < range; i++)
+ array[i] = UseFree();
+ }
+ public void UseFreeRange(List list, int range)
+ {
+ for (int i = 0; i < range; i++)
+ list.Add(UseFree());
+ }
+ /// Marks as used a free or reserved id, after this id cannot be retrieved via UseFree.
+ public void Use(int id)
+ {
+ CheckOrResize(id);
+#if DEBUG
+ if (IsUsed(id) || IsReserved(id))
+ {
+ if (IsUsed(id)) ThrowHalper.ThrowIsAlreadyInUse(id);
+ else ThrowHalper.ThrowIsHasBeenReserved(id);
+ }
+#endif
+ if (IsFree(id))
+ Add(id);
+ _sparseState[id] = IDState.Used;
+ }
+ public void UseRange(IEnumerable ids)
+ {
+ foreach (var item in ids)
+ Use(item);
+ }
+ /// Marks as reserved and returns next free id, after this id cannot be retrieved via UseFree.
+ public int ReserveFree()
+ {
+ int count = _usedCount + _reservedCount;
+ CheckOrResize(count + 1);
+ int id = _dense[count];
+ _sparseState[id] = IDState.Reserved;
+ AddReserved(id);
+ return id;
+ }
+ /// Marks as reserved a free id, after this id cannot be retrieved via UseFree.
+ public void Reserve(int id)
+ {
+ CheckOrResize(id);
+#if DEBUG
+ if (!IsFree(id)) ThrowHalper.ThrowIsNotAvailable(id);
+#endif
+ _sparseState[id] = IDState.Reserved;
+ AddReserved(id);
+ }
+ public void ReserveRange(IEnumerable ids)
+ {
+ foreach (var item in ids)
+ Reserve(item);
+ }
+ public void Release(int id)
+ {
+ CheckOrResize(id);
+#if DEBUG
+ if (IsFree(id) || IsNullID(id))
+ {
+ if (IsFree(id)) ThrowHalper.ThrowIsNotUsed(id);
+ else ThrowHalper.ThrowIsNullID(id);
+ }
+#endif
+ if (_sparseState[id] == IDState.Used)
+ Remove(id);
+ else
+ RemoveReserved(id);
+ _sparseState[id] = IDState.Free;
+ }
+ public void ReleaseRange(IEnumerable ids)
+ {
+ foreach (var item in ids)
+ Release(item);
+ }
+ public void ReleaseAll()
+ {
+ _usedCount = 0;
+ _reservedCount = 0;
+ for (int i = 0; i < _size;)
+ {
+ _sparse[i] = i;
+ _sparseState[i] = IDState.Free;
+ _dense[i] = i++;
+ _sparse[i] = i;
+ _sparseState[i] = IDState.Free;
+ _dense[i] = i++;
+ _sparse[i] = i;
+ _sparseState[i] = IDState.Free;
+ _dense[i] = i++;
+ _sparse[i] = i;
+ _sparseState[i] = IDState.Free;
+ _dense[i] = i++;
+ }
+ SetNullID(_nullID);
+ }
+ #endregion
+
+ #region Checks
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsFree(int id) => _sparseState[id] == IDState.Free;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsReserved(int id) => _sparseState[id] == IDState.Reserved;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsUsed(int id) => _sparseState[id] == IDState.Used;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public bool IsNullID(int id) => id == _nullID;
+
+ #endregion
+
+ #region Sort
+ /// O(n) Sort. n = Size. Allows the UseFree method to return denser ids.
+ public void Sort()
+ {
+ int usedInc = _reservedCount;
+ int reservedInc = 0;
+ int freeInc = _reservedCount + _usedCount;
+ for (int i = 0; i < _size; i++)
+ {
+ switch (_sparseState[i])
+ {
+ case IDState.Free:
+ _sparse[i] = freeInc;
+ _dense[freeInc++] = i;
+ break;
+ case IDState.Reserved:
+ _sparse[i] = reservedInc;
+ _dense[reservedInc++] = i;
+ break;
+ case IDState.Used:
+ _sparse[i] = usedInc;
+ _dense[usedInc++] = i;
+ break;
+ }
+ }
+ }
+ #endregion
+
+ #region Other
+ private void SetNullID(int nullID)
+ {
+ _nullID = nullID;
+ if (nullID >= 0)
+ {
+ AddReserved(nullID);
+ _sparseState[nullID] = IDState.Reserved;
+ }
+ }
+ private bool IsValid()
+ {
+ for (int i = 0; i < _usedCount; i++)
+ {
+ if (_sparse[_dense[i]] != i || _dense[_sparse[i]] != i)
+ return false;
+ }
+ return true;
+ }
+ private void CheckOrResize(int id)
+ {
+ if (id > _size)
+ {
+ int leftBit = 0;
+ while (id != 0)
+ {
+ id >>= 1;
+ id &= int.MaxValue;
+ leftBit++;
+ }
+ if (leftBit >= 32)
+ Resize(int.MaxValue);
+ else
+ Resize(1 << leftBit);
+ }
+ }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void Add(int value)
+ {
+ Swap(value, _reservedCount + _usedCount++);
+ }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void Remove(int value)
+ {
+ Swap(value, _reservedCount + --_usedCount);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void AddReserved(int value)
+ {
+ Swap(value, _reservedCount + _usedCount);
+ Swap(value, _reservedCount++);
+ }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void RemoveReserved(int value)
+ {
+ Swap(value, --_reservedCount);
+ Swap(value, _reservedCount + _usedCount);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private void Swap(int sparseIndex, int denseIndex)
+ {
+ int _dense_denseIndex_ = _dense[denseIndex];
+ int _sparse_sparseIndex_ = _sparse[sparseIndex];
+ _dense[denseIndex] = _dense[_sparse_sparseIndex_];
+ _dense[_sparse_sparseIndex_] = _dense_denseIndex_;
+ _sparse[_dense_denseIndex_] = _sparse_sparseIndex_;
+ _sparse[sparseIndex] = denseIndex;
+ }
+ private void Resize(int newSize)
+ {
+ if (newSize < MIN_SIZE)
+ newSize = MIN_SIZE;
+ Array.Resize(ref _dense, newSize);
+ Array.Resize(ref _sparse, newSize);
+ Array.Resize(ref _sparseState, newSize);
+ for (int i = _size; i < newSize;)
+ {
+ _sparse[i] = i;
+ _dense[i] = i++;
+ _sparse[i] = i;
+ _dense[i] = i++;
+ _sparse[i] = i;
+ _dense[i] = i++;
+ _sparse[i] = i;
+ _dense[i] = i++;
+ }
+ _size = newSize;
+ Resized(newSize);
+ }
+ #endregion
+
+ public delegate void ResizedHandler(int newSize);
+ public event ResizedHandler Resized = delegate { };
+
+ internal enum IDState : byte
+ {
+ Free,
+ Reserved,
+ Used,
+ }
+
+ #region Enumerable
+ public UsedSpan Used;
+ public ReservedSpan Reserved;
+ public Enumerator GetEnumerator() => new Enumerator(_dense, _reservedCount, _usedCount);
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ public struct Enumerator : IEnumerator
+ {
+ private readonly int[] _dense;
+ private readonly int _count;
+ private int _index;
+ public int Current => _dense[_index];
+ object IEnumerator.Current => Current;
+ public Enumerator(int[] dense, int startIndex, int count)
+ {
+ _dense = dense;
+ _count = startIndex + count;
+ _index = startIndex - 1;
+ }
+ public bool MoveNext() => ++_index < _count;
+ public void Dispose() { }
+ public void Reset() => _index = -1;
+ }
+ public readonly struct UsedSpan : IEnumerable
+ {
+ private readonly IdDispenser _instance;
+ public int Count => _instance._usedCount;
+ internal UsedSpan(IdDispenser instance) => _instance = instance;
+ public Enumerator GetEnumerator() => new Enumerator(_instance._dense, _instance._reservedCount, _instance._usedCount);
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+ public readonly struct ReservedSpan : IEnumerable
+ {
+ private readonly IdDispenser _instance;
+ public int Count => _instance._reservedCount;
+ internal ReservedSpan(IdDispenser instance) => _instance = instance;
+ public Enumerator GetEnumerator() => new Enumerator(_instance._dense, 0, _instance._reservedCount);
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+ }
+ #endregion
+
+ #region Utils
+ private static class ThrowHalper
+ {
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void ThrowIsAlreadyInUse(int id) => throw new ArgumentException($"Id {id} is already in use.");
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void ThrowIsHasBeenReserved(int id) => throw new ArgumentException($"Id {id} has been reserved.");
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void ThrowIsNotUsed(int id) => throw new ArgumentException($"Id {id} is not used.");
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void ThrowIsNotAvailable(int id) => throw new ArgumentException($"Id {id} is not available.");
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void ThrowIsNullID(int id) => throw new ArgumentException($"Id {id} cannot be released because it is used as a null id.");
+ }
+
+ internal class DebuggerProxy
+ {
+ private IdDispenser _dispenser;
+ public DebuggerProxy(IdDispenser dispenser) => _dispenser = dispenser;
+#if DEBUG
+ public IEnumerable Used => _dispenser.Used;
+ public IEnumerable Reserved => _dispenser.Reserved;
+ public Pair[] Pairs
+ {
+ get
+ {
+ Pair[] result = new Pair[_dispenser.Size];
+ for (int i = 0; i < result.Length; i++)
+ result[i] = new Pair(_dispenser._dense[i], _dispenser._sparse[i]);
+ return result;
+ }
+ }
+ public ID[] All
+ {
+ get
+ {
+ ID[] result = new ID[_dispenser.Size];
+ for (int i = 0; i < result.Length; i++)
+ {
+ int id = _dispenser._dense[i];
+ result[i] = new ID(id, _dispenser._sparseState[id].ToString());
+ }
+ return result;
+ }
+ }
+ public bool IsValid => _dispenser.IsValid();
+ public int Count => _dispenser.ReservedCount;
+ public int Size => _dispenser.Size;
+ public int NullID => _dispenser._nullID;
+ internal readonly struct ID
+ {
+ public readonly int id;
+ public readonly string state;
+ public ID(int id, string state) { this.id = id; this.state = state; }
+ public override string ToString() => $"{id} - {state}";
+ }
+ internal readonly struct Pair
+ {
+ public readonly int dense;
+ public readonly int sparse;
+ public Pair(int dense, int sparse) { this.dense = dense; this.sparse = sparse; }
+ public override string ToString() => $"{dense} - {sparse}";
+ }
+#endif
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Utils/IdDispenser.cs.meta b/src/Utils/IdDispenser.cs.meta
new file mode 100644
index 0000000..eda80df
--- /dev/null
+++ b/src/Utils/IdDispenser.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 54c009cfa7ae0fd49938525468703c8b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
From 26e45a6f16dccb541e87d58eedb84b8271cb9388 Mon Sep 17 00:00:00 2001
From: Mikhail <99481254+DCFApixels@users.noreply.github.com>
Date: Thu, 29 Jun 2023 17:57:28 +0800
Subject: [PATCH 015/104] update debug utils/ add DebugGroup attribute
---
src/Debug/Attributes/DebugColorAttribute.cs | 162 ++++++++++--------
src/Debug/Attributes/DebugGroupAttribute.cs | 33 ++++
.../Attributes/DebugGroupAttribute.cs.meta | 11 ++
src/Debug/EcsDebugUtility.cs | 80 +++++++--
src/Utils/EcsTypeCode.cs | 2 +-
5 files changed, 196 insertions(+), 92 deletions(-)
create mode 100644 src/Debug/Attributes/DebugGroupAttribute.cs
create mode 100644 src/Debug/Attributes/DebugGroupAttribute.cs.meta
diff --git a/src/Debug/Attributes/DebugColorAttribute.cs b/src/Debug/Attributes/DebugColorAttribute.cs
index fe603dc..5ec68dd 100644
--- a/src/Debug/Attributes/DebugColorAttribute.cs
+++ b/src/Debug/Attributes/DebugColorAttribute.cs
@@ -6,89 +6,99 @@ namespace DCFApixels.DragonECS
[AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public sealed class DebugColorAttribute : Attribute
{
- private Color color;
+ public readonly DebugColor color;
public byte r => color.r;
public byte g => color.g;
public byte b => color.b;
- public DebugColorAttribute(byte r, byte g, byte b) => color = new Color(r, g, b);
- public DebugColorAttribute(DebugColor color) => this.color = new Color((int)color);
-
- [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)]
- internal readonly struct Color
- {
- [FieldOffset(0)] public readonly int full;
- [FieldOffset(3)] public readonly byte r;
- [FieldOffset(2)] public readonly byte g;
- [FieldOffset(1)] public readonly byte b;
- public Color(byte r, byte g, byte b) : this()
- {
- this.r = r;
- this.g = g;
- this.b = b;
- }
- public Color(int full) : this() => this.full = full;
- public (byte, byte, byte) ToTuple() => (r, g, b);
-
- public Color UpContrastColor()
- {
- byte minChannel = Math.Min(Math.Min(r, g), b);
- byte maxChannel = Math.Max(Math.Max(r, g), b);
- if (maxChannel == minChannel)
- return default;
- float factor = 255f / (maxChannel - minChannel);
- return new Color((byte)((r - minChannel) * factor), (byte)((g - minChannel) * factor), (byte)((b - minChannel) * factor));
- }
-
- public static Color operator /(Color a, float b)
- {
- return new Color((byte)(a.r / b), (byte)(a.g / b), (byte)(a.b / b));
- }
- }
+ public DebugColorAttribute(byte r, byte g, byte b) => color = new DebugColor(r, g, b, 255);
+ public DebugColorAttribute(int colorCode) => color = new DebugColor(colorCode, true);
}
- public enum DebugColor
+ [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 4)]
+ public readonly struct DebugColor
{
- /// Red. RGB is (255, 0, 0)
- Red = (255 << 24) + (000 << 16) + (000 << 8),
- /// Green. RGB is (0, 255, 0)
- Green = (000 << 24) + (255 << 16) + (000 << 8),
- /// Blue. RGB is (0, 0, 255)
- Blue = (000 << 24) + (000 << 16) + (255 << 8),
+ public static readonly DebugColor BlackColor = new DebugColor(Black);
+ /// color code Red. RGB is (255, 0, 0)
+ public const int Red = (255 << 24) | (000 << 16) | (000 << 8) | 255;
+ /// color code Green. RGB is (0, 255, 0)
+ public const int Green = (000 << 24) | (255 << 16) | (000 << 8) | 255;
+ /// color code Blue. RGB is (0, 0, 255)
+ public const int Blue = (000 << 24) | (000 << 16) | (255 << 8) | 255;
- /// Yellow. RGB is (255, 255, 0)
- Yellow = (255 << 24) + (255 << 16) + (000 << 8),
- /// Cyan. RGB is (0, 255, 255)
- Cyan = (000 << 24) + (255 << 16) + (255 << 8),
- /// Magenta. RGB is (255, 0, 255)
- Magenta = (255 << 24) + (000 << 16) + (255 << 8),
+ /// color code Yellow. RGB is (255, 255, 0)
+ public const int Yellow = (255 << 24) | (255 << 16) | (000 << 8) | 255;
+ /// color code Cyan. RGB is (0, 255, 255)
+ public const int Cyan = (000 << 24) | (255 << 16) | (255 << 8) | 255;
+ /// color code Magenta. RGB is (255, 0, 255)
+ public const int Magenta = (255 << 24) | (000 << 16) | (255 << 8) | 255;
- /// Yellow. RGB is (255, 165, 0)
- Orange = (255 << 24) + (165 << 16) + (000 << 8),
- /// Yellow. RGB is (255, 69, 0)
- OrangeRed = (255 << 24) + (69 << 16) + (000 << 8),
- /// Lime. RGB is (125, 255, 0)
- Lime = (125 << 24) + (255 << 16) + (000 << 8),
- /// Lime. RGB is (127, 255, 212)
- Aquamarine = (127 << 24) + (255 << 16) + (212 << 8),
- /// Lime. RGB is (218, 165, 32)
- Goldenrod = (218 << 24) + (165 << 16) + (32 << 8),
- /// Yellow. RGB is (255, 105, 180)
- DeepPink = (255 << 24) + (105 << 16) + (180 << 8),
- /// Yellow. RGB is (220, 20, 60)
- Crimson = (220 << 24) + (20 << 16) + (60 << 8),
- /// Yellow. RGB is (138, 43, 226)
- BlueViolet = (138 << 24) + (43 << 16) + (226 << 8),
- /// Yellow. RGB is (255, 3, 62)
- AmericanRose = (255 << 24) + (3 << 16) + (62 << 8),
+ /// color code Orange. RGB is (255, 165, 0)
+ public const int Orange = (255 << 24) | (165 << 16) | (000 << 8) | 255;
+ /// color code OrangeRed. RGB is (255, 69, 0)
+ public const int OrangeRed = (255 << 24) | (69 << 16) | (000 << 8) | 255;
+ /// color code Lime. RGB is (125, 255, 0)
+ public const int Lime = (125 << 24) | (255 << 16) | (000 << 8) | 255;
+ /// color code Aquamarine. RGB is (127, 255, 212)
+ public const int Aquamarine = (127 << 24) | (255 << 16) | (212 << 8) | 255;
+ /// color code Goldenrod. RGB is (218, 165, 32)
+ public const int Goldenrod = (218 << 24) | (165 << 16) | (32 << 8) | 255;
+ /// color code DeepPink. RGB is (255, 105, 180)
+ public const int DeepPink = (255 << 24) | (105 << 16) | (180 << 8) | 255;
+ /// color code Crimson. RGB is (220, 20, 60)
+ public const int Crimson = (220 << 24) | (20 << 16) | (60 << 8) | 255;
+ /// color code BlueViolet. RGB is (138, 43, 226)
+ public const int BlueViolet = (138 << 24) | (43 << 16) | (226 << 8) | 255;
+ /// color code AmericanRose. RGB is (255, 3, 62)
+ public const int AmericanRose = (255 << 24) | (3 << 16) | (62 << 8) | 255;
- /// Grey/Gray. RGB is (127, 127, 127)
- Gray = (127 << 24) + (127 << 16) + (127 << 8),
- /// Grey/Gray. RGB is (127, 127, 127)
- Grey = Gray,
- /// Grey/Gray. RGB is (192, 192, 192)
- Silver = (192 << 24) + (192 << 16) + (192 << 8),
- /// White. RGB is (255, 255, 255)
- White = -1,
- /// Black. RGB is (0, 0, 0)
- Black = 0,
+ /// color code Grey/Gray. RGB is (127, 127, 127)
+ public const int Gray = (127 << 24) | (127 << 16) | (127 << 8) | 255;
+ /// color code Grey/Gray. RGB is (127, 127, 127)
+ public const int Grey = Gray;
+ /// color code Silver. RGB is (192, 192, 192)
+ public const int Silver = (192 << 24) | (192 << 16) | (192 << 8) | 255;
+ /// color code White. RGB is (255, 255, 255)
+ public const int White = -1;
+ /// color code Black. RGB is (0, 0, 0)
+ public const int Black = 0;
+
+
+ [FieldOffset(0)] public readonly int colorCode;
+ [FieldOffset(3)] public readonly byte r;
+ [FieldOffset(2)] public readonly byte g;
+ [FieldOffset(1)] public readonly byte b;
+ [FieldOffset(0)] public readonly byte a;
+ public DebugColor(byte r, byte g, byte b) : this()
+ {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ a = 255;
+ }
+ public DebugColor(byte r, byte g, byte b, byte a) : this()
+ {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+ }
+ public DebugColor(int colorCode) : this() => this.colorCode = colorCode;
+ public DebugColor(int colorCode, bool withoutAlpha) : this() => this.colorCode = withoutAlpha ? colorCode | 255 : colorCode;
+ public (byte, byte, byte) ToTupleRGB() => (r, g, b);
+ public (byte, byte, byte, byte) ToTupleRGBA() => (r, g, b, a);
+
+ public DebugColor UpContrastColor()
+ {
+ byte minChannel = Math.Min(Math.Min(r, g), b);
+ byte maxChannel = Math.Max(Math.Max(r, g), b);
+ if (maxChannel == minChannel)
+ return default;
+ float factor = 255f / (maxChannel - minChannel);
+ return new DebugColor((byte)((r - minChannel) * factor), (byte)((g - minChannel) * factor), (byte)((b - minChannel) * factor));
+ }
+ public static DebugColor operator /(DebugColor a, float b)
+ {
+ return new DebugColor((byte)(a.r / b), (byte)(a.g / b), (byte)(a.b / b));
+ }
+ //public static explicit operator DebugColor(int colorCode) => new DebugColor(colorCode);
}
}
\ No newline at end of file
diff --git a/src/Debug/Attributes/DebugGroupAttribute.cs b/src/Debug/Attributes/DebugGroupAttribute.cs
new file mode 100644
index 0000000..e0c7567
--- /dev/null
+++ b/src/Debug/Attributes/DebugGroupAttribute.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Text.RegularExpressions;
+
+namespace DCFApixels.DragonECS
+{
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = false, AllowMultiple = false)]
+ public sealed class DebugGroupAttribute : Attribute
+ {
+ public static readonly DebugGroupAttribute Empty = new DebugGroupAttribute("");
+ public readonly string name;
+ public readonly string rootCategory;
+ public DebugGroupAttribute(string name)
+ {
+ name = Regex.Replace(name, @"^[/|\\]+|[/|\\]+$", "");
+ rootCategory = Regex.Match(name, @"^(.*?)[/\\]").Groups[1].Value;
+ this.name = name;
+ }
+ public string[] SplitCategories()
+ {
+ return Regex.Split(name, @"[/|\\]");
+ }
+ public DebugGroup GetData() => new DebugGroup(this);
+ }
+ public readonly struct DebugGroup
+ {
+ public static readonly DebugGroup Empty = new DebugGroup(DebugGroupAttribute.Empty);
+ private readonly DebugGroupAttribute _source;
+ public string Name => _source.name;
+ public string RootCategory => _source.rootCategory;
+ public DebugGroup(DebugGroupAttribute source) => _source = source;
+ public string[] SplitCategories() => _source.SplitCategories();
+ }
+}
diff --git a/src/Debug/Attributes/DebugGroupAttribute.cs.meta b/src/Debug/Attributes/DebugGroupAttribute.cs.meta
new file mode 100644
index 0000000..594d6fb
--- /dev/null
+++ b/src/Debug/Attributes/DebugGroupAttribute.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c447392c75f8b4a42a2e5c3eb49e5b82
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/Debug/EcsDebugUtility.cs b/src/Debug/EcsDebugUtility.cs
index 7985286..803c9b6 100644
--- a/src/Debug/EcsDebugUtility.cs
+++ b/src/Debug/EcsDebugUtility.cs
@@ -72,6 +72,22 @@ namespace DCFApixels.DragonECS
}
#endregion
+ #region GetGroup
+ public static DebugGroup GetGroup() => GetGroup(typeof(T));
+ public static DebugGroup GetGroup(Type type) => type.TryGetCustomAttribute(out DebugGroupAttribute atr) ? atr.GetData() : DebugGroup.Empty;
+ public static bool TryGetGroup(out DebugGroup text) => TryGetGroup(typeof(T), out text);
+ public static bool TryGetGroup(Type type, out DebugGroup group)
+ {
+ if (type.TryGetCustomAttribute(out DebugGroupAttribute atr))
+ {
+ group = atr.GetData();
+ return true;
+ }
+ group = DebugGroup.Empty;
+ return false;
+ }
+ #endregion
+
#region GetDescription
public static string GetDescription() => GetDescription(typeof(T));
public static string GetDescription(Type type) => type.TryGetCustomAttribute(out DebugDescriptionAttribute atr) ? atr.description : string.Empty;
@@ -94,7 +110,7 @@ namespace DCFApixels.DragonECS
private class WordColor
{
public int wordsCount;
- public DebugColorAttribute.Color color;
+ public DebugColor color;
}
private class NameColor
{
@@ -107,7 +123,7 @@ namespace DCFApixels.DragonECS
{
color = new WordColor();
_words.Add(word, color);
- color.color = new DebugColorAttribute.Color((byte)random.Next(), (byte)random.Next(), (byte)random.Next()).UpContrastColor() / 2;
+ color.color = new DebugColor((byte)random.Next(), (byte)random.Next(), (byte)random.Next()).UpContrastColor() / 2;
}
color.wordsCount++;
colors.Add(color);
@@ -122,7 +138,7 @@ namespace DCFApixels.DragonECS
}
return result;
}
- public DebugColorAttribute.Color CalcColor()
+ public DebugColor CalcColor()
{
float r = 0, g = 0, b = 0;
int totalWordsCount = CalcTotalWordsColor();
@@ -134,11 +150,11 @@ namespace DCFApixels.DragonECS
g += m * color.color.g;
b += m * color.color.b;
}
- return new DebugColorAttribute.Color((byte)r, (byte)g, (byte)b);
+ return new DebugColor((byte)r, (byte)g, (byte)b);
}
}
private static Dictionary _names = new Dictionary();
- private static DebugColorAttribute.Color CalcNameColorFor(Type type)
+ private static DebugColor CalcNameColorFor(Type type)
{
Type targetType = type.IsGenericType ? type.GetGenericTypeDefinition() : type;
if (!_names.TryGetValue(targetType, out NameColor nameColor))
@@ -169,27 +185,27 @@ namespace DCFApixels.DragonECS
return words;
}
- public static (byte, byte, byte) GetColorRGB