2023-02-13 21:11:54 +08:00
using System ;
using System.Runtime.CompilerServices ;
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 10:46:57 +08:00
public interface IEcsReadonlyGroup
2023-02-14 03:26:34 +08:00
{
2023-03-30 10:46:57 +08:00
int Count { get ; }
bool Contains ( int entityID ) ;
EcsGroup . Enumerator GetEnumerator ( ) ;
2023-02-14 03:26:34 +08:00
}
public interface IEcsGroup : IEcsReadonlyGroup
{
2023-03-30 10:46:57 +08:00
void Add ( int entityID ) ;
void Remove ( int entityID ) ;
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
public class EcsGroup : IEcsGroup
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-02-13 21:11:54 +08:00
#endregion
#region Constrcutors
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup ( IEcsWorld source , int denseCapacity = 64 , int sparseCapacity = 256 , int delayedOpsCapacity = 128 )
2023-02-13 21:11:54 +08:00
{
2023-03-30 10:46:57 +08:00
_source = source ;
_dense = new int [ denseCapacity ] ;
_sparse = new int [ sparseCapacity ] ;
_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 )
{
return /*entityID > 0 && */ entityID < _sparse . Length & & _sparse [ entityID ] > 0 ;
}
#endregion
#region add / remove
2023-02-13 21:11:54 +08:00
public void Add ( int entityID )
{
2023-03-30 10:46:57 +08:00
if ( _lockCount > 0 )
{
AddDelayedOp ( entityID , DEALAYED_ADD ) ;
return ;
}
if ( Contains ( entityID ) )
return ;
if ( + + _count > = _dense . Length )
Array . Resize ( ref _dense , _dense . Length < < 1 ) ;
if ( entityID > _sparse . Length )
{
int neadedSpace = _sparse . Length ;
while ( entityID > = neadedSpace )
neadedSpace < < = 1 ;
Array . Resize ( ref _sparse , neadedSpace ) ;
}
_dense [ _count ] = entityID ;
_sparse [ entityID ] = _count ;
2023-02-13 21:11:54 +08:00
}
public void Remove ( int entityID )
{
if ( _lockCount > 0 )
2023-03-30 10:46:57 +08:00
{
AddDelayedOp ( entityID , DEALAYED_REMOVE ) ;
return ;
}
if ( ! Contains ( entityID ) )
return ;
_dense [ _sparse [ entityID ] ] = _dense [ _count ] ;
_sparse [ _dense [ _count - - ] ] = _sparse [ entityID ] ;
_sparse [ entityID ] = 0 ;
2023-02-13 21:11:54 +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-03-30 10:46:57 +08:00
//TODO добавить автосоритровку при каждом GetEnumerator
2023-03-26 11:19:03 +08:00
2023-02-14 03:26:34 +08:00
#region AddGroup / RemoveGroup
public void AddGroup ( IEcsReadonlyGroup group )
{
foreach ( var item in group )
{
2023-03-30 10:46:57 +08:00
Add ( item . id ) ;
2023-02-14 03:26:34 +08:00
}
}
public void RemoveGroup ( IEcsReadonlyGroup group )
{
foreach ( var item in group )
{
2023-03-30 10:46:57 +08:00
Remove ( 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-03-30 10:46:57 +08:00
#if 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-02-13 21:11:54 +08:00
{
2023-03-30 10:46:57 +08:00
Add ( op & int . MaxValue ) ; //delayedOp.Entity
2023-02-13 21:11:54 +08:00
}
else
{
2023-03-30 10:46:57 +08:00
Remove ( 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
#region Utils
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-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-03-30 10:46:57 +08:00
_pointer = 0 ;
2023-02-13 21:11:54 +08:00
}
2023-03-30 10:46:57 +08:00
private static EcsProfilerMarker _marker = new EcsProfilerMarker ( "EcsGroup.Enumerator.Current" ) ;
2023-03-26 11:19:03 +08:00
public ent Current
2023-02-13 21:11:54 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-30 10:46:57 +08:00
get
{
using ( _marker . Auto ( ) )
return _source . World . GetEntity ( _source . _dense [ _pointer ] ) ;
// return _source._dense[_pointer];
}
2023-02-13 21:11:54 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-30 10:46:57 +08:00
public bool MoveNext ( )
{
return + + _pointer < = _source . Count ;
}
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-03-30 10:46:57 +08:00
public void Reset ( )
{
_pointer = - 1 ;
}
2023-02-13 21:11:54 +08:00
}
#endregion
}
}