From ce6fdfa33ad07801e72df46a6ed0eb3c61a0cfd5 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Mon, 4 Nov 2024 07:36:42 +0800 Subject: [PATCH] add debug locking of pools --- src/EcsWorld.pools.cs | 49 ++++++++++++++++++++++++++++++++++++++++ src/Pools/EcsPool.cs | 16 +++++++++++-- src/Pools/EcsPoolBase.cs | 7 +++++- src/Pools/EcsTagPool.cs | 7 ++++++ 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index f4ac365..1274411 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -13,6 +13,7 @@ namespace DCFApixels.DragonECS private int _poolsCount; internal IEcsPoolImplementation[] _pools; internal PoolSlot[] _poolSlots; + private int _lockedPoolCount = 0; private readonly PoolsMediator _poolsMediator; @@ -360,11 +361,59 @@ namespace DCFApixels.DragonECS } #endregion + #region LockPool/UnLockPool + public void LockPool_Debug(int ComponentTypeID) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + ref var slot = ref _poolSlots[ComponentTypeID]; + if (slot.locked == false) + { + slot.locked = true; + if (_lockedPoolCount == 0) + { + ReleaseDelEntityBufferAll(); + } + _lockedPoolCount++; + _pools[ComponentTypeID].OnLockedChanged_Debug(true); + } +#endif + } + public void UnlockPool_Debug(int ComponentTypeID) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + ref var slot = ref _poolSlots[ComponentTypeID]; + if (slot.locked == true) + { + slot.locked = false; + _lockedPoolCount--; + + if (_lockedPoolCount < 0) + { + _lockedPoolCount = 0; + Throw.UndefinedException(); + } + _pools[ComponentTypeID].OnLockedChanged_Debug(false); + } +#endif + } + public bool CheckPoolLocked_Debug(int ComponentTypeID) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + return _poolSlots[ComponentTypeID].locked; +#else + return false; +#endif + } + #endregion + #region PoolSlot internal struct PoolSlot { public int count; public long version; +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + public bool locked; +#endif } #endregion } diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index fc18147..598b8c2 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -47,6 +47,7 @@ namespace DCFApixels.DragonECS private readonly List _listeners = new List(); private int _listenersCachedCount = 0; #endif + private bool _isLocked; private EcsWorld.PoolsMediator _mediator; @@ -83,6 +84,7 @@ namespace DCFApixels.DragonECS ref int itemIndex = ref _mapping[entityID]; #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (itemIndex > 0) { EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID); } + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } #endif if (_recycledItemsCount > 0) { @@ -127,7 +129,10 @@ namespace DCFApixels.DragonECS { ref int itemIndex = ref _mapping[entityID]; if (itemIndex <= 0) - { + { //Add block +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } +#endif if (_recycledItemsCount > 0) { itemIndex = _recycledItems[--_recycledItemsCount]; @@ -146,7 +151,7 @@ namespace DCFApixels.DragonECS #if !DISABLE_POOLS_EVENTS _listeners.InvokeOnAdd(entityID, _listenersCachedCount); #endif - } + } //Add block end #if !DISABLE_POOLS_EVENTS _listeners.InvokeOnGet(entityID, _listenersCachedCount); #endif @@ -159,6 +164,9 @@ namespace DCFApixels.DragonECS } public void Del(int entityID) { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } +#endif ref int itemIndex = ref _mapping[entityID]; #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (itemIndex <= 0) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } @@ -200,6 +208,9 @@ namespace DCFApixels.DragonECS public void ClearAll() { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } +#endif var span = _source.Where(out SingleAspect> _); _itemsCount = 0; _recycledItemsCount = 0; @@ -244,6 +255,7 @@ namespace DCFApixels.DragonECS TryDel(entityID); } } + void IEcsPoolImplementation.OnLockedChanged_Debug(bool locked) { _isLocked = locked; } #endregion #region Other diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs index 9b72577..f2ac2dc 100644 --- a/src/Pools/EcsPoolBase.cs +++ b/src/Pools/EcsPoolBase.cs @@ -14,6 +14,7 @@ namespace DCFApixels.DragonECS.PoolsCore void OnWorldResize(int newSize); void OnReleaseDelEntityBuffer(ReadOnlySpan buffer); void OnWorldDestroy(); + void OnLockedChanged_Debug(bool locked); #endregion } @@ -43,6 +44,10 @@ namespace DCFApixels.DragonECS.PoolsCore { throw new ArgumentNullException("listener is null"); } + public static void ThrowPoolLocked() + { + throw new EcsFrameworkException("The pool is currently locked and cannot add or remove components."); + } } } @@ -56,7 +61,6 @@ namespace DCFApixels.DragonECS.Internal public sealed class EcsNullPool : IEcsPoolImplementation { public static readonly EcsNullPool instance = new EcsNullPool(); - #region Properties int IEcsReadonlyPool.ComponentTypeID { get { return 0; } }//TODO Првоерить что NullComponent всегда имеет id 0 Type IEcsReadonlyPool.ComponentType { get { return typeof(NullComponent); } } @@ -131,6 +135,7 @@ namespace DCFApixels.DragonECS.Internal void IEcsPoolImplementation.OnWorldDestroy() { } void IEcsPoolImplementation.OnWorldResize(int newSize) { } void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { } + void IEcsPoolImplementation.OnLockedChanged_Debug(bool locked) { } #endregion #region Listeners diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs index dc85d32..6c11a48 100644 --- a/src/Pools/EcsTagPool.cs +++ b/src/Pools/EcsTagPool.cs @@ -41,6 +41,7 @@ namespace DCFApixels.DragonECS private List _listeners = new List(); private int _listenersCachedCount = 0; #endif + private bool _isLocked; private T _fakeComponent; private EcsWorld.PoolsMediator _mediator; @@ -92,6 +93,7 @@ namespace DCFApixels.DragonECS { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (Has(entityID)) { EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID); } + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } #endif _count++; _mapping[entityID] = true; @@ -116,6 +118,7 @@ namespace DCFApixels.DragonECS { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } #endif _mapping[entityID] = false; _count--; @@ -174,6 +177,9 @@ namespace DCFApixels.DragonECS public void ClearAll() { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (_isLocked) { EcsPoolThrowHalper.ThrowPoolLocked(); } +#endif var span = _source.Where(out SingleAspect> _); _count = 0; foreach (var entityID in span) @@ -214,6 +220,7 @@ namespace DCFApixels.DragonECS TryDel(entityID); } } + void IEcsPoolImplementation.OnLockedChanged_Debug(bool locked) { _isLocked = locked; } #endregion #region Other