From 5a3725a02b399ee9590249ec38082641d8e48b1a Mon Sep 17 00:00:00 2001 From: DCFApixels <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 9 May 2025 19:38:28 +0800 Subject: [PATCH] update unchecked utils / EntitySlotInfo --- src/Collections/EcsGroup.cs | 1 + src/Collections/EcsSpan.cs | 1 + src/EcsWorld.cs | 1 + src/Utils/Uncheked/EntitiesMatrix.cs | 44 +++++ src/Utils/Uncheked/EntitySlotInfo.cs | 137 +++++++++++++++ .../UncheckedUtility.cs} | 68 +++++--- .../UncheckedUtility.cs.meta} | 0 src/entlong.cs | 157 ++---------------- 8 files changed, 246 insertions(+), 163 deletions(-) create mode 100644 src/Utils/Uncheked/EntitiesMatrix.cs create mode 100644 src/Utils/Uncheked/EntitySlotInfo.cs rename src/Utils/{UncheckedCoreUtility.cs => Uncheked/UncheckedUtility.cs} (54%) rename src/Utils/{UncheckedCoreUtility.cs.meta => Uncheked/UncheckedUtility.cs.meta} (100%) diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index 5d70cfe..997b4ce 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -1,6 +1,7 @@ #if DISABLE_DEBUG #undef DEBUG #endif +using DCFApixels.DragonECS.Core.Unchecked; using DCFApixels.DragonECS.Internal; using System; using System.Collections; diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs index 48c26c4..11161e6 100644 --- a/src/Collections/EcsSpan.cs +++ b/src/Collections/EcsSpan.cs @@ -1,6 +1,7 @@ #if DISABLE_DEBUG #undef DEBUG #endif +using DCFApixels.DragonECS.Core.Unchecked; using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 891ac6c..35ca962 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -2,6 +2,7 @@ #undef DEBUG #endif using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Core.Unchecked; using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.PoolsCore; using System; diff --git a/src/Utils/Uncheked/EntitiesMatrix.cs b/src/Utils/Uncheked/EntitiesMatrix.cs new file mode 100644 index 0000000..75baf56 --- /dev/null +++ b/src/Utils/Uncheked/EntitiesMatrix.cs @@ -0,0 +1,44 @@ +#if DISABLE_DEBUG +#undef DEBUG +#endif + +namespace DCFApixels.DragonECS.UncheckedCore +{ + public readonly struct EntitiesMatrix + { + private readonly EcsWorld _world; + public EntitiesMatrix(EcsWorld world) + { + _world = world; + } + public int PoolsCount + { + get { return _world.PoolsCount; } + } + public int EntitesCount + { + get { return _world.Capacity; } + } + public int GetEntityComponentsCount(int entityID) + { + return _world.GetComponentsCount(entityID); + } + public int GetEntityGen(int entityID) + { + return _world.GetGen(entityID); + } + public bool IsEntityUsed(int entityID) + { + return _world.IsUsed(entityID); + } + public bool this[int entityID, int poolID] + { + get + { + int entityStartChunkIndex = entityID << _world._entityComponentMaskLengthBitShift; + var chunkInfo = EcsMaskChunck.FromID(poolID); + return (_world._entityComponentMasks[entityStartChunkIndex + chunkInfo.chunkIndex] & chunkInfo.mask) != 0; + } + } + } +} \ No newline at end of file diff --git a/src/Utils/Uncheked/EntitySlotInfo.cs b/src/Utils/Uncheked/EntitySlotInfo.cs new file mode 100644 index 0000000..942d666 --- /dev/null +++ b/src/Utils/Uncheked/EntitySlotInfo.cs @@ -0,0 +1,137 @@ +#if DISABLE_DEBUG +#undef DEBUG +#endif +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace DCFApixels.DragonECS.Core.Unchecked +{ + [StructLayout(LayoutKind.Explicit, Pack = 2, Size = 8)] + [DebuggerTypeProxy(typeof(EntityDebuggerProxy))] + public struct EntitySlotInfo : IEquatable + { +#if UNITY_EDITOR + [UnityEngine.SerializeField] +#endif + [FieldOffset(0)] + public long full; //Union + [FieldOffset(0), NonSerialized] + public int id; + [FieldOffset(4), NonSerialized] + public short gen; + [FieldOffset(6), NonSerialized] + public short worldID; + + #region Properties + public EcsWorld World { get { return EcsWorld.GetWorld(worldID); } } + public StateFlag State { get { return full == 0 ? StateFlag.Null : World.IsAlive(id, gen) ? StateFlag.Alive : StateFlag.Dead; } } + #endregion + + #region Constructors/Deconstructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntitySlotInfo(long full) : this() + { + this.full = full; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EntitySlotInfo(int id, short gen, short world) : this() + { + this.id = id; + this.gen = gen; + worldID = world; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Deconstruct(out int id, out int gen, out int worldID) + { + id = this.id; + gen = this.gen; + worldID = this.worldID; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Deconstruct(out int id, out int worldID) + { + id = this.id; + worldID = this.worldID; + } + #endregion + + #region Operators + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator ==(EntitySlotInfo a, EntitySlotInfo b) { return a.full == b.full; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool operator !=(EntitySlotInfo a, EntitySlotInfo b) { return a.full != b.full; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator EntitySlotInfo(entlong a) { return new EntitySlotInfo(a._full); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static explicit operator entlong(EntitySlotInfo a) { return new entlong(a.full); } + #endregion + + #region Other + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override int GetHashCode() { return unchecked(id ^ gen ^ (worldID * EcsConsts.MAGIC_PRIME)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override string ToString() { return $"slot(id:{id} g:{gen} w:{worldID} {(State == StateFlag.Null ? "null" : State == StateFlag.Alive ? "alive" : "not alive")})"; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override bool Equals(object obj) { return obj is EntitySlotInfo other && this == other; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Equals(EntitySlotInfo other) { return this == other; } + + public enum StateFlag { Null, Dead, Alive, } + #endregion + } + + + + internal class EntityDebuggerProxy + { + private List _componentsList = new List(); + private EntitySlotInfo _info; + public long full { get { return _info.full; } } + public int id { get { return _info.id; } } + public short gen { get { return _info.gen; } } + public short worldID { get { return _info.worldID; } } + public EntitySlotInfo.StateFlag State { get { return _info.State; } } + public EcsWorld World { get { return _info.World; } } + public IEnumerable Components + { + get + { + if (State == EntitySlotInfo.StateFlag.Alive) + { + World.GetComponentsFor(id, _componentsList); + return _componentsList; + } + return Array.Empty(); + } + set + { + if (State == EntitySlotInfo.StateFlag.Alive) + { + foreach (var component in value) + { + if (component == null) { continue; } + var componentType = component.GetType(); + var world = World; + + if (componentType.IsValueType && world.TryFindPoolInstance(componentType, out IEcsPool pool)) + { + pool.SetRaw(id, component); + } + } + } + } + } + public EntityDebuggerProxy(EntitySlotInfo info) + { + _info = info; + } + public EntityDebuggerProxy(int entityID, short gen, short worldID) + { + _info = new EntitySlotInfo(entityID, gen, worldID); + } + } +} \ No newline at end of file diff --git a/src/Utils/UncheckedCoreUtility.cs b/src/Utils/Uncheked/UncheckedUtility.cs similarity index 54% rename from src/Utils/UncheckedCoreUtility.cs rename to src/Utils/Uncheked/UncheckedUtility.cs index 3ae009f..1775abc 100644 --- a/src/Utils/UncheckedCoreUtility.cs +++ b/src/Utils/Uncheked/UncheckedUtility.cs @@ -1,13 +1,13 @@ #if DISABLE_DEBUG #undef DEBUG #endif - using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS.UncheckedCore { + [Obsolete("Use DCFApixels.DragonECS.Core.UncheckedUtility")] public static class UncheckedCoreUtility { #region CreateEntLong @@ -70,42 +70,70 @@ namespace DCFApixels.DragonECS.UncheckedCore } #endregion } +} - public readonly struct EntitiesMatrix +namespace DCFApixels.DragonECS.Core.Unchecked +{ + public static class UncheckedUtility { - private readonly EcsWorld _world; - public EntitiesMatrix(EcsWorld world) + #region CreateEntLong + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static entlong CreateEntLong(int entityID, short gen, short worldID) { - _world = world; + return new entlong(entityID, gen, worldID); } - public int PoolsCount + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static entlong CreateEntLong(long entityGenWorld) { - get { return _world.PoolsCount; } + return new entlong(entityGenWorld); } - public int EntitesCount + #endregion + + #region CreateSpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsSpan CreateSpan(short worldID, ReadOnlySpan entitesArray) { - get { return _world.Capacity; } + return new EcsSpan(worldID, entitesArray); } - public int GetEntityComponentsCount(int entityID) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int startIndex, int length) { - return _world.GetComponentsCount(entityID); + return new EcsSpan(worldID, entitesArray, startIndex, length); } - public int GetEntityGen(int entityID) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int length) { - return _world.GetGen(entityID); + return new EcsSpan(worldID, entitesArray, length); } - public bool IsEntityUsed(int entityID) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsSpan CreateSpan(short worldID, int[] entitesArray) { - return _world.IsUsed(entityID); + return new EcsSpan(worldID, entitesArray); } - public bool this[int entityID, int poolID] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsSpan CreateEmptySpan(short worldID) { - get + return new EcsSpan(worldID, Array.Empty()); + } + public static bool CheckSpanValideDebug(EcsSpan span) + { + HashSet set = new HashSet(); + foreach (var e in span) { - int entityStartChunkIndex = entityID << _world._entityComponentMaskLengthBitShift; - var chunkInfo = EcsMaskChunck.FromID(poolID); - return (_world._entityComponentMasks[entityStartChunkIndex + chunkInfo.chunkIndex] & chunkInfo.mask) != 0; + if (set.Add(e) == false) + { + return false; + } } + return true; } + #endregion + + #region EcsGroup + public static EcsGroup GetSourceInstance(EcsReadonlyGroup group) + { + return group.GetSource_Internal(); + } + #endregion } } \ No newline at end of file diff --git a/src/Utils/UncheckedCoreUtility.cs.meta b/src/Utils/Uncheked/UncheckedUtility.cs.meta similarity index 100% rename from src/Utils/UncheckedCoreUtility.cs.meta rename to src/Utils/Uncheked/UncheckedUtility.cs.meta diff --git a/src/entlong.cs b/src/entlong.cs index 7458d31..4ed3662 100644 --- a/src/entlong.cs +++ b/src/entlong.cs @@ -3,9 +3,9 @@ #endif #pragma warning disable IDE1006 #pragma warning disable CS8981 +using DCFApixels.DragonECS.Core.Unchecked; using DCFApixels.DragonECS.Internal; using System; -using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -54,6 +54,11 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _full == 0L; } } + public bool IsDeadOrNull + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return IsAlive == false; } + } public int ID { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -370,154 +375,20 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(long other) { return _full == other; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int CompareTo(entlong other) + public int CompareTo(entlong other) { return Compare(_id, other._id); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Compare(entlong left, entlong right) { return left.CompareTo(right); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int Compare(int left, int right) { // NOTE: Because _id cannot be less than 0, // the case “_id - other._id > MaxValue” is impossible. - return _id - other._id; + return left - right; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int Compare(entlong left, entlong right) { return left.CompareTo(right); } - - internal class DebuggerProxy + internal class DebuggerProxy : EntityDebuggerProxy { - private List _componentsList = new List(); - private entlong _value; - public long full { get { return _value._full; } } - public int id { get { return _value._id; } } - public short gen { get { return _value._gen; } } - public short world { get { return _value._world; } } - public EntState State { get { return _value.IsNull ? EntState.Null : _value.IsAlive ? EntState.Alive : EntState.Dead; } } - public EcsWorld EcsWorld { get { return EcsWorld.GetWorld(world); } } - public IEnumerable components - { - get - { - _value.World.GetComponentsFor(_value.ID, _componentsList); - return _componentsList; - } - } - public DebuggerProxy(entlong value) - { - _value = value; - } - public DebuggerProxy(EntitySlotInfo value) - { - _value = new entlong(value.id, value.gen, value.world); - } - public enum EntState { Null, Dead, Alive, } - } - #endregion - } -} - -namespace DCFApixels.DragonECS -{ - [DebuggerTypeProxy(typeof(DebuggerProxy))] - public readonly struct EntitySlotInfo : IEquatable - { - private readonly long _full; - public readonly int id; - public readonly short gen; - public readonly short world; - - #region Properties - private EcsWorld World { get { return EcsWorld.GetWorld(world); } } - private EntState State { get { return _full == 0 ? EntState.Null : World.IsAlive(id, gen) ? EntState.Alive : EntState.Dead; } } - - #endregion - - #region Constructors - public EntitySlotInfo(long full) - { - unchecked - { - ulong ufull = (ulong)full; - id = (int)((ufull >> 0) & 0x0000_0000_FFFF_FFFF); - gen = (short)((ufull >> 32) & 0x0000_0000_0000_FFFF); - world = (short)((ufull >> 48) & 0x0000_0000_0000_FFFF); - _full = full; - } - } - public EntitySlotInfo(int id, short gen, short world) - { - this.id = id; - this.gen = gen; - this.world = world; - _full = ((long)world << 48 | (long)gen << 32 | (long)id); - } - #endregion - - #region Operators - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(EntitySlotInfo a, EntitySlotInfo b) - { - return a.id == b.id && - a.gen == b.gen && - a.world == b.world; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(EntitySlotInfo a, EntitySlotInfo b) - { - return a.id != b.id || - a.gen != b.gen || - a.world != b.world; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static explicit operator EntitySlotInfo(entlong a) { return new EntitySlotInfo(a._full); } - #endregion - - #region Other - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() { return unchecked(id ^ gen ^ (world * EcsConsts.MAGIC_PRIME)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override string ToString() { return $"slot(id:{id} g:{gen} w:{world} {(State == EntState.Null ? "null" : State == EntState.Alive ? "alive" : "not alive")})"; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object obj) { return obj is EntitySlotInfo other && this == other; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(EntitySlotInfo other) { return this == other; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Deconstruct(out int id, out int gen, out int world) - { - id = this.id; - gen = this.gen; - world = this.world; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Deconstruct(out int id, out int world) - { - id = this.id; - world = this.world; - } - public enum EntState { Null, Dead, Alive, } - internal class DebuggerProxy - { - private List _componentsList = new List(); - private EntitySlotInfo _source; - public long full { get { return _source._full; } } - public int id { get { return _source.id; } } - public short gen { get { return _source.gen; } } - public short world { get { return _source.world; } } - public EntState State { get { return _source.State; } } - public EcsWorld World { get { return _source.World; } } - public IEnumerable Components - { - get - { - if (State == EntState.Alive) - { - World.GetComponentsFor(id, _componentsList); - return _componentsList; - } - return Array.Empty(); - } - } - public DebuggerProxy(EntitySlotInfo value) - { - _source = value; - } + public DebuggerProxy(entlong entity) : base(entity._id, entity._gen, entity._world) { } } #endregion }