polishing pools

This commit is contained in:
Mikhail 2024-02-24 02:26:42 +08:00
parent efed7dcdbd
commit c3ece37bf5
4 changed files with 120 additions and 57 deletions

View File

@ -30,11 +30,26 @@ namespace DCFApixels.DragonECS
private EcsWorld.PoolsMediator _mediator; private EcsWorld.PoolsMediator _mediator;
#region Properites #region Properites
public int Count => _itemsCount; public int Count
public int Capacity => _items.Length; {
public int ComponentID => _componentTypeID; get { return _itemsCount; }
public Type ComponentType => typeof(T); }
public EcsWorld World => _source; 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 #endregion
#region Methods #region Methods
@ -42,7 +57,7 @@ namespace DCFApixels.DragonECS
{ {
ref int itemIndex = ref _mapping[entityID]; ref int itemIndex = ref _mapping[entityID];
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (itemIndex > 0) EcsPoolThrowHalper.ThrowAlreadyHasComponent<T>(entityID); if (itemIndex > 0) { EcsPoolThrowHalper.ThrowAlreadyHasComponent<T>(entityID); }
#endif #endif
if (_recycledItemsCount > 0) if (_recycledItemsCount > 0)
{ {
@ -53,7 +68,9 @@ namespace DCFApixels.DragonECS
{ {
itemIndex = ++_itemsCount; itemIndex = ++_itemsCount;
if (itemIndex >= _items.Length) if (itemIndex >= _items.Length)
{
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
}
} }
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAddAndGet(entityID); _listeners.InvokeOnAddAndGet(entityID);
@ -64,7 +81,7 @@ namespace DCFApixels.DragonECS
public ref T Get(int entityID) public ref T Get(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
_listeners.InvokeOnGet(entityID); _listeners.InvokeOnGet(entityID);
return ref _items[_mapping[entityID]]; return ref _items[_mapping[entityID]];
@ -73,7 +90,7 @@ namespace DCFApixels.DragonECS
public ref readonly T Read(int entityID) public ref readonly T Read(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
return ref _items[_mapping[entityID]]; return ref _items[_mapping[entityID]];
} }
@ -91,7 +108,9 @@ namespace DCFApixels.DragonECS
{ {
itemIndex = ++_itemsCount; itemIndex = ++_itemsCount;
if (itemIndex >= _items.Length) if (itemIndex >= _items.Length)
{
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
}
} }
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit); _mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
@ -107,36 +126,39 @@ namespace DCFApixels.DragonECS
} }
public void Del(int entityID) public void Del(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID);
#endif
ref int itemIndex = ref _mapping[entityID]; ref int itemIndex = ref _mapping[entityID];
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (itemIndex <= 0) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif
ResetComponent(ref _items[itemIndex]); ResetComponent(ref _items[itemIndex]);
if (_recycledItemsCount >= _recycledItems.Length) if (_recycledItemsCount >= _recycledItems.Length)
{ {
Array.Resize(ref _recycledItems, _recycledItems.Length << 1); Array.Resize(ref _recycledItems, _recycledItems.Length << 1);
} }
_recycledItems[_recycledItemsCount++] = itemIndex; _recycledItems[_recycledItemsCount++] = itemIndex;
_mapping[entityID] = 0; itemIndex = 0;
_itemsCount--; _itemsCount--;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit); _mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void TryDel(int entityID) public void TryDel(int entityID)
{ {
if (Has(entityID)) Del(entityID); if (Has(entityID))
{
Del(entityID);
}
} }
public void Copy(int fromEntityID, int toEntityID) public void Copy(int fromEntityID, int toEntityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); }
#endif #endif
CopyComponent(ref Get(fromEntityID), ref TryAddOrGet(toEntityID)); CopyComponent(ref Get(fromEntityID), ref TryAddOrGet(toEntityID));
} }
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); }
#endif #endif
CopyComponent(ref Get(fromEntityID), ref toWorld.GetPool<T>().TryAddOrGet(toEntityID)); CopyComponent(ref Get(fromEntityID), ref toWorld.GetPool<T>().TryAddOrGet(toEntityID));
} }
@ -171,11 +193,9 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region Other #region Other
void IEcsPool.AddRaw(int entityID, object dataRaw) => Add(entityID) = (T)dataRaw; void IEcsPool.AddRaw(int entityID, object dataRaw) { Add(entityID) = (T)dataRaw; }
object IEcsPool.GetRaw(int entityID) => Read(entityID); object IEcsPool.GetRaw(int entityID) { return Get(entityID); }
void IEcsPool.SetRaw(int entityID, object dataRaw) => Get(entityID) = (T)dataRaw; void IEcsPool.SetRaw(int entityID, object dataRaw) { Get(entityID) = (T)dataRaw; }
ref readonly T IEcsStructPool<T>.Read(int entityID) => ref Read(entityID);
ref T IEcsStructPool<T>.Get(int entityID) => ref Get(entityID);
#endregion #endregion
#region Listeners #region Listeners
@ -219,8 +239,8 @@ namespace DCFApixels.DragonECS
#endregion #endregion
#region IEnumerator - IntelliSense hack #region IEnumerator - IntelliSense hack
IEnumerator<T> IEnumerable<T>.GetEnumerator() => throw new NotImplementedException(); IEnumerator<T> IEnumerable<T>.GetEnumerator() { throw new NotImplementedException(); }
IEnumerator IEnumerable.GetEnumerator() => throw new NotImplementedException(); IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
#endregion #endregion
} }
/// <summary>Standard component</summary> /// <summary>Standard component</summary>

View File

@ -12,7 +12,7 @@ namespace DCFApixels.DragonECS
Type ComponentType { get; } Type ComponentType { get; }
EcsWorld World { get; } EcsWorld World { get; }
int Count { get; } int Count { get; }
int Capacity { get; } int Capacity { get; } //TODO удалить. не во всех реализация нужен, проще привести к типу
#endregion #endregion
#region Methods #region Methods
@ -30,18 +30,21 @@ namespace DCFApixels.DragonECS
void RemoveListener(IEcsPoolEventListener listener); void RemoveListener(IEcsPoolEventListener listener);
#endregion #endregion
} }
public interface IEcsStructPool<T> : IEcsPool /// <summary>A pool for struct components.</summary>
public interface IEcsStructPool<T> : IEcsPool where T: struct
{ {
ref T Add(int entityID); ref T Add(int entityID);
ref readonly T Read(int entityID); ref readonly T Read(int entityID);
ref T Get(int entityID); ref T Get(int entityID);
} }
public interface IEcsClassPool<T> : IEcsPool /// <summary>A pool for reference components of type T that instantiates components itself.</summary>
public interface IEcsClassPool<T> : IEcsPool where T: class
{ {
T Add(int entityID); T Add(int entityID);
T Get(int entityID); T Get(int entityID);
} }
public interface IEcsHybridPool<T> : IEcsPool /// <summary>A pool for reference components of type T, which does not instantiate components itself but receives components from external sources..</summary>
public interface IEcsHybridPool<T> : IEcsPool where T: class
{ {
void Add(int entityID, T component); void Add(int entityID, T component);
T Get(int entityID); T Get(int entityID);
@ -68,6 +71,14 @@ namespace DCFApixels.DragonECS
{ {
throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName<T>()}."); throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName<T>()}.");
} }
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 public static class IEcsPoolImplementationExtensions
{ {

View File

@ -33,24 +33,41 @@ namespace DCFApixels.DragonECS
public EcsTagPool() public EcsTagPool()
{ {
if (_isInvalidType) if (_isInvalidType)
{
throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data."); throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data.");
}
} }
#endif #endif
#endregion #endregion
#region Properites #region Properites
public int Count => _count; public int Count
int IEcsPool.Capacity => -1; {
public int ComponentID => _componentTypeID; get { return _count; }
public Type ComponentType => typeof(T); }
public EcsWorld World => _source; 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 #endregion
#region Method #region Method
public void Add(int entityID) public void Add(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (Has(entityID)) EcsPoolThrowHalper.ThrowAlreadyHasComponent<T>(entityID); if (Has(entityID)) { EcsPoolThrowHalper.ThrowAlreadyHasComponent<T>(entityID); }
#endif #endif
_count++; _count++;
_mapping[entityID] = true; _mapping[entityID] = true;
@ -59,12 +76,9 @@ namespace DCFApixels.DragonECS
} }
public void TryAdd(int entityID) public void TryAdd(int entityID)
{ {
if (!_mapping[entityID]) if (Has(entityID) == false)
{ {
_count++; Add(entityID);
_mapping[entityID] = true;
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
_listeners.InvokeOnAdd(entityID);
} }
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -75,7 +89,7 @@ namespace DCFApixels.DragonECS
public void Del(int entityID) public void Del(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); if (!Has(entityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
_mapping[entityID] = false; _mapping[entityID] = false;
_count--; _count--;
@ -84,19 +98,22 @@ namespace DCFApixels.DragonECS
} }
public void TryDel(int entityID) public void TryDel(int entityID)
{ {
if (Has(entityID)) Del(entityID); if (Has(entityID))
{
Del(entityID);
}
} }
public void Copy(int fromEntityID, int toEntityID) public void Copy(int fromEntityID, int toEntityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); }
#endif #endif
TryAdd(toEntityID); TryAdd(toEntityID);
} }
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(fromEntityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); if (!Has(fromEntityID)) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(fromEntityID); }
#endif #endif
toWorld.GetPool<T>().TryAdd(toEntityID); toWorld.GetPool<T>().TryAdd(toEntityID);
} }
@ -105,20 +122,28 @@ namespace DCFApixels.DragonECS
if (isHas) if (isHas)
{ {
if (!Has(entityID)) if (!Has(entityID))
{
Add(entityID); Add(entityID);
}
} }
else else
{ {
if (Has(entityID)) if (Has(entityID))
{
Del(entityID); Del(entityID);
}
} }
} }
public void Toggle(int entityID) public void Toggle(int entityID)
{ {
if (Has(entityID)) if (Has(entityID))
{
Del(entityID); Del(entityID);
}
else else
{
Add(entityID); Add(entityID);
}
} }
#endregion #endregion
@ -142,11 +167,27 @@ namespace DCFApixels.DragonECS
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer)
{ {
foreach (var entityID in buffer) foreach (var entityID in buffer)
{
TryDel(entityID); TryDel(entityID);
}
} }
#endregion #endregion
#region Other #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<T>(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<T>(entityID); }
#endif
}
ref T IEcsStructPool<T>.Add(int entityID) ref T IEcsStructPool<T>.Add(int entityID)
{ {
Add(entityID); Add(entityID);
@ -155,31 +196,17 @@ namespace DCFApixels.DragonECS
ref readonly T IEcsStructPool<T>.Read(int entityID) ref readonly T IEcsStructPool<T>.Read(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); if (Has(entityID) == false) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
return ref _fakeComponent; return ref _fakeComponent;
} }
ref T IEcsStructPool<T>.Get(int entityID) ref T IEcsStructPool<T>.Get(int entityID)
{ {
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); if (Has(entityID) == false) { EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID); }
#endif #endif
return ref _fakeComponent; 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<T>(entityID);
#endif
return _fakeComponent;
}
void IEcsPool.SetRaw(int entityID, object dataRaw)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (!Has(entityID)) EcsPoolThrowHalper.ThrowNotHaveComponent<T>(entityID);
#endif
}
#endregion #endregion
#region Listeners #region Listeners

View File

@ -123,6 +123,11 @@ namespace DCFApixels.DragonECS.Internal
{ {
throw new Exception(); throw new Exception();
} }
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void Exception(string message)
{
throw new Exception(message);
}
} }
} }