diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 40a345a..06923d2 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -189,11 +189,8 @@ namespace DCFApixels.DragonECS #endregion #region Entity - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsSpan ToSpan() - { - return _entityDispenser.UsedToEcsSpan(id); - } + + #region New/Del [MethodImpl(MethodImplOptions.AggressiveInlining)] public int NewEntity() { @@ -201,15 +198,37 @@ namespace DCFApixels.DragonECS int entityID = _entityDispenser.UseFree(); _entitiesCount++; - if (_gens.Length <= entityID) + if (_entitesCapacity <= entityID) { Upsize_Internal(_gens.Length << 1); } - _gens[entityID] &= GEN_BITS; + _gens[entityID] &= GEN_MASK; _entityListeners.InvokeOnNewEntity(entityID); return entityID; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void NewEntity(int entityID) + { +#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS + if (IsUsed(entityID)) + { + Throw.World_EntityIsAlreadyСontained(entityID); + } +#endif + unchecked { _version++; } + _entityDispenser.Use(entityID); + _entitiesCount++; + + if (_entitesCapacity <= entityID) + { + Upsize_Internal(_gens.Length << 1); + } + + _gens[entityID] &= GEN_MASK; + _entityListeners.InvokeOnNewEntity(entityID); + } + public entlong NewEntityLong() { int e = NewEntity(); @@ -238,6 +257,14 @@ namespace DCFApixels.DragonECS _entitiesCount--; _entityListeners.InvokeOnDelEntity(entityID); } + #endregion + + #region Other + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan ToSpan() + { + return _entityDispenser.UsedToEcsSpan(id); + } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe entlong GetEntityLong(int entityID) { @@ -282,6 +309,11 @@ namespace DCFApixels.DragonECS } } } + //public void Densify() + //{ + // _entityDispenser.Sort(); + //} + #endregion #region Copy/Clone public void CopyEntity(int fromEntityID, int toEntityID) @@ -374,6 +406,7 @@ namespace DCFApixels.DragonECS unchecked { _gens[e]++; }//up gen _gens[e] |= DEATH_GEN_BIT; } + _entityDispenser.Sort(); //уплотнение свободных айдишников } #endregion diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 0cad189..3789982 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -16,7 +16,7 @@ namespace DCFApixels.DragonECS } public abstract partial class EcsWorld { - private const short GEN_BITS = 0x7fff; + private const short GEN_MASK = 0x7fff; private const short DEATH_GEN_BIT = short.MinValue; private const int DEL_ENT_BUFFER_SIZE_OFFSET = 5; private const int DEL_ENT_BUFFER_MIN_SIZE = 64; diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index a5558e2..f1fce0f 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -83,7 +83,11 @@ namespace DCFApixels.DragonECS.Internal { throw new EcsFrameworkException($"An entity with identifier {entityID} is not contained in this world"); } - + [MethodImpl(MethodImplOptions.NoInlining)] + public static void World_EntityIsAlreadyСontained(int entityID) + { + throw new EcsFrameworkException($"An entity with identifier {entityID} is already contained in this world"); + } [MethodImpl(MethodImplOptions.NoInlining)] internal static void Ent_ThrowIsNotAlive(entlong entity) @@ -109,7 +113,6 @@ namespace DCFApixels.DragonECS public EcsFrameworkException() { } public EcsFrameworkException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } public EcsFrameworkException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } - protected EcsFrameworkException(SerializationInfo info, StreamingContext context) : base(info, context) { } } [Serializable] public class EcsRunnerImplementationException : EcsFrameworkException @@ -117,6 +120,5 @@ namespace DCFApixels.DragonECS public EcsRunnerImplementationException() { } public EcsRunnerImplementationException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } public EcsRunnerImplementationException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } - protected EcsRunnerImplementationException(SerializationInfo info, StreamingContext context) : base(info, context) { } } } diff --git a/src/Utils/IdDispenser.cs b/src/Utils/IdDispenser.cs index 5e0b476..470e10c 100644 --- a/src/Utils/IdDispenser.cs +++ b/src/Utils/IdDispenser.cs @@ -13,14 +13,13 @@ namespace DCFApixels.DragonECS.Utils { private const int FREE_FLAG_BIT = ~INDEX_MASK; private const int INDEX_MASK = 0x7FFF_FFFF; - private const int MIN_SIZE = 4; private int[] _dense = Array.Empty(); private int[] _sparse = Array.Empty(); //hibit free flag - private int _usedCount; //[|uuuu| ] - private int _size; //[|uuuu|ffffff] + private int _usedCount; //[uuuu| ] + private int _size; //[uuuu|ffffff] private int _nullID; @@ -312,27 +311,6 @@ namespace DCFApixels.DragonECS.Utils } #endregion - #region Spans - 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, 0, _instance._usedCount); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } - public readonly struct FreeSpan : IEnumerable - { - private readonly IdDispenser _instance; - public int Count => _instance._size - _instance._usedCount; - internal FreeSpan(IdDispenser instance) => _instance = instance; - public Enumerator GetEnumerator() => new Enumerator(_instance._dense, _instance._usedCount, Count); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } - #endregion - #region Utils private enum IDState : byte { @@ -340,7 +318,6 @@ namespace DCFApixels.DragonECS.Utils Reserved = 1, Used = 2, } - private static class ThrowHalper { [MethodImpl(MethodImplOptions.NoInlining)] @@ -361,7 +338,7 @@ namespace DCFApixels.DragonECS.Utils public static void UndefinedException() { throw new Exception(); } } - internal class DebuggerProxy + private class DebuggerProxy { private IdDispenser _target; public DebuggerProxy(IdDispenser dispenser) @@ -370,6 +347,7 @@ namespace DCFApixels.DragonECS.Utils } #if DEBUG public ReadOnlySpan Used => new ReadOnlySpan(_target._dense, 0, _target._usedCount); + public ReadOnlySpan Free => new ReadOnlySpan(_target._dense, _target._usedCount, _target._size - _target._usedCount); public Pair[] Pairs { get