DragonECS/src/Pools/EcsPoolBase.cs

368 lines
13 KiB
C#
Raw Normal View History

2023-05-23 01:47:28 +08:00
using DCFApixels.DragonECS.Internal;
using DCFApixels.DragonECS.PoolsCore;
2023-05-23 01:47:28 +08:00
using System;
2024-05-13 20:41:07 +08:00
using System.Collections.Generic;
2024-12-03 16:59:32 +08:00
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS.PoolsCore
{
2025-01-06 10:48:39 +08:00
/// <summary> Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>. </summary>
public interface IEcsPoolImplementation : IEcsPool
{
#region Methods
void OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID);
void OnWorldResize(int newSize);
void OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer);
void OnWorldDestroy();
2024-11-04 07:36:42 +08:00
void OnLockedChanged_Debug(bool locked);
#endregion
}
2024-06-13 18:04:18 +08:00
2025-01-06 10:48:39 +08:00
/// <summary> Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>. </summary>
/// <typeparam name="T"> Component type. </typeparam>
public interface IEcsPoolImplementation<T> : IEcsPoolImplementation { }
2025-01-06 10:48:39 +08:00
#region EcsPoolThrowHelper
2024-11-05 15:56:46 +08:00
public static class EcsPoolThrowHelper
{
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowDifferentTypes()
{
throw new EcsFrameworkException($"The component instance type and the pool component type are different.");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowAlreadyHasComponent<T>(int entityID)
{
2023-06-26 02:53:55 +08:00
throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName<T>()}.");
}
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNotHaveComponent<T>(int entityID)
{
2023-06-26 02:53:55 +08:00
throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName<T>()}.");
}
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.NoInlining)]
2024-02-24 02:26:42 +08:00
public static void ThrowAlreadyHasComponent(Type type, int entityID)
{
throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName(type)}.");
}
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.NoInlining)]
2024-02-24 02:26:42 +08:00
public static void ThrowNotHaveComponent(Type type, int entityID)
{
throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName(type)}.");
}
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.NoInlining)]
2024-04-28 18:36:24 +08:00
public static void ThrowNullListener()
{
throw new ArgumentNullException("listener is null");
}
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.NoInlining)]
2024-11-04 07:36:42 +08:00
public static void ThrowPoolLocked()
{
throw new EcsFrameworkException("The pool is currently locked and cannot add or remove components.");
}
}
2025-01-06 10:48:39 +08:00
#endregion
}
namespace DCFApixels.DragonECS.Internal
{
2024-06-13 18:04:18 +08:00
[MetaColor(MetaColor.DragonRose)]
[MetaGroup(EcsConsts.PACK_GROUP, EcsConsts.POOLS_GROUP)]
[MetaDescription(EcsConsts.AUTHOR, "A placeholder type, an instance of this type replaces the null ref.")]
[MetaTags(MetaTags.HIDDEN)]
2024-10-12 00:08:12 +08:00
[MetaID("460E547C9201227A4956AC297F67B484")]
2024-12-03 16:59:32 +08:00
[DebuggerDisplay("-")]
public sealed class EcsNullPool : IEcsPoolImplementation<NullComponent>
{
public static readonly EcsNullPool instance = new EcsNullPool();
2025-01-06 10:48:39 +08:00
#region Properties
int IEcsReadonlyPool.ComponentTypeID { get { return 0; } }//TODO Првоерить что NullComponent всегда имеет id 0
Type IEcsReadonlyPool.ComponentType { get { return typeof(NullComponent); } }
EcsWorld IEcsReadonlyPool.World
{
get
2024-03-13 17:41:33 +08:00
{
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 22:18:17 +08:00
#else
return EcsWorld.GetWorld(0);
2024-03-13 17:41:33 +08:00
#endif
}
}
public int Count { get { return 0; } }
public bool IsReadOnly { get { return true; } }
#endregion
#region Methods
bool IEcsReadonlyPool.Has(int index)
{
return false;
}
void IEcsPool.Del(int entityID)
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-11-12 16:31:31 +08:00
#endif
}
void IEcsPool.AddEmpty(int entityID)
{
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 17:41:33 +08:00
#endif
}
void IEcsPool.AddRaw(int entityID, object dataRaw)
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 17:41:33 +08:00
#endif
}
object IEcsReadonlyPool.GetRaw(int entityID)
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 22:18:17 +08:00
#else
2024-11-12 16:31:31 +08:00
return null;
2024-03-13 17:41:33 +08:00
#endif
}
void IEcsPool.SetRaw(int entity, object dataRaw)
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 17:41:33 +08:00
#endif
}
void IEcsReadonlyPool.Copy(int fromEntityID, int toEntityID)
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 17:41:33 +08:00
#endif
}
void IEcsReadonlyPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 17:41:33 +08:00
#endif
}
void IEcsPool.ClearAll()
{
2024-03-13 17:41:33 +08:00
#if (DEBUG && !DISABLE_DEBUG)
throw new NullInstanceException();
2024-03-13 17:41:33 +08:00
#endif
}
#endregion
#region Callbacks
void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID) { }
void IEcsPoolImplementation.OnWorldDestroy() { }
void IEcsPoolImplementation.OnWorldResize(int newSize) { }
void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan<int> buffer) { }
2024-11-04 07:36:42 +08:00
void IEcsPoolImplementation.OnLockedChanged_Debug(bool locked) { }
#endregion
#region Listeners
2024-05-01 17:15:58 +08:00
#if !DISABLE_POOLS_EVENTS
void IEcsReadonlyPool.AddListener(IEcsPoolEventListener listener) { }
void IEcsReadonlyPool.RemoveListener(IEcsPoolEventListener listener) { }
2024-05-01 17:15:58 +08:00
#endif
#endregion
}
2024-06-13 18:04:18 +08:00
public struct NullComponent { }
}
namespace DCFApixels.DragonECS
{
#region Interfaces
2024-06-13 18:04:18 +08:00
public interface IEcsReadonlyPool : IEcsMember
{
#region Properties
int ComponentTypeID { get; }
Type ComponentType { get; }
EcsWorld World { get; }
int Count { get; }
bool IsReadOnly { get; }
#endregion
#region Methods
bool Has(int entityID);
object GetRaw(int entityID);
void Copy(int fromEntityID, int toEntityID);
void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID);
#endregion
2024-05-01 16:58:54 +08:00
#if !DISABLE_POOLS_EVENTS
#region Add/Remove Listeners
void AddListener(IEcsPoolEventListener listener);
void RemoveListener(IEcsPoolEventListener listener);
#endregion
2024-05-01 16:58:54 +08:00
#endif
}
2024-06-13 18:04:18 +08:00
public interface IEcsPool : IEcsReadonlyPool
{
#region Methods
2024-11-12 16:31:31 +08:00
void AddEmpty(int entityID);
void AddRaw(int entityID, object dataRaw);
void SetRaw(int entityID, object dataRaw);
void Del(int entityID);
void ClearAll();
#endregion
}
2024-06-13 18:04:18 +08:00
/// <summary> A pool for struct components. </summary>
public interface IEcsStructPool<T> : IEcsPool where T : struct
{
#region Methods
ref T Add(int entityID);
ref readonly T Read(int entityID);
ref T Get(int entityID);
#endregion
}
2024-06-13 18:04:18 +08:00
/// <summary> A pool for reference components of type T that instantiates components itself. </summary>
public interface IEcsClassPool<T> : IEcsPool where T : class
{
#region Methods
T Add(int entityID);
T Get(int entityID);
#endregion
}
2024-06-13 18:04:18 +08:00
/// <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
{
#region Methods
void Add(int entityID, T component);
T Get(int entityID);
#endregion
}
#endregion
#region Extensions
public static class IEcsPoolImplementationExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNullOrDummy(this IEcsPool self)
{
return self == null || self == EcsNullPool.instance;
}
}
#endregion
2023-05-28 05:53:08 +08:00
#region Callbacks Interface
public interface IEcsPoolEventListener
{
2023-05-30 16:07:45 +08:00
/// <summary>Called after adding an entity to the pool, but before changing values</summary>
2023-05-28 05:53:08 +08:00
void OnAdd(int entityID);
2023-05-30 16:07:45 +08:00
/// <summary>Is called when EcsPool.Get or EcsPool.Add is called, but before changing values</summary>
2023-05-30 16:01:16 +08:00
void OnGet(int entityID);
2023-05-28 05:53:08 +08:00
/// <summary>Called after deleting an entity from the pool</summary>
void OnDel(int entityID);
}
2024-05-01 16:58:54 +08:00
#if !DISABLE_POOLS_EVENTS
public static class PoolEventListExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID)
{
2024-04-27 19:05:05 +08:00
self.InvokeOnAdd(entityID, self.Count);
}
2024-04-27 19:05:05 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
2025-01-06 10:48:39 +08:00
for (int i = 0; i < cachedCount; i++) { self[i].OnAdd(entityID); }
2024-04-27 19:05:05 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-30 16:01:16 +08:00
public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID)
{
2024-04-27 19:05:05 +08:00
self.InvokeOnAddAndGet(entityID, self.Count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++)
{
self[i].OnAdd(entityID);
2023-05-30 16:01:16 +08:00
self[i].OnGet(entityID);
}
}
2024-04-27 19:05:05 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-30 16:01:16 +08:00
public static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID)
{
2024-04-27 19:05:05 +08:00
self.InvokeOnGet(entityID, self.Count);
}
2024-04-27 19:05:05 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
2025-01-06 10:48:39 +08:00
for (int i = 1; i < cachedCount; i++) { self[i].OnGet(entityID); }
2024-04-27 19:05:05 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID)
{
2024-04-27 19:05:05 +08:00
self.InvokeOnDel(entityID, self.Count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
2025-01-06 10:48:39 +08:00
for (int i = 0; i < cachedCount; i++) { self[i].OnDel(entityID); }
}
2024-12-04 16:10:09 +08:00
//
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAdd(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); }
}
2024-12-04 16:10:09 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAdd(this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
2025-01-06 10:48:39 +08:00
for (int i = 0; i < cachedCount; i++) { self[i].OnAdd(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAddAndGet(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++)
{
self[i].OnAdd(entityID);
self[i].OnGet(entityID);
}
2024-12-04 16:10:09 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAddAndGet(this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++)
{
self[i].OnAdd(entityID);
self[i].OnGet(entityID);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2025-01-06 10:48:39 +08:00
internal static void InvokeOnGet(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-12-04 16:10:09 +08:00
internal static void InvokeOnGet(this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
2025-01-06 10:48:39 +08:00
for (int i = 1; i < cachedCount; i++) { self[i].OnGet(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnDel(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); }
2024-12-04 16:10:09 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnDel(this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
2025-01-06 10:48:39 +08:00
for (int i = 0; i < cachedCount; i++) { self[i].OnDel(entityID); }
2024-12-04 16:10:09 +08:00
}
}
2024-05-01 16:58:54 +08:00
#endif
#endregion
}