From 5edd55df88651a0204c2649d7c9123e733185f43 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Wed, 22 Nov 2023 17:35:03 +0800 Subject: [PATCH] rework EcsMask --- src/EcsAspect.cs | 84 ++++++++++++++++++++++++-------------- src/EcsWorld.cs | 35 ++++++++++++---- src/EcsWorld.pools.cs | 3 ++ src/Pools/EcsHybridPool.cs | 4 +- src/Pools/EcsPool.cs | 9 ++-- src/Pools/EcsPoolBase.cs | 8 ++-- src/Pools/EcsTagPool.cs | 6 +-- src/Pools/EcsTestPool.cs | 4 +- src/Utils/EcsMaskBit.cs | 17 ++++++++ 9 files changed, 117 insertions(+), 53 deletions(-) create mode 100644 src/Utils/EcsMaskBit.cs diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index b082e5a..1db9584 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -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; /// Including constraints - public ReadOnlySpan Inc => inc; + public ReadOnlySpan Inc => incChunckMasks; /// Excluding constraints - public ReadOnlySpan Exc => exc; + public ReadOnlySpan 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; } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index d4ca88b..43ac5a2 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -30,6 +30,8 @@ namespace DCFApixels.DragonECS private List _listeners = new List(); private List _entityListeners = new List(); + 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 } diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index f6a9040..a68be2d 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -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) diff --git a/src/Pools/EcsHybridPool.cs b/src/Pools/EcsHybridPool.cs index 85f9383..68520b7 100644 --- a/src/Pools/EcsHybridPool.cs +++ b/src/Pools/EcsHybridPool.cs @@ -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) diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 7fdcfc7..cd7d1aa 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -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]; diff --git a/src/Pools/EcsPoolBase.cs b/src/Pools/EcsPoolBase.cs index bcd8b90..370dfca 100644 --- a/src/Pools/EcsPoolBase.cs +++ b/src/Pools/EcsPoolBase.cs @@ -72,14 +72,14 @@ namespace DCFApixels.DragonECS public static class IEcsPoolImplementationExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void IncrementEntityComponentCount(this IEcsPoolImplementation self, int entityID) + public static void IncrementEntityComponentCount(this IEcsPoolImplementation self, int entityID, int componentID) { - self.World.IncrementEntityComponentCount(entityID); + self.World.IncrementEntityComponentCount(entityID, componentID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void DecrementEntityComponentCount(this IEcsPoolImplementation self, int entityID) + public static void DecrementEntityComponentCount(this IEcsPoolImplementation self, int entityID, int componentID) { - self.World.DecrementEntityComponentCount(entityID); + self.World.DecrementEntityComponentCount(entityID, componentID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs index 30d7d61..c5175b3 100644 --- a/src/Pools/EcsTagPool.cs +++ b/src/Pools/EcsTagPool.cs @@ -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) diff --git a/src/Pools/EcsTestPool.cs b/src/Pools/EcsTestPool.cs index b7abf99..7eaff35 100644 --- a/src/Pools/EcsTestPool.cs +++ b/src/Pools/EcsTestPool.cs @@ -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; } diff --git a/src/Utils/EcsMaskBit.cs b/src/Utils/EcsMaskBit.cs new file mode 100644 index 0000000..7050222 --- /dev/null +++ b/src/Utils/EcsMaskBit.cs @@ -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)); + } + } +}