2023-02-13 21:11:54 +08:00
using System ;
using System.Runtime.CompilerServices ;
2023-03-30 20:47:39 +08:00
using System.Runtime.InteropServices ;
2023-03-30 10:46:57 +08:00
using delayedOp = System . Int32 ;
2023-02-13 21:11:54 +08:00
namespace DCFApixels.DragonECS
{
2023-03-30 20:47:39 +08:00
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
public readonly ref struct EcsReadonlyGroup
2023-02-14 03:26:34 +08:00
{
2023-03-30 20:47:39 +08:00
private readonly EcsGroup _source ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsReadonlyGroup ( EcsGroup source ) = > _source = source ;
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source . Count ;
}
2023-04-01 20:45:37 +08:00
public int CapacityDense
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source . CapacityDense ;
}
public int CapacitySparce
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source . CapacitySparce ;
}
2023-03-30 20:47:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains ( int entityID ) = > _source . Contains ( entityID ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup . Enumerator GetEnumerator ( ) = > _source . GetEnumerator ( ) ;
2023-02-14 03:26:34 +08:00
}
2023-03-30 10:46:57 +08:00
// не может содержать значение 0
// _delayedOps это int[] для отложенных операций, хранятся отложенные операции в виде int значения, если старший бит = 0 то это опреация добавленияб если = 1 то это операция вычитания
// this collection can only store numbers greater than 0
2023-04-01 21:16:08 +08:00
public class EcsGroup
2023-02-13 21:11:54 +08:00
{
2023-03-30 10:46:57 +08:00
public const int DEALAYED_ADD = 0 ;
public const int DEALAYED_REMOVE = int . MinValue ;
2023-03-02 14:42:44 +08:00
private IEcsWorld _source ;
2023-02-13 21:11:54 +08:00
2023-03-30 10:46:57 +08:00
private int [ ] _dense ;
private int [ ] _sparse ;
private int _count ;
private delayedOp [ ] _delayedOps ;
2023-02-13 21:11:54 +08:00
private int _delayedOpsCount ;
private int _lockCount ;
#region Properties
2023-03-02 14:42:44 +08:00
public IEcsWorld World = > _source ;
2023-03-30 10:46:57 +08:00
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _count ;
}
2023-04-01 20:45:37 +08:00
public int CapacityDense
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _dense . Length ;
}
public int CapacitySparce
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _sparse . Length ;
}
2023-03-30 20:47:39 +08:00
public EcsReadonlyGroup Readonly
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > new EcsReadonlyGroup ( this ) ;
}
2023-02-13 21:11:54 +08:00
#endregion
#region Constrcutors
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-01 20:45:37 +08:00
internal EcsGroup ( IEcsWorld source , int denseCapacity , int sparceCapacity , int delayedOpsCapacity )
2023-02-13 21:11:54 +08:00
{
2023-03-30 10:46:57 +08:00
_source = source ;
2023-04-01 20:45:37 +08:00
source . RegisterGroup ( this ) ;
2023-03-30 10:46:57 +08:00
_dense = new int [ denseCapacity ] ;
2023-04-01 20:45:37 +08:00
_sparse = new int [ sparceCapacity ] ;
_delayedOps = new delayedOp [ delayedOpsCapacity ] ;
_lockCount = 0 ;
_delayedOpsCount = 0 ;
_count = 0 ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup ( IEcsWorld source , int denseCapacity = 64 , int delayedOpsCapacity = 128 )
{
_source = source ;
source . RegisterGroup ( this ) ;
_dense = new int [ denseCapacity ] ;
_sparse = new int [ source . Entities . CapacitySparce ] ;
2023-03-30 10:46:57 +08:00
_delayedOps = new delayedOp [ delayedOpsCapacity ] ;
2023-02-13 21:11:54 +08:00
_lockCount = 0 ;
2023-03-30 10:46:57 +08:00
_delayedOpsCount = 0 ;
_count = 0 ;
2023-02-13 21:11:54 +08:00
}
#endregion
2023-03-30 10:46:57 +08:00
#region Contains
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Contains ( int entityID )
{
2023-04-01 20:45:37 +08:00
//TODO добавить проверку на больше 0 в #if (DEBUG && !DISABLE_DRAGONECS_DEBUG) || !DRAGONECS_NO_SANITIZE_CHECKS
#if ( DEBUG & & ! DISABLE_DRAGONECS_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
#endif
return /*entityID > 0 && entityID < _sparse.Length && */ _sparse [ entityID ] > 0 ;
}
#endregion
#region IndexOf
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IndexOf ( int entityID )
{
return _sparse [ entityID ] ;
2023-03-30 10:46:57 +08:00
}
#endregion
#region add / remove
2023-04-01 20:45:37 +08:00
public void UncheckedAdd ( int entityID ) = > AddInternal ( entityID ) ;
2023-02-13 21:11:54 +08:00
public void Add ( int entityID )
{
2023-04-01 20:45:37 +08:00
if ( Contains ( entityID ) ) return ;
Add ( entityID ) ;
}
private void AddInternal ( int entityID )
{
if ( _lockCount > 0 )
2023-03-30 10:46:57 +08:00
{
AddDelayedOp ( entityID , DEALAYED_ADD ) ;
return ;
}
2023-04-01 20:45:37 +08:00
if ( + + _count > = _dense . Length )
2023-03-30 10:46:57 +08:00
Array . Resize ( ref _dense , _dense . Length < < 1 ) ;
_dense [ _count ] = entityID ;
_sparse [ entityID ] = _count ;
2023-02-13 21:11:54 +08:00
}
2023-04-01 20:45:37 +08:00
public void UncheckedRemove ( int entityID ) = > RemoveInternal ( entityID ) ;
2023-02-13 21:11:54 +08:00
public void Remove ( int entityID )
2023-04-01 20:45:37 +08:00
{
if ( ! Contains ( entityID ) ) return ;
RemoveInternal ( entityID ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void RemoveInternal ( int entityID )
2023-02-13 21:11:54 +08:00
{
if ( _lockCount > 0 )
2023-03-30 10:46:57 +08:00
{
AddDelayedOp ( entityID , DEALAYED_REMOVE ) ;
return ;
}
_dense [ _sparse [ entityID ] ] = _dense [ _count ] ;
_sparse [ _dense [ _count - - ] ] = _sparse [ entityID ] ;
_sparse [ entityID ] = 0 ;
2023-02-13 21:11:54 +08:00
}
2023-04-01 20:45:37 +08:00
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AddDelayedOp ( int entityID , int isAddBitFlag )
2023-02-13 21:11:54 +08:00
{
if ( _delayedOpsCount > = _delayedOps . Length )
{
Array . Resize ( ref _delayedOps , _delayedOps . Length < < 1 ) ;
}
2023-03-30 10:46:57 +08:00
_delayedOps [ _delayedOpsCount + + ] = entityID | isAddBitFlag ; // delayedOp = entityID add isAddBitFlag
2023-02-13 21:11:54 +08:00
}
#endregion
2023-04-01 20:45:37 +08:00
internal void OnWorldResize ( int newSize )
{
Array . Resize ( ref _sparse , newSize ) ;
}
//TODO добавить метод Sort
//TODO добавить автосоритровку при каждом GetEnumerator и проверить будет ли прирост производительности или е е падение.
//Суть в том что так возможно можно будет более плотно подавать данные в проц
2023-03-26 11:19:03 +08:00
2023-02-14 03:26:34 +08:00
#region AddGroup / RemoveGroup
2023-03-30 20:47:39 +08:00
public void AddGroup ( EcsReadonlyGroup group )
2023-04-01 21:16:08 +08:00
{ foreach ( var item in group ) Add ( item . id ) ; }
2023-03-30 20:47:39 +08:00
public void RemoveGroup ( EcsReadonlyGroup group )
2023-04-01 21:16:08 +08:00
{ foreach ( var item in group ) Remove ( item . id ) ; }
2023-03-30 20:47:39 +08:00
public void AddGroup ( EcsGroup group )
2023-04-01 21:16:08 +08:00
{ foreach ( var item in group ) Add ( item . id ) ; }
2023-03-30 20:47:39 +08:00
public void RemoveGroup ( EcsGroup group )
2023-04-01 21:16:08 +08:00
{ foreach ( var item in group ) Remove ( item . id ) ; }
public void UncheckedAddGroup ( EcsReadonlyGroup group )
{ foreach ( var item in group ) AddInternal ( item . id ) ; }
public void UncheckedRemoveGroup ( EcsReadonlyGroup group )
{ foreach ( var item in group ) RemoveInternal ( item . id ) ; }
public void UncheckedAddGroup ( EcsGroup group )
{ foreach ( var item in group ) AddInternal ( item . id ) ; }
public void UncheckedRemoveGroup ( EcsGroup group )
{ foreach ( var item in group ) RemoveInternal ( item . id ) ; }
2023-02-14 03:26:34 +08:00
#endregion
2023-02-13 21:11:54 +08:00
#region GetEnumerator
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-02-13 21:11:54 +08:00
private void Unlock ( )
{
2023-04-01 20:45:37 +08:00
#if ( DEBUG & & ! DISABLE_DRAGONECS_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-02-13 21:11:54 +08:00
if ( _lockCount < = 0 )
{
2023-03-30 10:46:57 +08:00
throw new Exception ( $"Invalid lock-unlock balance for {nameof(EcsGroup)}." ) ;
2023-02-13 21:11:54 +08:00
}
#endif
if ( - - _lockCount < = 0 )
{
for ( int i = 0 ; i < _delayedOpsCount ; i + + )
{
2023-03-30 10:46:57 +08:00
delayedOp op = _delayedOps [ i ] ;
if ( op > = 0 ) //delayedOp.IsAdded
2023-04-01 20:45:37 +08:00
UncheckedAdd ( op & int . MaxValue ) ; //delayedOp.Entity
2023-02-13 21:11:54 +08:00
else
2023-04-01 20:45:37 +08:00
UncheckedRemove ( op & int . MaxValue ) ; //delayedOp.Entity
2023-02-13 21:11:54 +08:00
}
}
}
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-02-13 21:11:54 +08:00
public Enumerator GetEnumerator ( )
{
_lockCount + + ;
return new Enumerator ( this ) ;
}
#endregion
2023-03-30 20:47:39 +08:00
#region Enumerator
2023-03-30 10:46:57 +08:00
public struct Enumerator : IDisposable
2023-02-13 21:11:54 +08:00
{
private readonly EcsGroup _source ;
2023-04-01 21:16:08 +08:00
private readonly int [ ] _dense ;
private readonly int _count ;
2023-03-30 10:46:57 +08:00
private int _pointer ;
2023-02-13 21:11:54 +08:00
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-02-13 21:11:54 +08:00
public Enumerator ( EcsGroup group )
{
_source = group ;
2023-04-01 21:16:08 +08:00
_dense = group . _dense ;
_count = group . Count ;
2023-03-30 10:46:57 +08:00
_pointer = 0 ;
2023-02-13 21:11:54 +08:00
}
2023-03-26 11:19:03 +08:00
public ent Current
2023-02-13 21:11:54 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-01 21:16:08 +08:00
get = > _source . World . GetEntity ( _dense [ _pointer ] ) ;
2023-02-13 21:11:54 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-30 10:46:57 +08:00
public bool MoveNext ( )
{
2023-04-01 21:16:08 +08:00
return + + _pointer < = _count & & _count < _dense . Length ; //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
2023-03-30 10:46:57 +08:00
}
2023-02-13 21:11:54 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-30 10:46:57 +08:00
public void Dispose ( )
{
_source . Unlock ( ) ;
}
2023-02-13 21:11:54 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-01 21:16:08 +08:00
public void Reset ( ) { }
2023-02-13 21:11:54 +08:00
}
#endregion
}
2023-04-01 20:45:37 +08:00
public static class EcsGroupExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Normalize < T > ( this EcsGroup self , ref T [ ] array )
{
if ( array . Length < self . CapacityDense ) Array . Resize ( ref array , self . CapacityDense ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Normalize < T > ( this EcsReadonlyGroup self , ref T [ ] array )
{
if ( array . Length < self . CapacityDense ) Array . Resize ( ref array , self . CapacityDense ) ;
}
}
2023-02-13 21:11:54 +08:00
}