2023-04-20 10:59:55 +08:00
using System ;
2023-03-02 14:42:44 +08:00
using System.Collections.Generic ;
using System.Runtime.CompilerServices ;
2023-04-01 20:45:37 +08:00
using System.Runtime.InteropServices ;
2023-03-02 14:42:44 +08:00
namespace DCFApixels.DragonECS
{
2023-04-18 19:35:42 +08:00
public interface IEcsWorld : IEcsTable
2023-03-02 14:42:44 +08:00
{
#region Properties
2023-04-18 19:35:42 +08:00
public int UniqueID { get ; }
2023-04-01 20:45:37 +08:00
public EcsPipeline Pipeline { get ; }
2023-03-02 14:42:44 +08:00
#endregion
2023-04-06 23:40:47 +08:00
#region Entities
2023-04-08 05:50:44 +08:00
public EcsEntity NewEntity ( ) ;
public void DelEntity ( EcsEntity entity ) ;
2023-03-26 11:19:03 +08:00
public bool EntityIsAlive ( int entityID , short gen ) ;
2023-04-18 19:35:42 +08:00
public EcsEntity GetEcsEntity ( int entityID ) ;
2023-04-08 21:29:18 +08:00
#endregion
2023-03-02 14:42:44 +08:00
}
2023-03-11 17:11:40 +08:00
public abstract class EcsWorld
2023-03-02 14:42:44 +08:00
{
2023-04-15 00:23:46 +08:00
public static IEcsWorld [ ] Worlds = new IEcsWorld [ 8 ] ;
2023-04-07 15:11:48 +08:00
private static IntDispenser _worldIdDispenser = new IntDispenser ( 0 ) ;
2023-04-18 19:35:42 +08:00
public readonly short uniqueID ;
protected EcsWorld ( )
2023-03-11 17:11:40 +08:00
{
2023-04-18 19:35:42 +08:00
uniqueID = ( short ) _worldIdDispenser . GetFree ( ) ;
if ( uniqueID > = Worlds . Length )
Array . Resize ( ref Worlds , Worlds . Length < < 1 ) ;
Worlds [ uniqueID ] = ( IEcsWorld ) this ;
2023-03-11 17:11:40 +08:00
}
2023-03-30 02:29:11 +08:00
protected void Realeze ( )
{
2023-04-18 19:35:42 +08:00
Worlds [ uniqueID ] = null ;
_worldIdDispenser . Release ( uniqueID ) ;
2023-03-30 02:29:11 +08:00
}
2023-03-11 17:11:40 +08:00
}
2023-04-07 05:08:48 +08:00
public abstract class EcsWorld < TWorldArchetype > : EcsWorld , IEcsWorld
where TWorldArchetype : EcsWorld < TWorldArchetype >
2023-03-11 17:11:40 +08:00
{
2023-04-20 11:37:27 +08:00
private const int DEL_ENT_BUFFER_SIZE_OFFSET = 2 ;
2023-04-18 19:35:42 +08:00
private readonly int _worldArchetypeID = ComponentIndexer . GetWorldId < TWorldArchetype > ( ) ;
2023-03-11 17:11:40 +08:00
private IntDispenser _entityDispenser ;
2023-04-01 22:18:40 +08:00
private int _entitiesCount ;
2023-04-18 19:35:42 +08:00
private int _entitesCapacity ;
2023-04-01 22:18:40 +08:00
private short [ ] _gens ; //старший бит указывает на то жива ли сущьность.
2023-03-26 11:19:03 +08:00
//private short[] _componentCounts; //TODO
2023-04-20 11:37:27 +08:00
private EcsGroup _allEntites ;
private int [ ] _delEntBuffer ; //буфер удаления нужен для того чтобы запускать некоторые процесыы связанные с удалением сущьности не по одному при каждом удалении, а пачкой
private int _delEntBufferCount ;
2023-04-18 19:35:42 +08:00
2023-04-09 02:52:39 +08:00
private EcsPool [ ] _pools ;
2023-03-13 04:32:24 +08:00
private EcsNullPool _nullPool ;
2023-03-02 14:42:44 +08:00
2023-04-17 22:58:52 +08:00
private EcsQueryBase [ ] _queries ;
2023-03-02 14:42:44 +08:00
2023-04-01 20:45:37 +08:00
private EcsPipeline _pipeline ;
2023-04-17 22:58:52 +08:00
private List < WeakReference < EcsGroup > > _groups ;
2023-04-18 19:35:42 +08:00
private Stack < EcsGroup > _groupsPool = new Stack < EcsGroup > ( 64 ) ;
2023-04-01 20:45:37 +08:00
private PoolRunnres _poolRunnres ;
private IEcsEntityCreate _entityCreate ;
private IEcsEntityDestroy _entityDestry ;
2023-03-30 20:47:39 +08:00
#region GetterMethods
2023-04-09 02:52:39 +08:00
public ReadOnlySpan < EcsPool > GetAllPools ( ) = > new ReadOnlySpan < EcsPool > ( _pools ) ;
2023-04-10 22:22:17 +08:00
public int GetComponentID < T > ( ) = > ComponentIndexer . GetComponentId < T > ( _worldArchetypeID ) ; ////ComponentType<T>.uniqueID;
2023-03-30 20:47:39 +08:00
#endregion
2023-03-02 14:42:44 +08:00
#region Properties
2023-04-07 05:08:48 +08:00
public Type ArchetypeType = > typeof ( TWorldArchetype ) ;
2023-04-18 19:35:42 +08:00
public int UniqueID = > uniqueID ;
public int Count = > _entitiesCount ;
public int Capacity = > _entitesCapacity ; //_denseEntities.Length;
2023-04-01 20:45:37 +08:00
public EcsPipeline Pipeline = > _pipeline ;
2023-04-09 02:52:39 +08:00
public EcsReadonlyGroup Entities = > _allEntites . Readonly ;
2023-03-02 14:42:44 +08:00
#endregion
#region Constructors
2023-04-20 10:59:55 +08:00
public EcsWorld ( EcsPipeline pipline )
2023-04-18 19:35:42 +08:00
{
2023-04-01 20:45:37 +08:00
_pipeline = pipline ? ? EcsPipeline . Empty ;
if ( ! _pipeline . IsInit ) pipline . Init ( ) ;
2023-04-07 15:11:48 +08:00
_entityDispenser = new IntDispenser ( 0 ) ;
2023-04-06 23:40:47 +08:00
_nullPool = EcsNullPool . instance ;
2023-04-09 02:52:39 +08:00
_pools = new EcsPool [ 512 ] ;
2023-04-08 00:47:35 +08:00
ArrayUtility . Fill ( _pools , _nullPool ) ;
2023-04-01 20:45:37 +08:00
2023-03-12 20:45:18 +08:00
_gens = new short [ 512 ] ;
2023-04-18 19:35:42 +08:00
_entitesCapacity = _gens . Length ;
2023-04-20 11:37:27 +08:00
_delEntBufferCount = 0 ;
_delEntBuffer = new int [ _gens . Length > > DEL_ENT_BUFFER_SIZE_OFFSET ] ;
2023-04-18 19:35:42 +08:00
2023-04-17 22:58:52 +08:00
_groups = new List < WeakReference < EcsGroup > > ( ) ;
2023-04-20 10:59:55 +08:00
_allEntites = GetGroupFromPool ( ) ;
_queries = new EcsQuery [ QueryType . capacity ] ;
2023-04-01 20:45:37 +08:00
_poolRunnres = new PoolRunnres ( _pipeline ) ;
_entityCreate = _pipeline . GetRunner < IEcsEntityCreate > ( ) ;
_entityDestry = _pipeline . GetRunner < IEcsEntityDestroy > ( ) ;
2023-04-07 05:08:48 +08:00
_pipeline . GetRunner < IEcsInject < TWorldArchetype > > ( ) . Inject ( ( TWorldArchetype ) this ) ;
2023-04-01 20:45:37 +08:00
_pipeline . GetRunner < IEcsInject < IEcsWorld > > ( ) . Inject ( this ) ;
_pipeline . GetRunner < IEcsWorldCreate > ( ) . OnWorldCreate ( this ) ;
2023-03-02 14:42:44 +08:00
}
#endregion
#region GetPool
public EcsPool < T > GetPool < T > ( ) where T : struct
{
2023-04-10 22:22:17 +08:00
int uniqueID = ComponentIndexer . GetComponentId < T > ( _worldArchetypeID ) ;
2023-03-02 14:42:44 +08:00
if ( uniqueID > = _pools . Length )
{
2023-03-13 04:32:24 +08:00
int oldCapacity = _pools . Length ;
2023-04-10 22:22:17 +08:00
Array . Resize ( ref _pools , _pools . Length < < 1 ) ;
2023-04-08 00:47:35 +08:00
ArrayUtility . Fill ( _pools , _nullPool , oldCapacity , oldCapacity - _pools . Length ) ;
2023-03-02 14:42:44 +08:00
}
2023-03-13 04:32:24 +08:00
if ( _pools [ uniqueID ] = = _nullPool )
2023-03-02 14:42:44 +08:00
{
2023-04-10 22:22:17 +08:00
_pools [ uniqueID ] = new EcsPool < T > ( this , uniqueID , 512 , _poolRunnres ) ;
2023-03-02 14:42:44 +08:00
}
return ( EcsPool < T > ) _pools [ uniqueID ] ;
}
#endregion
2023-04-20 11:37:27 +08:00
#region Queries
2023-04-20 10:59:55 +08:00
public TQuery Where < TQuery > ( out TQuery query ) where TQuery : EcsQueryBase
{
query = Select < TQuery > ( ) ;
query . Execute ( ) ;
return query ;
}
public TQuery Select < TQuery > ( ) where TQuery : EcsQueryBase
2023-03-12 20:45:18 +08:00
{
2023-04-08 00:47:35 +08:00
int uniqueID = QueryType < TQuery > . uniqueID ;
if ( _queries . Length < QueryType . capacity )
Array . Resize ( ref _queries , QueryType . capacity ) ;
2023-04-07 16:03:42 +08:00
if ( _queries [ uniqueID ] = = null )
2023-04-17 22:58:52 +08:00
_queries [ uniqueID ] = EcsQueryBase . Builder . Build < TQuery > ( this ) ;
2023-04-20 10:59:55 +08:00
return ( TQuery ) _queries [ uniqueID ] ;
2023-04-07 05:08:48 +08:00
}
2023-03-02 14:42:44 +08:00
#endregion
2023-04-15 00:23:46 +08:00
#region IsMaskCompatible
2023-04-01 22:19:36 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsMaskCompatible < TInc , TExc > ( int entityID ) where TInc : struct , IInc where TExc : struct , IExc
{
2023-04-07 05:08:48 +08:00
return IsMaskCompatible ( EcsMaskMap < TWorldArchetype > . GetMask < TInc , TExc > ( ) , entityID ) ;
2023-04-01 22:19:36 +08:00
}
2023-04-08 00:47:35 +08:00
public bool IsMaskCompatible ( EcsComponentMask mask , int entityID )
2023-03-02 14:42:44 +08:00
{
2023-04-01 20:45:37 +08:00
#if ( DEBUG & & ! DISABLE_DRAGONECS_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-04-07 05:08:48 +08:00
if ( mask . WorldArchetypeType ! = typeof ( TWorldArchetype ) )
2023-04-08 00:47:35 +08:00
throw new EcsFrameworkException ( "mask.WorldArchetypeType != typeof(TTableArhetype)" ) ;
2023-03-13 01:39:04 +08:00
#endif
2023-04-07 18:21:52 +08:00
for ( int i = 0 , iMax = mask . Inc . Length ; i < iMax ; i + + )
2023-03-02 14:42:44 +08:00
{
2023-04-08 00:47:35 +08:00
if ( ! _pools [ mask . Inc [ i ] ] . Has ( entityID ) )
2023-03-02 14:42:44 +08:00
return false ;
}
2023-04-07 18:21:52 +08:00
for ( int i = 0 , iMax = mask . Exc . Length ; i < iMax ; i + + )
2023-03-02 14:42:44 +08:00
{
2023-04-08 00:47:35 +08:00
if ( _pools [ mask . Exc [ i ] ] . Has ( entityID ) )
2023-03-02 14:42:44 +08:00
return false ;
}
return true ;
}
#endregion
2023-03-26 11:19:03 +08:00
#region Entity
2023-04-08 05:50:44 +08:00
public EcsEntity NewEntity ( )
2023-03-02 14:42:44 +08:00
{
2023-03-26 11:19:03 +08:00
int entityID = _entityDispenser . GetFree ( ) ;
2023-04-18 19:35:42 +08:00
_entitiesCount + + ;
2023-04-01 22:18:40 +08:00
2023-04-01 20:45:37 +08:00
if ( _gens . Length < = entityID )
{
2023-03-26 11:19:03 +08:00
Array . Resize ( ref _gens , _gens . Length < < 1 ) ;
2023-04-18 19:35:42 +08:00
_entitesCapacity = _gens . Length ;
2023-04-17 22:58:52 +08:00
for ( int i = 0 ; i < _groups . Count ; i + + )
{
if ( _groups [ i ] . TryGetTarget ( out EcsGroup group ) )
{
group . OnWorldResize ( _gens . Length ) ;
}
else
{
int last = _groups . Count - 1 ;
_groups [ i - - ] = _groups [ last ] ;
_groups . RemoveAt ( last ) ;
}
}
2023-04-01 20:45:37 +08:00
foreach ( var item in _pools )
item . OnWorldResize ( _gens . Length ) ;
}
2023-04-01 22:18:40 +08:00
_gens [ entityID ] | = short . MinValue ;
2023-04-18 19:35:42 +08:00
EcsEntity entity = new EcsEntity ( entityID , _gens [ entityID ] + + , uniqueID ) ;
2023-04-01 20:45:37 +08:00
_entityCreate . OnEntityCreate ( entity ) ;
2023-04-09 02:52:39 +08:00
_allEntites . Add ( entityID ) ;
2023-04-01 20:45:37 +08:00
return entity ;
2023-03-26 11:19:03 +08:00
}
2023-04-08 05:50:44 +08:00
public void DelEntity ( EcsEntity entity )
2023-03-26 11:19:03 +08:00
{
2023-04-09 02:52:39 +08:00
_allEntites . Remove ( entity . id ) ;
2023-04-20 11:37:27 +08:00
_delEntBuffer [ _delEntBufferCount + + ] = entity . id ;
2023-04-01 22:18:40 +08:00
_gens [ entity . id ] | = short . MinValue ;
_entitiesCount - - ;
2023-04-01 20:45:37 +08:00
_entityDestry . OnEntityDestroy ( entity ) ;
2023-04-20 11:37:27 +08:00
if ( _delEntBufferCount > = _delEntBuffer . Length )
ReleaseDelEntBuffer ( ) ;
}
private void ReleaseDelEntBuffer ( ) //TODO проверить что буфер удаления работает нормально
{
for ( int i = 0 ; i < _delEntBufferCount ; i + + )
_entityDispenser . Release ( _delEntBuffer [ i ] ) ;
_delEntBufferCount = 0 ;
2023-03-02 14:42:44 +08:00
}
2023-04-01 20:45:37 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-18 19:35:42 +08:00
public EcsEntity GetEcsEntity ( int entityID )
2023-03-13 04:32:24 +08:00
{
2023-04-18 19:35:42 +08:00
return new EcsEntity ( entityID , _gens [ entityID ] , uniqueID ) ;
2023-03-13 04:32:24 +08:00
}
2023-03-26 11:19:03 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool EntityIsAlive ( int entityID , short gen )
{
2023-04-01 22:18:40 +08:00
return _gens [ entityID ] = = gen ;
2023-03-26 11:19:03 +08:00
}
2023-03-02 14:42:44 +08:00
#endregion
#region Destroy
public void Destroy ( )
{
2023-03-30 02:29:11 +08:00
_entityDispenser = null ;
2023-04-18 19:35:42 +08:00
//_denseEntities = null;
2023-03-30 02:29:11 +08:00
_gens = null ;
_pools = null ;
_nullPool = null ;
2023-04-07 16:03:42 +08:00
_queries = null ;
2023-03-30 02:29:11 +08:00
Realeze ( ) ;
2023-03-02 14:42:44 +08:00
}
2023-04-01 20:45:37 +08:00
public void DestryWithPipeline ( )
{
Destroy ( ) ;
_pipeline . Destroy ( ) ;
}
2023-03-02 14:42:44 +08:00
#endregion
2023-04-18 19:35:42 +08:00
#region Groups
void IEcsTable . RegisterGroup ( EcsGroup group )
2023-04-07 05:08:48 +08:00
{
2023-04-17 22:58:52 +08:00
_groups . Add ( new WeakReference < EcsGroup > ( group ) ) ;
2023-04-07 05:08:48 +08:00
}
2023-04-20 10:59:55 +08:00
EcsGroup IEcsTable . GetGroupFromPool ( ) = > GetGroupFromPool ( ) ;
2023-04-18 19:35:42 +08:00
internal EcsGroup GetGroupFromPool ( )
{
if ( _groupsPool . Count < = 0 )
return new EcsGroup ( this ) ;
return _groupsPool . Pop ( ) ;
}
2023-04-20 10:59:55 +08:00
void IEcsTable . ReleaseGroup ( EcsGroup group )
2023-04-18 19:35:42 +08:00
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
if ( group . World ! = this )
throw new ArgumentException ( "groupFilter.World != this" ) ;
#endif
group . Clear ( ) ;
_groupsPool . Push ( group ) ;
}
2023-04-07 05:08:48 +08:00
#endregion
2023-03-02 14:42:44 +08:00
#region Utils
2023-04-08 00:47:35 +08:00
internal static class QueryType
2023-04-07 05:08:48 +08:00
{
public static int increment = 0 ;
public static int capacity = 128 ;
}
2023-04-08 00:47:35 +08:00
internal static class QueryType < TQuery >
2023-04-07 05:08:48 +08:00
{
public static int uniqueID ;
2023-04-08 00:47:35 +08:00
static QueryType ( )
2023-04-07 05:08:48 +08:00
{
2023-04-08 00:47:35 +08:00
uniqueID = QueryType . increment + + ;
if ( QueryType . increment > QueryType . capacity )
QueryType . capacity < < = 1 ;
2023-04-07 05:08:48 +08:00
}
}
2023-04-08 21:29:18 +08:00
#endregion
2023-04-01 20:45:37 +08:00
}
2023-04-08 21:29:18 +08:00
2023-04-18 19:35:42 +08:00
#region Utils
2023-04-01 20:45:37 +08:00
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 24)]
internal readonly struct PoolRunnres
2023-03-30 01:14:43 +08:00
{
2023-04-01 20:45:37 +08:00
public readonly IEcsComponentAdd add ;
public readonly IEcsComponentWrite write ;
public readonly IEcsComponentDel del ;
public PoolRunnres ( EcsPipeline pipeline )
2023-03-30 01:14:43 +08:00
{
2023-04-01 20:45:37 +08:00
add = pipeline . GetRunner < IEcsComponentAdd > ( ) ;
write = pipeline . GetRunner < IEcsComponentWrite > ( ) ;
del = pipeline . GetRunner < IEcsComponentDel > ( ) ;
2023-03-30 01:14:43 +08:00
}
}
2023-04-10 22:22:17 +08:00
public static class ComponentIndexer
{
private static List < Resizer > resizer = new List < Resizer > ( ) ;
private static int tokenCount = 0 ;
private static int [ ] componentCounts = new int [ 0 ] ;
private static class World < TWorldArchetype >
{
public static int id = GetToken ( ) ;
}
private static int GetToken ( )
{
tokenCount + + ;
Array . Resize ( ref componentCounts , tokenCount ) ;
foreach ( var item in resizer )
item . Resize ( tokenCount ) ;
return tokenCount - 1 ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetWorldId < TWorldArchetype > ( ) = > World < TWorldArchetype > . id ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetComponentId < TComponent > ( int worldID ) = > Component < TComponent > . Get ( worldID ) ;
private abstract class Resizer
{
public abstract void Resize ( int size ) ;
}
private sealed class Resizer < T > : Resizer
{
public override void Resize ( int size ) = > Array . Resize ( ref Component < T > . ids , size ) ;
}
private static class Component < TComponent >
{
public static int [ ] ids ;
static Component ( )
{
ids = new int [ tokenCount ] ;
for ( int i = 0 ; i < ids . Length ; i + + )
ids [ i ] = - 1 ;
resizer . Add ( new Resizer < TComponent > ( ) ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Get ( int token )
{
ref int id = ref ids [ token ] ;
if ( id < 0 )
id = componentCounts [ token ] + + ;
return id ;
}
}
}
2023-04-18 19:35:42 +08:00
#endregion
2023-03-02 14:42:44 +08:00
}