This commit is contained in:
Mikhail 2026-03-23 15:22:43 +08:00
parent 8e3a2d68c6
commit f1b13c94a7
2 changed files with 144 additions and 91 deletions

View File

@ -43,11 +43,17 @@ namespace DCFApixels.DragonECS
private EcsMaskChunck _maskBit; private EcsMaskChunck _maskBit;
private HMem<int> _dense; private HMem<int> _dense;
private int _denseCount = 0; private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID.
private (int ComponentPosIndex, int EntityPosIndex)[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID. private (T Cmp, int EntityID)[] _items; // dense; _items[0] - fake component.
private T[] _items; // dense; _items[0] - fake component.
private int _itemsCount = 0; private int _itemsCount = 0;
private int _recycledItemsCount; private int _recycledItemsCount;
private int _usedBlockCount;
private struct Slot
{
public T Cmp;
public int EntityID;
}
private readonly IEcsComponentLifecycle<T> _customLifecycle = EcsComponentLifecycle<T>.CustomHandler; private readonly IEcsComponentLifecycle<T> _customLifecycle = EcsComponentLifecycle<T>.CustomHandler;
private readonly bool _isCustomLifecycle = EcsComponentLifecycle<T>.IsCustom; private readonly bool _isCustomLifecycle = EcsComponentLifecycle<T>.IsCustom;
@ -103,7 +109,7 @@ namespace DCFApixels.DragonECS
{ {
recycledCapacity = capacity / 2; recycledCapacity = capacity / 2;
} }
_items = new T[capacity]; _items = new (T, int)[capacity];
//_dense = new int[capacity]; //_dense = new int[capacity];
_dense = Alloc<int>(capacity); _dense = Alloc<int>(capacity);
} }
@ -115,11 +121,11 @@ namespace DCFApixels.DragonECS
_componentTypeID = componentTypeID; _componentTypeID = componentTypeID;
_maskBit = EcsMaskChunck.FromID(componentTypeID); _maskBit = EcsMaskChunck.FromID(componentTypeID);
_mapping = new (int,int)[world.Capacity]; _mapping = new int[world.Capacity];
var worldConfig = world.Configs.GetWorldConfigOrDefault(); var worldConfig = world.Configs.GetWorldConfigOrDefault();
if (_items == null) if (_items == null)
{ {
_items = new T[ArrayUtility.CeilPow2Safe(worldConfig.PoolComponentsCapacity)]; _items = new (T, int)[ArrayUtility.CeilPow2Safe(worldConfig.PoolComponentsCapacity)];
//_dense = new int[ArrayUtility.CeilPow2Safe(worldConfig.PoolComponentsCapacity)]; //_dense = new int[ArrayUtility.CeilPow2Safe(worldConfig.PoolComponentsCapacity)];
_dense = Alloc<int>(ArrayUtility.CeilPow2Safe(worldConfig.PoolComponentsCapacity)); _dense = Alloc<int>(ArrayUtility.CeilPow2Safe(worldConfig.PoolComponentsCapacity));
} }
@ -134,7 +140,7 @@ namespace DCFApixels.DragonECS
#if DEBUG #if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (_world.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (_world.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (mappingSlot.ComponentPosIndex > 0) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); } if (mappingSlot > 0) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE #elif DRAGONECS_STABILITY_MODE
if (itemIndex > 0) { return ref Get(entityID); } if (itemIndex > 0) { return ref Get(entityID); }
@ -142,31 +148,32 @@ namespace DCFApixels.DragonECS
#endif #endif
if (_recycledItemsCount > 0) if (_recycledItemsCount > 0)
{ {
//mappingSlot.ComponentPosIndex = _recycledItems[--_recycledItemsCount]; //mappingSlot = _recycledItems[--_recycledItemsCount];
//mappingSlot.ComponentPosIndex = _dense[_dense.Length - _recycledItemsCount] & int.MaxValue; //mappingSlot = _dense[_dense.Length - _recycledItemsCount] & int.MaxValue;
mappingSlot.ComponentPosIndex = _dense.Ptr[_denseCount]; mappingSlot = _dense.Ptr[_itemsCount];
_recycledItemsCount--; _recycledItemsCount--;
_itemsCount++;
} }
else else
{ {
mappingSlot.ComponentPosIndex = ++_itemsCount; mappingSlot = _itemsCount + 1;
if (mappingSlot.ComponentPosIndex >= _items.Length) if (mappingSlot >= _items.Length)
{ {
Array.Resize(ref _items, ArrayUtility.NextPow2(mappingSlot.ComponentPosIndex)); Array.Resize(ref _items, ArrayUtility.NextPow2(mappingSlot));
//Array.Resize(ref _dense, ArrayUtility.NextPow2(mappingSlot.ComponentPosIndex)); //Array.Resize(ref _dense, ArrayUtility.NextPow2(mappingSlot));
_dense = Realloc<int>(_dense, ArrayUtility.NextPow2(mappingSlot.ComponentPosIndex)); _dense = Realloc<int>(_dense, ArrayUtility.NextPow2(mappingSlot));
} }
_usedBlockCount++;
} }
mappingSlot.EntityPosIndex = _denseCount; _dense.Ptr[_itemsCount] = entityID;
_dense.Ptr[_denseCount++] = entityID;
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
ref T result = ref _items[mappingSlot.ComponentPosIndex]; ref var slot = ref _items[mappingSlot];
EcsComponentLifecycle<T>.OnAdd(_isCustomLifecycle, _customLifecycle, ref result, _worldID, entityID); slot.EntityID = entityID;
_itemsCount++;
EcsComponentLifecycle<T>.OnAdd(_isCustomLifecycle, _customLifecycle, ref slot.Cmp, _worldID, entityID);
#if !DRAGONECS_DISABLE_POOLS_EVENTS #if !DRAGONECS_DISABLE_POOLS_EVENTS
if (_hasAnyListener) { _listeners.InvokeOnAddAndGet(entityID); } if (_hasAnyListener) { _listeners.InvokeOnAddAndGet(entityID); }
#endif #endif
return ref result; return ref slot.Cmp;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T Get(int entityID) public ref T Get(int entityID)
@ -177,7 +184,7 @@ namespace DCFApixels.DragonECS
#if !DRAGONECS_DISABLE_POOLS_EVENTS #if !DRAGONECS_DISABLE_POOLS_EVENTS
if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); } if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); }
#endif #endif
return ref _items[_mapping[entityID].ComponentPosIndex]; return ref _items[_mapping[entityID]].Cmp;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref readonly T Read(int entityID) public ref readonly T Read(int entityID)
@ -185,89 +192,91 @@ namespace DCFApixels.DragonECS
#if DEBUG // íå íóæåí STAB_MODE #if DEBUG // íå íóæåí STAB_MODE
if (!Has(entityID)) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); } if (!Has(entityID)) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
return ref _items[_mapping[entityID].ComponentPosIndex]; return ref _items[_mapping[entityID]].Cmp;
} }
public ref T TryAddOrGet(int entityID) public ref T TryAddOrGet(int entityID)
{ {
#if DEBUG if (Has(entityID))
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } {
#endif return ref Get(entityID);
ref var mappingSlot = ref _mapping[entityID]; }
if (mappingSlot.ComponentPosIndex <= 0) return ref Add(entityID);
{ //Add block //#if DEBUG
#if DEBUG // if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } //#endif
#elif DRAGONECS_STABILITY_MODE // ref var mappingSlot = ref _mapping[entityID];
if (_isLocked) { return ref _items[0]; } // if (mappingSlot <= 0)
#endif // { //Add block
if (_recycledItemsCount > 0) //#if DEBUG
{ // if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
//mappingSlot.ComponentPosIndex = _dense[_dense.Length - _recycledItemsCount] & int.MaxValue; //#elif DRAGONECS_STABILITY_MODE
mappingSlot.ComponentPosIndex = _dense.Ptr[_denseCount]; // if (_isLocked) { return ref _items[0]; }
_recycledItemsCount--; //#endif
_itemsCount++; // if (_recycledItemsCount > 0)
} // {
else // //mappingSlot = _dense[_dense.Length - _recycledItemsCount] & int.MaxValue;
{ // mappingSlot = _dense.Ptr[_denseCount];
mappingSlot.ComponentPosIndex = ++_itemsCount; // _recycledItemsCount--;
if (mappingSlot.ComponentPosIndex >= _items.Length) // _itemsCount++;
{ // }
Array.Resize(ref _items, ArrayUtility.NextPow2(mappingSlot.ComponentPosIndex)); // else
//Array.Resize(ref _dense, ArrayUtility.NextPow2(mappingSlot.ComponentPosIndex)); // {
_dense = Realloc<int>(_dense, ArrayUtility.NextPow2(mappingSlot.ComponentPosIndex)); // mappingSlot = ++_itemsCount;
} // if (mappingSlot >= _items.Length)
} // {
mappingSlot.EntityPosIndex = _denseCount; // Array.Resize(ref _items, ArrayUtility.NextPow2(mappingSlot));
_dense.Ptr[_denseCount++] = entityID; // //Array.Resize(ref _dense, ArrayUtility.NextPow2(mappingSlot));
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); // _dense = Realloc<int>(_dense, ArrayUtility.NextPow2(mappingSlot));
EcsComponentLifecycle<T>.OnAdd(_isCustomLifecycle, _customLifecycle, ref _items[mappingSlot.ComponentPosIndex], _worldID, entityID); // }
#if !DRAGONECS_DISABLE_POOLS_EVENTS // }
if (_hasAnyListener) { _listeners.InvokeOnAdd(entityID); } // mappingSlot.EntityPosIndex = _denseCount;
#endif // _dense.Ptr[_denseCount++] = entityID;
} //Add block end // _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS // EcsComponentLifecycle<T>.OnAdd(_isCustomLifecycle, _customLifecycle, ref _items[mappingSlot], _worldID, entityID);
if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); } //#if !DRAGONECS_DISABLE_POOLS_EVENTS
#endif // if (_hasAnyListener) { _listeners.InvokeOnAdd(entityID); }
return ref _items[mappingSlot.ComponentPosIndex]; //#endif
// } //Add block end
//#if !DRAGONECS_DISABLE_POOLS_EVENTS
// if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); }
//#endif
// return ref _items[mappingSlot];
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Has(int entityID) public bool Has(int entityID)
{ {
return _mapping[entityID].ComponentPosIndex > 0; return _mapping[entityID] > 0;
} }
public void Del(int entityID) public void Del(int entityID)
{ {
ref var mappingSlot = ref _mapping[entityID]; var mapIndex = _mapping[entityID];
#if DEBUG #if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); } if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (mappingSlot.ComponentPosIndex <= 0) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); } if (mappingSlot <= 0) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); } if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE #elif DRAGONECS_STABILITY_MODE
if (itemIndex <= 0) { return; } if (itemIndex <= 0) { return; }
if (_isLocked) { return; } if (_isLocked) { return; }
#endif #endif
EcsComponentLifecycle<T>.OnDel(_isCustomLifecycle, _customLifecycle, ref _items[mappingSlot.ComponentPosIndex], _worldID, entityID); EcsComponentLifecycle<T>.OnDel(_isCustomLifecycle, _customLifecycle, ref _items[mapIndex].Cmp, _worldID, entityID);
_items[mapIndex].EntityID = 0;
//_dense[_sparse[entityID]] = _dense[_count];
//_sparse[_dense[_count--]] = _sparse[entityID];
//_dense[_mapping[entityID].EntityPosIndex] = _dense[_denseCount];
//_mapping[_dense[_denseCount--]].EntityPosIndex = _mapping[entityID].EntityPosIndex;
//_dense[mappingSlot.EntityPosIndex] = _dense[_denseCount];
//_mapping[_dense[_denseCount--]].EntityPosIndex = mappingSlot.EntityPosIndex;
_dense.Ptr[mappingSlot.EntityPosIndex] = _dense.Ptr[--_denseCount];
_mapping[_dense.Ptr[_denseCount]].EntityPosIndex = mappingSlot.EntityPosIndex;
//_dense[_dense.Length - _recycledItemsCount] = mappingSlot.ComponentPosIndex | int.MinValue;
_dense.Ptr[_denseCount] = mappingSlot.ComponentPosIndex;
_recycledItemsCount++;
mappingSlot.ComponentPosIndex = 0;
_itemsCount--; _itemsCount--;
_dense.Ptr[_itemsCount] = mapIndex;
_mapping[entityID] = 0;
_recycledItemsCount++;
_isDensified = false;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
//if(_itemsCount == 0)
//{
// _itemsCount = 0;
// _usedBlockCount = 0;
// _recycledItemsCount = 0;
// _isDensified = true;
//}
#if !DRAGONECS_DISABLE_POOLS_EVENTS #if !DRAGONECS_DISABLE_POOLS_EVENTS
if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); } if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); }
#endif #endif
@ -311,16 +320,47 @@ namespace DCFApixels.DragonECS
foreach (var entityID in span) foreach (var entityID in span)
{ {
ref var mappingSlot = ref _mapping[entityID]; ref var mappingSlot = ref _mapping[entityID];
EcsComponentLifecycle<T>.OnDel(_isCustomLifecycle, _customLifecycle, ref _items[mappingSlot.ComponentPosIndex], _worldID, entityID); ref var slot = ref _items[mappingSlot];
mappingSlot.ComponentPosIndex = 0; EcsComponentLifecycle<T>.OnDel(_isCustomLifecycle, _customLifecycle, ref slot.Cmp, _worldID, entityID);
slot.EntityID = 0;
mappingSlot = 0;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS #if !DRAGONECS_DISABLE_POOLS_EVENTS
if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); } if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); }
#endif #endif
} }
_denseCount = 0;
_itemsCount = 0; _itemsCount = 0;
_usedBlockCount = 0;
_recycledItemsCount = 0; _recycledItemsCount = 0;
_isDensified = true;
}
private bool _isDensified;
private void Densify()
{
if (_isDensified) { return; }
var newUsedBlockCount = 0;
int denseIndex = 0;
for (int i = 0; i < _usedBlockCount; i++)
{
ref var slot = ref _items[i + 1];
if (slot.EntityID != 0)
{
_dense.Ptr[denseIndex] = slot.EntityID;
denseIndex++;
newUsedBlockCount = i + 1;
}
else
{
_dense.Ptr[denseIndex] = i;
}
}
//if (denseIndex != _itemsCount) { Throw.DeepDebugException(); }
_usedBlockCount = newUsedBlockCount;
_recycledItemsCount = newUsedBlockCount - _itemsCount;
_isDensified = true;
} }
#endregion #endregion
@ -359,7 +399,8 @@ namespace DCFApixels.DragonECS
public EcsSpan ToSpan() public EcsSpan ToSpan()
{ {
return new EcsSpan(_worldID, new ReadOnlySpan<int>(_dense.Ptr, _denseCount)); Densify();
return new EcsSpan(_worldID, new ReadOnlySpan<int>(_dense.Ptr, _itemsCount));
} }
#region Listeners #region Listeners

View File

@ -1,6 +1,12 @@
#if DISABLE_DEBUG #if DISABLE_DEBUG
#undef DEBUG #undef DEBUG
#endif #endif
#if !DRAGONECS_DISABLE_POOLS_EVENTS
#define DRAGONECS_ENABLE_POOLS_EVENTS
#else
#undef DRAGONECS_ENABLE_POOLS_EVENTS
#endif
using DCFApixels.DragonECS.Core.Internal; using DCFApixels.DragonECS.Core.Internal;
using DCFApixels.DragonECS.PoolsCore; using DCFApixels.DragonECS.PoolsCore;
using System; using System;
@ -178,7 +184,7 @@ namespace DCFApixels.DragonECS.Core.Internal
void IEcsReadonlyPool.AddListener(IEcsPoolEventListener listener) { } void IEcsReadonlyPool.AddListener(IEcsPoolEventListener listener) { }
void IEcsReadonlyPool.RemoveListener(IEcsPoolEventListener listener) { } void IEcsReadonlyPool.RemoveListener(IEcsPoolEventListener listener) { }
#endif #endif
#endregion #endregion
} }
public struct NullComponent { } public struct NullComponent { }
} }
@ -291,14 +297,15 @@ namespace DCFApixels.DragonECS
/// <summary>Called after deleting an entity from the pool</summary> /// <summary>Called after deleting an entity from the pool</summary>
void OnDel(int entityID); void OnDel(int entityID);
} }
#if !DRAGONECS_DISABLE_POOLS_EVENTS
public static class PoolEventListExtensions public static class PoolEventListExtensions
{ {
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID) public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID)
{ {
for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); } for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); }
} }
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID) public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID)
{ {
@ -308,11 +315,13 @@ namespace DCFApixels.DragonECS
self[i].OnGet(entityID); self[i].OnGet(entityID);
} }
} }
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID) public static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID)
{ {
for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); } for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); }
} }
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID) public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID)
{ {
@ -322,11 +331,13 @@ namespace DCFApixels.DragonECS
// //
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAdd(this StructList<IEcsPoolEventListener> self, int entityID) internal static void InvokeOnAdd(this StructList<IEcsPoolEventListener> self, int entityID)
{ {
for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); } for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); }
} }
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAddAndGet(this StructList<IEcsPoolEventListener> self, int entityID) internal static void InvokeOnAddAndGet(this StructList<IEcsPoolEventListener> self, int entityID)
{ {
@ -336,17 +347,18 @@ namespace DCFApixels.DragonECS
self[i].OnGet(entityID); self[i].OnGet(entityID);
} }
} }
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnGet(this StructList<IEcsPoolEventListener> self, int entityID) internal static void InvokeOnGet(this StructList<IEcsPoolEventListener> self, int entityID)
{ {
for (int i = 0; i < self.Count; i++) { self[i].OnGet(entityID); } for (int i = 0; i < self.Count; i++) { self[i].OnGet(entityID); }
} }
[Conditional("DRAGONECS_ENABLE_POOLS_EVENTS")]
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnDel(this StructList<IEcsPoolEventListener> self, int entityID) internal static void InvokeOnDel(this StructList<IEcsPoolEventListener> self, int entityID)
{ {
for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); } for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); }
} }
} }
#endif
#endregion #endregion
} }