mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 18:14:37 +08:00
update entity copying/EcsTypeCode Api/add IdDispenser/import module with inject
This commit is contained in:
parent
709ecf9cf8
commit
7a5aa6477d
@ -147,7 +147,10 @@ namespace DCFApixels.DragonECS
|
|||||||
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
|
public static EcsPipeline.Builder Inject<T>(this EcsPipeline.Builder self, T data)
|
||||||
{
|
{
|
||||||
if (data == null) Throw.ArgumentNull();
|
if (data == null) Throw.ArgumentNull();
|
||||||
return self.Add(new InjectSystem<T>(data));
|
self.Add(new InjectSystem<T>(data));
|
||||||
|
if (data is IEcsModule module)
|
||||||
|
self.AddModule(module);
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
public static EcsPipeline.Builder Inject<A, B>(this EcsPipeline.Builder self, A a, B b)
|
public static EcsPipeline.Builder Inject<A, B>(this EcsPipeline.Builder self, A a, B b)
|
||||||
{
|
{
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
using DCFApixels.DragonECS.Utils;
|
using DCFApixels.DragonECS.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public partial class EcsWorld
|
public abstract partial class EcsWorld
|
||||||
{
|
{
|
||||||
internal readonly struct PoolCache<T> : IEcsWorldComponent<PoolCache<T>>
|
internal readonly struct PoolCache<T> : IEcsWorldComponent<PoolCache<T>>
|
||||||
where T : IEcsPoolImplementation, new()
|
where T : IEcsPoolImplementation, new()
|
||||||
|
@ -3,7 +3,6 @@ using DCFApixels.DragonECS.Utils;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using typecode = System.Int32;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
@ -14,6 +13,8 @@ namespace DCFApixels.DragonECS
|
|||||||
private Type _worldType;
|
private Type _worldType;
|
||||||
private int _worldTypeID;
|
private int _worldTypeID;
|
||||||
|
|
||||||
|
private bool _isDestroyed;
|
||||||
|
|
||||||
private IntDispenser _entityDispenser;
|
private IntDispenser _entityDispenser;
|
||||||
private int _entitiesCount;
|
private int _entitiesCount;
|
||||||
private int _entitesCapacity;
|
private int _entitesCapacity;
|
||||||
@ -34,6 +35,7 @@ namespace DCFApixels.DragonECS
|
|||||||
private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
|
private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
public bool IsDestroyed => _isDestroyed;
|
||||||
public int WorldTypeID => _worldTypeID;
|
public int WorldTypeID => _worldTypeID;
|
||||||
public int Count => _entitiesCount;
|
public int Count => _entitiesCount;
|
||||||
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
public int Capacity => _entitesCapacity; //_denseEntities.Length;
|
||||||
@ -80,6 +82,7 @@ namespace DCFApixels.DragonECS
|
|||||||
Worlds[id] = null;
|
Worlds[id] = null;
|
||||||
ReleaseData(id);
|
ReleaseData(id);
|
||||||
_worldIdDispenser.Release(id);
|
_worldIdDispenser.Release(id);
|
||||||
|
_isDestroyed = true;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -242,7 +245,16 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
foreach (var pool in _pools)
|
foreach (var pool in _pools)
|
||||||
{
|
{
|
||||||
if (pool.Has(fromEntityID)) pool.Copy(fromEntityID, toEntityID);
|
if (pool.Has(fromEntityID))
|
||||||
|
pool.Copy(fromEntityID, toEntityID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void CopyEntity(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
|
{
|
||||||
|
foreach (var pool in _pools)
|
||||||
|
{
|
||||||
|
if (pool.Has(fromEntityID))
|
||||||
|
pool.Copy(fromEntityID, toWorld, toEntityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public int CloneEntity(int fromEntityID)
|
public int CloneEntity(int fromEntityID)
|
||||||
@ -251,6 +263,12 @@ namespace DCFApixels.DragonECS
|
|||||||
CopyEntity(fromEntityID, newEntity);
|
CopyEntity(fromEntityID, newEntity);
|
||||||
return newEntity;
|
return newEntity;
|
||||||
}
|
}
|
||||||
|
public int CloneEntity(int fromEntityID, EcsWorld toWorld)
|
||||||
|
{
|
||||||
|
int newEntity = NewEmptyEntity();
|
||||||
|
CopyEntity(fromEntityID, toWorld, newEntity);
|
||||||
|
return newEntity;
|
||||||
|
}
|
||||||
public void CloneEntity(int fromEntityID, int toEntityID)
|
public void CloneEntity(int fromEntityID, int toEntityID)
|
||||||
{
|
{
|
||||||
CopyEntity(fromEntityID, toEntityID);
|
CopyEntity(fromEntityID, toEntityID);
|
||||||
@ -260,6 +278,7 @@ namespace DCFApixels.DragonECS
|
|||||||
pool.Del(toEntityID);
|
pool.Del(toEntityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//public void CloneEntity(int fromEntityID, EcsWorld toWorld, int toEntityID)
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Components Increment
|
#region Components Increment
|
||||||
|
@ -19,10 +19,10 @@ namespace DCFApixels.DragonECS
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
public static int Count => _codes.Count;
|
public static int Count => _codes.Count;
|
||||||
}
|
internal static class Cache<T>
|
||||||
internal static class EcsTypeCodeCache<T>
|
{
|
||||||
{
|
public static readonly int code = EcsTypeCode.GetCode(typeof(T));
|
||||||
public static readonly int code = EcsTypeCode.GetCode(typeof(T));
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
415
src/Utils/IdDispenser.cs
Normal file
415
src/Utils/IdDispenser.cs
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
// Sparse Set based ID dispenser, with the ability to reserve IDs.
|
||||||
|
// Warning! Release version omits error exceptions, incorrect use may lead to unstable state.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
public class IdDispenser : IEnumerable<int>, IReadOnlyCollection<int>
|
||||||
|
{
|
||||||
|
private const int MIN_SIZE = 4;
|
||||||
|
|
||||||
|
private int[] _dense = Array.Empty<int>();
|
||||||
|
private int[] _sparse = Array.Empty<int>();
|
||||||
|
private IDState[] _sparseState = Array.Empty<IDState>();
|
||||||
|
|
||||||
|
private int _usedCount; //[ |uuuu| ]
|
||||||
|
private int _reservedCount; //[rrr| | ]
|
||||||
|
private int _size; //[rrr|uuuu|ffffff]
|
||||||
|
|
||||||
|
private int _nullID;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
/// <summary> Used Count </summary>
|
||||||
|
public int Count => _usedCount;
|
||||||
|
public int ReservedCount => _reservedCount;
|
||||||
|
public int Size => _size;
|
||||||
|
public int NullID => _nullID;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public IdDispenser(int capacity, int nullID = 0)
|
||||||
|
{
|
||||||
|
if (capacity % MIN_SIZE > 0)
|
||||||
|
capacity += MIN_SIZE;
|
||||||
|
Resize(capacity);
|
||||||
|
SetNullID(nullID);
|
||||||
|
|
||||||
|
Reserved = new ReservedSpan(this);
|
||||||
|
Used = new UsedSpan(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Use/Reserve/Release
|
||||||
|
/// <summary>Marks as used and returns next free id.</summary>
|
||||||
|
public int UseFree()
|
||||||
|
{
|
||||||
|
int count = _usedCount + _reservedCount;
|
||||||
|
CheckOrResize(count + 1);
|
||||||
|
int id = _dense[count];
|
||||||
|
Add(id);
|
||||||
|
_sparseState[id] = IDState.Used;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void UseFreeRange(ref int[] array, int range)
|
||||||
|
{
|
||||||
|
if (array.Length < range)
|
||||||
|
Array.Resize(ref array, range);
|
||||||
|
for (int i = 0; i < range; i++)
|
||||||
|
array[i] = UseFree();
|
||||||
|
}
|
||||||
|
public void UseFreeRange(List<int> list, int range)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < range; i++)
|
||||||
|
list.Add(UseFree());
|
||||||
|
}
|
||||||
|
/// <summary>Marks as used a free or reserved id, after this id cannot be retrieved via UseFree.</summary>
|
||||||
|
public void Use(int id)
|
||||||
|
{
|
||||||
|
CheckOrResize(id);
|
||||||
|
#if DEBUG
|
||||||
|
if (IsUsed(id) || IsReserved(id))
|
||||||
|
{
|
||||||
|
if (IsUsed(id)) ThrowHalper.ThrowIsAlreadyInUse(id);
|
||||||
|
else ThrowHalper.ThrowIsHasBeenReserved(id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (IsFree(id))
|
||||||
|
Add(id);
|
||||||
|
_sparseState[id] = IDState.Used;
|
||||||
|
}
|
||||||
|
public void UseRange(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
foreach (var item in ids)
|
||||||
|
Use(item);
|
||||||
|
}
|
||||||
|
/// <summary>Marks as reserved and returns next free id, after this id cannot be retrieved via UseFree.</summary>
|
||||||
|
public int ReserveFree()
|
||||||
|
{
|
||||||
|
int count = _usedCount + _reservedCount;
|
||||||
|
CheckOrResize(count + 1);
|
||||||
|
int id = _dense[count];
|
||||||
|
_sparseState[id] = IDState.Reserved;
|
||||||
|
AddReserved(id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
/// <summary>Marks as reserved a free id, after this id cannot be retrieved via UseFree.</summary>
|
||||||
|
public void Reserve(int id)
|
||||||
|
{
|
||||||
|
CheckOrResize(id);
|
||||||
|
#if DEBUG
|
||||||
|
if (!IsFree(id)) ThrowHalper.ThrowIsNotAvailable(id);
|
||||||
|
#endif
|
||||||
|
_sparseState[id] = IDState.Reserved;
|
||||||
|
AddReserved(id);
|
||||||
|
}
|
||||||
|
public void ReserveRange(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
foreach (var item in ids)
|
||||||
|
Reserve(item);
|
||||||
|
}
|
||||||
|
public void Release(int id)
|
||||||
|
{
|
||||||
|
CheckOrResize(id);
|
||||||
|
#if DEBUG
|
||||||
|
if (IsFree(id) || IsNullID(id))
|
||||||
|
{
|
||||||
|
if (IsFree(id)) ThrowHalper.ThrowIsNotUsed(id);
|
||||||
|
else ThrowHalper.ThrowIsNullID(id);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (_sparseState[id] == IDState.Used)
|
||||||
|
Remove(id);
|
||||||
|
else
|
||||||
|
RemoveReserved(id);
|
||||||
|
_sparseState[id] = IDState.Free;
|
||||||
|
}
|
||||||
|
public void ReleaseRange(IEnumerable<int> ids)
|
||||||
|
{
|
||||||
|
foreach (var item in ids)
|
||||||
|
Release(item);
|
||||||
|
}
|
||||||
|
public void ReleaseAll()
|
||||||
|
{
|
||||||
|
_usedCount = 0;
|
||||||
|
_reservedCount = 0;
|
||||||
|
for (int i = 0; i < _size;)
|
||||||
|
{
|
||||||
|
_sparse[i] = i;
|
||||||
|
_sparseState[i] = IDState.Free;
|
||||||
|
_dense[i] = i++;
|
||||||
|
_sparse[i] = i;
|
||||||
|
_sparseState[i] = IDState.Free;
|
||||||
|
_dense[i] = i++;
|
||||||
|
_sparse[i] = i;
|
||||||
|
_sparseState[i] = IDState.Free;
|
||||||
|
_dense[i] = i++;
|
||||||
|
_sparse[i] = i;
|
||||||
|
_sparseState[i] = IDState.Free;
|
||||||
|
_dense[i] = i++;
|
||||||
|
}
|
||||||
|
SetNullID(_nullID);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Checks
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool IsFree(int id) => _sparseState[id] == IDState.Free;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool IsReserved(int id) => _sparseState[id] == IDState.Reserved;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool IsUsed(int id) => _sparseState[id] == IDState.Used;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool IsNullID(int id) => id == _nullID;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Sort
|
||||||
|
/// <summary>O(n) Sort. n = Size. Allows the UseFree method to return denser ids.</summary>
|
||||||
|
public void Sort()
|
||||||
|
{
|
||||||
|
int usedInc = _reservedCount;
|
||||||
|
int reservedInc = 0;
|
||||||
|
int freeInc = _reservedCount + _usedCount;
|
||||||
|
for (int i = 0; i < _size; i++)
|
||||||
|
{
|
||||||
|
switch (_sparseState[i])
|
||||||
|
{
|
||||||
|
case IDState.Free:
|
||||||
|
_sparse[i] = freeInc;
|
||||||
|
_dense[freeInc++] = i;
|
||||||
|
break;
|
||||||
|
case IDState.Reserved:
|
||||||
|
_sparse[i] = reservedInc;
|
||||||
|
_dense[reservedInc++] = i;
|
||||||
|
break;
|
||||||
|
case IDState.Used:
|
||||||
|
_sparse[i] = usedInc;
|
||||||
|
_dense[usedInc++] = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Other
|
||||||
|
private void SetNullID(int nullID)
|
||||||
|
{
|
||||||
|
_nullID = nullID;
|
||||||
|
if (nullID >= 0)
|
||||||
|
{
|
||||||
|
AddReserved(nullID);
|
||||||
|
_sparseState[nullID] = IDState.Reserved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool IsValid()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _usedCount; i++)
|
||||||
|
{
|
||||||
|
if (_sparse[_dense[i]] != i || _dense[_sparse[i]] != i)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private void CheckOrResize(int id)
|
||||||
|
{
|
||||||
|
if (id > _size)
|
||||||
|
{
|
||||||
|
int leftBit = 0;
|
||||||
|
while (id != 0)
|
||||||
|
{
|
||||||
|
id >>= 1;
|
||||||
|
id &= int.MaxValue;
|
||||||
|
leftBit++;
|
||||||
|
}
|
||||||
|
if (leftBit >= 32)
|
||||||
|
Resize(int.MaxValue);
|
||||||
|
else
|
||||||
|
Resize(1 << leftBit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void Add(int value)
|
||||||
|
{
|
||||||
|
Swap(value, _reservedCount + _usedCount++);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void Remove(int value)
|
||||||
|
{
|
||||||
|
Swap(value, _reservedCount + --_usedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void AddReserved(int value)
|
||||||
|
{
|
||||||
|
Swap(value, _reservedCount + _usedCount);
|
||||||
|
Swap(value, _reservedCount++);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void RemoveReserved(int value)
|
||||||
|
{
|
||||||
|
Swap(value, --_reservedCount);
|
||||||
|
Swap(value, _reservedCount + _usedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void Swap(int sparseIndex, int denseIndex)
|
||||||
|
{
|
||||||
|
int _dense_denseIndex_ = _dense[denseIndex];
|
||||||
|
int _sparse_sparseIndex_ = _sparse[sparseIndex];
|
||||||
|
_dense[denseIndex] = _dense[_sparse_sparseIndex_];
|
||||||
|
_dense[_sparse_sparseIndex_] = _dense_denseIndex_;
|
||||||
|
_sparse[_dense_denseIndex_] = _sparse_sparseIndex_;
|
||||||
|
_sparse[sparseIndex] = denseIndex;
|
||||||
|
}
|
||||||
|
private void Resize(int newSize)
|
||||||
|
{
|
||||||
|
if (newSize < MIN_SIZE)
|
||||||
|
newSize = MIN_SIZE;
|
||||||
|
Array.Resize(ref _dense, newSize);
|
||||||
|
Array.Resize(ref _sparse, newSize);
|
||||||
|
Array.Resize(ref _sparseState, newSize);
|
||||||
|
for (int i = _size; i < newSize;)
|
||||||
|
{
|
||||||
|
_sparse[i] = i;
|
||||||
|
_dense[i] = i++;
|
||||||
|
_sparse[i] = i;
|
||||||
|
_dense[i] = i++;
|
||||||
|
_sparse[i] = i;
|
||||||
|
_dense[i] = i++;
|
||||||
|
_sparse[i] = i;
|
||||||
|
_dense[i] = i++;
|
||||||
|
}
|
||||||
|
_size = newSize;
|
||||||
|
Resized(newSize);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public delegate void ResizedHandler(int newSize);
|
||||||
|
public event ResizedHandler Resized = delegate { };
|
||||||
|
|
||||||
|
internal enum IDState : byte
|
||||||
|
{
|
||||||
|
Free,
|
||||||
|
Reserved,
|
||||||
|
Used,
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Enumerable
|
||||||
|
public UsedSpan Used;
|
||||||
|
public ReservedSpan Reserved;
|
||||||
|
public Enumerator GetEnumerator() => new Enumerator(_dense, _reservedCount, _usedCount);
|
||||||
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public struct Enumerator : IEnumerator<int>
|
||||||
|
{
|
||||||
|
private readonly int[] _dense;
|
||||||
|
private readonly int _count;
|
||||||
|
private int _index;
|
||||||
|
public int Current => _dense[_index];
|
||||||
|
object IEnumerator.Current => Current;
|
||||||
|
public Enumerator(int[] dense, int startIndex, int count)
|
||||||
|
{
|
||||||
|
_dense = dense;
|
||||||
|
_count = startIndex + count;
|
||||||
|
_index = startIndex - 1;
|
||||||
|
}
|
||||||
|
public bool MoveNext() => ++_index < _count;
|
||||||
|
public void Dispose() { }
|
||||||
|
public void Reset() => _index = -1;
|
||||||
|
}
|
||||||
|
public readonly struct UsedSpan : IEnumerable<int>
|
||||||
|
{
|
||||||
|
private readonly IdDispenser _instance;
|
||||||
|
public int Count => _instance._usedCount;
|
||||||
|
internal UsedSpan(IdDispenser instance) => _instance = instance;
|
||||||
|
public Enumerator GetEnumerator() => new Enumerator(_instance._dense, _instance._reservedCount, _instance._usedCount);
|
||||||
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
||||||
|
public readonly struct ReservedSpan : IEnumerable<int>
|
||||||
|
{
|
||||||
|
private readonly IdDispenser _instance;
|
||||||
|
public int Count => _instance._reservedCount;
|
||||||
|
internal ReservedSpan(IdDispenser instance) => _instance = instance;
|
||||||
|
public Enumerator GetEnumerator() => new Enumerator(_instance._dense, 0, _instance._reservedCount);
|
||||||
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Utils
|
||||||
|
private static class ThrowHalper
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
public static void ThrowIsAlreadyInUse(int id) => throw new ArgumentException($"Id {id} is already in use.");
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
public static void ThrowIsHasBeenReserved(int id) => throw new ArgumentException($"Id {id} has been reserved.");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
public static void ThrowIsNotUsed(int id) => throw new ArgumentException($"Id {id} is not used.");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
public static void ThrowIsNotAvailable(int id) => throw new ArgumentException($"Id {id} is not available.");
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
public static void ThrowIsNullID(int id) => throw new ArgumentException($"Id {id} cannot be released because it is used as a null id.");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DebuggerProxy
|
||||||
|
{
|
||||||
|
private IdDispenser _dispenser;
|
||||||
|
public DebuggerProxy(IdDispenser dispenser) => _dispenser = dispenser;
|
||||||
|
#if DEBUG
|
||||||
|
public IEnumerable<int> Used => _dispenser.Used;
|
||||||
|
public IEnumerable<int> Reserved => _dispenser.Reserved;
|
||||||
|
public Pair[] Pairs
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Pair[] result = new Pair[_dispenser.Size];
|
||||||
|
for (int i = 0; i < result.Length; i++)
|
||||||
|
result[i] = new Pair(_dispenser._dense[i], _dispenser._sparse[i]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ID[] All
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
ID[] result = new ID[_dispenser.Size];
|
||||||
|
for (int i = 0; i < result.Length; i++)
|
||||||
|
{
|
||||||
|
int id = _dispenser._dense[i];
|
||||||
|
result[i] = new ID(id, _dispenser._sparseState[id].ToString());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool IsValid => _dispenser.IsValid();
|
||||||
|
public int Count => _dispenser.ReservedCount;
|
||||||
|
public int Size => _dispenser.Size;
|
||||||
|
public int NullID => _dispenser._nullID;
|
||||||
|
internal readonly struct ID
|
||||||
|
{
|
||||||
|
public readonly int id;
|
||||||
|
public readonly string state;
|
||||||
|
public ID(int id, string state) { this.id = id; this.state = state; }
|
||||||
|
public override string ToString() => $"{id} - {state}";
|
||||||
|
}
|
||||||
|
internal readonly struct Pair
|
||||||
|
{
|
||||||
|
public readonly int dense;
|
||||||
|
public readonly int sparse;
|
||||||
|
public Pair(int dense, int sparse) { this.dense = dense; this.sparse = sparse; }
|
||||||
|
public override string ToString() => $"{dense} - {sparse}";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
11
src/Utils/IdDispenser.cs.meta
Normal file
11
src/Utils/IdDispenser.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 54c009cfa7ae0fd49938525468703c8b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Loading…
Reference in New Issue
Block a user