diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index a07e9ab..fa2cae6 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -65,6 +65,8 @@ namespace DCFApixels.DragonECS private int[] _delEntBuffer = Array.Empty(); private int _delEntBufferCount = 0; + private int[] _emptyEntities = Array.Empty(); + private int _emptyEntitiesCount = 0; private bool _isEnableAutoReleaseDelEntBuffer = true; internal int _entityComponentMaskLength; @@ -384,6 +386,7 @@ namespace DCFApixels.DragonECS slot.gen |= GEN_SLEEP_MASK; } _entityListeners.InvokeOnNewEntity(entityID); + MoveToEmptyEntities(entityID); } @@ -416,7 +419,7 @@ namespace DCFApixels.DragonECS public void DelEntity(int entityID) { #if DEBUG - if (IsUsed(entityID) == false) { Throw.World_EntityIsAlreadyСontained(entityID); } + if (IsUsed(entityID) == false) { Throw.World_EntityIsNotContained(entityID); } #elif DRAGONECS_STABILITY_MODE if (IsUsed(entityID) == false) { return; } #endif @@ -426,6 +429,24 @@ namespace DCFApixels.DragonECS _entitiesCount--; _entityListeners.InvokeOnDelEntity(entityID); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveToEmptyEntities(int entityID) + { + _emptyEntities[_emptyEntitiesCount++] = entityID; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool RemoveFromEmptyEntities(int entityID) + { + for (int i = _emptyEntitiesCount - 1; i >= 0; i--) + { + if(_emptyEntities[i] == entityID) + { + _emptyEntities[i] = _emptyEntities[--_emptyEntitiesCount]; + return true; + } + } + return false; + } #endregion #region Other @@ -821,13 +842,24 @@ namespace DCFApixels.DragonECS } public void ReleaseDelEntityBufferAll() { - ReleaseDelEntityBuffer(_delEntBufferCount); + ReleaseDelEntityBuffer(-1); } public unsafe void ReleaseDelEntityBuffer(int count) { - if (_delEntBufferCount <= 0) { return; } + if (_emptyEntitiesCount <= 0 && _delEntBufferCount <= 0) { return; } unchecked { _version++; } + for (int i = 0; i < _emptyEntitiesCount; i++) + { + TryDelEntity(_emptyEntities[i]); + } + _emptyEntitiesCount = 0; + + if(count < 0) + { + count = _delEntBufferCount; + } + count = Math.Max(0, Math.Min(count, _delEntBufferCount)); _delEntBufferCount -= count; int slisedCount = count; @@ -907,6 +939,7 @@ namespace DCFApixels.DragonECS SetEntityComponentMaskLength(CalcEntityComponentMaskLength()); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1; Array.Resize(ref _entities, newSize); Array.Resize(ref _delEntBuffer, newSize); + Array.Resize(ref _emptyEntities, newSize); Array.Resize(ref _entityComponentMasks, newSize * _entityComponentMaskLength); ArrayUtility.Fill(_entities, EntitySlot.Empty, _entitiesCapacity); diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 357b891..d2216d5 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -278,7 +278,11 @@ namespace DCFApixels.DragonECS ref PoolSlot slot = ref _poolSlots[componentTypeID]; slot.count++; slot.version++; - _entities[entityID].componentsCount++; + var count = _entities[entityID].componentsCount++; + if (count == 0 && IsUsed(entityID)) + { + RemoveFromEmptyEntities(entityID); + } _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chunkIndex] |= maskBit.mask; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -293,7 +297,7 @@ namespace DCFApixels.DragonECS if (count == 0 && IsUsed(entityID)) { - DelEntity(entityID); + MoveToEmptyEntities(entityID); } CheckUnregisterValid(count, entityID); } @@ -309,7 +313,11 @@ namespace DCFApixels.DragonECS ref PoolSlot slot = ref _poolSlots[componentTypeID]; slot.count++; slot.version++; - _entities[entityID].componentsCount++; + var count = _entities[entityID].componentsCount++; + if(count == 0 && IsUsed(entityID)) + { + RemoveFromEmptyEntities(entityID); + } return true; } return false; @@ -330,7 +338,7 @@ namespace DCFApixels.DragonECS if (count == 0 && IsUsed(entityID)) { - DelEntity(entityID); + MoveToEmptyEntities(entityID); } CheckUnregisterValid(count, entityID); return true;