2025-03-14 16:53:25 +08:00
|
|
|
|
#if DISABLE_DEBUG
|
|
|
|
|
|
#undef DEBUG
|
|
|
|
|
|
#endif
|
2025-05-17 14:55:31 +08:00
|
|
|
|
using DCFApixels.DragonECS.Core.Internal;
|
2025-05-09 19:38:28 +08:00
|
|
|
|
using DCFApixels.DragonECS.Core.Unchecked;
|
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
|
|
|
|
|
2024-09-04 12:11:35 +08:00
|
|
|
|
//_dense заполняется с индекса 1
|
|
|
|
|
|
//в операциях изменяющих состояние группы нельзя итерироваться по this, либо осторожно учитывать этот момент
|
2023-05-26 04:25:09 +08:00
|
|
|
|
namespace DCFApixels.DragonECS
|
|
|
|
|
|
{
|
2024-04-28 19:43:10 +08:00
|
|
|
|
#if ENABLE_IL2CPP
|
|
|
|
|
|
using Unity.IL2CPP.CompilerServices;
|
2024-04-29 17:46:32 +08:00
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
2024-04-28 19:43:10 +08:00
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
|
#endif
|
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 Properties
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool IsNull
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
get { return _source == null; }
|
|
|
|
|
|
}
|
2023-12-24 15:40:19 +08:00
|
|
|
|
public int WorldID
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
get { return _source.WorldID; }
|
2023-12-24 15:40:19 +08:00
|
|
|
|
}
|
2023-04-24 00:31:03 +08:00
|
|
|
|
public EcsWorld World
|
2023-04-09 02:52:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
get { return _source.World; }
|
2023-04-09 02:52:39 +08:00
|
|
|
|
}
|
2023-03-30 20:47:39 +08:00
|
|
|
|
public int Count
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
get { return _source.Count; }
|
2023-03-30 20:47:39 +08:00
|
|
|
|
}
|
2023-04-01 20:45:37 +08:00
|
|
|
|
public int CapacityDense
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
get { return _source.CapacityDense; }
|
2023-04-01 20:45:37 +08:00
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
public EcsLongsSpan Longs
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
get { return _source.Longs; }
|
|
|
|
|
|
}
|
2023-04-15 00:23:46 +08:00
|
|
|
|
public bool IsReleazed
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
get { return _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)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
get { return _source[index]; }
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public EcsReadonlyGroup(EcsGroup source)
|
|
|
|
|
|
{
|
|
|
|
|
|
_source = source;
|
2023-05-07 00:50:02 +08:00
|
|
|
|
}
|
2023-04-01 22:29:34 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Methods
|
2023-03-30 20:47:39 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool Has(int entityID) { return _source.Has(entityID); }
|
2023-03-30 20:47:39 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public int IndexOf(int entityID) { return _source.IndexOf(entityID); }
|
2023-06-01 19:13:04 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-09-03 17:30:26 +08:00
|
|
|
|
public void CopyTo(int[] array, int arrayIndex) { _source.CopyTo(array, arrayIndex); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public EcsGroup Clone() { return _source.Clone(); }
|
2023-06-01 19:13:04 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 06:07:50 +08:00
|
|
|
|
public EcsSpan Slice(int start) { return _source.Slice(start); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public EcsSpan Slice(int start, int length) { return _source.Slice(start, length); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public EcsSpan ToSpan() { return _source.ToSpan(); }
|
2023-07-02 21:41:06 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 06:07:50 +08:00
|
|
|
|
public int[] ToArray() { return _source.ToArray(); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-08-31 14:51:13 +08:00
|
|
|
|
public int ToArray(ref int[] dynamicBuffer) { return _source.ToArray(ref dynamicBuffer); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public void ToCollection(ICollection<int> collection) { _source.ToCollection(collection); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 06:07:50 +08:00
|
|
|
|
public EcsGroup.Enumerator GetEnumerator() { return _source.GetEnumerator(); }
|
2023-06-01 19:13:04 +08:00
|
|
|
|
|
2023-05-07 00:50:02 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public int First() { return _source.First(); }
|
2023-05-07 00:50:02 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public int Last() { return _source.Last(); }
|
2023-12-24 15:54:34 +08:00
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool SetEquals(EcsGroup group) { return _source.SetEquals(group); }
|
2023-12-24 15:54:34 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool SetEquals(EcsReadonlyGroup group) { return _source.SetEquals(group._source); }
|
2023-12-24 16:04:24 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool SetEquals(EcsSpan span) { return _source.SetEquals(span); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool SetEquals(IEnumerable<int> other) { return _source.SetEquals(other); }
|
2023-12-24 15:54:34 +08:00
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool Overlaps(EcsGroup group) { return _source.Overlaps(group); }
|
2023-12-24 15:54:34 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool Overlaps(EcsReadonlyGroup group) { return _source.Overlaps(group._source); }
|
2023-12-24 16:04:24 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool Overlaps(EcsSpan span) { return _source.Overlaps(span); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool Overlaps(IEnumerable<int> other) { return _source.Overlaps(other); }
|
2023-12-24 15:54:34 +08:00
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool IsSubsetOf(EcsGroup group) { return _source.IsSubsetOf(group); }
|
2024-01-29 01:09:17 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool IsSubsetOf(EcsReadonlyGroup group) { return _source.IsSubsetOf(group._source); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsSubsetOf(EcsSpan span) { return _source.IsSubsetOf(span); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsSubsetOf(IEnumerable<int> other) { return _source.IsSubsetOf(other); }
|
|
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSubsetOf(EcsGroup group) { return _source.IsProperSubsetOf(group); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSubsetOf(EcsReadonlyGroup group) { return _source.IsProperSubsetOf(group._source); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSubsetOf(EcsSpan span) { return _source.IsProperSubsetOf(span); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSubsetOf(IEnumerable<int> other) { return _source.IsProperSubsetOf(other); }
|
2023-12-24 15:54:34 +08:00
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool IsSupersetOf(EcsGroup group) { return _source.IsSupersetOf(group); }
|
2024-01-29 01:09:17 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public bool IsSupersetOf(EcsReadonlyGroup group) { return _source.IsSupersetOf(group._source); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
public bool IsSupersetOf(EcsSpan span) { return _source.IsSupersetOf(span); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsSupersetOf(IEnumerable<int> other) { return _source.IsSupersetOf(other); }
|
|
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSupersetOf(EcsGroup group) { return _source.IsProperSupersetOf(group); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSupersetOf(EcsReadonlyGroup group) { return _source.IsProperSupersetOf(group._source); }
|
|
|
|
|
|
public bool IsProperSupersetOf(EcsSpan span) { return _source.IsProperSupersetOf(span); }
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSupersetOf(IEnumerable<int> other) { return _source.IsProperSupersetOf(other); }
|
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)]
|
2024-03-02 06:07:50 +08:00
|
|
|
|
internal EcsGroup GetSource_Internal() { return _source; }
|
2023-04-08 23:01:10 +08:00
|
|
|
|
#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)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public override bool Equals(object obj) { throw new NotSupportedException(); }
|
2024-01-05 22:16:48 +08:00
|
|
|
|
[Obsolete("GetHashCode() on EcsGroup will always throw an exception.")]
|
|
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public override int GetHashCode() { throw new NotSupportedException(); }
|
2024-01-05 22:16:48 +08:00
|
|
|
|
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
|
2023-12-23 20:17:28 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public static implicit operator EcsSpan(EcsReadonlyGroup a) { return a.ToSpan(); }
|
2023-05-28 06:29:04 +08:00
|
|
|
|
#endregion
|
2023-02-14 03:26:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-25 10:30:23 +08:00
|
|
|
|
public unsafe partial class EcsWorld
|
|
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private List<WeakReference<EcsGroup>> _groups = new List<WeakReference<EcsGroup>>();
|
|
|
|
|
|
private Stack<EcsGroup> _groupsPool = new Stack<EcsGroup>(64);
|
|
|
|
|
|
|
2025-05-17 14:55:31 +08:00
|
|
|
|
private MemoryAllocator.Handler[] _groupSparsePagePool = new MemoryAllocator.Handler[64];
|
2024-11-25 10:30:23 +08:00
|
|
|
|
private int _groupSparsePagePoolCount = 0;
|
2024-11-26 01:49:39 +08:00
|
|
|
|
|
|
|
|
|
|
#region Pages
|
2024-11-25 10:30:23 +08:00
|
|
|
|
internal int* TakePage()
|
|
|
|
|
|
{
|
2024-12-03 16:59:32 +08:00
|
|
|
|
if (_groupSparsePagePoolCount <= 0)
|
2024-11-25 10:30:23 +08:00
|
|
|
|
{
|
2026-03-16 21:52:45 +08:00
|
|
|
|
return MemoryAllocator.AllocAndInit<int>(EcsGroup.PAGE_SIZE).Ptr;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2025-05-15 20:41:02 +08:00
|
|
|
|
var takedPage = _groupSparsePagePool[--_groupSparsePagePoolCount];
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_groupSparsePagePool[_groupSparsePagePoolCount] = MemoryAllocator.Handler.Empty;
|
|
|
|
|
|
return takedPage.As<int>();
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2024-11-26 01:49:39 +08:00
|
|
|
|
internal void ReturnPage(int* page)
|
2024-11-25 10:30:23 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
|
|
|
|
|
var h = MemoryAllocator.Handler.FromDataPtr(page);
|
2025-05-17 16:30:59 +08:00
|
|
|
|
if (h.GetID_Debug() == 0 || page == null)
|
2025-05-17 14:55:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
Throw.DeepDebugException();
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2024-11-25 10:30:23 +08:00
|
|
|
|
if (_groupSparsePagePoolCount >= _groupSparsePagePool.Length)
|
|
|
|
|
|
{
|
|
|
|
|
|
var old = _groupSparsePagePool;
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_groupSparsePagePool = new MemoryAllocator.Handler[_groupSparsePagePoolCount << 1];
|
2024-11-25 10:30:23 +08:00
|
|
|
|
for (int j = 0; j < old.Length; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
_groupSparsePagePool[j] = old[j];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_groupSparsePagePool[_groupSparsePagePoolCount++] = MemoryAllocator.Handler.FromDataPtr(page);
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
private void DisposeGroups()
|
2025-05-15 20:41:02 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
for (int i = 0; i < _groupSparsePagePoolCount; i++)
|
2025-05-15 20:41:02 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
ref var page = ref _groupSparsePagePool[i];
|
2026-03-16 21:52:45 +08:00
|
|
|
|
if (page.IsCreated)
|
2025-05-15 20:41:02 +08:00
|
|
|
|
{
|
2025-05-21 17:41:28 +08:00
|
|
|
|
MemoryAllocator.FreeAndClear(ref page);
|
2025-05-15 20:41:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_groupSparsePagePoolCount = 0;
|
2025-05-15 20:41:02 +08:00
|
|
|
|
}
|
2024-11-26 01:49:39 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Groups Pool
|
|
|
|
|
|
private void RemoveGroupAt(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
int last = _groups.Count - 1;
|
|
|
|
|
|
_groups[index] = _groups[last];
|
|
|
|
|
|
_groups.RemoveAt(last);
|
|
|
|
|
|
}
|
|
|
|
|
|
internal void RegisterGroup(EcsGroup group)
|
|
|
|
|
|
{
|
|
|
|
|
|
_groups.Add(new WeakReference<EcsGroup>(group));
|
|
|
|
|
|
}
|
|
|
|
|
|
internal EcsGroup GetFreeGroup()
|
|
|
|
|
|
{
|
|
|
|
|
|
EcsGroup result = _groupsPool.Count <= 0 ? new EcsGroup(this, _configs.GetWorldConfigOrDefault().GroupCapacity) : _groupsPool.Pop();
|
|
|
|
|
|
result._isReleased = false;
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
internal void ReleaseGroup(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-11-26 01:49:39 +08:00
|
|
|
|
if (group.World != this) { Throw.World_GroupDoesNotBelongWorld(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (group.World != this)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (TryGetWorld(group.WorldID, out EcsWorld sourceWorld))
|
|
|
|
|
|
{
|
|
|
|
|
|
group.World.ReleaseGroup(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-11-26 01:49:39 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
group._isReleased = true;
|
|
|
|
|
|
group.Clear();
|
|
|
|
|
|
_groupsPool.Push(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-28 19:43:10 +08:00
|
|
|
|
#if ENABLE_IL2CPP
|
2024-11-08 17:21:36 +08:00
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
2024-04-28 19:43:10 +08:00
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
|
#endif
|
2023-05-28 06:29:04 +08:00
|
|
|
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
2024-11-26 01:49:39 +08:00
|
|
|
|
public unsafe class EcsGroup : IDisposable, IEnumerable<int>, ISet<int>, IEntityStorage
|
2023-02-13 21:11:54 +08:00
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
internal const int PAGE_SIZE = PageSlot.SIZE;
|
2023-04-20 20:03:26 +08:00
|
|
|
|
private EcsWorld _source;
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private int[] _dense; // 0 индекс для нулевой записи
|
|
|
|
|
|
private PageSlot* _sparsePages; //Старший бит занят временной маркировкой в операциях над множествами
|
2025-05-17 14:55:31 +08:00
|
|
|
|
private MemoryAllocator.Handler _sparsePagesHandler; //Старший бит занят временной маркировкой в операциях над множествами
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private int _sparsePagesCount;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
private int _totalCapacity;
|
2024-03-02 04:20:34 +08:00
|
|
|
|
private int _count = 0;
|
2023-05-28 06:29:04 +08:00
|
|
|
|
internal bool _isReleased = true;
|
2023-04-15 00:23:46 +08:00
|
|
|
|
|
2026-03-16 21:52:45 +08:00
|
|
|
|
internal static readonly int* _nullPage = MemoryAllocator.AllocAndInit<int>(PageSlot.SIZE).Ptr;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
internal static readonly long _nullPagePtrFake = (long)_nullPage;
|
2024-11-26 02:40:59 +08:00
|
|
|
|
|
2023-02-13 21:11:54 +08:00
|
|
|
|
#region Properties
|
2024-04-16 12:46:09 +08:00
|
|
|
|
public short WorldID
|
2023-12-24 15:40:19 +08:00
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-10-31 16:27:53 +08:00
|
|
|
|
get { return _source.ID; }
|
2023-12-24 15:40:19 +08:00
|
|
|
|
}
|
2023-12-20 19:15:48 +08:00
|
|
|
|
public EcsWorld World
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:25:18 +08:00
|
|
|
|
get { return _source; }
|
2023-12-20 19:15:48 +08:00
|
|
|
|
}
|
2023-03-30 10:46:57 +08:00
|
|
|
|
public int Count
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:25:18 +08:00
|
|
|
|
get { return _count; }
|
2023-03-30 10:46:57 +08:00
|
|
|
|
}
|
2023-04-01 20:45:37 +08:00
|
|
|
|
public int CapacityDense
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:25:18 +08:00
|
|
|
|
get { return _dense.Length; }
|
2023-04-01 20:45:37 +08:00
|
|
|
|
}
|
2023-03-30 20:47:39 +08:00
|
|
|
|
public EcsReadonlyGroup Readonly
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:25:18 +08:00
|
|
|
|
get { return new EcsReadonlyGroup(this); }
|
2023-03-30 20:47:39 +08:00
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
public EcsLongsSpan Longs
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
get { return new EcsLongsSpan(this); }
|
|
|
|
|
|
}
|
2023-05-26 00:24:38 +08:00
|
|
|
|
public bool IsReleased
|
2023-04-15 00:23:46 +08:00
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:25:18 +08:00
|
|
|
|
get { return _isReleased; }
|
2023-04-15 00:23:46 +08:00
|
|
|
|
}
|
2024-09-07 17:18:35 +08:00
|
|
|
|
bool ICollection<int>.IsReadOnly { get { return false; } }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
|
2023-05-07 00:50:02 +08:00
|
|
|
|
public int this[int index]
|
|
|
|
|
|
{
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-03-02 04:20:34 +08:00
|
|
|
|
if (index < 0 || index >= Count) { Throw.ArgumentOutOfRange(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (index < 0 || index >= Count) { return EcsConsts.NULL_ENTITY_ID; }
|
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
|
|
|
|
}
|
2024-03-02 21:59:02 +08:00
|
|
|
|
internal EcsGroup(EcsWorld world, int denseCapacity)
|
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);
|
2024-03-02 21:59:02 +08:00
|
|
|
|
_dense = new int[denseCapacity];
|
2024-11-25 10:30:23 +08:00
|
|
|
|
_totalCapacity = world.Capacity;
|
2024-11-26 01:49:39 +08:00
|
|
|
|
_sparsePagesCount = CalcSparseSize(_totalCapacity);
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_sparsePagesHandler = MemoryAllocator.Alloc<PageSlot>(_sparsePagesCount);
|
|
|
|
|
|
_sparsePages = _sparsePagesHandler.As<PageSlot>();
|
2024-11-26 02:40:59 +08:00
|
|
|
|
for (int i = 0; i < _sparsePagesCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
_sparsePages[i] = PageSlot.Empty;
|
|
|
|
|
|
}
|
2023-02-13 21:11:54 +08:00
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
~EcsGroup()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (this)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < _sparsePagesCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
ref PageSlot page = ref _sparsePages[i];
|
|
|
|
|
|
if (page.Indexes != _nullPage)
|
|
|
|
|
|
{
|
|
|
|
|
|
MemoryAllocator.Free(page.Indexes);
|
|
|
|
|
|
page = default;
|
|
|
|
|
|
page.Indexes = _nullPage;
|
|
|
|
|
|
}
|
|
|
|
|
|
page.IndexesXOR = 0;
|
|
|
|
|
|
page.Count = 0;
|
|
|
|
|
|
}
|
2026-03-16 21:52:45 +08:00
|
|
|
|
_sparsePagesHandler.DisposeAndReset();
|
2025-05-17 14:55:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-02 04:20:34 +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
|
|
|
|
{
|
2024-11-26 19:16:14 +08:00
|
|
|
|
ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT];
|
|
|
|
|
|
return page.Count == 1 ? _dense[page.IndexesXOR] == entityID : page.Indexes[entityID & PageSlot.MASK] != 0;
|
2023-04-01 20:45:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public int IndexOf(int entityID)
|
|
|
|
|
|
{
|
2024-11-26 19:16:14 +08:00
|
|
|
|
ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT];
|
|
|
|
|
|
return page.Count == 1 ? page.IndexesXOR : page.Indexes[entityID & PageSlot.MASK];
|
2023-03-30 10:46:57 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2023-04-08 21:29:18 +08:00
|
|
|
|
#region Add/Remove
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public void AddUnchecked(int entityID)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-08-23 22:31:43 +08:00
|
|
|
|
if (Has(entityID)) { Throw.Group_AlreadyContains(entityID); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (Has(entityID)) { return; }
|
2024-08-23 22:31:43 +08:00
|
|
|
|
#endif
|
2024-03-02 04:20:34 +08:00
|
|
|
|
Add_Internal(entityID);
|
|
|
|
|
|
}
|
2023-12-22 18:11:41 +08:00
|
|
|
|
public bool Add(int entityID)
|
2023-02-13 21:11:54 +08:00
|
|
|
|
{
|
2023-12-22 18:11:41 +08:00
|
|
|
|
if (Has(entityID))
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
2023-12-22 18:11:41 +08:00
|
|
|
|
return false;
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
Add_Internal(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)]
|
2024-08-23 22:31:43 +08:00
|
|
|
|
private void Add_Internal(int entityID)
|
2023-04-01 20:45:37 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (++_count >= _dense.Length)
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
2025-08-26 15:50:11 +08:00
|
|
|
|
Array.Resize(ref _dense, ArrayUtility.NextPow2(_count));
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
2023-03-30 10:46:57 +08:00
|
|
|
|
_dense[_count] = entityID;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
|
2024-11-26 19:16:14 +08:00
|
|
|
|
ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT];
|
2024-12-04 16:48:54 +08:00
|
|
|
|
page.Count++;
|
|
|
|
|
|
// page.Count != 0
|
|
|
|
|
|
if (page.Count == 1)
|
2024-11-26 19:16:14 +08:00
|
|
|
|
{
|
2024-12-04 16:48:54 +08:00
|
|
|
|
page.IndexesXOR = _count;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
}
|
2024-12-04 16:48:54 +08:00
|
|
|
|
else // page.Count > 1
|
2024-11-25 10:30:23 +08:00
|
|
|
|
{
|
2024-12-04 16:48:54 +08:00
|
|
|
|
if (page.Count == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
page.Indexes = _source.TakePage();
|
|
|
|
|
|
page.Indexes[_dense[page.IndexesXOR] & PageSlot.MASK] = page.IndexesXOR;
|
|
|
|
|
|
}
|
2024-11-26 19:16:14 +08:00
|
|
|
|
page.IndexesXOR ^= _count;
|
2024-12-04 16:48:54 +08:00
|
|
|
|
page.Indexes[entityID & PageSlot.MASK] = _count;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2023-02-13 21:11:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public void RemoveUnchecked(int entityID)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-04 12:02:18 +08:00
|
|
|
|
if (Has(entityID) == false) { Throw.Group_DoesNotContain(entityID); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (Has(entityID) == false) { return; }
|
2024-09-04 12:02:18 +08:00
|
|
|
|
#endif
|
2024-03-02 04:20:34 +08:00
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
2023-12-22 18:11:41 +08:00
|
|
|
|
public bool Remove(int entityID)
|
2023-04-01 20:45:37 +08:00
|
|
|
|
{
|
2024-03-02 04:20:34 +08:00
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
2023-12-22 18:11:41 +08:00
|
|
|
|
return false;
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
Remove_Internal(entityID);
|
2023-12-22 18:11:41 +08:00
|
|
|
|
return true;
|
2023-04-01 20:45:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-12-31 21:38:56 +08:00
|
|
|
|
private void ChangeIndexInSparse(int entityID, int index)
|
2023-02-13 21:11:54 +08:00
|
|
|
|
{
|
2024-12-31 21:38:56 +08:00
|
|
|
|
ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT];
|
2025-03-14 16:53:25 +08:00
|
|
|
|
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
2025-03-14 21:57:52 +08:00
|
|
|
|
if (page.Count == 0) { Throw.DeepDebugException(); }
|
2024-12-31 21:38:56 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (page.Count == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
page.IndexesXOR = index;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
int localEntityID = entityID & PageSlot.MASK;
|
2025-03-14 16:53:25 +08:00
|
|
|
|
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
2025-03-14 21:57:52 +08:00
|
|
|
|
if (page.Indexes[localEntityID] == 0) { Throw.DeepDebugException(); }
|
2024-12-31 21:38:56 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
page.Indexes[localEntityID] = index;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-11-25 10:30:23 +08:00
|
|
|
|
|
2024-12-31 21:38:56 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void Remove_Internal(int entityID)
|
|
|
|
|
|
{
|
2024-11-26 19:16:14 +08:00
|
|
|
|
ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT];
|
2024-11-26 01:49:39 +08:00
|
|
|
|
int localEntityID = entityID & PageSlot.MASK;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
|
2024-11-26 19:16:14 +08:00
|
|
|
|
if (--page.Count == 0)
|
2024-11-26 01:49:39 +08:00
|
|
|
|
{
|
2024-12-31 21:38:56 +08:00
|
|
|
|
_dense[page.IndexesXOR] = _dense[_count]; //_dense[_sparse[entityID]] = _dense[_count];
|
|
|
|
|
|
ChangeIndexInSparse(_dense[_count], page.IndexesXOR); //_sparse[_dense[_count--]] = _sparse[entityID];
|
|
|
|
|
|
page.IndexesXOR = 0; //_sparse[entityID] = 0;
|
2024-11-26 01:49:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-12-31 21:38:56 +08:00
|
|
|
|
_dense[page.Indexes[localEntityID]] = _dense[_count]; //_dense[_sparse[entityID]] = _dense[_count];
|
|
|
|
|
|
ChangeIndexInSparse(_dense[_count], page.Indexes[localEntityID]); //_sparse[_dense[_count--]] = _sparse[entityID];
|
2024-11-26 19:16:14 +08:00
|
|
|
|
page.IndexesXOR ^= page.Indexes[localEntityID];
|
2024-12-31 21:38:56 +08:00
|
|
|
|
page.Indexes[localEntityID] = 0; //_sparse[entityID] = 0;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
if (page.Count == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
_source.ReturnPage(page.Indexes);
|
|
|
|
|
|
page.Indexes = _nullPage;
|
|
|
|
|
|
}
|
2024-11-26 01:49:39 +08:00
|
|
|
|
}
|
2024-12-31 21:38:56 +08:00
|
|
|
|
_count--;
|
2023-02-13 21:11:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-24 16:48:18 +08:00
|
|
|
|
public void RemoveUnusedEntityIDs()
|
|
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in this)
|
2023-04-24 16:48:18 +08:00
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
if (_source.IsUsed(entityID) == false)
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
Remove_Internal(entityID);
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
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()
|
|
|
|
|
|
{
|
2024-12-31 21:38:56 +08:00
|
|
|
|
if (_count == 0) { return; }
|
2025-05-17 14:55:31 +08:00
|
|
|
|
|
|
|
|
|
|
if (_source.IsDestroyed == false)
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
for (int i = 0; i < _sparsePagesCount; i++)
|
2024-11-25 10:30:23 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
ref PageSlot page = ref _sparsePages[i];
|
|
|
|
|
|
if (page.Indexes != _nullPage)
|
2024-11-25 10:30:23 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
for (int j = 0; j < PageSlot.SIZE; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
page.Indexes[j] = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
_source.ReturnPage(page.Indexes);
|
|
|
|
|
|
page.Indexes = _nullPage;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
page.IndexesXOR = 0;
|
|
|
|
|
|
page.Count = 0;
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_count = 0;
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
2023-04-15 00:23:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-03-02 21:57:25 +08:00
|
|
|
|
#region Upsize
|
|
|
|
|
|
public void Upsize(int minSize)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (minSize >= _dense.Length)
|
|
|
|
|
|
{
|
2025-08-26 15:50:11 +08:00
|
|
|
|
Array.Resize(ref _dense, ArrayUtility.CeilPow2_ClampOverflow(minSize));
|
2024-03-02 21:57:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-03 22:46:09 +08:00
|
|
|
|
|
2024-03-02 21:57:25 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-03-02 17:12:35 +08:00
|
|
|
|
#region CopyFrom/Clone/Slice/ToSpan/ToArray
|
2023-04-08 23:01:10 +08:00
|
|
|
|
public void CopyFrom(EcsGroup group)
|
2023-04-08 21:29:18 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-03-02 04:20:34 +08:00
|
|
|
|
if (group.World != _source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (group.World != _source)
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
2023-04-17 22:58:52 +08:00
|
|
|
|
Clear();
|
2025-03-15 15:00:07 +08:00
|
|
|
|
return;
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
Clear();
|
2024-08-23 22:31:43 +08:00
|
|
|
|
foreach (var entityID in group)
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
2024-08-23 22:31:43 +08:00
|
|
|
|
Add_Internal(entityID);
|
2024-03-02 04:20:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public void CopyFrom(EcsReadonlyGroup group)
|
|
|
|
|
|
{
|
|
|
|
|
|
CopyFrom(group.GetSource_Internal());
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public void CopyFrom(EcsSpan span)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Clear();
|
|
|
|
|
|
}
|
2024-03-02 04:22:29 +08:00
|
|
|
|
for (int i = 0; i < span.Count; i++)
|
2024-03-02 04:20:34 +08:00
|
|
|
|
{
|
|
|
|
|
|
Add_Internal(span[i]);
|
|
|
|
|
|
}
|
2023-04-09 02:52:39 +08:00
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-09-03 17:30:26 +08:00
|
|
|
|
public void CopyTo(int[] array, int arrayIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in this)
|
|
|
|
|
|
{
|
|
|
|
|
|
array[arrayIndex++] = item;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
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
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public EcsSpan Slice(int start)
|
2023-12-31 13:07:53 +08:00
|
|
|
|
{
|
2024-08-23 23:00:40 +08:00
|
|
|
|
return Slice(start, _count - start);
|
2023-12-31 13:07:53 +08:00
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public EcsSpan Slice(int start, int length)
|
2023-06-01 19:13:04 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-08-23 23:00:40 +08:00
|
|
|
|
if (start < 0 || start + length > _count) { Throw.ArgumentOutOfRange(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (start < 0) { start = 0; }
|
|
|
|
|
|
if (start + length > _count) { length = _count - start; }
|
2023-06-01 19:13:04 +08:00
|
|
|
|
#endif
|
2024-08-23 23:00:40 +08:00
|
|
|
|
return new EcsSpan(WorldID, _dense, start + 1, length);
|
2023-06-01 19:13:04 +08:00
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public EcsSpan ToSpan()
|
|
|
|
|
|
{
|
|
|
|
|
|
return new EcsSpan(WorldID, _dense, 1, _count);
|
|
|
|
|
|
}
|
|
|
|
|
|
public int[] ToArray()
|
|
|
|
|
|
{
|
|
|
|
|
|
int[] result = new int[_count];
|
|
|
|
|
|
Array.Copy(_dense, 1, result, 0, _count);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-08-31 14:51:13 +08:00
|
|
|
|
public int ToArray(ref int[] dynamicBuffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (dynamicBuffer.Length < _count)
|
|
|
|
|
|
{
|
2025-08-26 15:50:11 +08:00
|
|
|
|
Array.Resize(ref dynamicBuffer, ArrayUtility.CeilPow2(_count));
|
2024-08-31 14:51:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
foreach (var e in this)
|
|
|
|
|
|
{
|
|
|
|
|
|
dynamicBuffer[i++] = e;
|
|
|
|
|
|
}
|
|
|
|
|
|
return i;
|
|
|
|
|
|
}
|
|
|
|
|
|
public void ToCollection(ICollection<int> collection)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var e in this)
|
|
|
|
|
|
{
|
|
|
|
|
|
collection.Add(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
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
|
|
|
|
public void UnionWith(EcsGroup group)
|
2023-04-09 02:52:39 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return; }
|
2023-04-08 23:01:10 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
foreach (var entityID in group) { UnionWithStep(entityID); }
|
2023-04-08 21:29:18 +08:00
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
/// <summary>as Union sets</summary>
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public void UnionWith(EcsReadonlyGroup group) { UnionWith(group.GetSource_Internal()); }
|
2024-03-02 04:57:52 +08:00
|
|
|
|
/// <summary>as Union sets</summary>
|
2023-12-24 15:48:24 +08:00
|
|
|
|
public void UnionWith(EcsSpan span)
|
2023-12-22 18:11:41 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return; }
|
2023-12-24 15:48:24 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
foreach (var entityID in span) { UnionWithStep(entityID); }
|
|
|
|
|
|
}
|
|
|
|
|
|
public void UnionWith(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in other) { UnionWithStep(entityID); }
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void UnionWithStep(int entityID)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID) == false)
|
2023-12-22 18:11:41 +08:00
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
Add_Internal(entityID);
|
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 ExceptWith
|
2023-04-08 23:01:10 +08:00
|
|
|
|
/// <summary>as Except sets</summary>
|
2023-04-15 00:23:46 +08:00
|
|
|
|
public void ExceptWith(EcsGroup group)
|
2023-04-08 21:29:18 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return; }
|
2023-04-09 02:52:39 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (group.Count > Count) //мини оптимизация, итеррируемся по короткому списку
|
2023-12-22 18:11:41 +08:00
|
|
|
|
{
|
2023-12-24 18:05:30 +08:00
|
|
|
|
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
|
|
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
int entityID = _dense[i];
|
|
|
|
|
|
if (group.Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
2023-12-24 18:05:30 +08:00
|
|
|
|
}
|
2023-12-22 18:11:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
foreach (var entityID in group) { ExceptWithStep_Internal(entityID); }
|
2023-12-22 18:11:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
/// <summary>as Except sets</summary>
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public void ExceptWith(EcsReadonlyGroup group) { ExceptWith(group.GetSource_Internal()); }
|
|
|
|
|
|
/// <summary>as Except sets</summary>
|
2023-12-24 15:48:24 +08:00
|
|
|
|
public void ExceptWith(EcsSpan span)
|
2023-12-22 18:11:41 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return; }
|
2023-12-24 15:48:24 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
foreach (var entityID in span) { ExceptWithStep_Internal(entityID); }
|
|
|
|
|
|
}
|
|
|
|
|
|
public void ExceptWith(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in other) { ExceptWithStep_Internal(entityID); }
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void ExceptWithStep_Internal(int entityID)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
2023-12-22 18:11:41 +08:00
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
Remove_Internal(entityID);
|
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-06-05 00:23:18 +08:00
|
|
|
|
public void IntersectWith(EcsGroup group)
|
2023-04-09 02:52:39 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return; }
|
2023-04-08 21:29:18 +08:00
|
|
|
|
#endif
|
2023-12-24 18:05:30 +08:00
|
|
|
|
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
|
|
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
int entityID = _dense[i];
|
|
|
|
|
|
if (group.Has(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
2023-12-24 18:05:30 +08:00
|
|
|
|
}
|
2023-04-08 21:29:18 +08:00
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public void IntersectWith(EcsReadonlyGroup group) { IntersectWith(group.GetSource_Internal()); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
/// <summary>as Intersect sets</summary>
|
2024-10-31 16:27:53 +08:00
|
|
|
|
public void IntersectWith(EcsSpan span)
|
2023-04-09 02:52:39 +08:00
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return; }
|
2023-04-08 21:29:18 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
foreach (var entityID in span)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
MarkEntity_Internal(entityID);
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
ClearUnmarked_Internal();
|
|
|
|
|
|
}
|
|
|
|
|
|
public void IntersectWith(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (other is ISet<int> set)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
int entityID = _dense[i];
|
|
|
|
|
|
if (set.Contains(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-09-04 12:11:35 +08:00
|
|
|
|
else
|
2024-09-03 17:30:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
MarkEntity_Internal(entityID);
|
2024-09-03 17:30:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ClearUnmarked_Internal();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region SymmetricExceptWith
|
|
|
|
|
|
/// <summary>as Symmetric Except sets</summary>
|
|
|
|
|
|
public void SymmetricExceptWith(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
foreach (var entityID in group) { SymmetricExceptWithStep_Internal(entityID); }
|
2023-04-08 21:29:18 +08:00
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
/// <summary>as Symmetric Except sets</summary>
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public void SymmetricExceptWith(EcsReadonlyGroup group) { SymmetricExceptWith(group.GetSource_Internal()); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>as Symmetric Except sets</summary>
|
|
|
|
|
|
public void SymmetricExceptWith(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
foreach (var entityID in span) { SymmetricExceptWithStep_Internal(entityID); }
|
|
|
|
|
|
}
|
|
|
|
|
|
public void SymmetricExceptWith(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in other) { SymmetricExceptWithStep_Internal(entityID); }
|
|
|
|
|
|
}
|
|
|
|
|
|
private void SymmetricExceptWithStep_Internal(int entityID)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
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()
|
|
|
|
|
|
{
|
2024-03-02 21:45:09 +08:00
|
|
|
|
if (_count == 0)
|
2024-03-02 21:14:30 +08:00
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in _source.Entities)
|
|
|
|
|
|
{
|
|
|
|
|
|
Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in _source.Entities)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
2023-06-01 20:14:34 +08:00
|
|
|
|
else
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-06-01 20:14:34 +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 SetEquals
|
2023-12-20 19:15:48 +08:00
|
|
|
|
public bool SetEquals(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return false; }
|
2023-12-20 19:15:48 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (group.Count != Count) { return false; }
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in group)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return false;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool SetEquals(EcsReadonlyGroup group) { return SetEquals(group.GetSource_Internal()); }
|
2023-12-24 16:04:24 +08:00
|
|
|
|
public bool SetEquals(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return false; }
|
2023-12-24 16:04:24 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (span.Count != Count) { return false; }
|
|
|
|
|
|
foreach (var entityID in span)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool SetEquals(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (other is ICollection collection && collection.Count != Count) { return false; }
|
|
|
|
|
|
foreach (var entityID in other)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
2023-12-24 16:04:24 +08:00
|
|
|
|
return false;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-24 16:04:24 +08:00
|
|
|
|
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
|
|
|
|
public bool Overlaps(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return false; }
|
2023-12-20 19:15:48 +08:00
|
|
|
|
#endif
|
2024-01-07 19:32:16 +08:00
|
|
|
|
if (group.Count > Count)
|
2023-12-24 16:04:24 +08:00
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in this)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (group.Has(entityID))
|
|
|
|
|
|
{
|
2023-12-24 16:04:24 +08:00
|
|
|
|
return true;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-24 16:04:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in group)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
2023-12-24 16:04:24 +08:00
|
|
|
|
return true;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-24 16:04:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool Overlaps(EcsReadonlyGroup group) { return Overlaps(group.GetSource_Internal()); }
|
2023-12-24 16:04:24 +08:00
|
|
|
|
public bool Overlaps(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return false; }
|
2023-12-24 16:04:24 +08:00
|
|
|
|
#endif
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in span)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return true;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
public bool Overlaps(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2023-12-22 18:11:41 +08:00
|
|
|
|
#endregion
|
2023-12-20 19:15:48 +08:00
|
|
|
|
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#region IsSubsetOf/IsProperSubsetOf
|
2023-12-20 19:15:48 +08:00
|
|
|
|
public bool IsSubsetOf(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return false; }
|
2023-12-20 19:15:48 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (Count == 0) { return true; }
|
|
|
|
|
|
if (group.Count < Count) { return false; }
|
|
|
|
|
|
return IsSubsetOf_Internal(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsSubsetOf(EcsReadonlyGroup group) { return IsSubsetOf(group.GetSource_Internal()); }
|
|
|
|
|
|
public bool IsSubsetOf(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return false; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (Count == 0) { return true; }
|
|
|
|
|
|
if (span.Count < Count) { return false; }
|
|
|
|
|
|
return IsSubsetOf_Internal(span);
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool IsSubsetOf(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Count == 0) { return true; }
|
|
|
|
|
|
if (other is ICollection collection && collection.Count < Count) { return false; }
|
|
|
|
|
|
return IsSubsetOf_Internal(other);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsProperSubsetOf(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return false; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (Count == 0) { return true; }
|
|
|
|
|
|
if (group.Count <= Count) { return false; }
|
|
|
|
|
|
return IsSubsetOf_Internal(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSubsetOf(EcsReadonlyGroup group) { return IsProperSubsetOf(group.GetSource_Internal()); }
|
|
|
|
|
|
public bool IsProperSubsetOf(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return false; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (Count == 0) { return true; }
|
|
|
|
|
|
if (span.Count <= Count) { return false; }
|
|
|
|
|
|
return IsSubsetOf_Internal(span);
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool IsProperSubsetOf(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Count == 0) { return true; }
|
|
|
|
|
|
if (other is ICollection collection && collection.Count <= Count) { return false; }
|
|
|
|
|
|
return IsSubsetOf_Internal(other);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private bool IsSubsetOf_Internal(EcsGroup group)
|
|
|
|
|
|
{
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in this)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (group.Has(entityID) == false)
|
|
|
|
|
|
{
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return false;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-09-03 17:30:26 +08:00
|
|
|
|
private bool IsSubsetOf_Internal(EcsSpan span)
|
|
|
|
|
|
{
|
|
|
|
|
|
int uniqueCount = 0;
|
|
|
|
|
|
foreach (var entityID in span)
|
|
|
|
|
|
{
|
2025-03-14 21:57:52 +08:00
|
|
|
|
#if DEBUG && DRAGONECS_DEEP_DEBUG
|
2024-12-31 21:38:56 +08:00
|
|
|
|
HashSet<int> thisHS = new HashSet<int>();
|
|
|
|
|
|
ToCollection(thisHS);
|
2025-03-14 21:57:52 +08:00
|
|
|
|
if (thisHS.Contains(entityID) && Has(entityID) == false) { Throw.DeepDebugException(); }
|
2024-12-31 21:38:56 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (Has(entityID))
|
2024-09-03 17:30:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
uniqueCount++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-31 21:38:56 +08:00
|
|
|
|
return uniqueCount == this.Count;
|
2024-09-03 17:30:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private bool IsSubsetOf_Internal(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
int uniqueCount = 0;
|
|
|
|
|
|
foreach (var entityID in other)
|
|
|
|
|
|
{
|
2024-12-31 21:38:56 +08:00
|
|
|
|
if (Has(entityID))
|
2024-09-03 17:30:26 +08:00
|
|
|
|
{
|
|
|
|
|
|
uniqueCount++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return uniqueCount == Count;
|
|
|
|
|
|
}
|
2023-12-22 18:11:41 +08:00
|
|
|
|
#endregion
|
2023-12-20 19:15:48 +08:00
|
|
|
|
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#region IsSupersetOf/IsProperSupersetOf
|
2023-12-20 19:15:48 +08:00
|
|
|
|
public bool IsSupersetOf(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return false; }
|
2023-12-20 19:15:48 +08:00
|
|
|
|
#endif
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (group.Count > Count) { return false; }
|
|
|
|
|
|
return IsSupersetOf_Internal(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsSupersetOf(EcsReadonlyGroup group) { return IsSupersetOf(group.GetSource_Internal()); }
|
|
|
|
|
|
public bool IsSupersetOf(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return false; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (span.Count > Count) { return false; }
|
|
|
|
|
|
return IsSupersetOf_Internal(span);
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool IsSupersetOf(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (other is ICollection collection && collection.Count > Count) { return false; }
|
|
|
|
|
|
return IsSupersetOf_Internal(other);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsProperSupersetOf(EcsGroup group)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (_source != group._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (_source != group._source) { return false; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (group.Count >= Count) { return false; }
|
|
|
|
|
|
return IsSupersetOf_Internal(group);
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
public bool IsProperSupersetOf(EcsReadonlyGroup group) { return IsProperSupersetOf(group.GetSource_Internal()); }
|
|
|
|
|
|
public bool IsProperSupersetOf(EcsSpan span)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (WorldID != span.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (WorldID != span.WorldID) { return false; }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
if (span.Count >= Count) { return false; }
|
|
|
|
|
|
return IsSupersetOf_Internal(span);
|
|
|
|
|
|
}
|
|
|
|
|
|
public bool IsProperSupersetOf(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (other is ICollection collection && collection.Count >= Count) { return false; }
|
|
|
|
|
|
return IsSupersetOf_Internal(other);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================================
|
|
|
|
|
|
|
|
|
|
|
|
private bool IsSupersetOf_Internal(EcsGroup group)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in group)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
private bool IsSupersetOf_Internal(EcsSpan span)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in span)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
private bool IsSupersetOf_Internal(IEnumerable<int> other)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var entityID in other)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID) == false)
|
|
|
|
|
|
{
|
2023-12-20 19:15:48 +08:00
|
|
|
|
return false;
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-12-20 19:15:48 +08:00
|
|
|
|
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
|
2024-09-03 17:30:26 +08:00
|
|
|
|
|
|
|
|
|
|
#region Union
|
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)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-03-02 04:57:52 +08:00
|
|
|
|
if (a._source != b._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a._source != b._source) { return a.World.GetFreeGroup(); }
|
2023-06-01 19:13:04 +08:00
|
|
|
|
#endif
|
2023-06-01 20:14:34 +08:00
|
|
|
|
EcsGroup result = a._source.GetFreeGroup();
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var entityID in b)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add(entityID);
|
|
|
|
|
|
}
|
2023-06-01 19:13:04 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
2024-03-02 04:57:52 +08:00
|
|
|
|
public static EcsGroup Union(EcsReadonlyGroup a, EcsReadonlyGroup b)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Union(a.GetSource_Internal(), b.GetSource_Internal());
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup Union(EcsSpan a, EcsSpan b)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (a.WorldID != b.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { return a.World.GetFreeGroup(); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
EcsGroup result = a.World.GetFreeGroup();
|
|
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var entityID in b)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2024-03-02 04:57:52 +08:00
|
|
|
|
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#region Except
|
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
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-03-02 04:57:52 +08:00
|
|
|
|
if (a._source != b._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a._source != b._source) { return a.World.GetFreeGroup(); }
|
2023-04-10 22:22:17 +08:00
|
|
|
|
#endif
|
2023-06-01 20:14:34 +08:00
|
|
|
|
EcsGroup result = a._source.GetFreeGroup();
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (b.Has(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-04-15 00:23:46 +08:00
|
|
|
|
return result;
|
2023-04-10 22:22:17 +08:00
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
/// <summary>as Except sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup Except(EcsSpan a, EcsGroup b)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { return a.World.GetFreeGroup(); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
EcsGroup result = b._source.GetFreeGroup();
|
|
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (b.Has(entityID) == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>as Except sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup Except(EcsSpan a, EcsSpan b)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (a.WorldID != b.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { return a.World.GetFreeGroup(); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
EcsGroup result = a.World.GetFreeGroup();
|
|
|
|
|
|
result.CopyFrom(a);
|
|
|
|
|
|
result.ExceptWith(b);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>as Except sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
2024-03-02 04:57:52 +08:00
|
|
|
|
public static EcsGroup Except(EcsReadonlyGroup a, EcsReadonlyGroup b)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Except(a.GetSource_Internal(), b.GetSource_Internal());
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endregion
|
2024-03-02 04:57:52 +08:00
|
|
|
|
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#region Intersect
|
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
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-03-02 04:57:52 +08:00
|
|
|
|
if (a._source != b._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a._source != b._source) { return a.World.GetFreeGroup(); }
|
2023-04-10 22:22:17 +08:00
|
|
|
|
#endif
|
2023-06-01 20:14:34 +08:00
|
|
|
|
EcsGroup result = a._source.GetFreeGroup();
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (b.Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-04-15 00:23:46 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup Intersect(EcsSpan a, EcsGroup b)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { return a.World.GetFreeGroup(); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
EcsGroup result = b._source.GetFreeGroup();
|
|
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (b.Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup Intersect(EcsGroup a, EcsSpan b)
|
|
|
|
|
|
{
|
|
|
|
|
|
//операция симметричная, можно просто переставить параметры
|
|
|
|
|
|
return Intersect(b, a);
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup Intersect(EcsSpan a, EcsSpan b)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (a.WorldID != b.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { return a.World.GetFreeGroup(); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
EcsGroup result = b.World.GetFreeGroup();
|
|
|
|
|
|
result.CopyFrom(a);
|
|
|
|
|
|
result.IntersectWith(b);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>as Intersect sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
2024-03-02 04:57:52 +08:00
|
|
|
|
public static EcsGroup Intersect(EcsReadonlyGroup a, EcsReadonlyGroup b)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Intersect(a.GetSource_Internal(), b.GetSource_Internal());
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endregion
|
2023-06-01 19:13:04 +08:00
|
|
|
|
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#region SymmetricExcept
|
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
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-03-02 04:57:52 +08:00
|
|
|
|
if (a._source != b._source) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a._source != b._source) { return a.World.GetFreeGroup(); }
|
2023-04-15 00:23:46 +08:00
|
|
|
|
#endif
|
2023-06-01 20:14:34 +08:00
|
|
|
|
EcsGroup result = a._source.GetFreeGroup();
|
2024-03-02 04:57:52 +08:00
|
|
|
|
foreach (var entityID in a)
|
|
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (b.Has(entityID) == false)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (var entityID in b)
|
|
|
|
|
|
{
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (a.Has(entityID) == false)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-04-15 00:23:46 +08:00
|
|
|
|
return result;
|
2023-04-10 22:22:17 +08:00
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
/// <summary>as Symmetric Except sets</summary>
|
|
|
|
|
|
/// <returns>new group from pool</returns>
|
|
|
|
|
|
public static EcsGroup SymmetricExcept(EcsSpan a, EcsSpan b)
|
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2024-09-03 17:30:26 +08:00
|
|
|
|
if (a.WorldID != b.WorldID) { Throw.Group_ArgumentDifferentWorldsException(); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
|
if (a.WorldID != b.WorldID) { return a.World.GetFreeGroup(); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
EcsGroup result = a.World.GetFreeGroup();
|
|
|
|
|
|
result.CopyFrom(a);
|
|
|
|
|
|
foreach (var entityID in b)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (result.Has(entityID))
|
|
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
result.MarkEntity_Internal(entityID);
|
2024-09-03 17:30:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
result.Add_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
result.ClearMarked_Internal();
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
public static EcsGroup SymmetricExcept(EcsReadonlyGroup a, EcsReadonlyGroup b)
|
|
|
|
|
|
{
|
|
|
|
|
|
return SymmetricExcept(a.GetSource_Internal(), b.GetSource_Internal());
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#endregion
|
2023-06-01 20:14:34 +08:00
|
|
|
|
|
2024-09-03 17:30:26 +08:00
|
|
|
|
#region Inverse
|
2023-06-01 20:14:34 +08:00
|
|
|
|
public static EcsGroup Inverse(EcsGroup a)
|
|
|
|
|
|
{
|
|
|
|
|
|
EcsGroup result = a._source.GetFreeGroup();
|
2024-08-23 22:31:43 +08:00
|
|
|
|
foreach (var entityID in a._source.Entities)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
2024-08-23 22:31:43 +08:00
|
|
|
|
if (a.Has(entityID) == false)
|
2024-03-02 04:57:52 +08:00
|
|
|
|
{
|
2024-08-23 22:31:43 +08:00
|
|
|
|
result.Add_Internal(entityID);
|
2024-03-02 04:57:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-06-01 20:14:34 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
2024-03-02 04:57:52 +08:00
|
|
|
|
public static EcsGroup Inverse(EcsReadonlyGroup a)
|
|
|
|
|
|
{
|
|
|
|
|
|
return Inverse(a.GetSource_Internal());
|
|
|
|
|
|
}
|
2024-09-03 17:30:26 +08:00
|
|
|
|
public static EcsGroup Inverse(EcsSpan a)
|
|
|
|
|
|
{
|
|
|
|
|
|
EcsGroup result = a.World.GetFreeGroup();
|
|
|
|
|
|
result.CopyFrom(a.World.Entities);
|
|
|
|
|
|
result.ExceptWith(a);
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
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)]
|
2024-03-02 21:02:32 +08:00
|
|
|
|
public Enumerator GetEnumerator() { return new Enumerator(this); }
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
|
|
|
|
|
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() { return GetEnumerator(); }
|
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;
|
2024-03-02 21:02:32 +08:00
|
|
|
|
//для оптимизации компилятором
|
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)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
get { return _dense[_index]; }
|
2023-02-13 21:11:54 +08:00
|
|
|
|
}
|
2024-03-02 21:02:32 +08:00
|
|
|
|
object IEnumerator.Current { get { return Current; } }
|
2023-02-13 21:11:54 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
public bool MoveNext() { return --_index > 0; } // проверка с учтом что отсчет начинается с индекса 1
|
2023-12-24 15:40:19 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-09-07 17:18:35 +08:00
|
|
|
|
void IDisposable.Dispose() { }
|
|
|
|
|
|
void IEnumerator.Reset() { throw new NotSupportedException(); }
|
2023-02-13 21:11:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2023-04-08 23:01:10 +08:00
|
|
|
|
|
2024-09-04 12:11:35 +08:00
|
|
|
|
#region HiBitMarking
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private void MarkEntity_Internal(int entityID)
|
2024-09-04 12:11:35 +08:00
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
_dense[IndexOf(entityID)] |= int.MinValue;
|
2024-09-04 12:11:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private bool IsMarkIndex_Internal(int index)
|
2024-09-04 12:11:35 +08:00
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
return (_dense[index] & int.MinValue) == int.MinValue;
|
2024-09-04 12:11:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private void UnmarkIndex_Internal(int index)
|
2024-09-04 12:11:35 +08:00
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
_dense[index] &= int.MaxValue;
|
2024-09-04 12:11:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void ClearUnmarked_Internal()
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
|
|
|
|
|
|
{
|
|
|
|
|
|
int entityID = _dense[i];
|
2024-11-26 01:49:39 +08:00
|
|
|
|
if (IsMarkIndex_Internal(i))
|
2024-09-04 12:11:35 +08:00
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
UnmarkIndex_Internal(i);
|
2024-09-04 12:11:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
private void ClearMarked_Internal()
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = _count; i > 0; i--)//итерация в обратном порядке исключает ошибки при удалении элементов
|
|
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
if (IsMarkIndex_Internal(i))
|
2024-09-04 12:11:35 +08:00
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
UnmarkIndex_Internal(i); // Unmark_Internal должен быть до Remove_Internal
|
2024-12-31 21:38:56 +08:00
|
|
|
|
int entityID = _dense[i];
|
2024-09-04 12:11:35 +08:00
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2023-12-24 15:40:19 +08:00
|
|
|
|
#region Other
|
2023-04-15 00:23:46 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public int First() { return _dense[1]; }
|
2023-12-23 20:17:28 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public int Last() { return _dense[_count]; }
|
2023-12-23 20:17:28 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 20:53:23 +08:00
|
|
|
|
internal void OnWorldResize_Internal(int newSize)
|
|
|
|
|
|
{
|
2024-11-25 10:30:23 +08:00
|
|
|
|
//Array.Resize(ref _sparse, newSize);
|
|
|
|
|
|
_totalCapacity = newSize;
|
2024-11-26 01:49:39 +08:00
|
|
|
|
var oldPagesCount = _sparsePagesCount;
|
|
|
|
|
|
_sparsePagesCount = CalcSparseSize(_totalCapacity);
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_sparsePagesHandler = MemoryAllocator.Realloc<PageSlot>(_sparsePagesHandler, _sparsePagesCount);
|
|
|
|
|
|
_sparsePages = _sparsePagesHandler.As<PageSlot>();
|
|
|
|
|
|
//_sparsePages = UnmanagedArrayUtility.Resize<PageSlot>(_sparsePages, _sparsePagesCount);
|
2024-11-26 02:40:59 +08:00
|
|
|
|
for (int i = oldPagesCount; i < _sparsePagesCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
_sparsePages[i] = PageSlot.Empty;
|
|
|
|
|
|
}
|
2024-03-02 20:53:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
|
internal void OnReleaseDelEntityBuffer_Internal(ReadOnlySpan<int> buffer)
|
|
|
|
|
|
{
|
2024-09-04 12:02:18 +08:00
|
|
|
|
if (_count <= 0) { return; }
|
2024-03-02 20:53:23 +08:00
|
|
|
|
foreach (var entityID in buffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Has(entityID))
|
|
|
|
|
|
{
|
|
|
|
|
|
Remove_Internal(entityID);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-02 06:07:50 +08:00
|
|
|
|
public override string ToString()
|
|
|
|
|
|
{
|
|
|
|
|
|
return CollectionUtility.EntitiesToString(_dense.Skip(1).Take(_count), "group");
|
|
|
|
|
|
}
|
2024-09-04 12:02:18 +08:00
|
|
|
|
void ICollection<int>.Add(int item) { Add(item); }
|
|
|
|
|
|
bool ICollection<int>.Contains(int item) { return Has(item); }
|
2024-09-03 17:30:26 +08:00
|
|
|
|
|
2023-12-31 13:07:53 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public static implicit operator EcsReadonlyGroup(EcsGroup a) { return a.Readonly; }
|
2023-12-31 13:07:53 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public static implicit operator EcsSpan(EcsGroup a) { return 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;
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public EcsWorld World { get { return _group.World; } }
|
|
|
|
|
|
public bool IsReleased { get { return _group.IsReleased; } }
|
2024-02-29 22:42:33 +08:00
|
|
|
|
public EntitySlotInfo[] Entities
|
2023-05-28 06:29:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2024-02-29 22:42:33 +08:00
|
|
|
|
EntitySlotInfo[] result = new EntitySlotInfo[_group.Count];
|
2023-05-28 06:29:04 +08:00
|
|
|
|
int i = 0;
|
|
|
|
|
|
foreach (var e in _group)
|
2024-02-29 22:42:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
result[i++] = _group.World.GetEntitySlotInfoDebug(e);
|
|
|
|
|
|
}
|
2023-05-28 06:29:04 +08:00
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-02 04:20:34 +08:00
|
|
|
|
public int Count { get { return _group.Count; } }
|
|
|
|
|
|
public int CapacityDense { get { return _group.CapacityDense; } }
|
|
|
|
|
|
public override string ToString() { return _group.ToString(); }
|
|
|
|
|
|
public DebuggerProxy(EcsGroup group) { _group = group; }
|
2024-01-29 01:09:17 +08:00
|
|
|
|
public DebuggerProxy(EcsReadonlyGroup group) : this(group.GetSource_Internal()) { }
|
2023-04-01 20:45:37 +08:00
|
|
|
|
}
|
2023-05-28 06:29:04 +08:00
|
|
|
|
#endregion
|
2024-11-25 10:30:23 +08:00
|
|
|
|
|
2024-11-26 01:49:39 +08:00
|
|
|
|
#region PageSlot
|
2024-11-25 10:30:23 +08:00
|
|
|
|
private static int CalcSparseSize(int capacity)
|
|
|
|
|
|
{
|
2024-11-26 01:49:39 +08:00
|
|
|
|
return (capacity >> PageSlot.SHIFT) + ((capacity & PageSlot.MASK) == 0 ? 0 : 1);
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2024-11-26 19:16:14 +08:00
|
|
|
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
2024-12-31 21:38:56 +08:00
|
|
|
|
[DebuggerDisplay("Page: {Count}")]
|
2024-11-26 01:49:39 +08:00
|
|
|
|
private struct PageSlot
|
2024-11-25 10:30:23 +08:00
|
|
|
|
{
|
|
|
|
|
|
public const int SHIFT = 6; // 64
|
|
|
|
|
|
public const int SIZE = 1 << SHIFT;
|
|
|
|
|
|
public const int MASK = SIZE - 1;
|
|
|
|
|
|
|
2024-11-26 19:16:14 +08:00
|
|
|
|
public static readonly PageSlot Empty = new PageSlot(_nullPage);
|
2024-11-26 02:40:59 +08:00
|
|
|
|
|
2024-11-25 10:30:23 +08:00
|
|
|
|
public int* Indexes;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
public int IndexesXOR;
|
|
|
|
|
|
public sbyte Count;
|
|
|
|
|
|
public PageSlot(int* indexes)
|
2024-11-26 02:40:59 +08:00
|
|
|
|
{
|
|
|
|
|
|
Indexes = indexes;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
IndexesXOR = 0;
|
|
|
|
|
|
Count = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
private class DebuggerProxy
|
|
|
|
|
|
{
|
|
|
|
|
|
private PageSlot _page;
|
|
|
|
|
|
public int[] Indexes;
|
|
|
|
|
|
public IntPtr IndexesPtr;
|
2025-05-17 14:55:31 +08:00
|
|
|
|
public bool IsNullPage;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
public int IndexesXOR;
|
|
|
|
|
|
public sbyte Count;
|
|
|
|
|
|
|
2024-12-31 21:38:56 +08:00
|
|
|
|
public DebuggerProxy(PageSlot page)
|
|
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
//if (page.Indexes == null) { return; }
|
|
|
|
|
|
//try
|
2024-11-26 19:16:14 +08:00
|
|
|
|
{
|
2025-05-17 14:55:31 +08:00
|
|
|
|
_page = page;
|
|
|
|
|
|
Indexes = new int[SIZE];
|
|
|
|
|
|
for (int i = 0; i < SIZE; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
Indexes[i] = page.Indexes[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
IndexesPtr = (IntPtr)page.Indexes;
|
|
|
|
|
|
IndexesXOR = page.IndexesXOR;
|
|
|
|
|
|
Count = page.Count;
|
|
|
|
|
|
IsNullPage = IndexesPtr == (IntPtr)_nullPagePtrFake;
|
2024-11-26 19:16:14 +08:00
|
|
|
|
}
|
2025-05-17 14:55:31 +08:00
|
|
|
|
//catch (Exception)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// _page = default;
|
|
|
|
|
|
// Indexes = null;
|
|
|
|
|
|
// IndexesPtr = default;
|
|
|
|
|
|
// IndexesXOR = default;
|
|
|
|
|
|
// Count = default;
|
|
|
|
|
|
// IsNullPage = default;
|
|
|
|
|
|
//}
|
2024-11-26 19:16:14 +08:00
|
|
|
|
}
|
2024-11-26 02:40:59 +08:00
|
|
|
|
}
|
2024-11-25 10:30:23 +08:00
|
|
|
|
}
|
2024-11-26 01:49:39 +08:00
|
|
|
|
#endregion
|
2023-04-01 20:45:37 +08:00
|
|
|
|
}
|
2023-05-28 06:29:04 +08:00
|
|
|
|
}
|