From 9c033e6330ff3917babadd96aa044e467344c2e5 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 23 Aug 2024 22:31:43 +0800 Subject: [PATCH] update queries stash --- src/Collections/EcsGroup.cs | 18 +- src/EcsAspect.cs | 240 +---------------- src/EcsMask.cs | 318 +++++++++++++++++++---- src/EcsWorld.cs | 11 +- src/EcsWorld.pools.cs | 44 +++- src/Executors/EcsQueryExecutor.cs | 34 +++ src/Executors/EcsWhereExecutor.cs | 55 ++-- src/Executors/EcsWhereToGroupExecutor.cs | 18 +- src/Internal/ArraySortHalperX.cs | 16 +- 9 files changed, 426 insertions(+), 328 deletions(-) diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index 9f8690a..f1e0ec1 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -242,6 +242,9 @@ namespace DCFApixels.DragonECS #region Add/Remove public void AddUnchecked(int entityID) { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (Has(entityID)) { Throw.Group_AlreadyContains(entityID); } +#endif Add_Internal(entityID); } public bool Add(int entityID) @@ -254,11 +257,8 @@ namespace DCFApixels.DragonECS return true; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void Add_Internal(int entityID) + private void Add_Internal(int entityID) { -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (Has(entityID)) { Throw.Group_AlreadyContains(entityID); } -#endif if (++_count >= _dense.Length) { Array.Resize(ref _dense, _dense.Length << 1); @@ -340,9 +340,9 @@ namespace DCFApixels.DragonECS { Clear(); } - foreach (var item in group) + foreach (var entityID in group) { - Add_Internal(item); + Add_Internal(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -786,11 +786,11 @@ namespace DCFApixels.DragonECS public static EcsGroup Inverse(EcsGroup a) { EcsGroup result = a._source.GetFreeGroup(); - foreach (var item in a._source.Entities) + foreach (var entityID in a._source.Entities) { - if (a.Has(item) == false) + if (a.Has(entityID) == false) { - result.Add_Internal(item); + result.Add_Internal(entityID); } } return result; diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 1844bf6..b2fc09b 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -8,10 +8,7 @@ namespace DCFApixels.DragonECS { public abstract class EcsAspect : ITemplateNode { - internal EcsWorld _source; - internal EcsMask _mask; - private bool _isBuilt = false; - + #region Initialization Halpers [ThreadStatic] private static Stack _constructorBuildersStack = null; private static Stack GetBuildersStack() @@ -70,11 +67,11 @@ namespace DCFApixels.DragonECS return buildersStack.Peek().Opt; } } + #endregion - private UnsafeArray _sortIncBuffer; - private UnsafeArray _sortExcBuffer; - private UnsafeArray _sortIncChunckBuffer; - private UnsafeArray _sortExcChunckBuffer; + internal EcsWorld _source; + internal EcsMask _mask; + private bool _isBuilt = false; #region Properties public EcsMask Mask @@ -274,219 +271,6 @@ namespace DCFApixels.DragonECS _span = span; this.aspect = aspect; } - - #region CopyTo - public void CopyTo(EcsGroup group) - { - group.Clear(); - var enumerator = GetEnumerator(); - while (enumerator.MoveNext()) - { - group.Add_Internal(enumerator.Current); - } - } - public int CopyTo(ref int[] array) - { - int count = 0; - var enumerator = GetEnumerator(); - while (enumerator.MoveNext()) - { - if (array.Length <= count) - { - Array.Resize(ref array, array.Length << 1); - } - array[count++] = enumerator.Current; - } - return count; - } - public EcsSpan CopyToSpan(ref int[] array) - { - int count = CopyTo(ref array); - return new EcsSpan(worldID, array, count); - } - #endregion - - #region Other - public override string ToString() - { - List ints = new List(); - foreach (var e in this) - { - ints.Add(e); - } - return CollectionUtility.EntitiesToString(ints, "it"); - } - #endregion - - #region Enumerator - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() { return new Enumerator(_span, aspect); } - - public unsafe ref struct Enumerator - { - #region CountComparers - private readonly struct IncCountComparer : IComparerX - { - public readonly int[] counts; - public IncCountComparer(int[] counts) - { - this.counts = counts; - } - public int Compare(int a, int b) - { - return counts[a] - counts[b]; - } - } - private readonly struct ExcCountComparer : IComparerX - { - public readonly int[] counts; - public ExcCountComparer(int[] counts) - { - this.counts = counts; - } - public int Compare(int a, int b) - { - return counts[b] - counts[a]; - } - } - #endregion - - private ReadOnlySpan.Enumerator _span; - private readonly int[] _entityComponentMasks; - - private static EcsMaskChunck* _preSortedIncBuffer; - private static EcsMaskChunck* _preSortedExcBuffer; - - private UnsafeArray _sortIncChunckBuffer; - private UnsafeArray _sortExcChunckBuffer; - - private readonly int _entityComponentMaskLengthBitShift; - - public unsafe Enumerator(EcsSpan span, EcsAspect aspect) - { - _entityComponentMasks = aspect.World._entityComponentMasks; - _sortIncChunckBuffer = aspect._sortIncChunckBuffer; - _sortExcChunckBuffer = aspect._sortExcChunckBuffer; - - _entityComponentMaskLengthBitShift = aspect.World._entityComponentMaskLengthBitShift; - - if (aspect.Mask.IsBroken) - { - _span = span.Slice(0, 0).GetEnumerator(); - return; - } - - #region Sort - UnsafeArray _sortIncBuffer = aspect._sortIncBuffer; - UnsafeArray _sortExcBuffer = aspect._sortExcBuffer; - int[] counts = aspect.World._poolComponentCounts; - - if (_preSortedIncBuffer == null) - { - _preSortedIncBuffer = UnmanagedArrayUtility.New(256); - _preSortedExcBuffer = UnmanagedArrayUtility.New(256); - } - - if (_sortIncChunckBuffer.Length > 1) - { - IncCountComparer incComparer = new IncCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer); - for (int i = 0; i < _sortIncBuffer.Length; i++) - { - _preSortedIncBuffer[i] = EcsMaskChunck.FromID(_sortIncBuffer.ptr[i]); - } - for (int i = 0, ii = 0; ii < _sortIncChunckBuffer.Length; ii++) - { - EcsMaskChunck chunkX = _preSortedIncBuffer[i]; - int chankIndexX = chunkX.chankIndex; - int maskX = chunkX.mask; - - for (int j = i + 1; j < _sortIncBuffer.Length; j++) - { - if (_preSortedIncBuffer[j].chankIndex == chankIndexX) - { - maskX |= _preSortedIncBuffer[j].mask; - } - } - _sortIncChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX); - while (++i < _sortIncBuffer.Length && _preSortedIncBuffer[i].chankIndex == chankIndexX) - { - // skip - } - } - } - if (_sortIncChunckBuffer.Length > 0 && counts[_sortIncBuffer.ptr[0]] <= 0) - { - _span = span.Slice(0, 0).GetEnumerator(); - return; - } - if (_sortExcChunckBuffer.Length > 1) - { - ExcCountComparer excComparer = new ExcCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer); - for (int i = 0; i < _sortExcBuffer.Length; i++) - { - _preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]); - } - - for (int i = 0, ii = 0; ii < _sortExcChunckBuffer.Length; ii++) - { - EcsMaskChunck bas = _preSortedExcBuffer[i]; - int chankIndexX = bas.chankIndex; - int maskX = bas.mask; - - for (int j = i + 1; j < _sortExcBuffer.Length; j++) - { - if (_preSortedExcBuffer[j].chankIndex == chankIndexX) - { - maskX |= _preSortedExcBuffer[j].mask; - } - } - _sortExcChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX); - while (++i < _sortExcBuffer.Length && _preSortedExcBuffer[i].chankIndex == chankIndexX) - { - // skip - } - } - } - #endregion - - _span = span.GetEnumerator(); - } - public int Current - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _span.Current; } - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() - { - while (_span.MoveNext()) - { - int chunck = _span.Current << _entityComponentMaskLengthBitShift; - for (int i = 0; i < _sortIncChunckBuffer.Length; i++) - { - var bit = _sortIncChunckBuffer.ptr[i]; - if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != bit.mask) - { - goto skip; - } - } - for (int i = 0; i < _sortExcChunckBuffer.Length; i++) - { - var bit = _sortExcChunckBuffer.ptr[i]; - if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != 0) - { - goto skip; - } - } - return true; - skip: continue; - } - return false; - } - } - #endregion } #endregion @@ -522,6 +306,8 @@ namespace DCFApixels.DragonECS } #endregion } + + #region Constraint Markers public readonly ref struct IncludeMarker { private readonly EcsAspect.Builder _builder; @@ -529,8 +315,7 @@ namespace DCFApixels.DragonECS { _builder = builder; } - public T GetInstance() - where T : IEcsPoolImplementation, new() + public T GetInstance() where T : IEcsPoolImplementation, new() { return _builder.IncludePool(); } @@ -542,8 +327,7 @@ namespace DCFApixels.DragonECS { _builder = builder; } - public T GetInstance() - where T : IEcsPoolImplementation, new() + public T GetInstance() where T : IEcsPoolImplementation, new() { return _builder.ExcludePool(); } @@ -555,10 +339,10 @@ namespace DCFApixels.DragonECS { _builder = builder; } - public T GetInstance() - where T : IEcsPoolImplementation, new() + public T GetInstance() where T : IEcsPoolImplementation, new() { return _builder.OptionalPool(); } } -} + #endregion +} \ No newline at end of file diff --git a/src/EcsMask.cs b/src/EcsMask.cs index 6f16b76..1e7434e 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -22,6 +22,8 @@ namespace DCFApixels.DragonECS internal readonly int[] _inc; //Sorted internal readonly int[] _exc; //Sorted + private EcsMaskIterator _iterator; + #region Properties public int ID { @@ -217,6 +219,17 @@ namespace DCFApixels.DragonECS } #endregion + #region Other + public EcsMaskIterator GetIterator() + { + if(_iterator == null) + { + _iterator = new EcsMaskIterator(EcsWorld.GetWorld(_worldID), this); + } + return _iterator; + } + #endregion + #region Debug utils #if DEBUG private static HashSet _dummyHashSet = new HashSet(); @@ -381,50 +394,6 @@ namespace DCFApixels.DragonECS } return result; } - //internal EcsMask ExceptMask(EcsMask a, EcsMask b) - //{ - // int operation = OpMaskKey.EXCEPT_OP; - // if (_opMasks.TryGetValue(new OpMaskKey(a.id, b.id, operation), out EcsMask result) == false) - // { - // var builder = New(a.World); - // if (a.IsConflictWith(b)) - // { - // return a.World.Get().BrokenMask; - // } - // ExceptMaskConstraint(builder, a.inc, b.inc, true); - // ExceptMaskConstraint(builder, a.exc, b.exc, false); - // result = builder.Build(); - // _opMasks.Add(new OpMaskKey(a.id, b.id, operation), result); - // } - // return result; - //} - //private void ExceptMaskConstraint(Builder b, int[] acnstrs, int[] bcnstrs, bool isInc) - //{ - // for (int i = 0, ii = 0; i < acnstrs.Length; i++) - // { - // int acnst = acnstrs[i]; - // while (ii < bcnstrs.Length && acnst > bcnstrs[ii]) - // { - // ii++; - // } - // if (ii >= bcnstrs.Length) - // { - // break; - // } - // int binc = bcnstrs[ii]; - // if (acnst == binc) - // { - // if (isInc) - // { - // b.Include(acnst); - // } - // else - // { - // b.Exclude(acnst); - // } - // } - // } - //} internal EcsMask GetMask(Key maskKey) { if (!_masks.TryGetValue(maskKey, out EcsMask result)) @@ -681,4 +650,265 @@ namespace DCFApixels.DragonECS } } #endregion + + public class EcsMaskIterator + { + #region CountStructComparers + private readonly struct IncCountComparer : IStructComparer + { + public readonly EcsWorld.PoolSlot[] counts; + public IncCountComparer(EcsWorld.PoolSlot[] counts) + { + this.counts = counts; + } + public int Compare(int a, int b) + { + return counts[a].count - counts[b].count; + } + } + private readonly struct ExcCountComparer : IStructComparer + { + public readonly EcsWorld.PoolSlot[] counts; + public ExcCountComparer(EcsWorld.PoolSlot[] counts) + { + this.counts = counts; + } + public int Compare(int a, int b) + { + return counts[b].count - counts[a].count; + } + } + #endregion + + internal EcsWorld _source; + internal EcsMask _mask; + + private UnsafeArray _sortIncBuffer; + private UnsafeArray _sortExcBuffer; + private UnsafeArray _sortIncChunckBuffer; + private UnsafeArray _sortExcChunckBuffer; + + #region Constructors + public EcsMaskIterator(EcsWorld source, EcsMask mask) + { + _source = source; + _mask = mask; + } + #endregion + + #region Properties + public EcsWorld World + { + get { return _source; } + } + public EcsMask Mask + { + get { return _mask; } + } + #endregion + + #region Enumerable + public Enumerable Iterate(EcsSpan span) + { + return new Enumerable(); + } + public readonly ref struct Enumerable + { + private readonly EcsMaskIterator _iterator; + private readonly EcsSpan _span; + + public Enumerable(EcsMaskIterator iterator, EcsSpan span) + { + _iterator = iterator; + _span = span; + } + + #region CopyTo + public void CopyTo(EcsGroup group) + { + group.Clear(); + var enumerator = GetEnumerator(); + while (enumerator.MoveNext()) + { + group.AddUnchecked(enumerator.Current); + } + } + public int CopyTo(ref int[] array) + { + int count = 0; + var enumerator = GetEnumerator(); + while (enumerator.MoveNext()) + { + if (array.Length <= count) + { + Array.Resize(ref array, array.Length << 1); + } + array[count++] = enumerator.Current; + } + return count; + } + public EcsSpan CopyToSpan(ref int[] array) + { + int count = CopyTo(ref array); + return new EcsSpan(_iterator.World.id, array, count); + } + #endregion + + #region Other + public override string ToString() + { + List ints = new List(); + foreach (var e in this) + { + ints.Add(e); + } + return CollectionUtility.EntitiesToString(ints, "it"); + } + #endregion + + #region Enumerator + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Enumerator GetEnumerator() { return new Enumerator(_span, _iterator); } + + public unsafe ref struct Enumerator + { + private ReadOnlySpan.Enumerator _span; + private readonly int[] _entityComponentMasks; + + private static EcsMaskChunck* _preSortedIncBuffer; + private static EcsMaskChunck* _preSortedExcBuffer; + + private UnsafeArray _sortIncChunckBuffer; + private UnsafeArray _sortExcChunckBuffer; + + private readonly int _entityComponentMaskLengthBitShift; + + public unsafe Enumerator(EcsSpan span, EcsMaskIterator iterator) + { + _entityComponentMasks = iterator.World._entityComponentMasks; + _sortIncChunckBuffer = iterator._sortIncChunckBuffer; + _sortExcChunckBuffer = iterator._sortExcChunckBuffer; + + _entityComponentMaskLengthBitShift = iterator.World._entityComponentMaskLengthBitShift; + + if (iterator.Mask.IsBroken) + { + _span = span.Slice(0, 0).GetEnumerator(); + return; + } + + #region Sort + UnsafeArray _sortIncBuffer = iterator._sortIncBuffer; + UnsafeArray _sortExcBuffer = iterator._sortExcBuffer; + EcsWorld.PoolSlot[] counts = iterator.World._poolSlots; + + if (_preSortedIncBuffer == null) + { + _preSortedIncBuffer = UnmanagedArrayUtility.New(256); + _preSortedExcBuffer = UnmanagedArrayUtility.New(256); + } + + if (_sortIncChunckBuffer.Length > 1) + { + IncCountComparer incComparer = new IncCountComparer(counts); + UnsafeArraySortHalperX.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer); + for (int i = 0; i < _sortIncBuffer.Length; i++) + { + _preSortedIncBuffer[i] = EcsMaskChunck.FromID(_sortIncBuffer.ptr[i]); + } + for (int i = 0, ii = 0; ii < _sortIncChunckBuffer.Length; ii++) + { + EcsMaskChunck chunkX = _preSortedIncBuffer[i]; + int chankIndexX = chunkX.chankIndex; + int maskX = chunkX.mask; + + for (int j = i + 1; j < _sortIncBuffer.Length; j++) + { + if (_preSortedIncBuffer[j].chankIndex == chankIndexX) + { + maskX |= _preSortedIncBuffer[j].mask; + } + } + _sortIncChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX); + while (++i < _sortIncBuffer.Length && _preSortedIncBuffer[i].chankIndex == chankIndexX) + { + // skip + } + } + } + if (_sortIncChunckBuffer.Length > 0 && counts[_sortIncBuffer.ptr[0]].count <= 0) + { + _span = span.Slice(0, 0).GetEnumerator(); + return; + } + if (_sortExcChunckBuffer.Length > 1) + { + ExcCountComparer excComparer = new ExcCountComparer(counts); + UnsafeArraySortHalperX.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer); + for (int i = 0; i < _sortExcBuffer.Length; i++) + { + _preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]); + } + + for (int i = 0, ii = 0; ii < _sortExcChunckBuffer.Length; ii++) + { + EcsMaskChunck bas = _preSortedExcBuffer[i]; + int chankIndexX = bas.chankIndex; + int maskX = bas.mask; + + for (int j = i + 1; j < _sortExcBuffer.Length; j++) + { + if (_preSortedExcBuffer[j].chankIndex == chankIndexX) + { + maskX |= _preSortedExcBuffer[j].mask; + } + } + _sortExcChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX); + while (++i < _sortExcBuffer.Length && _preSortedExcBuffer[i].chankIndex == chankIndexX) + { + // skip + } + } + } + #endregion + + _span = span.GetEnumerator(); + } + public int Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _span.Current; } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + while (_span.MoveNext()) + { + int chunck = _span.Current << _entityComponentMaskLengthBitShift; + for (int i = 0; i < _sortIncChunckBuffer.Length; i++) + { + var bit = _sortIncChunckBuffer.ptr[i]; + if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != bit.mask) + { + goto skip; + } + } + for (int i = 0; i < _sortExcChunckBuffer.Length; i++) + { + var bit = _sortExcChunckBuffer.ptr[i]; + if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != 0) + { + goto skip; + } + } + return true; + skip: continue; + } + return false; + } + } + #endregion + } + #endregion + } } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 9bef4af..947623a 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -169,7 +169,7 @@ namespace DCFApixels.DragonECS int poolsCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.PoolsCapacity); _pools = new IEcsPoolImplementation[poolsCapacity]; - _poolComponentCounts = new int[poolsCapacity]; + _poolSlots = new int[poolsCapacity]; ArrayUtility.Fill(_pools, _nullPool); int entitiesCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.EntitiesCapacity); @@ -816,10 +816,19 @@ namespace DCFApixels.DragonECS public static class EcsWorldExtenssions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrDetroyed(this EcsWorld self) { return self == null || self.IsDestroyed; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void ReleaseDelEntityBufferAllAuto(this EcsWorld self) + { + if (self.IsEnableReleaseDelEntBuffer) + { + self.ReleaseDelEntityBufferAll(); + } + } } #region Callbacks Interface diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 0fb1595..48bca1b 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -12,11 +12,11 @@ namespace DCFApixels.DragonECS private SparseArray _cmpTypeCode_2_CmpTypeIDs = new SparseArray(); private int _poolsCount; internal IEcsPoolImplementation[] _pools; - internal int[] _poolComponentCounts; + internal PoolSlot[] _poolSlots; private readonly PoolsMediator _poolsMediator; - private readonly EcsNullPool _nullPool = EcsNullPool.instance; + private EcsNullPool _nullPool = EcsNullPool.instance; #region FindPoolInstance [Obsolete("The GetPoolInstance(int componentTypeID) method will be removed in future updates, use FindPoolInstance(Type componentType)")] @@ -146,7 +146,7 @@ namespace DCFApixels.DragonECS } #endregion - #region Create + #region CreatePool private TPool CreatePool() where TPool : IEcsPoolImplementation, new() { int poolTypeCode = EcsTypeCode.Get(); @@ -184,7 +184,7 @@ namespace DCFApixels.DragonECS { int oldCapacity = _pools.Length; Array.Resize(ref _pools, _pools.Length << 1); - Array.Resize(ref _poolComponentCounts, _pools.Length); + Array.Resize(ref _poolSlots, _pools.Length); ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length); int newEntityComponentMaskLength = CalcEntityComponentMaskLength(); //_pools.Length / COMPONENT_MASK_CHUNK_SIZE + 1; @@ -231,7 +231,9 @@ namespace DCFApixels.DragonECS private void RegisterEntityComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit) { UpVersion(); - _poolComponentCounts[componentTypeID]++; + ref PoolSlot slot = ref _poolSlots[componentTypeID]; + slot.count++; + slot.version++; _entities[entityID].componentsCount++; _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chankIndex] |= maskBit.mask; } @@ -239,7 +241,9 @@ namespace DCFApixels.DragonECS private void UnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit) { UpVersion(); - _poolComponentCounts[componentTypeID]--; + ref PoolSlot slot = ref _poolSlots[componentTypeID]; + slot.count--; + slot.version++; var count = --_entities[entityID].componentsCount; _entityComponentMasks[(entityID << _entityComponentMaskLengthBitShift) + maskBit.chankIndex] &= ~maskBit.mask; @@ -262,7 +266,9 @@ namespace DCFApixels.DragonECS { UpVersion(); chunk = newChunk; - _poolComponentCounts[componentTypeID]++; + ref PoolSlot slot = ref _poolSlots[componentTypeID]; + slot.count++; + slot.version++; _entities[entityID].componentsCount++; return true; } @@ -276,7 +282,9 @@ namespace DCFApixels.DragonECS if (chunk != newChunk) { UpVersion(); - _poolComponentCounts[componentTypeID]--; + ref PoolSlot slot = ref _poolSlots[componentTypeID]; + slot.count--; + slot.version++; var count = --_entities[entityID].componentsCount; chunk = newChunk; @@ -295,7 +303,12 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] private int GetPoolComponentCount(int componentTypeID) { - return _poolComponentCounts[componentTypeID]; + return _poolSlots[componentTypeID].count; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private long GetPoolVersion(int componentTypeID) + { + return _poolSlots[componentTypeID].version; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool HasEntityComponent(int entityID, EcsMaskChunck maskBit) @@ -343,11 +356,24 @@ namespace DCFApixels.DragonECS return World.GetPoolComponentCount(componentTypeID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] + public long GetVersion(int componentTypeID) + { + return World.GetPoolVersion(componentTypeID); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool HasComponent(int entityID, EcsMaskChunck maskBit) { return World.HasEntityComponent(entityID, maskBit); } } #endregion + + #region PoolSlot + internal struct PoolSlot + { + public int count; + public long version; + } + #endregion } } diff --git a/src/Executors/EcsQueryExecutor.cs b/src/Executors/EcsQueryExecutor.cs index 5d4a036..fc7b1b5 100644 --- a/src/Executors/EcsQueryExecutor.cs +++ b/src/Executors/EcsQueryExecutor.cs @@ -29,4 +29,38 @@ namespace DCFApixels.DragonECS protected abstract void OnInitialize(); protected abstract void OnDestroy(); } + + public readonly struct PoolVersionsChecker + { + private readonly EcsMask _mask; + private readonly long[] _versions; + + public PoolVersionsChecker(EcsMask mask) : this() + { + _mask = mask; + _versions = new long[mask._inc.Length + mask._exc.Length]; + } + + public bool NextEquals() + { + var slots = _mask.World._poolSlots; + bool result = true; + int index = 0; + foreach (var i in _mask._inc) + { + if (slots[i].version != _versions[index++]) + { + result = false; + } + } + foreach (var i in _mask._exc) + { + if (slots[i].version != _versions[index++]) + { + result = false; + } + } + return result; + } + } } \ No newline at end of file diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs index 8a9326b..72fa2ee 100644 --- a/src/Executors/EcsWhereExecutor.cs +++ b/src/Executors/EcsWhereExecutor.cs @@ -15,10 +15,7 @@ namespace DCFApixels.DragonECS private int _filteredEntitiesCount; private long _lastWorldVersion; - -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - //private readonly EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Where"); -#endif + private PoolVersionsChecker _versionsChecker; #region Properties public TAspect Aspect @@ -38,11 +35,39 @@ namespace DCFApixels.DragonECS { _aspect = World.GetAspect(); _filteredEntities = new int[32]; + _versionsChecker = new PoolVersionsChecker(_aspect._mask); } protected sealed override void OnDestroy() { } #endregion #region Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Filter(EcsSpan span) + { + _filteredEntitiesCount = _aspect.GetIteratorFor(span).CopyTo(ref _filteredEntities); + _lastWorldVersion = World.Version; + } + + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public EcsSpan Execute(Comparison comparison) + // { + // return ExecuteFor(_aspect.World.Entities, comparison); + // } + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // public EcsSpan ExecuteFor(EcsSpan span, Comparison comparison) + // { + //#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + // if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } + // if (span.WorldID != WorldID) { Throw.Quiery_ArgumentDifferentWorldsException(); } + //#endif + // World.ReleaseDelEntityBufferAllAuto(); + // if (_lastWorldVersion != World.Version) + // { + // Filter(span); + // } + // Array.Sort(_filteredEntities, 0, _filteredEntitiesCount, comparison); + // } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsSpan Execute() { @@ -52,29 +77,15 @@ namespace DCFApixels.DragonECS public EcsSpan ExecuteFor(EcsSpan span) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - //_executeMarker.Begin(); if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } if (span.WorldID != WorldID) { Throw.Quiery_ArgumentDifferentWorldsException(); } #endif - if (World.IsEnableReleaseDelEntBuffer) + World.ReleaseDelEntityBufferAllAuto(); + if (_lastWorldVersion != World.Version || _versionsChecker.NextEquals() == false) { - World.ReleaseDelEntityBufferAll(); + Filter(span); } - EcsSpan result; - if (_lastWorldVersion != World.Version) - { - result = _aspect.GetIteratorFor(span).CopyToSpan(ref _filteredEntities); - _filteredEntitiesCount = result.Count; - _lastWorldVersion = World.Version; - } - else - { - result = new EcsSpan(WorldID, _filteredEntities, _filteredEntitiesCount); - } -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - //_executeMarker.End(); -#endif - return result; + return new EcsSpan(WorldID, _filteredEntities, _filteredEntitiesCount); } #endregion } diff --git a/src/Executors/EcsWhereToGroupExecutor.cs b/src/Executors/EcsWhereToGroupExecutor.cs index df492cc..357fd49 100644 --- a/src/Executors/EcsWhereToGroupExecutor.cs +++ b/src/Executors/EcsWhereToGroupExecutor.cs @@ -14,6 +14,7 @@ namespace DCFApixels.DragonECS private EcsGroup _filteredGroup; private long _lastWorldVersion; + private PoolVersionsChecker _versionsChecker; #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS private readonly EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Where"); @@ -37,6 +38,7 @@ namespace DCFApixels.DragonECS { _aspect = World.GetAspect(); _filteredGroup = EcsGroup.New(World); + _versionsChecker = new PoolVersionsChecker(_aspect._mask); } protected sealed override void OnDestroy() { @@ -46,6 +48,12 @@ namespace DCFApixels.DragonECS #region Methods [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Filter(EcsSpan span) + { + _aspect.GetIteratorFor(span).CopyTo(_filteredGroup); + _lastWorldVersion = World.Version; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsReadonlyGroup Execute() { return ExecuteFor(_aspect.World.Entities); @@ -58,14 +66,10 @@ namespace DCFApixels.DragonECS if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } if (span.WorldID != WorldID) { Throw.Quiery_ArgumentDifferentWorldsException(); } #endif - if (World.IsEnableReleaseDelEntBuffer) + World.ReleaseDelEntityBufferAllAuto(); + if (_lastWorldVersion != World.Version || _versionsChecker.NextEquals() == false) { - World.ReleaseDelEntityBufferAll(); - } - if (_lastWorldVersion != World.Version) - { - _aspect.GetIteratorFor(span).CopyTo(_filteredGroup); - _lastWorldVersion = World.Version; + Filter(span); } #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS _executeMarker.End(); diff --git a/src/Internal/ArraySortHalperX.cs b/src/Internal/ArraySortHalperX.cs index 3bc60be..39a8b34 100644 --- a/src/Internal/ArraySortHalperX.cs +++ b/src/Internal/ArraySortHalperX.cs @@ -4,7 +4,7 @@ using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS.Internal { - internal interface IComparerX + internal interface IStructComparer { // a > b = return > 0 int Compare(T a, T b); @@ -14,7 +14,7 @@ namespace DCFApixels.DragonECS.Internal private const int IntrosortSizeThreshold = 16; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SwapIfGreater(T[] items, ref TComparer comparer, int i, int j) where TComparer : IComparerX + public static void SwapIfGreater(T[] items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer { if (comparer.Compare(items[i], items[j]) > 0) { @@ -24,7 +24,7 @@ namespace DCFApixels.DragonECS.Internal } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InsertionSort(T[] items, ref TComparer comparer) where TComparer : IComparerX + public static void InsertionSort(T[] items, ref TComparer comparer) where TComparer : IStructComparer { for (int i = 0; i < items.Length - 1; i++) { @@ -41,7 +41,7 @@ namespace DCFApixels.DragonECS.Internal } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Sort(T[] items, ref TComparer comparer) where TComparer : IComparerX + public static void Sort(T[] items, ref TComparer comparer) where TComparer : IStructComparer { int length = items.Length; if (length == 1) @@ -69,7 +69,7 @@ namespace DCFApixels.DragonECS.Internal InsertionSort(items, ref comparer); return; } - IComparerX packed = comparer; + IStructComparer packed = comparer; Array.Sort(items, comparer.Compare); comparer = (TComparer)packed; } @@ -80,7 +80,7 @@ namespace DCFApixels.DragonECS.Internal private const int IntrosortSizeThreshold = 16; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SwapIfGreater(T* items, ref TComparer comparer, int i, int j) where TComparer : IComparerX + public static void SwapIfGreater(T* items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer { if (comparer.Compare(items[i], items[j]) > 0) { @@ -90,7 +90,7 @@ namespace DCFApixels.DragonECS.Internal } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void InsertionSort_Unchecked(T* items, int length, ref TComparer comparer) where TComparer : IComparerX + public static void InsertionSort_Unchecked(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer { for (int i = 0; i < length - 1; i++) { @@ -127,7 +127,7 @@ namespace DCFApixels.DragonECS.Internal // break; // } //} - public static void InsertionSort(T* items, int length, ref TComparer comparer) where TComparer : IComparerX + public static void InsertionSort(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer { if (length == 1) {