2023-07-04 00:00:25 +08:00
using DCFApixels.DragonECS.Internal ;
using System ;
2024-02-23 18:34:40 +08:00
using System.Linq ;
2023-07-04 00:00:25 +08:00
using System.Runtime.CompilerServices ;
namespace DCFApixels.DragonECS
{
2024-02-22 15:39:37 +08:00
public partial class EcsWorld
2023-07-04 00:00:25 +08:00
{
2024-02-14 21:13:00 +08:00
private SparseArray < int > _poolTypeCode_2_CmpTypeIDs = new SparseArray < int > ( ) ;
2024-02-24 03:02:41 +08:00
private SparseArray < int > _cmpTypeCode_2_CmpTypeIDs = new SparseArray < int > ( ) ;
2023-07-04 00:00:25 +08:00
private int _poolsCount ;
internal IEcsPoolImplementation [ ] _pools ;
2024-01-06 00:07:07 +08:00
internal int [ ] _poolComponentCounts ;
2024-01-01 21:44:33 +08:00
2024-02-15 18:11:24 +08:00
private readonly PoolsMediator _poolsMediator ;
2024-02-16 21:27:24 +08:00
private EcsNullPool _nullPool = EcsNullPool . instance ;
2023-07-04 00:00:25 +08:00
#region Getters
2024-01-06 00:07:07 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-24 03:02:41 +08:00
public IEcsPool GetPool ( Type componentType )
//TODO. Есть проблема, возврат виртуального пула и последующая девиртуализация сделает ссылку невалидной. Одно из решений возвращать обертку
2024-01-06 00:07:07 +08:00
{
2024-02-24 03:02:41 +08:00
#if DEBUG
#endif
int componentTypeID = GetComponentTypeID ( componentType ) ;
ref var pool = ref _pools [ componentTypeID ] ;
if ( pool = = _nullPool )
{
pool = new EcsVirtualPool ( ) ;
pool . OnInit ( this , _poolsMediator , componentTypeID ) ;
}
return pool ;
2024-01-06 00:07:07 +08:00
}
2023-07-04 00:00:25 +08:00
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TPool GetPool < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
{
return Get < PoolCache < TPool > > ( ) . instance ;
}
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-11-21 10:41:41 +08:00
public TPool GetPoolUnchecked < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
2023-07-04 00:00:25 +08:00
{
2023-12-31 13:07:53 +08:00
return GetUnchecked < PoolCache < TPool > > ( ) . instance ;
2023-07-04 00:00:25 +08:00
}
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPool GetPool < TPool > ( int worldID ) where TPool : IEcsPoolImplementation , new ( )
{
return Get < PoolCache < TPool > > ( worldID ) . instance ;
}
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPool UncheckedGetPool < TPool > ( int worldID ) where TPool : IEcsPoolImplementation , new ( )
{
2023-12-31 13:07:53 +08:00
return GetUnchecked < PoolCache < TPool > > ( worldID ) . instance ;
2023-07-04 00:00:25 +08:00
}
#endregion
2024-02-14 21:13:00 +08:00
#region ComponentInfo
public int GetComponentTypeID < TComponent > ( )
{
return DeclareOrGetComponentTypeID ( EcsTypeCode . Get < TComponent > ( ) ) ;
}
public int GetComponentTypeID ( Type componentType )
{
return DeclareOrGetComponentTypeID ( EcsTypeCode . Get ( componentType ) ) ;
}
public bool IsComponentTypeDeclared < TComponent > ( )
{
2024-02-24 03:02:41 +08:00
return _cmpTypeCode_2_CmpTypeIDs . Contains ( EcsTypeCode . Get < TComponent > ( ) ) ;
2024-02-14 21:13:00 +08:00
}
public bool IsComponentTypeDeclared ( Type componentType )
{
2024-02-24 03:02:41 +08:00
return _cmpTypeCode_2_CmpTypeIDs . Contains ( EcsTypeCode . Get ( componentType ) ) ;
2024-02-14 21:13:00 +08:00
}
public bool IsComponentTypeDeclared ( int componentTypeID )
{
if ( componentTypeID > = 0 & & componentTypeID < _pools . Length )
{
return _pools [ componentTypeID ] ! = _nullPool ;
}
return false ;
}
public Type GetComponentType ( int componentTypeID )
{
return _pools [ componentTypeID ] . ComponentType ;
}
#endregion
2023-07-04 00:00:25 +08:00
#region Declare / Create
2024-02-14 21:13:00 +08:00
private int DeclareOrGetComponentTypeID ( int componentTypeCode )
2023-07-04 00:00:25 +08:00
{
2024-02-24 03:02:41 +08:00
if ( _cmpTypeCode_2_CmpTypeIDs . TryGetValue ( componentTypeCode , out int ComponentTypeID ) = = false )
2023-07-04 00:00:25 +08:00
{
2024-02-14 21:13:00 +08:00
ComponentTypeID = _poolsCount + + ;
2024-02-24 03:02:41 +08:00
_cmpTypeCode_2_CmpTypeIDs . Add ( componentTypeCode , ComponentTypeID ) ;
2023-07-04 00:00:25 +08:00
}
2024-02-14 21:13:00 +08:00
return ComponentTypeID ;
2023-07-04 00:00:25 +08:00
}
2024-02-24 03:02:41 +08:00
private bool TryDeclareComponentTypeID ( int componentTypeCode , out int componentTypeID )
{
if ( _cmpTypeCode_2_CmpTypeIDs . TryGetValue ( componentTypeCode , out componentTypeID ) = = false )
{
componentTypeID = _poolsCount + + ;
_cmpTypeCode_2_CmpTypeIDs . Add ( componentTypeCode , componentTypeID ) ;
return true ;
}
return false ;
}
2023-07-04 00:00:25 +08:00
private TPool CreatePool < TPool > ( ) where TPool : IEcsPoolImplementation , new ( )
{
2023-11-15 17:47:11 +08:00
int poolTypeCode = EcsTypeCode . Get < TPool > ( ) ;
2024-02-14 21:13:00 +08:00
if ( _poolTypeCode_2_CmpTypeIDs . Contains ( poolTypeCode ) )
{
Throw . World_PoolAlreadyCreated ( ) ;
}
2024-02-14 21:20:00 +08:00
TPool newPool = new TPool ( ) ;
2023-07-04 00:00:25 +08:00
2024-02-14 21:20:00 +08:00
Type componentType = newPool . ComponentType ;
2024-02-23 18:34:40 +08:00
#if DEBUG //проверка соответсвия типов
#pragma warning disable IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
if ( componentType ! = typeof ( TPool ) . GetInterfaces ( )
. First ( o = > o . IsGenericType & & o . GetGenericTypeDefinition ( ) = = typeof ( IEcsPoolImplementation < > ) )
. GetGenericArguments ( ) [ 0 ] )
{
Throw . UndefinedException ( ) ;
}
#pragma warning restore IL2090 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The generic parameter of the source method or type does not have matching annotations.
#endif
2023-07-04 00:00:25 +08:00
int componentTypeCode = EcsTypeCode . Get ( componentType ) ;
2024-02-24 03:02:41 +08:00
if ( _cmpTypeCode_2_CmpTypeIDs . TryGetValue ( componentTypeCode , out int componentTypeID ) )
2023-07-04 00:00:25 +08:00
{
2024-02-14 21:13:00 +08:00
_poolTypeCode_2_CmpTypeIDs [ poolTypeCode ] = componentTypeID ;
2023-07-04 00:00:25 +08:00
}
else
{
2023-12-06 18:58:06 +08:00
componentTypeID = _poolsCount + + ;
2024-02-14 21:13:00 +08:00
_poolTypeCode_2_CmpTypeIDs [ poolTypeCode ] = componentTypeID ;
2024-02-24 03:02:41 +08:00
_cmpTypeCode_2_CmpTypeIDs [ componentTypeCode ] = componentTypeID ;
2023-07-04 00:00:25 +08:00
}
if ( _poolsCount > = _pools . Length )
{
int oldCapacity = _pools . Length ;
Array . Resize ( ref _pools , _pools . Length < < 1 ) ;
2024-01-06 00:07:07 +08:00
Array . Resize ( ref _poolComponentCounts , _pools . Length ) ;
2023-07-04 00:00:25 +08:00
ArrayUtility . Fill ( _pools , _nullPool , oldCapacity , oldCapacity - _pools . Length ) ;
2023-11-22 17:35:03 +08:00
2024-02-16 21:17:20 +08:00
int newEntityComponentMaskLength = _pools . Length / COMPONENT_MATRIX_MASK_BITSIZE + 1 ;
int dif = newEntityComponentMaskLength - _entityComponentMaskLength ;
if ( dif > 0 )
2024-02-14 21:13:00 +08:00
{
2024-02-16 21:17:20 +08:00
int [ ] newEntityComponentMasks = new int [ _entitiesCapacity * newEntityComponentMaskLength ] ;
int indxMax = _entityComponentMaskLength * _entitiesCapacity ;
int indx = 0 ;
int newIndx = 0 ;
int nextIndx = _entityComponentMaskLength ;
while ( indx < indxMax )
{
while ( indx < nextIndx )
{
newEntityComponentMasks [ newIndx ] = _entityComponentMasks [ indx ] ;
indx + + ;
newIndx + + ;
}
newIndx + = dif ;
nextIndx + = _entityComponentMaskLength ;
}
_entityComponentMaskLength = newEntityComponentMaskLength ;
_entityComponentMasks = newEntityComponentMasks ;
2024-02-14 21:13:00 +08:00
}
2024-02-16 21:17:20 +08:00
2023-07-04 00:00:25 +08:00
}
2024-02-14 21:20:00 +08:00
if ( _pools [ componentTypeID ] ! = _nullPool )
2023-07-04 00:00:25 +08:00
{
2024-02-14 21:20:00 +08:00
Throw . UndefinedException ( ) ;
2023-07-04 00:00:25 +08:00
}
2024-02-14 21:20:00 +08:00
_pools [ componentTypeID ] = newPool ;
newPool . OnInit ( this , _poolsMediator , componentTypeID ) ;
return newPool ;
2023-07-04 00:00:25 +08:00
}
#endregion
2024-01-01 21:44:33 +08:00
2024-01-06 00:07:07 +08:00
2024-01-01 21:44:33 +08:00
#region Pools mediation
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-07 18:52:54 +08:00
private void RegisterEntityComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
2024-01-01 21:44:33 +08:00
{
2024-01-06 00:07:07 +08:00
_poolComponentCounts [ componentTypeID ] + + ;
2024-01-01 21:44:33 +08:00
_componentCounts [ entityID ] + + ;
2024-02-16 21:17:20 +08:00
_entityComponentMasks [ entityID * _entityComponentMaskLength + maskBit . chankIndex ] | = maskBit . mask ;
2024-01-01 21:44:33 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-07 18:52:54 +08:00
private void UnregisterEntityComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
2024-01-01 21:44:33 +08:00
{
2024-02-13 21:13:46 +08:00
_poolComponentCounts [ componentTypeID ] - - ;
var count = - - _componentCounts [ entityID ] ;
2024-02-16 21:17:20 +08:00
_entityComponentMasks [ entityID * _entityComponentMaskLength + maskBit . chankIndex ] & = ~ maskBit . mask ;
2024-02-13 21:13:46 +08:00
if ( count = = 0 & & IsUsed ( entityID ) )
{
DelEntity ( entityID ) ;
}
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
if ( count < 0 ) Throw . World_InvalidIncrementComponentsBalance ( ) ;
#endif
2024-01-01 21:44:33 +08:00
}
2024-02-23 20:44:11 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool TryRegisterEntityComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
{
ref int chunk = ref _entityComponentMasks [ entityID * _entityComponentMaskLength + maskBit . chankIndex ] ;
int newChunk = chunk | maskBit . mask ;
if ( chunk ! = newChunk )
{
chunk = newChunk ;
_poolComponentCounts [ componentTypeID ] + + ;
_componentCounts [ entityID ] + + ;
return true ;
}
return false ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool TryUnregisterEntityComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
{
ref int chunk = ref _entityComponentMasks [ entityID * _entityComponentMaskLength + maskBit . chankIndex ] ;
int newChunk = chunk & ~ maskBit . mask ;
if ( chunk ! = newChunk )
{
_poolComponentCounts [ componentTypeID ] - - ;
var count = - - _componentCounts [ entityID ] ;
chunk = newChunk ;
if ( count = = 0 & & IsUsed ( entityID ) )
{
DelEntity ( entityID ) ;
}
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
if ( count < 0 ) Throw . World_InvalidIncrementComponentsBalance ( ) ;
#endif
return true ;
}
return false ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetPoolComponentCount ( int componentTypeID )
{
return _poolComponentCounts [ componentTypeID ] ;
}
2024-01-01 21:44:33 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-07 18:52:54 +08:00
private bool HasEntityComponent ( int entityID , EcsMaskChunck maskBit )
2024-01-01 21:44:33 +08:00
{
2024-02-23 20:43:56 +08:00
return ( _entityComponentMasks [ entityID * _entityComponentMaskLength + maskBit . chankIndex ] & maskBit . mask ) = = maskBit . mask ;
2024-01-01 21:44:33 +08:00
}
#endregion
#region PoolsMediator
public readonly struct PoolsMediator
{
private readonly EcsWorld _world ;
internal PoolsMediator ( EcsWorld world )
{
if ( world = = null | | world . _poolsMediator . _world ! = null )
{
2024-02-23 20:44:11 +08:00
throw new InvalidOperationException ( ) ;
2024-01-01 21:44:33 +08:00
}
_world = world ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-07 18:52:54 +08:00
public void RegisterComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
2024-01-01 21:44:33 +08:00
{
_world . RegisterEntityComponent ( entityID , componentTypeID , maskBit ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-07 18:52:54 +08:00
public void UnregisterComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
2024-01-01 21:44:33 +08:00
{
_world . UnregisterEntityComponent ( entityID , componentTypeID , maskBit ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-02-23 20:44:11 +08:00
public bool TryRegisterComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
{
return _world . TryRegisterEntityComponent ( entityID , componentTypeID , maskBit ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnregisterComponent ( int entityID , int componentTypeID , EcsMaskChunck maskBit )
{
return _world . TryUnregisterEntityComponent ( entityID , componentTypeID , maskBit ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetComponentCount ( int componentTypeID )
{
return _world . GetPoolComponentCount ( componentTypeID ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-01-07 18:52:54 +08:00
public bool HasComponent ( int entityID , EcsMaskChunck maskBit )
2024-01-01 21:44:33 +08:00
{
return _world . HasEntityComponent ( entityID , maskBit ) ;
}
}
#endregion
2023-07-04 00:00:25 +08:00
}
}