2023-02-13 21:11:54 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
|
|
|
|
namespace DCFApixels.DragonECS
|
|
|
|
|
{
|
2023-02-14 03:26:34 +08:00
|
|
|
|
public interface IEcsReadonlyGroup
|
|
|
|
|
{
|
2023-03-02 14:42:44 +08:00
|
|
|
|
public IEcsWorld World { get; }
|
2023-02-14 03:26:34 +08:00
|
|
|
|
public int Count { get; }
|
|
|
|
|
public EcsGroup.Enumerator GetEnumerator();
|
|
|
|
|
}
|
|
|
|
|
public interface IEcsGroup : IEcsReadonlyGroup
|
|
|
|
|
{
|
|
|
|
|
public void Add(int entityID);
|
|
|
|
|
public void Remove(int entityID);
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 18:16:23 +08:00
|
|
|
|
public class EcsGroup : IEcsGroup
|
2023-02-13 21:11:54 +08:00
|
|
|
|
{
|
2023-03-02 14:42:44 +08:00
|
|
|
|
private IEcsWorld _source;
|
2023-02-13 21:11:54 +08:00
|
|
|
|
private SparseSet _entities;
|
|
|
|
|
|
|
|
|
|
private DelayedOp[] _delayedOps;
|
|
|
|
|
private int _delayedOpsCount;
|
|
|
|
|
|
|
|
|
|
private int _lockCount;
|
|
|
|
|
|
|
|
|
|
#region Properties
|
2023-03-02 14:42:44 +08:00
|
|
|
|
public IEcsWorld World => _source;
|
2023-02-14 03:26:34 +08:00
|
|
|
|
public int Count => _entities.Count;
|
2023-02-13 21:11:54 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constrcutors
|
2023-03-02 14:42:44 +08:00
|
|
|
|
public EcsGroup(IEcsWorld world, int entitiesCapacity, int delayedOpsCapacity = 128)
|
2023-02-13 21:11:54 +08:00
|
|
|
|
{
|
|
|
|
|
_source = world;
|
2023-03-11 17:11:40 +08:00
|
|
|
|
_entities = new SparseSet(entitiesCapacity, entitiesCapacity);
|
2023-02-13 21:11:54 +08:00
|
|
|
|
_delayedOps = new DelayedOp[delayedOpsCapacity];
|
|
|
|
|
_lockCount = 0;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-03-11 17:11:40 +08:00
|
|
|
|
#region Add/Remove
|
2023-02-13 21:11:54 +08:00
|
|
|
|
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
|
|
|
|
|
|
2023-02-14 03:26:34 +08:00
|
|
|
|
#region AddGroup/RemoveGroup
|
|
|
|
|
public void AddGroup(IEcsReadonlyGroup group)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in group)
|
|
|
|
|
{
|
|
|
|
|
_entities.TryAdd(item.id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void RemoveGroup(IEcsReadonlyGroup group)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in group)
|
|
|
|
|
{
|
|
|
|
|
_entities.TryRemove(item.id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2023-02-13 21:11:54 +08:00
|
|
|
|
#region GetEnumerator
|
|
|
|
|
private void Unlock()
|
|
|
|
|
{
|
|
|
|
|
#if DEBUG
|
|
|
|
|
if (_lockCount <= 0)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception($"Invalid lock-unlock balance for {nameof(EcsFilter)}.");
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
if (--_lockCount <= 0)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < _delayedOpsCount; i++)
|
|
|
|
|
{
|
|
|
|
|
ref DelayedOp op = ref _delayedOps[i];
|
|
|
|
|
if (op.Added)
|
|
|
|
|
{
|
|
|
|
|
Add(op.Entity);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Remove(op.Entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public Enumerator GetEnumerator()
|
|
|
|
|
{
|
|
|
|
|
_lockCount++;
|
|
|
|
|
return new Enumerator(this);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Utils
|
|
|
|
|
public ref struct Enumerator
|
|
|
|
|
{
|
|
|
|
|
private readonly EcsGroup _source;
|
|
|
|
|
private readonly SparseSet _entities;
|
|
|
|
|
private int _index;
|
|
|
|
|
private Entity _currentEntity;
|
|
|
|
|
|
|
|
|
|
public Enumerator(EcsGroup group)
|
|
|
|
|
{
|
|
|
|
|
_source = group;
|
|
|
|
|
_entities = group._entities;
|
|
|
|
|
_index = -1;
|
|
|
|
|
_currentEntity = new Entity(group.World, -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Entity Current
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
_currentEntity.id = _entities[_index];
|
|
|
|
|
return _currentEntity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool MoveNext()
|
|
|
|
|
{
|
|
|
|
|
return ++_index < _entities.Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_source.Unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public void Reset()
|
|
|
|
|
{
|
|
|
|
|
_index = -1;
|
|
|
|
|
_currentEntity.id = -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private struct DelayedOp
|
|
|
|
|
{
|
|
|
|
|
public bool Added;
|
|
|
|
|
public int Entity;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|