rework EcsMask

This commit is contained in:
Mikhail 2023-11-22 17:35:03 +08:00
parent 12f166a01a
commit 5edd55df88
9 changed files with 117 additions and 53 deletions

View File

@ -123,10 +123,10 @@ namespace DCFApixels.DragonECS
foreach (var item in _combined) foreach (var item in _combined)
{ {
EcsMask submask = item.aspect.mask; EcsMask submask = item.aspect.mask;
maskInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения maskInc.ExceptWith(submask.excChunckMasks);//удаляю конфликтующие ограничения
maskExc.ExceptWith(submask.inc);//удаляю конфликтующие ограничения maskExc.ExceptWith(submask.incChunckMasks);//удаляю конфликтующие ограничения
maskInc.UnionWith(submask.inc); maskInc.UnionWith(submask.incChunckMasks);
maskExc.UnionWith(submask.exc); maskExc.UnionWith(submask.excChunckMasks);
} }
maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
@ -139,12 +139,29 @@ namespace DCFApixels.DragonECS
maskExc = _exc; maskExc = _exc;
} }
var inc = maskInc.ToArray(); int[] inc = new int[0];
Array.Sort(inc); int[] exc = new int[0];
var exc = maskExc.ToArray(); foreach (var v in maskInc)
Array.Sort(exc); {
var bit = EcsMaskBit.FromPoolID(v);
if (inc.Length <= bit.chankIndex)
Array.Resize(ref inc, bit.chankIndex + 1);
inc[bit.chankIndex] |= bit.mask;
}
foreach (var v in maskExc)
{
var bit = EcsMaskBit.FromPoolID(v);
if (exc.Length <= bit.chankIndex)
Array.Resize(ref exc, bit.chankIndex + 1);
exc[bit.chankIndex] |= bit.mask;
}
mask = new EcsMask(_world.id, inc, exc); //var inc = maskInc.ToArray();
//Array.Sort(inc);
//var exc = maskExc.ToArray();
//Array.Sort(exc);
mask = new EcsMask(_world.id, inc.ToArray(), exc.ToArray());
_world = null; _world = null;
_inc = null; _inc = null;
_exc = null; _exc = null;
@ -203,25 +220,25 @@ namespace DCFApixels.DragonECS
public sealed class EcsMask public sealed class EcsMask
{ {
internal readonly int worldID; internal readonly int worldID;
internal readonly int[] inc; internal readonly int[] incChunckMasks;
internal readonly int[] exc; internal readonly int[] excChunckMasks;
public int WorldID => worldID; public int WorldID => worldID;
/// <summary>Including constraints</summary> /// <summary>Including constraints</summary>
public ReadOnlySpan<int> Inc => inc; public ReadOnlySpan<int> Inc => incChunckMasks;
/// <summary>Excluding constraints</summary> /// <summary>Excluding constraints</summary>
public ReadOnlySpan<int> Exc => exc; public ReadOnlySpan<int> Exc => excChunckMasks;
internal EcsMask(int worldID, int[] inc, int[] exc) internal EcsMask(int worldID, int[] inc, int[] exc)
{ {
#if DEBUG #if DEBUG
CheckConstraints(inc, exc); //CheckConstraints(inc, exc);
#endif #endif
this.worldID = worldID; this.worldID = worldID;
this.inc = inc; this.incChunckMasks = inc;
this.exc = exc; this.excChunckMasks = exc;
} }
#region Object #region Object
public override string ToString() => CreateLogString(worldID, inc, exc); public override string ToString() => CreateLogString(worldID, incChunckMasks, excChunckMasks);
#endregion #endregion
#region Debug utils #region Debug utils
@ -264,17 +281,17 @@ namespace DCFApixels.DragonECS
public readonly int worldID; public readonly int worldID;
public readonly int[] included; public readonly int[] included;
public readonly int[] excluded; public readonly int[] excluded;
public readonly Type[] includedTypes; //public readonly Type[] includedTypes;
public readonly Type[] excludedTypes; //public readonly Type[] excludedTypes;
public DebuggerProxy(EcsMask mask) public DebuggerProxy(EcsMask mask)
{ {
world = EcsWorld.GetWorld(mask.worldID); world = EcsWorld.GetWorld(mask.worldID);
worldID = mask.worldID; worldID = mask.worldID;
included = mask.inc; included = mask.incChunckMasks;
excluded = mask.exc; excluded = mask.excChunckMasks;
Type converter(int o) => world.GetComponentType(o); //Type converter(int o) => world.GetComponentType(o);
includedTypes = included.Select(converter).ToArray(); //includedTypes = included.Select(converter).ToArray();
excludedTypes = excluded.Select(converter).ToArray(); //excludedTypes = excluded.Select(converter).ToArray();
} }
public override string ToString() => CreateLogString(worldID, included, excluded); public override string ToString() => CreateLogString(worldID, included, excluded);
} }
@ -335,31 +352,36 @@ namespace DCFApixels.DragonECS
private EcsGroup.Enumerator _sourceGroup; private EcsGroup.Enumerator _sourceGroup;
private readonly int[] _inc; private readonly int[] _inc;
private readonly int[] _exc; private readonly int[] _exc;
private readonly IEcsPoolImplementation[] _pools; private readonly int[][] _entitiesComponentMasks;
public Enumerator(EcsReadonlyGroup sourceGroup, EcsMask mask) public Enumerator(EcsReadonlyGroup sourceGroup, EcsMask mask)
{ {
_sourceGroup = sourceGroup.GetEnumerator(); _sourceGroup = sourceGroup.GetEnumerator();
_inc = mask.inc; _inc = mask.incChunckMasks;
_exc = mask.exc; _exc = mask.excChunckMasks;
_pools = sourceGroup.World._pools; _entitiesComponentMasks = sourceGroup.World._entitiesComponentMasks;
} }
public int Current public int Current
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _sourceGroup.Current; get => _sourceGroup.Current;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext() public bool MoveNext()
{ {
while (_sourceGroup.MoveNext()) while (_sourceGroup.MoveNext())
{ {
int e = _sourceGroup.Current; int e = _sourceGroup.Current;
for (int i = 0, iMax = _inc.Length; i < iMax; i++) for (int i = 0, iMax = _inc.Length; i < iMax; i++)
if (!_pools[_inc[i]].Has(e)) goto next; {
if (_inc[i] > 0 && (_entitiesComponentMasks[e][i] & _inc[i]) == 0) goto skip;
}
for (int i = 0, iMax = _exc.Length; i < iMax; i++) for (int i = 0, iMax = _exc.Length; i < iMax; i++)
if (_pools[_exc[i]].Has(e)) goto next; {
if (_exc[i] > 0 && (_entitiesComponentMasks[e][i] & _exc[i]) != 0) goto skip;
}
return true; return true;
next: continue; skip: continue;
} }
return false; return false;
} }

View File

@ -30,6 +30,8 @@ namespace DCFApixels.DragonECS
private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>(); private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>();
private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>(); private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
internal int[][] _entitiesComponentMasks;
#region Properties #region Properties
public bool IsDestroyed => _isDestroyed; public bool IsDestroyed => _isDestroyed;
public int Count => _entitiesCount; public int Count => _entitiesCount;
@ -66,6 +68,10 @@ namespace DCFApixels.DragonECS
_delEntBufferCount = 0; _delEntBufferCount = 0;
//_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET]; //_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET];
_delEntBuffer = new int[_entitesCapacity]; _delEntBuffer = new int[_entitesCapacity];
_entitiesComponentMasks = new int[_entitesCapacity][];
for (int i = 0; i < _entitesCapacity; i++)
_entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1];
_delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE); _delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE);
_allEntites = GetFreeGroup(); _allEntites = GetFreeGroup();
@ -148,6 +154,10 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _gens, _gens.Length << 1); Array.Resize(ref _gens, _gens.Length << 1);
Array.Resize(ref _componentCounts, _gens.Length); Array.Resize(ref _componentCounts, _gens.Length);
Array.Resize(ref _delEntBuffer, _gens.Length); Array.Resize(ref _delEntBuffer, _gens.Length);
Array.Resize(ref _entitiesComponentMasks, _gens.Length);
for (int i = _entitesCapacity; i < _gens.Length; i++)
_entitiesComponentMasks[i] = new int[_pools.Length / 32 + 1];
_delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE); _delEntBufferMinCount = Math.Max(_delEntBuffer.Length >> DEL_ENT_BUFFER_SIZE_OFFSET, DEL_ENT_BUFFER_MIN_SIZE);
ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity); ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity);
_entitesCapacity = _gens.Length; _entitesCapacity = _gens.Length;
@ -212,14 +222,14 @@ namespace DCFApixels.DragonECS
if (mask.worldID != id) if (mask.worldID != id)
throw new EcsFrameworkException("The types of the target world of the mask and this world are different."); throw new EcsFrameworkException("The types of the target world of the mask and this world are different.");
#endif #endif
for (int i = 0, iMax = mask.inc.Length; i < iMax; i++) for (int i = 0, iMax = mask.incChunckMasks.Length; i < iMax; i++)
{ {
if (!_pools[mask.inc[i]].Has(entityID)) if (!_pools[mask.incChunckMasks[i]].Has(entityID))
return false; return false;
} }
for (int i = 0, iMax = mask.exc.Length; i < iMax; i++) for (int i = 0, iMax = mask.excChunckMasks.Length; i < iMax; i++)
{ {
if (_pools[mask.exc[i]].Has(entityID)) if (_pools[mask.excChunckMasks[i]].Has(entityID))
return false; return false;
} }
return true; return true;
@ -288,13 +298,22 @@ namespace DCFApixels.DragonECS
#region Components Increment #region Components Increment
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void IncrementEntityComponentCount(int entityID) => _componentCounts[entityID]++; internal void IncrementEntityComponentCount(int entityID, int componentID)
{
_componentCounts[entityID]++;
EcsMaskBit bit = EcsMaskBit.FromPoolID(componentID);
_entitiesComponentMasks[entityID][bit.chankIndex] |= bit.mask;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void DecrementEntityComponentCount(int entityID) internal void DecrementEntityComponentCount(int entityID, int componentID)
{ {
var count = --_componentCounts[entityID]; var count = --_componentCounts[entityID];
if (count == 0 && _allEntites.Has(entityID)) DelEntity(entityID); EcsMaskBit bit = EcsMaskBit.FromPoolID(componentID);
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS _entitiesComponentMasks[entityID][bit.chankIndex] &= ~bit.mask;
if (count == 0 && _allEntites.Has(entityID))
DelEntity(entityID);
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (count < 0) Throw.World_InvalidIncrementComponentsBalance(); if (count < 0) Throw.World_InvalidIncrementComponentsBalance();
#endif #endif
} }

View File

@ -93,6 +93,9 @@ namespace DCFApixels.DragonECS
int oldCapacity = _pools.Length; int oldCapacity = _pools.Length;
Array.Resize(ref _pools, _pools.Length << 1); Array.Resize(ref _pools, _pools.Length << 1);
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
for (int i = 0; i < _entitesCapacity; i++)
Array.Resize(ref _entitiesComponentMasks[i], _pools.Length / 32 + 1);
} }
if (_pools[componentID] == _nullPool) if (_pools[componentID] == _nullPool)

View File

@ -65,7 +65,7 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _entities, _items.Length); Array.Resize(ref _entities, _items.Length);
} }
} }
this.IncrementEntityComponentCount(entityID); this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
if(isMain) if(isMain)
component.OnAddToPool(_source.GetEntityLong(entityID)); component.OnAddToPool(_source.GetEntityLong(entityID));
@ -126,7 +126,7 @@ namespace DCFApixels.DragonECS
_mapping[entityID] = 0; _mapping[entityID] = 0;
_entities[itemIndex] = 0; _entities[itemIndex] = 0;
_itemsCount--; _itemsCount--;
this.DecrementEntityComponentCount(entityID); this.DecrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void Del(int entityID) public void Del(int entityID)

View File

@ -12,6 +12,7 @@ namespace DCFApixels.DragonECS
{ {
private EcsWorld _source; private EcsWorld _source;
private int _componentID; private int _componentID;
private EcsMaskBit _maskBit;
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
private T[] _items; //dense private T[] _items; //dense
@ -50,7 +51,7 @@ namespace DCFApixels.DragonECS
if (itemIndex >= _items.Length) if (itemIndex >= _items.Length)
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
this.IncrementEntityComponentCount(entityID); this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAddAndGet(entityID); _listeners.InvokeOnAddAndGet(entityID);
return ref _items[itemIndex]; return ref _items[itemIndex];
} }
@ -87,7 +88,7 @@ namespace DCFApixels.DragonECS
if (itemIndex >= _items.Length) if (itemIndex >= _items.Length)
Array.Resize(ref _items, _items.Length << 1); Array.Resize(ref _items, _items.Length << 1);
} }
this.IncrementEntityComponentCount(entityID); this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
_listeners.InvokeOnGet(entityID); _listeners.InvokeOnGet(entityID);
@ -110,7 +111,7 @@ namespace DCFApixels.DragonECS
_recycledItems[_recycledItemsCount++] = itemIndex; _recycledItems[_recycledItemsCount++] = itemIndex;
_mapping[entityID] = 0; _mapping[entityID] = 0;
_itemsCount--; _itemsCount--;
this.DecrementEntityComponentCount(entityID); this.DecrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void TryDel(int entityID) public void TryDel(int entityID)
@ -139,6 +140,8 @@ namespace DCFApixels.DragonECS
_source = world; _source = world;
_componentID = componentID; _componentID = componentID;
_maskBit = EcsMaskBit.FromPoolID(componentID);
const int capacity = 512; const int capacity = 512;
_mapping = new int[world.Capacity]; _mapping = new int[world.Capacity];

View File

@ -72,14 +72,14 @@ namespace DCFApixels.DragonECS
public static class IEcsPoolImplementationExtensions public static class IEcsPoolImplementationExtensions
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void IncrementEntityComponentCount<T>(this IEcsPoolImplementation<T> self, int entityID) public static void IncrementEntityComponentCount<T>(this IEcsPoolImplementation<T> self, int entityID, int componentID)
{ {
self.World.IncrementEntityComponentCount(entityID); self.World.IncrementEntityComponentCount(entityID, componentID);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void DecrementEntityComponentCount<T>(this IEcsPoolImplementation<T> self, int entityID) public static void DecrementEntityComponentCount<T>(this IEcsPoolImplementation<T> self, int entityID, int componentID)
{ {
self.World.DecrementEntityComponentCount(entityID); self.World.DecrementEntityComponentCount(entityID, componentID);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -47,7 +47,7 @@ namespace DCFApixels.DragonECS
#endif #endif
_count++; _count++;
_mapping[entityID] = true; _mapping[entityID] = true;
this.IncrementEntityComponentCount(entityID); this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
public void TryAdd(int entityID) public void TryAdd(int entityID)
@ -56,7 +56,7 @@ namespace DCFApixels.DragonECS
{ {
_count++; _count++;
_mapping[entityID] = true; _mapping[entityID] = true;
this.IncrementEntityComponentCount(entityID); this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAdd(entityID); _listeners.InvokeOnAdd(entityID);
} }
} }
@ -72,7 +72,7 @@ namespace DCFApixels.DragonECS
#endif #endif
_mapping[entityID] = false; _mapping[entityID] = false;
_count--; _count--;
this.DecrementEntityComponentCount(entityID); this.DecrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
} }
public void TryDel(int entityID) public void TryDel(int entityID)

View File

@ -167,7 +167,7 @@ namespace DCFApixels.DragonECS
entry.key = key; entry.key = key;
entry.value = default; entry.value = default;
_buckets[targetBucket] = index; _buckets[targetBucket] = index;
this.IncrementEntityComponentCount(entityID); this.IncrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnAddAndGet(entityID); _listeners.InvokeOnAddAndGet(entityID);
return ref entry.value; return ref entry.value;
} }
@ -235,7 +235,7 @@ namespace DCFApixels.DragonECS
_componentResetHandler.Reset(ref _entries[i].value); _componentResetHandler.Reset(ref _entries[i].value);
_freeList = i; _freeList = i;
_freeCount++; _freeCount++;
this.DecrementEntityComponentCount(entityID); this.DecrementEntityComponentCount(entityID, _componentID);
_listeners.InvokeOnDel(entityID); _listeners.InvokeOnDel(entityID);
return; return;
} }

17
src/Utils/EcsMaskBit.cs Normal file
View File

@ -0,0 +1,17 @@
namespace DCFApixels.DragonECS
{
public readonly struct EcsMaskBit
{
public readonly int chankIndex;
public readonly int mask;
public EcsMaskBit(int chankIndex, int mask)
{
this.chankIndex = chankIndex;
this.mask = mask;
}
public static EcsMaskBit FromPoolID(int id)
{
return new EcsMaskBit(id / 32, 1 << (id % 32));
}
}
}