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

View File

@ -30,6 +30,8 @@ namespace DCFApixels.DragonECS
private List<IEcsWorldEventListener> _listeners = new List<IEcsWorldEventListener>();
private List<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
internal int[][] _entitiesComponentMasks;
#region Properties
public bool IsDestroyed => _isDestroyed;
public int Count => _entitiesCount;
@ -66,6 +68,10 @@ namespace DCFApixels.DragonECS
_delEntBufferCount = 0;
//_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET];
_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);
_allEntites = GetFreeGroup();
@ -148,6 +154,10 @@ namespace DCFApixels.DragonECS
Array.Resize(ref _gens, _gens.Length << 1);
Array.Resize(ref _componentCounts, _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);
ArrayUtility.Fill(_gens, DEATH_GEN_BIT, _entitesCapacity);
_entitesCapacity = _gens.Length;
@ -212,14 +222,14 @@ namespace DCFApixels.DragonECS
if (mask.worldID != id)
throw new EcsFrameworkException("The types of the target world of the mask and this world are different.");
#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;
}
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 true;
@ -288,13 +298,22 @@ namespace DCFApixels.DragonECS
#region Components Increment
[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)]
internal void DecrementEntityComponentCount(int entityID)
internal void DecrementEntityComponentCount(int entityID, int componentID)
{
var count = --_componentCounts[entityID];
if (count == 0 && _allEntites.Has(entityID)) DelEntity(entityID);
#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS
EcsMaskBit bit = EcsMaskBit.FromPoolID(componentID);
_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();
#endif
}

View File

@ -93,6 +93,9 @@ namespace DCFApixels.DragonECS
int oldCapacity = _pools.Length;
Array.Resize(ref _pools, _pools.Length << 1);
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)

View File

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

View File

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

View File

@ -72,14 +72,14 @@ namespace DCFApixels.DragonECS
public static class IEcsPoolImplementationExtensions
{
[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)]
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)]

View File

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

View File

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