From c3ece37bf56e6c532e12eba82a16ad8f257c58ad Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sat, 24 Feb 2024 02:26:42 +0800 Subject: [PATCH] polishing pools --- src/Pools/EcsPool.cs | 64 +++++++++++++++++++---------- src/Pools/EcsPoolBase.cs | 19 +++++++-- src/Pools/EcsTagPool.cs | 89 ++++++++++++++++++++++++++-------------- src/Utils/Exceptions.cs | 5 +++ 4 files changed, 120 insertions(+), 57 deletions(-) diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index e7c43b7..e8f019c 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -30,11 +30,26 @@ namespace DCFApixels.DragonECS private EcsWorld.PoolsMediator _mediator; #region Properites - public int Count => _itemsCount; - public int Capacity => _items.Length; - public int ComponentID => _componentTypeID; - public Type ComponentType => typeof(T); - public EcsWorld World => _source; + public int Count + { + get { return _itemsCount; } + } + public int Capacity + { + get { return _items.Length; } + } + public int ComponentID + { + get { return _componentTypeID; } + } + public Type ComponentType + { + get { return typeof(T); } + } + public EcsWorld World + { + get { return _source; } + } #endregion #region Methods @@ -42,7 +57,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 (itemIndex > 0) { EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID); } #endif if (_recycledItemsCount > 0) { @@ -53,7 +68,9 @@ namespace DCFApixels.DragonECS { itemIndex = ++_itemsCount; if (itemIndex >= _items.Length) + { Array.Resize(ref _items, _items.Length << 1); + } } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnAddAndGet(entityID); @@ -64,7 +81,7 @@ namespace DCFApixels.DragonECS public ref T Get(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); + if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } #endif _listeners.InvokeOnGet(entityID); return ref _items[_mapping[entityID]]; @@ -73,7 +90,7 @@ namespace DCFApixels.DragonECS public ref readonly T Read(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); + if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } #endif return ref _items[_mapping[entityID]]; } @@ -91,7 +108,9 @@ namespace DCFApixels.DragonECS { itemIndex = ++_itemsCount; if (itemIndex >= _items.Length) + { Array.Resize(ref _items, _items.Length << 1); + } } _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnAdd(entityID); @@ -107,36 +126,39 @@ namespace DCFApixels.DragonECS } public void Del(int entityID) { -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); -#endif ref int itemIndex = ref _mapping[entityID]; +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (itemIndex <= 0) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } +#endif ResetComponent(ref _items[itemIndex]); if (_recycledItemsCount >= _recycledItems.Length) { Array.Resize(ref _recycledItems, _recycledItems.Length << 1); } _recycledItems[_recycledItemsCount++] = itemIndex; - _mapping[entityID] = 0; + itemIndex = 0; _itemsCount--; _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); _listeners.InvokeOnDel(entityID); } public void TryDel(int entityID) { - if (Has(entityID)) Del(entityID); + if (Has(entityID)) + { + Del(entityID); + } } public void Copy(int fromEntityID, int toEntityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); + if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); } #endif CopyComponent(ref Get(fromEntityID), ref TryAddOrGet(toEntityID)); } public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); + if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); } #endif CopyComponent(ref Get(fromEntityID), ref toWorld.GetPool().TryAddOrGet(toEntityID)); } @@ -171,11 +193,9 @@ namespace DCFApixels.DragonECS #endregion #region Other - void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID) = (T)dataRaw; - object IEcsPool.GetRaw(int entityID) => Read(entityID); - void IEcsPool.SetRaw(int entityID, object dataRaw) => Get(entityID) = (T)dataRaw; - ref readonly T IEcsStructPool.Read(int entityID) => ref Read(entityID); - ref T IEcsStructPool.Get(int entityID) => ref Get(entityID); + void IEcsPool.AddRaw(int entityID, object dataRaw) { Add(entityID) = (T)dataRaw; } + object IEcsPool.GetRaw(int entityID) { return Get(entityID); } + void IEcsPool.SetRaw(int entityID, object dataRaw) { Get(entityID) = (T)dataRaw; } #endregion #region Listeners @@ -219,8 +239,8 @@ namespace DCFApixels.DragonECS #endregion #region IEnumerator - IntelliSense hack - IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); - IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); + IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } + IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); } #endregion } /// Standard component diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs index b9314d5..97ca510 100644 --- a/src/Pools/EcsPoolBase.cs +++ b/src/Pools/EcsPoolBase.cs @@ -12,7 +12,7 @@ namespace DCFApixels.DragonECS Type ComponentType { get; } EcsWorld World { get; } int Count { get; } - int Capacity { get; } + int Capacity { get; } //TODO удалить. не во всех реализация нужен, проще привести к типу #endregion #region Methods @@ -30,18 +30,21 @@ namespace DCFApixels.DragonECS void RemoveListener(IEcsPoolEventListener listener); #endregion } - public interface IEcsStructPool : IEcsPool + /// A pool for struct components. + public interface IEcsStructPool : IEcsPool where T: struct { ref T Add(int entityID); ref readonly T Read(int entityID); ref T Get(int entityID); } - public interface IEcsClassPool : IEcsPool + /// A pool for reference components of type T that instantiates components itself. + public interface IEcsClassPool : IEcsPool where T: class { T Add(int entityID); T Get(int entityID); } - public interface IEcsHybridPool : IEcsPool + /// A pool for reference components of type T, which does not instantiate components itself but receives components from external sources.. + public interface IEcsHybridPool : IEcsPool where T: class { void Add(int entityID, T component); T Get(int entityID); @@ -68,6 +71,14 @@ namespace DCFApixels.DragonECS { throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName()}."); } + public static void ThrowAlreadyHasComponent(Type type, int entityID) + { + throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName(type)}."); + } + public static void ThrowNotHaveComponent(Type type, int entityID) + { + throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName(type)}."); + } } public static class IEcsPoolImplementationExtensions { diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs index 06f8d47..1a84e92 100644 --- a/src/Pools/EcsTagPool.cs +++ b/src/Pools/EcsTagPool.cs @@ -33,24 +33,41 @@ namespace DCFApixels.DragonECS public EcsTagPool() { if (_isInvalidType) + { throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data."); + } } #endif #endregion #region Properites - public int Count => _count; - int IEcsPool.Capacity => -1; - public int ComponentID => _componentTypeID; - public Type ComponentType => typeof(T); - public EcsWorld World => _source; + public int Count + { + get { return _count; } + } + int IEcsPool.Capacity + { + get { return -1; } + } + public int ComponentID + { + get { return _componentTypeID; } + } + public Type ComponentType + { + get { return typeof(T); } + } + public EcsWorld World + { + get { return _source; } + } #endregion #region Method public void Add(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (Has(entityID)) EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID); + if (Has(entityID)) { EcsPoolThrowHalper.ThrowAlreadyHasComponent(entityID); } #endif _count++; _mapping[entityID] = true; @@ -59,12 +76,9 @@ namespace DCFApixels.DragonECS } public void TryAdd(int entityID) { - if (!_mapping[entityID]) + if (Has(entityID) == false) { - _count++; - _mapping[entityID] = true; - _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); - _listeners.InvokeOnAdd(entityID); + Add(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -75,7 +89,7 @@ namespace DCFApixels.DragonECS public void Del(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); + if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } #endif _mapping[entityID] = false; _count--; @@ -84,19 +98,22 @@ namespace DCFApixels.DragonECS } public void TryDel(int entityID) { - if (Has(entityID)) Del(entityID); + if (Has(entityID)) + { + Del(entityID); + } } public void Copy(int fromEntityID, int toEntityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); + if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); } #endif TryAdd(toEntityID); } public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); + if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent(fromEntityID); } #endif toWorld.GetPool().TryAdd(toEntityID); } @@ -105,20 +122,28 @@ namespace DCFApixels.DragonECS if (isHas) { if (!Has(entityID)) + { Add(entityID); + } } else { if (Has(entityID)) + { Del(entityID); + } } } public void Toggle(int entityID) { if (Has(entityID)) + { Del(entityID); + } else + { Add(entityID); + } } #endregion @@ -142,11 +167,27 @@ namespace DCFApixels.DragonECS void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { foreach (var entityID in buffer) + { TryDel(entityID); + } } #endregion #region Other + void IEcsPool.AddRaw(int entityID, object dataRaw) { Add(entityID); } + object IEcsPool.GetRaw(int entityID) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (Has(entityID) == false) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } +#endif + return _fakeComponent; + } + void IEcsPool.SetRaw(int entityID, object dataRaw) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (Has(entityID) == false) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } +#endif + } ref T IEcsStructPool.Add(int entityID) { Add(entityID); @@ -155,31 +196,17 @@ namespace DCFApixels.DragonECS ref readonly T IEcsStructPool.Read(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); + if (Has(entityID) == false) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } #endif return ref _fakeComponent; } ref T IEcsStructPool.Get(int entityID) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); + if (Has(entityID) == false) { EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); } #endif return ref _fakeComponent; } - void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID); - object IEcsPool.GetRaw(int entityID) - { -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); -#endif - return _fakeComponent; - } - void IEcsPool.SetRaw(int entityID, object dataRaw) - { -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent(entityID); -#endif - } #endregion #region Listeners diff --git a/src/Utils/Exceptions.cs b/src/Utils/Exceptions.cs index 609f6ad..17fea7a 100644 --- a/src/Utils/Exceptions.cs +++ b/src/Utils/Exceptions.cs @@ -123,6 +123,11 @@ namespace DCFApixels.DragonECS.Internal { throw new Exception(); } + [MethodImpl(MethodImplOptions.NoInlining)] + internal static void Exception(string message) + { + throw new Exception(message); + } } }