2023-05-23 01:47:28 +08:00
using DCFApixels.DragonECS.Internal ;
2024-04-30 16:09:57 +08:00
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 ;
2023-04-26 16:45:37 +08:00
using System.Runtime.CompilerServices ;
2024-04-30 16:09:57 +08:00
namespace DCFApixels.DragonECS.PoolsCore
2023-04-26 16:45:37 +08:00
{
2023-05-07 00:50:02 +08:00
/// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary>
public interface IEcsPoolImplementation : IEcsPool
{
2024-04-30 16:09:57 +08:00
#region Methods
2023-12-06 18:58:06 +08:00
void OnInit ( EcsWorld world , EcsWorld . PoolsMediator mediator , int componentTypeID ) ;
2023-05-07 00:50:02 +08:00
void OnWorldResize ( int newSize ) ;
void OnReleaseDelEntityBuffer ( ReadOnlySpan < int > buffer ) ;
void OnWorldDestroy ( ) ;
2024-04-30 16:09:57 +08:00
#endregion
2023-05-07 00:50:02 +08:00
}
2024-06-13 18:04:18 +08:00
2023-05-07 00:50:02 +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>
2023-06-20 23:34:51 +08:00
public interface IEcsPoolImplementation < T > : IEcsPoolImplementation { }
2023-05-23 15:58:31 +08:00
2023-05-07 00:50:02 +08:00
public static class EcsPoolThrowHalper
{
public static void ThrowAlreadyHasComponent < T > ( int entityID )
2023-04-26 16:45:37 +08:00
{
2023-06-26 02:53:55 +08:00
throw new EcsFrameworkException ( $"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName<T>()}." ) ;
2023-04-26 16:45:37 +08:00
}
2023-05-07 00:50:02 +08:00
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>()}." ) ;
2023-05-07 00:50:02 +08:00
}
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)}." ) ;
}
public static void ThrowNotHaveComponent ( Type type , int entityID )
{
throw new EcsFrameworkException ( $"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName(type)}." ) ;
}
2024-04-28 18:36:24 +08:00
public static void ThrowNullListener ( )
{
throw new ArgumentNullException ( "listener is null" ) ;
}
2023-05-07 00:50:02 +08:00
}
2024-04-30 16:09:57 +08:00
}
2023-04-26 16:45:37 +08:00
2024-04-30 16:09:57 +08:00
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-04-30 16:09:57 +08:00
public sealed class EcsNullPool : IEcsPoolImplementation < NullComponent >
2023-05-07 00:50:02 +08:00
{
2024-04-30 16:09:57 +08:00
public static readonly EcsNullPool instance = new EcsNullPool ( ) ;
2023-04-26 16:45:37 +08:00
2024-04-30 16:09:57 +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 )
2024-04-30 16:09:57 +08:00
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
}
2024-04-30 16:09:57 +08:00
}
public int Count { get { return 0 ; } }
public bool IsReadOnly { get { return true ; } }
#endregion
2023-04-26 16:45:37 +08:00
2024-04-30 16:09:57 +08:00
#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 )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
void IEcsPool . AddRaw ( int entityID , object dataRaw )
{
2024-03-13 17:41:33 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
object IEcsReadonlyPool . GetRaw ( int entityID )
{
2024-03-13 17:41:33 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 22:18:17 +08:00
#else
return null ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
void IEcsPool . SetRaw ( int entity , object dataRaw )
{
2024-03-13 17:41:33 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
void IEcsReadonlyPool . Copy ( int fromEntityID , int toEntityID )
{
2024-03-13 17:41:33 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
void IEcsReadonlyPool . Copy ( int fromEntityID , EcsWorld toWorld , int toEntityID )
{
2024-03-13 17:41:33 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
void IEcsPool . ClearAll ( )
{
2024-03-13 17:41:33 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG )
2024-04-30 16:09:57 +08:00
throw new NullInstanceException ( ) ;
2024-03-13 17:41:33 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
#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 ) { }
#endregion
2023-05-07 00:50:02 +08:00
2024-04-30 16:09:57 +08:00
#region Listeners
2024-05-01 17:15:58 +08:00
#if ! DISABLE_POOLS_EVENTS
2024-04-30 16:09:57 +08:00
void IEcsReadonlyPool . AddListener ( IEcsPoolEventListener listener ) { }
void IEcsReadonlyPool . RemoveListener ( IEcsPoolEventListener listener ) { }
2024-05-01 17:15:58 +08:00
#endif
2024-04-30 16:09:57 +08:00
#endregion
}
2024-06-13 18:04:18 +08:00
public struct NullComponent { }
2024-04-30 16:09:57 +08:00
}
2023-05-23 15:58:31 +08:00
2024-04-30 16:09:57 +08:00
namespace DCFApixels.DragonECS
{
#region Interfaces
2024-06-13 18:04:18 +08:00
public interface IEcsReadonlyPool : IEcsMember
2024-04-30 16:09:57 +08:00
{
#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
2024-04-30 16:09:57 +08:00
#region Add / Remove Listeners
void AddListener ( IEcsPoolEventListener listener ) ;
void RemoveListener ( IEcsPoolEventListener listener ) ;
#endregion
2024-05-01 16:58:54 +08:00
#endif
2024-04-30 16:09:57 +08:00
}
2024-06-13 18:04:18 +08:00
2024-04-30 16:09:57 +08:00
public interface IEcsPool : IEcsReadonlyPool
{
#region Methods
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>
2024-04-30 16:09:57 +08:00
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>
2024-04-30 16:09:57 +08:00
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>
2024-04-30 16:09:57 +08:00
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 ;
2023-05-07 00:50:02 +08:00
}
2023-04-26 16:45:37 +08:00
}
2023-05-07 00:50:02 +08:00
#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
2023-05-23 15:58:31 +08:00
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 ) ;
2023-05-23 15:58:31 +08:00
}
2024-04-27 19:05:05 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAdd ( this List < IEcsPoolEventListener > self , int entityID , int cachedCount )
{
for ( int i = 0 ; i < cachedCount ; i + + ) self [ i ] . OnAdd ( entityID ) ;
}
2023-05-23 15:58:31 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-30 16:01:16 +08:00
public static void InvokeOnAddAndGet ( this List < IEcsPoolEventListener > self , int entityID )
2023-05-23 15:58:31 +08:00
{
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 + + )
2023-05-23 15:58:31 +08:00
{
self [ i ] . OnAdd ( entityID ) ;
2023-05-30 16:01:16 +08:00
self [ i ] . OnGet ( entityID ) ;
2023-05-23 15:58:31 +08:00
}
}
2024-04-27 19:05:05 +08:00
2023-05-23 15:58:31 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-30 16:01:16 +08:00
public static void InvokeOnGet ( this List < IEcsPoolEventListener > self , int entityID )
2023-05-23 15:58:31 +08:00
{
2024-04-27 19:05:05 +08:00
self . InvokeOnGet ( entityID , self . Count ) ;
2023-05-23 15:58:31 +08:00
}
2024-04-27 19:05:05 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnGet ( this List < IEcsPoolEventListener > self , int entityID , int cachedCount )
{
for ( int i = 1 ; i < cachedCount ; i + + ) self [ i ] . OnGet ( entityID ) ;
}
2023-05-23 15:58:31 +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 )
{
for ( int i = 0 ; i < cachedCount ; i + + ) self [ i ] . OnDel ( entityID ) ;
2023-05-23 15:58:31 +08:00
}
}
2024-05-01 16:58:54 +08:00
#endif
2023-05-23 15:58:31 +08:00
#endregion
2023-04-26 16:45:37 +08:00
}