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-04-08 23:01:10 +08:00
using static UnityEngine . Networking . UnityWebRequest ;
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 ;
2023-04-08 23:01:10 +08:00
2023-04-01 22:29:34 +08:00
#region Constructors
2023-03-30 20:47:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsReadonlyGroup ( EcsGroup source ) = > _source = source ;
2023-04-01 22:29:34 +08:00
#endregion
#region Properties
2023-03-30 20:47:39 +08:00
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-04-01 22:29:34 +08:00
#endregion
#region Methods
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-04-08 21:29:18 +08:00
public EcsGroup Extract ( )
{
return new EcsGroup ( _source ) ;
}
2023-04-01 22:29:34 +08:00
#endregion
2023-04-08 23:01:10 +08:00
#region Object
public override string ToString ( )
{
if ( _source ! = null )
return _source . ToString ( ) ;
return "NULL" ;
}
#endregion
#region Internal
internal void Release ( )
{
_source . World . ReleaseGroup ( _source ) ;
}
internal EcsGroup GetGroupInternal ( ) = > _source ;
#endregion
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-04-01 20:45:37 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup ( IEcsWorld source , int denseCapacity = 64 , int delayedOpsCapacity = 128 )
{
_source = source ;
2023-04-08 21:29:18 +08:00
_source . RegisterGroup ( this ) ;
2023-04-01 20:45:37 +08:00
_dense = new int [ denseCapacity ] ;
2023-04-01 22:18:40 +08:00
_sparse = new int [ source . EntitesCapacity ] ;
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 ;
2023-04-08 21:29:18 +08:00
_count = 0 ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup ( EcsGroup copyFrom , int delayedOpsCapacity = 128 )
{
_source = copyFrom . _source ;
_source . RegisterGroup ( this ) ;
_dense = new int [ copyFrom . _dense . Length ] ;
_sparse = new int [ copyFrom . _sparse . Length ] ;
_delayedOps = new delayedOp [ delayedOpsCapacity ] ;
2023-03-30 10:46:57 +08:00
2023-04-08 21:29:18 +08:00
_lockCount = 0 ;
_delayedOpsCount = 0 ;
2023-03-30 10:46:57 +08:00
_count = 0 ;
2023-04-08 21:29:18 +08:00
foreach ( var item in copyFrom )
AggressiveAdd ( item . id ) ;
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
2023-04-08 21:29:18 +08:00
#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 ;
2023-04-01 22:18:40 +08:00
AddInternal ( entityID ) ;
2023-04-01 20:45:37 +08:00
}
2023-04-01 22:18:40 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AddInternal ( int entityID )
2023-04-01 20:45:37 +08:00
{
if ( _lockCount > 0 )
2023-03-30 10:46:57 +08:00
{
AddDelayedOp ( entityID , DEALAYED_ADD ) ;
return ;
}
2023-04-08 21:29:18 +08:00
AggressiveAdd ( entityID ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AggressiveAdd ( int entityID )
{
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)]
2023-04-01 22:18:40 +08:00
internal 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 ;
}
2023-04-08 21:29:18 +08:00
AggressiveRemove ( entityID ) ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void AggressiveRemove ( int entityID )
{
2023-03-30 10:46:57 +08:00
_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-04-01 20:45:37 +08:00
internal void OnWorldResize ( int newSize )
{
Array . Resize ( ref _sparse , newSize ) ;
}
2023-04-07 03:12:56 +08:00
public void Sort ( )
{
int increment = 1 ;
for ( int i = 0 ; i < _dense . Length ; i + + )
{
if ( _sparse [ i ] > 0 )
{
_sparse [ i ] = increment ;
_dense [ increment + + ] = i ;
}
}
}
2023-04-08 21:29:18 +08:00
public void Clear ( ) = > _count = 0 ;
2023-04-07 03:12:56 +08:00
2023-04-08 23:01:10 +08:00
public void CopyFrom ( EcsGroup group )
2023-04-08 21:29:18 +08:00
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-04-08 23:01:10 +08:00
if ( group . World ! = _source ) throw new ArgumentException ( "group.World != World" ) ;
2023-04-08 21:29:18 +08:00
#endif
2023-04-08 23:01:10 +08:00
Clear ( ) ;
foreach ( var item in group )
AggressiveAdd ( item . id ) ;
}
2023-04-01 21:16:08 +08:00
2023-04-08 23:01:10 +08:00
#region Set operations
/// <summary>as Union sets</summary>
public void AddGroup ( EcsGroup group )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
if ( _source ! = group . World ) throw new ArgumentException ( "World != group.World" ) ;
#endif
foreach ( var item in group )
if ( ! Contains ( item . id ) )
AggressiveAdd ( item . id ) ;
2023-04-08 21:29:18 +08:00
}
2023-04-08 23:01:10 +08:00
/// <summary>as Except sets</summary>
public void RemoveGroup ( EcsGroup group )
2023-04-08 21:29:18 +08:00
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-04-08 23:01:10 +08:00
if ( _source ! = group . World ) throw new ArgumentException ( "World != group.World" ) ;
2023-04-08 21:29:18 +08:00
#endif
2023-04-08 23:01:10 +08:00
foreach ( var item in group )
if ( Contains ( item . id ) )
AggressiveRemove ( item . id ) ;
2023-04-08 21:29:18 +08:00
}
2023-04-08 23:01:10 +08:00
/// <summary>as Intersect sets</summary>
public void AndWith ( EcsGroup group )
2023-04-08 21:29:18 +08:00
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-04-08 23:01:10 +08:00
if ( World ! = group . World ) throw new ArgumentException ( "World != group.World" ) ;
2023-04-08 21:29:18 +08:00
#endif
2023-04-08 23:01:10 +08:00
foreach ( var item in this )
if ( group . Contains ( item . id ) )
AggressiveRemove ( item . id ) ;
2023-04-08 21:29:18 +08:00
}
2023-04-08 23:01:10 +08:00
/// <summary>as Symmetric Except sets</summary>
public void XorWith ( EcsGroup group )
2023-04-08 21:29:18 +08:00
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ! DRAGONECS_NO_SANITIZE_CHECKS
2023-04-08 23:01:10 +08:00
if ( _source ! = group . World ) throw new ArgumentException ( "World != group.World" ) ;
2023-04-08 21:29:18 +08:00
#endif
2023-04-08 23:01:10 +08:00
foreach ( var item in group )
if ( Contains ( item . id ) )
AggressiveRemove ( item . id ) ;
else
AggressiveAdd ( item . id ) ;
2023-04-08 21:29:18 +08:00
}
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-08 05:50:44 +08:00
UncheckedAdd ( op & int . MaxValue ) ; //delayedOp.EcsEntity
2023-02-13 21:11:54 +08:00
else
2023-04-08 05:50:44 +08:00
UncheckedRemove ( op & int . MaxValue ) ; //delayedOp.EcsEntity
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 ( )
{
2023-04-07 19:23:07 +08:00
Sort ( ) ;
2023-02-13 21:11:54 +08:00
_lockCount + + ;
return new Enumerator ( this ) ;
}
#endregion
2023-03-30 20:47:39 +08:00
#region Enumerator
2023-04-08 19:54:47 +08:00
public ref struct Enumerator
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-04-06 23:40:47 +08:00
private int _index ;
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-04-06 23:40:47 +08:00
_index = 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-08 05:50:44 +08:00
get = > new ent ( _dense [ _index ] ) ;
2023-02-13 21:11:54 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-08 00:47:35 +08:00
public bool MoveNext ( ) = > + + _index < = _count & & _count < _dense . Length ; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
2023-02-13 21:11:54 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-08 00:47:35 +08:00
public void Dispose ( ) = > _source . Unlock ( ) ;
2023-02-13 21:11:54 +08:00
}
#endregion
2023-04-08 23:01:10 +08:00
#region OObject
public override string ToString ( )
{
return string . Join ( ", " , _dense . AsSpan ( 1 , _count ) . ToArray ( ) ) ;
}
#endregion
2023-02-13 21:11:54 +08:00
}
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
}