mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-19 02:24:37 +08:00
rework EcsGroup
for performance
This commit is contained in:
parent
624abd5b51
commit
14e1a0ae09
199
src/EcsGroup.cs
199
src/EcsGroup.cs
@ -1,83 +1,138 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using delayedOp = System.Int32;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public interface IEcsReadonlyGroup
|
public interface IEcsReadonlyGroup
|
||||||
{
|
{
|
||||||
public IEcsWorld World { get; }
|
int Count { get; }
|
||||||
public int Count { get; }
|
bool Contains(int entityID);
|
||||||
public EcsGroup.Enumerator GetEnumerator();
|
EcsGroup.Enumerator GetEnumerator();
|
||||||
}
|
}
|
||||||
public interface IEcsGroup : IEcsReadonlyGroup
|
public interface IEcsGroup : IEcsReadonlyGroup
|
||||||
{
|
{
|
||||||
public void Add(int entityID);
|
void Add(int entityID);
|
||||||
public void Remove(int entityID);
|
void Remove(int entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EcsGroup : IEcsGroup
|
// не может содержать значение 0
|
||||||
{
|
// _delayedOps это int[] для отложенных операций, хранятся отложенные операции в виде int значения, если старший бит = 0 то это опреация добавленияб если = 1 то это операция вычитания
|
||||||
private IEcsWorld _source;
|
|
||||||
private SparseSet _entities;
|
|
||||||
|
|
||||||
private DelayedOp[] _delayedOps;
|
// this collection can only store numbers greater than 0
|
||||||
|
public class EcsGroup : IEcsGroup
|
||||||
|
{
|
||||||
|
public const int DEALAYED_ADD = 0;
|
||||||
|
public const int DEALAYED_REMOVE = int.MinValue;
|
||||||
|
|
||||||
|
private IEcsWorld _source;
|
||||||
|
|
||||||
|
private int[] _dense;
|
||||||
|
private int[] _sparse;
|
||||||
|
|
||||||
|
private int _count;
|
||||||
|
|
||||||
|
private delayedOp[] _delayedOps;
|
||||||
private int _delayedOpsCount;
|
private int _delayedOpsCount;
|
||||||
|
|
||||||
private int _lockCount;
|
private int _lockCount;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public IEcsWorld World => _source;
|
public IEcsWorld World => _source;
|
||||||
public int Count => _entities.Count;
|
public int Count
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _count;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constrcutors
|
#region Constrcutors
|
||||||
public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 32)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public EcsGroup(IEcsWorld source, int denseCapacity = 64, int sparseCapacity = 256, int delayedOpsCapacity = 128)
|
||||||
{
|
{
|
||||||
_source = world;
|
_source = source;
|
||||||
_entities = new SparseSet(entitiesCapacity, entitiesCapacity);
|
_dense = new int[denseCapacity];
|
||||||
_delayedOps = new DelayedOp[delayedOpsCapacity];
|
_sparse = new int[sparseCapacity];
|
||||||
|
|
||||||
|
_delayedOps = new delayedOp[delayedOpsCapacity];
|
||||||
|
|
||||||
_lockCount = 0;
|
_lockCount = 0;
|
||||||
}
|
_delayedOpsCount = 0;
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Add/Remove
|
_count = 0;
|
||||||
public void Add(int entityID)
|
|
||||||
{
|
|
||||||
if (_lockCount > 0)
|
|
||||||
AddDelayedOp(entityID, true);
|
|
||||||
_entities.Add(entityID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(int entityID)
|
|
||||||
{
|
|
||||||
if (_lockCount > 0)
|
|
||||||
AddDelayedOp(entityID, false);
|
|
||||||
_entities.Remove(entityID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddDelayedOp(int entityID, bool isAdd)
|
|
||||||
{
|
|
||||||
if (_delayedOpsCount >= _delayedOps.Length)
|
|
||||||
{
|
|
||||||
Array.Resize(ref _delayedOps, _delayedOps.Length << 1);
|
|
||||||
}
|
|
||||||
ref DelayedOp delayedOd = ref _delayedOps[_delayedOpsCount++];
|
|
||||||
delayedOd.Entity = entityID;
|
|
||||||
delayedOd.Added = isAdd;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Contains
|
#region Contains
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Contains(int entityID) => _entities.Contains(entityID);
|
public bool Contains(int entityID)
|
||||||
|
{
|
||||||
|
return /*entityID > 0 && */ entityID < _sparse.Length && _sparse[entityID] > 0;
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region add/remove
|
||||||
|
public void Add(int entityID)
|
||||||
|
{
|
||||||
|
if (_lockCount > 0)
|
||||||
|
{
|
||||||
|
AddDelayedOp(entityID, DEALAYED_ADD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Contains(entityID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(++_count >= _dense.Length)
|
||||||
|
Array.Resize(ref _dense, _dense.Length << 1);
|
||||||
|
|
||||||
|
if (entityID > _sparse.Length)
|
||||||
|
{
|
||||||
|
int neadedSpace = _sparse.Length;
|
||||||
|
while (entityID >= neadedSpace)
|
||||||
|
neadedSpace <<= 1;
|
||||||
|
Array.Resize(ref _sparse, neadedSpace);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dense[_count] = entityID;
|
||||||
|
_sparse[entityID] = _count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(int entityID)
|
||||||
|
{
|
||||||
|
if (_lockCount > 0)
|
||||||
|
{
|
||||||
|
AddDelayedOp(entityID, DEALAYED_REMOVE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Contains(entityID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_dense[_sparse[entityID]] = _dense[_count];
|
||||||
|
_sparse[_dense[_count--]] = _sparse[entityID];
|
||||||
|
_sparse[entityID] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private void AddDelayedOp(int entityID, int isAddBitFlag)
|
||||||
|
{
|
||||||
|
if (_delayedOpsCount >= _delayedOps.Length)
|
||||||
|
{
|
||||||
|
Array.Resize(ref _delayedOps, _delayedOps.Length << 1);
|
||||||
|
}
|
||||||
|
_delayedOps[_delayedOpsCount++] = entityID | isAddBitFlag; // delayedOp = entityID add isAddBitFlag
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//TODO добавить автосоритровку при каждом GetEnumerator
|
||||||
|
|
||||||
#region AddGroup/RemoveGroup
|
#region AddGroup/RemoveGroup
|
||||||
public void AddGroup(IEcsReadonlyGroup group)
|
public void AddGroup(IEcsReadonlyGroup group)
|
||||||
{
|
{
|
||||||
foreach (var item in group)
|
foreach (var item in group)
|
||||||
{
|
{
|
||||||
_entities.TryAdd(item.id);
|
Add(item.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,37 +140,38 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
foreach (var item in group)
|
foreach (var item in group)
|
||||||
{
|
{
|
||||||
_entities.TryRemove(item.id);
|
Remove(item.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GetEnumerator
|
#region GetEnumerator
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void Unlock()
|
private void Unlock()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG || !DRAGONECS_NO_SANITIZE_CHECKS
|
||||||
if (_lockCount <= 0)
|
if (_lockCount <= 0)
|
||||||
{
|
{
|
||||||
throw new Exception($"Invalid lock-unlock balance for {nameof(EcsFilter)}.");
|
throw new Exception($"Invalid lock-unlock balance for {nameof(EcsGroup)}.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (--_lockCount <= 0)
|
if (--_lockCount <= 0)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _delayedOpsCount; i++)
|
for (int i = 0; i < _delayedOpsCount; i++)
|
||||||
{
|
{
|
||||||
ref DelayedOp op = ref _delayedOps[i];
|
delayedOp op = _delayedOps[i];
|
||||||
if (op.Added)
|
if (op >= 0) //delayedOp.IsAdded
|
||||||
{
|
{
|
||||||
Add(op.Entity);
|
Add(op & int.MaxValue); //delayedOp.Entity
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Remove(op.Entity);
|
Remove(op & int.MaxValue); //delayedOp.Entity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_delayedOpsCount = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Enumerator GetEnumerator()
|
public Enumerator GetEnumerator()
|
||||||
{
|
{
|
||||||
_lockCount++;
|
_lockCount++;
|
||||||
@ -124,39 +180,48 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Utils
|
#region Utils
|
||||||
public ref struct Enumerator
|
public struct Enumerator : IDisposable
|
||||||
{
|
{
|
||||||
private readonly EcsGroup _source;
|
private readonly EcsGroup _source;
|
||||||
private readonly SparseSet _entities;
|
private int _pointer;
|
||||||
private int _index;
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Enumerator(EcsGroup group)
|
public Enumerator(EcsGroup group)
|
||||||
{
|
{
|
||||||
_source = group;
|
_source = group;
|
||||||
_entities = group._entities;
|
_pointer = 0;
|
||||||
_index = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static EcsProfilerMarker _marker = new EcsProfilerMarker("EcsGroup.Enumerator.Current");
|
||||||
|
|
||||||
public ent Current
|
public ent Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get { return _source.World.GetEntity(_entities[_index]); }
|
get
|
||||||
|
{
|
||||||
|
using (_marker.Auto())
|
||||||
|
return _source.World.GetEntity(_source._dense[_pointer]);
|
||||||
|
// return _source._dense[_pointer];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext() => ++_index < _entities.Count;
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
return ++_pointer <= _source.Count;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Dispose() => _source.Unlock();
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_source.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Reset() => _index = -1;
|
public void Reset()
|
||||||
}
|
{
|
||||||
|
_pointer = -1;
|
||||||
private struct DelayedOp
|
}
|
||||||
{
|
|
||||||
public bool Added;
|
|
||||||
public int Entity;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Constructors
|
#region Constructors
|
||||||
public EcsWorld()
|
public EcsWorld()
|
||||||
{
|
{
|
||||||
_entityDispenser = new IntDispenser();
|
_entityDispenser = new IntDispenser(1);
|
||||||
_nullPool = new EcsNullPool(this);
|
_nullPool = new EcsNullPool(this);
|
||||||
_pools = new IEcsPool[512];
|
_pools = new IEcsPool[512];
|
||||||
FillArray(_pools, _nullPool);
|
FillArray(_pools, _nullPool);
|
||||||
|
Loading…
Reference in New Issue
Block a user