2023-06-26 02:53:55 +08:00
using DCFApixels.DragonECS.Internal ;
2024-01-05 23:49:29 +08:00
using DCFApixels.DragonECS.Utils ;
2023-06-26 02:53:55 +08:00
using System ;
2023-06-01 19:13:04 +08:00
using System.Collections ;
using System.Collections.Generic ;
2024-01-05 22:16:48 +08:00
using System.ComponentModel ;
2023-05-28 06:29:04 +08:00
using System.Diagnostics ;
2023-06-26 02:53:55 +08:00
using System.Linq ;
2023-02-13 21:11:54 +08:00
using System.Runtime.CompilerServices ;
2023-03-30 20:47:39 +08:00
using System.Runtime.InteropServices ;
2023-05-07 00:50:02 +08:00
2023-05-26 04:25:09 +08:00
namespace DCFApixels.DragonECS
{
2023-12-22 18:11:41 +08:00
//_dense заполняется с индекса 1
2023-12-24 18:05:30 +08:00
//в операциях изменяющих состояние группы нельзя итерироваться по this, либо осторожно учитывать этот момент
2023-03-30 20:47:39 +08:00
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
2024-01-05 23:49:29 +08:00
[DebuggerTypeProxy(typeof(EcsGroup.DebuggerProxy))]
2023-03-30 20:47:39 +08:00
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-24 00:19:07 +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-05-07 00:50:02 +08:00
public bool IsNull = > _source = = null ;
2023-12-24 15:40:19 +08:00
public int WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source . World . id ;
}
2023-04-24 00:31:03 +08:00
public EcsWorld World
2023-04-09 02:52:39 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source . World ;
}
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-15 00:23:46 +08:00
public bool IsReleazed
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-26 00:24:38 +08:00
get = > _source . IsReleased ;
2023-04-15 00:23:46 +08:00
}
2023-05-07 00:50:02 +08:00
public int this [ int index ]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source [ index ] ;
}
2023-04-01 22:29:34 +08:00
#endregion
#region Methods
2023-03-30 20:47:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-07 00:50:02 +08:00
public bool Has ( int entityID ) = > _source . Has ( entityID ) ;
2023-03-30 20:47:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-06-01 19:13:04 +08:00
public int IndexOf ( int entityID ) = > _source . IndexOf ( entityID ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-03-30 20:47:39 +08:00
public EcsGroup . Enumerator GetEnumerator ( ) = > _source . GetEnumerator ( ) ;
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-17 22:58:52 +08:00
public EcsGroup Clone ( ) = > _source . Clone ( ) ;
2023-06-01 19:13:04 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int [ ] Bake ( ) = > _source . Bake ( ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Bake ( ref int [ ] entities ) = > _source . Bake ( ref entities ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Bake ( List < int > entities ) = > _source . Bake ( entities ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 13:07:53 +08:00
public EcsSpan ToSpan ( ) = > _source . ToSpan ( ) ;
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 13:07:53 +08:00
public EcsSpan ToSpan ( int start , int length ) = > _source . ToSpan ( start , length ) ;
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsGroup . LongsIterator GetLongs ( ) = > _source . GetLongs ( ) ;
2023-06-01 19:13:04 +08:00
2023-05-07 00:50:02 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int First ( ) = > _source . First ( ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Last ( ) = > _source . Last ( ) ;
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool SetEquals ( EcsReadonlyGroup group ) = > _source . SetEquals ( group . _source ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool SetEquals ( EcsGroup group ) = > _source . SetEquals ( group ) ;
2023-12-24 16:04:24 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool SetEquals ( EcsSpan span ) = > _source . SetEquals ( span ) ;
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Overlaps ( EcsReadonlyGroup group ) = > _source . Overlaps ( group . _source ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Overlaps ( EcsGroup group ) = > _source . Overlaps ( group ) ;
2023-12-24 16:04:24 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Overlaps ( EcsSpan span ) = > _source . Overlaps ( span ) ;
2023-12-24 15:54:34 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsSubsetOf ( EcsReadonlyGroup group ) = > _source . IsSubsetOf ( group . _source ) ;
public bool IsSubsetOf ( EcsGroup group ) = > _source . IsSubsetOf ( group ) ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 21:02:53 +08:00
public bool IsSupersetOf ( EcsReadonlyGroup group ) = > _source . IsSupersetOf ( group . _source ) ;
2023-12-24 15:54:34 +08:00
public bool IsSupersetOf ( EcsGroup group ) = > _source . IsSupersetOf ( group ) ;
2023-04-01 22:29:34 +08:00
#endregion
2023-04-08 23:01:10 +08:00
#region Internal
2023-04-09 02:52:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-08 23:01:10 +08:00
internal EcsGroup GetGroupInternal ( ) = > _source ;
#endregion
2023-04-15 00:23:46 +08:00
2023-12-31 13:07:53 +08:00
#region Other
2024-01-05 22:16:48 +08:00
public override string ToString ( )
{
return _source ! = null ? _source . ToString ( ) : "NULL" ;
}
#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член
[Obsolete("Equals() on EcsGroup will always throw an exception. Use the equality operator instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals ( object obj ) = > throw new NotSupportedException ( ) ;
[Obsolete("GetHashCode() on EcsGroup will always throw an exception.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode ( ) = > throw new NotSupportedException ( ) ;
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
2023-12-23 20:17:28 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 13:07:53 +08:00
public static implicit operator EcsSpan ( EcsReadonlyGroup a ) = > a . ToSpan ( ) ;
2024-01-05 23:49:29 +08:00
//internal class DebuggerProxy : EcsGroup.DebuggerProxy
//{
// public DebuggerProxy(EcsReadonlyGroup group) : base(group._source) { }
//}
2023-05-28 06:29:04 +08:00
#endregion
2023-02-14 03:26:34 +08:00
}
2023-05-28 06:29:04 +08:00
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2023-12-20 19:15:48 +08:00
public unsafe class EcsGroup : IDisposable , IEnumerable < int >
2023-02-13 21:11:54 +08:00
{
2023-04-20 20:03:26 +08:00
private EcsWorld _source ;
2023-03-30 10:46:57 +08:00
private int [ ] _dense ;
private int [ ] _sparse ;
private int _count ;
2023-05-28 06:29:04 +08:00
internal bool _isReleased = true ;
2023-04-15 00:23:46 +08:00
2023-02-13 21:11:54 +08:00
#region Properties
2023-12-24 15:40:19 +08:00
public int WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _source . id ;
}
2023-12-20 19:15:48 +08:00
public EcsWorld World
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > _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-05-26 00:24:38 +08:00
public bool IsReleased
2023-04-15 00:23:46 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-05-26 00:24:38 +08:00
get = > _isReleased ;
2023-04-15 00:23:46 +08:00
}
2023-05-07 00:50:02 +08:00
public int this [ int index ]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( index < 0 | | index > = Count ) Throw . ArgumentOutOfRange ( ) ;
2023-05-07 00:50:02 +08:00
#endif
2023-06-12 12:49:41 +08:00
return _dense [ + + index ] ;
2023-05-07 00:50:02 +08:00
}
}
2023-02-13 21:11:54 +08:00
#endregion
2023-06-10 00:55:00 +08:00
#region Constrcutors / Dispose
2023-04-17 22:58:52 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-20 20:03:26 +08:00
public static EcsGroup New ( EcsWorld world )
2023-04-01 20:45:37 +08:00
{
2023-06-01 20:14:34 +08:00
return world . GetFreeGroup ( ) ;
2023-04-08 21:29:18 +08:00
}
2023-05-26 00:24:38 +08:00
internal EcsGroup ( EcsWorld world , int denseCapacity = 64 )
2023-04-08 21:29:18 +08:00
{
2023-04-15 00:23:46 +08:00
_source = world ;
2023-04-08 21:29:18 +08:00
_source . RegisterGroup ( this ) ;
2023-04-15 00:23:46 +08:00
_dense = new int [ denseCapacity ] ;
2023-04-18 19:35:42 +08:00
_sparse = new int [ world . Capacity ] ;
2023-04-08 21:29:18 +08:00
2023-03-30 10:46:57 +08:00
_count = 0 ;
2023-02-13 21:11:54 +08:00
}
2023-06-10 00:55:00 +08:00
public void Dispose ( ) = > _source . ReleaseGroup ( this ) ;
2023-02-13 21:11:54 +08:00
#endregion
2023-06-01 19:13:04 +08:00
#region Has / IndexOf
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-24 16:48:18 +08:00
public bool Has ( int entityID )
2023-03-30 10:46:57 +08:00
{
2023-04-15 00:23:46 +08:00
return _sparse [ entityID ] > 0 ;
2023-04-01 20:45:37 +08:00
}
[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-12-22 18:11:41 +08:00
public void AddUnchecked ( int entityID ) = > AddInternal ( entityID ) ;
public bool Add ( int entityID )
2023-02-13 21:11:54 +08:00
{
2023-12-22 18:11:41 +08:00
if ( Has ( entityID ) )
return false ;
2023-04-01 22:18:40 +08:00
AddInternal ( entityID ) ;
2023-12-22 18:11:41 +08:00
return true ;
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
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( Has ( entityID ) ) Throw . Group_AlreadyContains ( entityID ) ;
2023-05-07 00:50:02 +08:00
#endif
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-12-22 18:11:41 +08:00
public void RemoveUnchecked ( int entityID ) = > RemoveInternal ( entityID ) ;
public bool Remove ( int entityID )
2023-04-01 20:45:37 +08:00
{
2023-12-22 18:11:41 +08:00
if ( ! Has ( entityID ) )
return false ;
2023-04-01 20:45:37 +08:00
RemoveInternal ( entityID ) ;
2023-12-22 18:11:41 +08:00
return true ;
2023-04-01 20:45:37 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-01 22:18:40 +08:00
internal void RemoveInternal ( int entityID )
2023-02-13 21:11:54 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( ! Has ( entityID ) ) Throw . Group_DoesNotContain ( entityID ) ;
2023-05-07 00:50:02 +08:00
#endif
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-04-24 16:48:18 +08:00
public void RemoveUnusedEntityIDs ( )
{
foreach ( var e in this )
{
if ( ! _source . IsUsed ( e ) )
2023-05-26 00:24:38 +08:00
RemoveInternal ( e ) ;
2023-04-24 16:48:18 +08:00
}
}
2023-02-13 21:11:54 +08:00
#endregion
2023-05-27 15:59:46 +08:00
#region Clear
2023-04-15 00:23:46 +08:00
public void Clear ( )
{
_count = 0 ;
2023-05-27 15:59:46 +08:00
//массив _dense нет смысла очищать
2023-04-15 00:23:46 +08:00
for ( int i = 0 ; i < _sparse . Length ; i + + )
_sparse [ i ] = 0 ;
}
#endregion
2023-06-01 19:13:04 +08:00
#region CopyFrom / Clone / Bake / ToSpan
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyFrom ( EcsReadonlyGroup group ) = > CopyFrom ( group . GetGroupInternal ( ) ) ;
2023-04-08 23:01:10 +08:00
public void CopyFrom ( EcsGroup group )
2023-04-08 21:29:18 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-04-20 18:23:23 +08:00
if ( group . World ! = _source ) throw new ArgumentException ( "groupFilter.WorldIndex != WorldIndex" ) ;
2023-04-09 02:52:39 +08:00
#endif
2023-05-30 18:30:10 +08:00
if ( _count > 0 )
2023-04-17 22:58:52 +08:00
Clear ( ) ;
2023-04-09 02:52:39 +08:00
foreach ( var item in group )
2023-05-26 00:24:38 +08:00
AddInternal ( item ) ;
2023-04-09 02:52:39 +08:00
}
2023-04-15 00:23:46 +08:00
public EcsGroup Clone ( )
2023-04-09 02:52:39 +08:00
{
2023-06-01 20:14:34 +08:00
EcsGroup result = _source . GetFreeGroup ( ) ;
2023-04-15 00:23:46 +08:00
result . CopyFrom ( this ) ;
return result ;
2023-04-08 23:01:10 +08:00
}
2023-06-01 19:13:04 +08:00
public int [ ] Bake ( )
{
int [ ] result = new int [ _count ] ;
2023-06-12 00:59:22 +08:00
Array . Copy ( _dense , 1 , result , 0 , _count ) ;
2023-06-01 19:13:04 +08:00
return result ;
}
public int Bake ( ref int [ ] entities )
{
2023-06-22 14:39:12 +08:00
if ( entities . Length < _count )
2023-06-01 19:13:04 +08:00
entities = new int [ _count ] ;
2023-06-12 00:59:22 +08:00
Array . Copy ( _dense , 1 , entities , 0 , _count ) ;
2023-06-01 19:13:04 +08:00
return _count ;
}
public void Bake ( List < int > entities )
{
entities . Clear ( ) ;
foreach ( var e in this )
entities . Add ( e ) ;
}
2023-12-31 13:07:53 +08:00
public EcsSpan ToSpan ( )
{
return new EcsSpan ( WorldID , _dense ) ;
}
public EcsSpan ToSpan ( int start , int length )
2023-06-01 19:13:04 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( start + length > _count ) Throw . ArgumentOutOfRange ( ) ;
2023-06-01 19:13:04 +08:00
#endif
2023-12-31 13:07:53 +08:00
return new EcsSpan ( WorldID , _dense , start , length ) ;
2023-06-01 19:13:04 +08:00
}
2023-04-15 00:23:46 +08:00
#endregion
2023-04-01 21:16:08 +08:00
2023-04-08 23:01:10 +08:00
#region Set operations
2023-12-22 18:11:41 +08:00
#region UnionWith
2023-04-08 23:01:10 +08:00
/// <summary>as Union sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void UnionWith ( EcsReadonlyGroup group ) = > UnionWith ( group . GetGroupInternal ( ) ) ;
2023-04-09 02:52:39 +08:00
/// <summary>as Union sets</summary>
2023-04-15 00:23:46 +08:00
public void UnionWith ( EcsGroup group )
2023-04-09 02:52:39 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-08 23:01:10 +08:00
#endif
foreach ( var item in group )
2023-04-24 16:48:18 +08:00
if ( ! Has ( item ) )
2023-05-26 00:24:38 +08:00
AddInternal ( item ) ;
2023-04-08 21:29:18 +08:00
}
2023-12-24 15:48:24 +08:00
public void UnionWith ( EcsSpan span )
2023-12-22 18:11:41 +08:00
{
2023-12-24 15:48:24 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if ( _source . id ! = span . WorldID ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-12-24 15:48:24 +08:00
#endif
foreach ( var item in span )
2023-12-22 18:11:41 +08:00
{
if ( ! Has ( item ) )
AddInternal ( item ) ;
}
}
#endregion
2023-04-15 00:23:46 +08:00
2023-12-22 18:11:41 +08:00
#region ExceptWith
2023-04-08 23:01:10 +08:00
/// <summary>as Except sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ExceptWith ( EcsReadonlyGroup group ) = > ExceptWith ( group . GetGroupInternal ( ) ) ;
/// <summary>as Except sets</summary>
public void ExceptWith ( EcsGroup group )
2023-04-08 21:29:18 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-09 02:52:39 +08:00
#endif
2023-12-24 18:05:30 +08:00
//if (group.Count > Count) // вариант 1. есть итерация по this
//{
// foreach (var item in this)
// if (group.Has(item))
// RemoveInternal(item);
//}
//else
//{
// foreach (var item in group)
// if (Has(item))
// RemoveInternal(item);
//}
//foreach (var item in group) // вариант 2
// if (Has(item))
// RemoveInternal(item);
2023-12-22 18:11:41 +08:00
if ( group . Count > Count )
{
2023-12-24 18:05:30 +08:00
for ( int i = _count ; i > 0 ; i - - ) //итерация в обратном порядке исключает ошибки при удалении элементов
{
int item = _dense [ i ] ;
2023-12-22 18:11:41 +08:00
if ( group . Has ( item ) )
RemoveInternal ( item ) ;
2023-12-24 18:05:30 +08:00
}
2023-12-22 18:11:41 +08:00
}
else
{
foreach ( var item in group )
2023-12-24 18:05:30 +08:00
{
2023-12-22 18:11:41 +08:00
if ( Has ( item ) )
RemoveInternal ( item ) ;
2023-12-24 18:05:30 +08:00
}
2023-12-22 18:11:41 +08:00
}
}
2023-12-24 15:48:24 +08:00
public void ExceptWith ( EcsSpan span )
2023-12-22 18:11:41 +08:00
{
2023-12-24 15:48:24 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if ( _source . id ! = span . WorldID ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-12-24 15:48:24 +08:00
#endif
foreach ( var item in span )
2023-12-22 18:11:41 +08:00
{
2023-12-22 23:25:31 +08:00
if ( Has ( item ) )
RemoveInternal ( item ) ;
2023-12-22 18:11:41 +08:00
}
2023-04-09 02:52:39 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-04-15 00:23:46 +08:00
2023-12-22 18:11:41 +08:00
#region IntersectWith
2023-04-08 23:01:10 +08:00
/// <summary>as Intersect sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-06-05 00:23:18 +08:00
public void IntersectWith ( EcsReadonlyGroup group ) = > IntersectWith ( group . GetGroupInternal ( ) ) ;
2023-04-09 02:52:39 +08:00
/// <summary>as Intersect sets</summary>
2023-06-05 00:23:18 +08:00
public void IntersectWith ( EcsGroup group )
2023-04-09 02:52:39 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( World ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-08 21:29:18 +08:00
#endif
2023-12-24 18:05:30 +08:00
for ( int i = _count ; i > 0 ; i - - ) //итерация в обратном порядке исключает ошибки при удалении элементов
{
int item = _dense [ i ] ;
2023-04-24 16:48:18 +08:00
if ( ! group . Has ( item ) )
2023-05-26 00:24:38 +08:00
RemoveInternal ( item ) ;
2023-12-24 18:05:30 +08:00
}
2023-04-08 21:29:18 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-04-15 00:23:46 +08:00
2023-12-22 18:11:41 +08:00
#region SymmetricExceptWith
2023-04-08 23:01:10 +08:00
/// <summary>as Symmetric Except sets</summary>
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-06-05 00:23:18 +08:00
public void SymmetricExceptWith ( EcsReadonlyGroup group ) = > SymmetricExceptWith ( group . GetGroupInternal ( ) ) ;
2023-04-09 02:52:39 +08:00
/// <summary>as Symmetric Except sets</summary>
2023-06-05 00:23:18 +08:00
public void SymmetricExceptWith ( EcsGroup group )
2023-04-09 02:52:39 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-08 21:29:18 +08:00
#endif
2023-04-08 23:01:10 +08:00
foreach ( var item in group )
2023-04-24 16:48:18 +08:00
if ( Has ( item ) )
2023-05-26 00:24:38 +08:00
RemoveInternal ( item ) ;
2023-04-08 23:01:10 +08:00
else
2023-05-26 00:24:38 +08:00
AddInternal ( item ) ;
2023-04-08 21:29:18 +08:00
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region Inverse
2023-06-01 20:14:34 +08:00
public void Inverse ( )
{
foreach ( var item in _source . Entities )
if ( Has ( item ) )
RemoveInternal ( item ) ;
else
AddInternal ( item ) ;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region SetEquals
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool SetEquals ( EcsReadonlyGroup group ) = > SetEquals ( group . GetGroupInternal ( ) ) ;
public bool SetEquals ( EcsGroup group )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
#endif
if ( group . Count ! = Count )
return false ;
foreach ( var item in group )
if ( ! Has ( item ) )
return false ;
return true ;
}
2023-12-24 16:04:24 +08:00
public bool SetEquals ( EcsSpan span )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if ( _source . id ! = span . WorldID ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-12-24 16:04:24 +08:00
#endif
if ( span . Length ! = Count )
return false ;
foreach ( var item in span )
if ( ! Has ( item ) )
return false ;
return true ;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region Overlaps
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Overlaps ( EcsReadonlyGroup group ) = > Overlaps ( group . GetGroupInternal ( ) ) ;
public bool Overlaps ( EcsGroup group )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
#endif
2023-12-24 16:04:24 +08:00
if ( group . Count > Count )
{
foreach ( var item in this )
if ( group . Has ( item ) )
return true ;
}
else
{
foreach ( var item in group )
if ( Has ( item ) )
return true ;
}
return false ;
}
public bool Overlaps ( EcsSpan span )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-12-24 17:09:01 +08:00
if ( _source . id ! = span . WorldID ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-12-24 16:04:24 +08:00
#endif
foreach ( var item in span )
if ( Has ( item ) )
2023-12-20 19:15:48 +08:00
return true ;
return false ;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region IsSubsetOf
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-24 15:54:34 +08:00
public bool IsSubsetOf ( EcsReadonlyGroup group ) = > IsSubsetOf ( group . GetGroupInternal ( ) ) ;
2023-12-20 19:15:48 +08:00
public bool IsSubsetOf ( EcsGroup group )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
#endif
if ( group . Count < Count )
return false ;
foreach ( var item in this )
if ( ! group . Has ( item ) )
return false ;
return true ;
}
2023-12-22 18:11:41 +08:00
#endregion
2023-12-20 19:15:48 +08:00
2023-12-22 18:11:41 +08:00
#region IsSupersetOf
2023-12-20 19:15:48 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-24 15:54:34 +08:00
public bool IsSupersetOf ( EcsReadonlyGroup group ) = > IsSupersetOf ( group . GetGroupInternal ( ) ) ;
2023-12-20 19:15:48 +08:00
public bool IsSupersetOf ( EcsGroup group )
{
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
if ( _source ! = group . World ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
#endif
if ( group . Count > Count )
return false ;
foreach ( var item in group )
if ( ! Has ( item ) )
return false ;
return true ;
}
2023-02-14 03:26:34 +08:00
#endregion
2023-12-22 18:11:41 +08:00
#endregion
2023-04-10 22:22:17 +08:00
#region Static Set operations
2023-06-01 19:13:04 +08:00
/// <summary>as Intersect sets</summary>
/// <returns>new group from pool</returns>
public static EcsGroup Union ( EcsGroup a , EcsGroup b )
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( a . _source ! = b . _source ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-06-01 19:13:04 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a . _source . GetFreeGroup ( ) ;
2023-06-01 19:13:04 +08:00
foreach ( var item in a )
result . AddInternal ( item ) ;
foreach ( var item in b )
result . Add ( item ) ;
return result ;
}
2023-04-10 22:22:17 +08:00
/// <summary>as Except sets</summary>
2023-04-15 00:23:46 +08:00
/// <returns>new group from pool</returns>
public static EcsGroup Except ( EcsGroup a , EcsGroup b )
2023-04-10 22:22:17 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( a . _source ! = b . _source ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-10 22:22:17 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a . _source . GetFreeGroup ( ) ;
2023-04-10 22:22:17 +08:00
foreach ( var item in a )
2023-04-24 16:48:18 +08:00
if ( ! b . Has ( item ) )
2023-05-26 00:24:38 +08:00
result . AddInternal ( item ) ;
2023-04-15 00:23:46 +08:00
return result ;
2023-04-10 22:22:17 +08:00
}
/// <summary>as Intersect sets</summary>
2023-04-15 00:23:46 +08:00
/// <returns>new group from pool</returns>
2023-06-05 00:23:18 +08:00
public static EcsGroup Intersect ( EcsGroup a , EcsGroup b )
2023-04-10 22:22:17 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( a . _source ! = b . _source ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-10 22:22:17 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a . _source . GetFreeGroup ( ) ;
2023-04-10 22:22:17 +08:00
foreach ( var item in a )
2023-04-24 16:48:18 +08:00
if ( b . Has ( item ) )
2023-05-26 00:24:38 +08:00
result . AddInternal ( item ) ;
2023-04-15 00:23:46 +08:00
return result ;
}
2023-06-01 19:13:04 +08:00
/// <summary>as Symmetric Except sets</summary>
2023-04-15 00:23:46 +08:00
/// <returns>new group from pool</returns>
2023-06-05 00:23:18 +08:00
public static EcsGroup SymmetricExcept ( EcsGroup a , EcsGroup b )
2023-04-15 00:23:46 +08:00
{
2023-06-02 01:20:46 +08:00
#if ( DEBUG & & ! DISABLE_DEBUG ) | | ENABLE_DRAGONECS_ASSERT_CHEKS
2023-06-26 01:57:50 +08:00
if ( a . _source ! = b . _source ) Throw . Group_ArgumentDifferentWorldsException ( ) ;
2023-04-15 00:23:46 +08:00
#endif
2023-06-01 20:14:34 +08:00
EcsGroup result = a . _source . GetFreeGroup ( ) ;
2023-04-15 00:23:46 +08:00
foreach ( var item in a )
2023-06-01 19:13:04 +08:00
if ( ! b . Has ( item ) )
result . AddInternal ( item ) ;
foreach ( var item in b )
if ( ! a . Has ( item ) )
result . AddInternal ( item ) ;
2023-04-15 00:23:46 +08:00
return result ;
2023-04-10 22:22:17 +08:00
}
2023-06-01 20:14:34 +08:00
public static EcsGroup Inverse ( EcsGroup a )
{
EcsGroup result = a . _source . GetFreeGroup ( ) ;
foreach ( var item in a . _source . Entities )
if ( ! a . Has ( item ) )
result . AddInternal ( item ) ;
return result ;
}
2023-04-10 22:22:17 +08:00
#endregion
2023-06-01 19:13:04 +08:00
#region Enumerator
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-07-02 21:41:06 +08:00
public Enumerator GetEnumerator ( ) = > new Enumerator ( this ) ;
2023-12-31 13:07:53 +08:00
IEnumerator IEnumerable . GetEnumerator ( ) = > GetEnumerator ( ) ;
IEnumerator < int > IEnumerable < int > . GetEnumerator ( ) = > GetEnumerator ( ) ;
2023-07-02 21:41:06 +08:00
public LongsIterator GetLongs ( ) = > new LongsIterator ( this ) ;
2023-12-24 15:40:19 +08:00
public struct Enumerator : IEnumerator < int >
2023-02-13 21:11:54 +08:00
{
2023-04-01 21:16:08 +08:00
private readonly int [ ] _dense ;
2023-12-31 13:07:53 +08:00
private uint _index ;
2023-03-30 10:46:57 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-02-13 21:11:54 +08:00
public Enumerator ( EcsGroup group )
{
2023-04-01 21:16:08 +08:00
_dense = group . _dense ;
2023-12-31 21:02:53 +08:00
_index = ( uint ) ( group . _count > _dense . Length ? _dense . Length : group . _count ) + 1 ;
2023-02-13 21:11:54 +08:00
}
2023-04-23 15:57:35 +08:00
public int Current
2023-02-13 21:11:54 +08:00
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-04-23 15:57:35 +08:00
get = > _dense [ _index ] ;
2023-02-13 21:11:54 +08:00
}
2023-12-24 15:40:19 +08:00
object IEnumerator . Current = > Current ;
2023-02-13 21:11:54 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 13:07:53 +08:00
public bool MoveNext ( ) = > - - _index > 0 ; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
2023-12-24 15:40:19 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose ( ) { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset ( ) { }
2023-02-13 21:11:54 +08:00
}
2023-07-02 21:41:06 +08:00
public readonly struct LongsIterator : IEnumerable < entlong >
{
private readonly EcsGroup _group ;
public LongsIterator ( EcsGroup group ) = > _group = group ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator GetEnumerator ( ) = > new Enumerator ( _group ) ;
IEnumerator IEnumerable . GetEnumerator ( )
{
for ( int i = 0 ; i < _group . _count ; i + + )
yield return _group . World . GetEntityLong ( _group . _dense [ i ] ) ;
}
IEnumerator < entlong > IEnumerable < entlong > . GetEnumerator ( )
{
for ( int i = 0 ; i < _group . _count ; i + + )
yield return _group . World . GetEntityLong ( _group . _dense [ i ] ) ;
}
2023-12-31 13:07:53 +08:00
public struct Enumerator : IEnumerator < entlong >
2023-07-02 21:41:06 +08:00
{
private readonly EcsWorld world ;
private readonly int [ ] _dense ;
2023-12-31 13:07:53 +08:00
private uint _index ;
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerator ( EcsGroup group )
{
world = group . World ;
_dense = group . _dense ;
2023-12-31 21:02:53 +08:00
_index = ( uint ) ( group . _count > _dense . Length ? _dense . Length : group . _count ) + 1 ;
2023-07-02 21:41:06 +08:00
}
public entlong Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get = > world . GetEntityLong ( _dense [ _index ] ) ;
}
2023-12-31 13:07:53 +08:00
object IEnumerator . Current = > Current ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 21:02:53 +08:00
public bool MoveNext ( ) = > - - _index > 0 ; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны
2023-07-02 21:41:06 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-31 13:07:53 +08:00
public void Dispose ( ) { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Reset ( ) { }
2023-07-02 21:41:06 +08:00
}
}
2023-02-13 21:11:54 +08:00
#endregion
2023-04-08 23:01:10 +08:00
2023-12-24 15:40:19 +08:00
#region Other
public override string ToString ( )
{
2024-01-05 23:49:29 +08:00
return EntitiesCollectionUtility . AutoToString ( _dense . Skip ( 1 ) . Take ( _count ) , "group" ) ;
//return $"group({_count}) {{{string.Join(", ", _dense.Skip(1).Take(_count).OrderBy(o => o))}}}";
2023-12-24 15:40:19 +08:00
}
2023-04-15 00:23:46 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-24 15:40:19 +08:00
public int First ( )
2023-04-15 00:23:46 +08:00
{
2023-12-24 15:40:19 +08:00
return _dense [ 1 ] ;
2023-04-15 00:23:46 +08:00
}
2023-12-23 20:17:28 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-24 15:40:19 +08:00
public int Last ( )
{
return _dense [ _count ] ;
}
2023-12-23 20:17:28 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2023-12-24 15:40:19 +08:00
internal void OnWorldResize ( int newSize )
{
Array . Resize ( ref _sparse , newSize ) ;
}
2023-12-31 13:07:53 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator EcsReadonlyGroup ( EcsGroup a ) = > a . Readonly ;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator EcsSpan ( EcsGroup a ) = > a . ToSpan ( ) ;
2023-05-28 06:29:04 +08:00
internal class DebuggerProxy
2023-04-01 20:45:37 +08:00
{
2023-05-28 06:29:04 +08:00
private EcsGroup _group ;
public EcsWorld World = > _group . World ;
public bool IsReleased = > _group . IsReleased ;
public entlong [ ] Entities
{
get
{
entlong [ ] result = new entlong [ _group . Count ] ;
int i = 0 ;
foreach ( var e in _group )
result [ i + + ] = _group . World . GetEntityLong ( e ) ;
return result ;
}
}
public int Count = > _group . Count ;
public int CapacityDense = > _group . CapacityDense ;
public int CapacitySparce = > _group . CapacitySparce ;
2023-06-01 20:14:34 +08:00
public override string ToString ( ) = > _group . ToString ( ) ;
2023-05-28 06:29:04 +08:00
public DebuggerProxy ( EcsGroup group ) = > _group = group ;
2024-01-05 23:49:29 +08:00
public DebuggerProxy ( EcsReadonlyGroup group ) : this ( group . GetGroupInternal ( ) ) { }
2023-04-01 20:45:37 +08:00
}
2023-05-28 06:29:04 +08:00
#endregion
2023-04-01 20:45:37 +08:00
}
2023-12-22 23:25:31 +08:00
#if false
public static class EcsGroupAliases
{
/// <summary>Alias for UnionWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add ( this EcsGroup self , EcsGroup group )
{
self . UnionWith ( group ) ;
}
/// <summary>Alias for UnionWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add ( this EcsGroup self , EcsReadonlyGroup group )
{
self . UnionWith ( group ) ;
}
/// <summary>Alias for ExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Remove ( this EcsGroup self , EcsGroup group )
{
self . ExceptWith ( group ) ;
}
/// <summary>Alias for ExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Remove ( this EcsGroup self , EcsReadonlyGroup group )
{
self . ExceptWith ( group ) ;
}
/// <summary>Alias for SymmetricExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Xor ( this EcsGroup self , EcsGroup group )
{
self . SymmetricExceptWith ( group ) ;
}
/// <summary>Alias for SymmetricExceptWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Xor ( this EcsGroup self , EcsReadonlyGroup group )
{
self . SymmetricExceptWith ( group ) ;
}
/// <summary>Alias for IntersectWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void And ( this EcsGroup self , EcsGroup group )
{
self . IntersectWith ( group ) ;
}
/// <summary>Alias for IntersectWith</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void And ( this EcsGroup self , EcsReadonlyGroup group )
{
self . IntersectWith ( group ) ;
}
}
#endif
2023-05-28 06:29:04 +08:00
}