From c569007e8f617a8461f8380fd450225e0f08a6cf Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sun, 3 Nov 2024 18:57:56 +0800 Subject: [PATCH] update --- src/EcsMask.cs | 193 ++++++++++++++++------------- src/EcsWorld.cache.cs | 17 ++- src/EcsWorld.cs | 2 +- src/Internal/ArrayUtility.cs | 2 + src/Internal/EcsTypeCodeManager.cs | 4 +- src/Internal/UnsafeArray.cs | 44 ++++++- 6 files changed, 165 insertions(+), 97 deletions(-) diff --git a/src/EcsMask.cs b/src/EcsMask.cs index b9920d3..ff565d1 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -22,7 +22,6 @@ namespace DCFApixels.DragonECS { using static EcsMaskIteratorUtility; - #if ENABLE_IL2CPP [Il2CppSetOption (Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] @@ -483,12 +482,19 @@ namespace DCFApixels.DragonECS #endif public class EcsMaskIterator { + // TODO есть идея перенести эти ChunckBuffer-ы в стек, + // для этого нужно проработать дизайн так чтобы память в стеке выделялась за пределами итератора и GetEnumerator, + // а далее передавались поинтеры, в противном случае использовался бы стандартный подход + public readonly EcsWorld World; public readonly EcsMask Mask; private readonly UnsafeArray _sortIncBuffer; + /// slised _sortIncBuffer private readonly UnsafeArray _sortExcBuffer; + private readonly UnsafeArray _sortIncChunckBuffer; + /// slised _sortIncChunckBuffer private readonly UnsafeArray _sortExcChunckBuffer; private readonly bool _isOnlyInc; @@ -498,21 +504,86 @@ namespace DCFApixels.DragonECS { World = source; Mask = mask; - _sortIncBuffer = UnsafeArray.FromArray(mask._incs); - _sortExcBuffer = UnsafeArray.FromArray(mask._excs); - _sortIncChunckBuffer = UnsafeArray.FromArray(mask._incChunckMasks); - _sortExcChunckBuffer = UnsafeArray.FromArray(mask._excChunckMasks); + + //_sortIncBuffer = UnsafeArray.FromArray(mask._incs); + //_sortExcBuffer = UnsafeArray.FromArray(mask._excs); + //_sortIncChunckBuffer = UnsafeArray.FromArray(mask._incChunckMasks); + //_sortExcChunckBuffer = UnsafeArray.FromArray(mask._excChunckMasks); + + var sortBuffer = new UnsafeArray(mask._incs.Length + mask._excs.Length); + var sortChunckBuffer = new UnsafeArray(mask._incChunckMasks.Length + mask._excChunckMasks.Length); + + _sortIncBuffer = sortBuffer.Slice(0, mask._incs.Length); + _sortIncBuffer.CopyFromArray_Unchecked(mask._incs); + _sortExcBuffer = sortBuffer.Slice(mask._incs.Length, mask._excs.Length); + _sortExcBuffer.CopyFromArray_Unchecked(mask._excs); + + _sortIncChunckBuffer = sortChunckBuffer.Slice(0, mask._incChunckMasks.Length); + _sortIncChunckBuffer.CopyFromArray_Unchecked(mask._incChunckMasks); + _sortExcChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length, mask._excChunckMasks.Length); + _sortExcChunckBuffer.CopyFromArray_Unchecked(mask._excChunckMasks); + _isOnlyInc = _sortExcBuffer.Length <= 0; } unsafe ~EcsMaskIterator() { _sortIncBuffer.ReadonlyDispose(); - _sortExcBuffer.ReadonlyDispose(); + //_sortExcBuffer.ReadonlyDispose();// использует общую памяять с _sortIncBuffer; _sortIncChunckBuffer.ReadonlyDispose(); - _sortExcChunckBuffer.ReadonlyDispose(); + //_sortExcChunckBuffer.ReadonlyDispose();// использует общую памяять с _sortIncChunckBuffer; } #endregion + #region SortConstraints + private unsafe int SortConstraints_Internal() + { + UnsafeArray sortIncBuffer = _sortIncBuffer; + UnsafeArray sortExcBuffer = _sortExcBuffer; + + EcsWorld.PoolSlot[] counts = World._poolSlots; + int maxBufferSize = sortIncBuffer.Length > sortExcBuffer.Length ? sortIncBuffer.Length : sortExcBuffer.Length; + int maxEntites = int.MaxValue; + + EcsMaskChunck* preSortingBuffer; + if (maxBufferSize > STACK_BUFFER_THRESHOLD) + { + preSortingBuffer = TempBuffer.Get(maxBufferSize); + } + else + { + EcsMaskChunck* ptr = stackalloc EcsMaskChunck[maxBufferSize]; + preSortingBuffer = ptr; + } + + if (_sortIncChunckBuffer.Length > 1) + { + var comparer = new IncCountComparer(counts); + UnsafeArraySortHalperX.InsertionSort(sortIncBuffer.ptr, sortIncBuffer.Length, ref comparer); + ConvertToChuncks(preSortingBuffer, sortIncBuffer, _sortIncChunckBuffer); + } + + if (_sortIncChunckBuffer.Length > 0) + { + maxEntites = counts[_sortIncBuffer.ptr[0]].count; + if (maxEntites <= 0) + { + return 0; + } + } + + if (_sortExcChunckBuffer.Length > 1) + { + ExcCountComparer comparer = new ExcCountComparer(counts); + UnsafeArraySortHalperX.InsertionSort(sortExcBuffer.ptr, sortExcBuffer.Length, ref comparer); + ConvertToChuncks(preSortingBuffer, sortExcBuffer, _sortExcChunckBuffer); + } + // Выражение мало IncCount < (AllEntitesCount - ExcCount) вероятно будет истинным. + // ExcCount = максимальное количество ентитей с исключеющим ограничением и IncCount = минимальоне количество ентитей с включающим ограничением + // Поэтому исключающее ограничение игнорируется для maxEntites. + + return maxEntites; + } + #endregion #region IterateTo [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -598,7 +669,20 @@ namespace DCFApixels.DragonECS #region Enumerator [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() { return new Enumerator(_span, _iterator); } + public Enumerator GetEnumerator() + { + if (_iterator.Mask.IsBroken) + { + return new Enumerator(_span.Slice(0, 0), _iterator); + } + int maxEntities = _iterator.SortConstraints_Internal(); + if (maxEntities <= 0) + { + return new Enumerator(_span.Slice(0, 0), _iterator); + } + return new Enumerator(_span, _iterator); + } + #if ENABLE_IL2CPP [Il2CppSetOption (Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] @@ -621,49 +705,6 @@ namespace DCFApixels.DragonECS _entityComponentMasks = iterator.World._entityComponentMasks; _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; - int max = _sortIncBuffer.Length > _sortExcBuffer.Length ? _sortIncBuffer.Length : _sortExcBuffer.Length; - - EcsMaskChunck* preSortingBuffer; - if (max > STACK_BUFFER_THRESHOLD) - { - preSortingBuffer = TempBuffer.Get(max); - } - else - { - EcsMaskChunck* ptr = stackalloc EcsMaskChunck[max]; - preSortingBuffer = ptr; - } - - if (_sortIncChunckBuffer.Length > 1) - { - var comparer = new IncCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref comparer); - ConvertToChuncks(preSortingBuffer, _sortIncBuffer, _sortIncChunckBuffer); - } - if (_sortIncChunckBuffer.Length > 0 && counts[_sortIncBuffer.ptr[0]].count <= 0) - { - _span = span.Slice(0, 0).GetEnumerator(); - return; - } - - if (_sortExcChunckBuffer.Length > 1) - { - ExcCountComparer comparer = new ExcCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref comparer); - ConvertToChuncks(preSortingBuffer, _sortExcBuffer, _sortExcChunckBuffer); - } - #endregion - _span = span.GetEnumerator(); } public int Current @@ -761,7 +802,20 @@ namespace DCFApixels.DragonECS #region Enumerator [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Enumerator GetEnumerator() { return new Enumerator(_span, _iterator); } + public Enumerator GetEnumerator() + { + if (_iterator.Mask.IsBroken) + { + return new Enumerator(_span.Slice(0, 0), _iterator); + } + int maxEntities = _iterator.SortConstraints_Internal(); + if (maxEntities <= 0) + { + return new Enumerator(_span.Slice(0, 0), _iterator); + } + return new Enumerator(_span, _iterator); + } + #if ENABLE_IL2CPP [Il2CppSetOption (Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] @@ -782,41 +836,6 @@ namespace DCFApixels.DragonECS _entityComponentMasks = iterator.World._entityComponentMasks; _entityComponentMaskLengthBitShift = iterator.World._entityComponentMaskLengthBitShift; - if (iterator.Mask.IsBroken) - { - _span = span.Slice(0, 0).GetEnumerator(); - return; - } - - #region Sort - UnsafeArray _sortIncBuffer = iterator._sortIncBuffer; - EcsWorld.PoolSlot[] counts = iterator.World._poolSlots; - int max = _sortIncBuffer.Length; - - EcsMaskChunck* preSortingBuffer; - if (max > STACK_BUFFER_THRESHOLD) - { - preSortingBuffer = TempBuffer.Get(max); - } - else - { - EcsMaskChunck* ptr = stackalloc EcsMaskChunck[max]; - preSortingBuffer = ptr; - } - - if (_sortIncChunckBuffer.Length > 1) - { - var comparer = new IncCountComparer(counts); - UnsafeArraySortHalperX.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref comparer); - ConvertToChuncks(preSortingBuffer, _sortIncBuffer, _sortIncChunckBuffer); - } - if (_sortIncChunckBuffer.Length > 0 && counts[_sortIncBuffer.ptr[0]].count <= 0) - { - _span = span.Slice(0, 0).GetEnumerator(); - return; - } - #endregion - _span = span.GetEnumerator(); } public int Current diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs index 9da136a..c4393d6 100644 --- a/src/EcsWorld.cache.cs +++ b/src/EcsWorld.cache.cs @@ -32,25 +32,32 @@ namespace DCFApixels.DragonECS component = default; } } - internal readonly struct QueryCache : IEcsWorldComponent> + + //TODO добавить сквозной кеш для инстансов TExecutor + //private readonly struct WhereCache : IEcsWorldComponent> + //{ + // private readonly SparseArray _pairs + //} + // Это не подохидт + internal readonly struct WhereQueryCache : IEcsWorldComponent> where TExecutor : EcsQueryExecutor, new() where TAspcet : EcsAspect, new() { public readonly TExecutor Executor; public readonly TAspcet Aspcet; - public QueryCache(TExecutor executor, TAspcet aspcet) + public WhereQueryCache(TExecutor executor, TAspcet aspcet) { Executor = executor; Aspcet = aspcet; } - void IEcsWorldComponent>.Init(ref QueryCache component, EcsWorld world) + void IEcsWorldComponent>.Init(ref WhereQueryCache component, EcsWorld world) { TExecutor instance = new TExecutor(); TAspcet aspect = world.GetAspect(); instance.Initialize(world, aspect.Mask); - component = new QueryCache(instance, aspect); + component = new WhereQueryCache(instance, aspect); } - void IEcsWorldComponent>.OnDestroy(ref QueryCache component, EcsWorld world) + void IEcsWorldComponent>.OnDestroy(ref WhereQueryCache component, EcsWorld world) { component = default; } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 2e34c5d..0b360bf 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -234,7 +234,7 @@ namespace DCFApixels.DragonECS where TExecutor : EcsQueryExecutor, new() where TAspect : EcsAspect, new() { - ref var cmp = ref Get>(); + ref var cmp = ref Get>(); executor = cmp.Executor; aspect = cmp.Aspcet; } diff --git a/src/Internal/ArrayUtility.cs b/src/Internal/ArrayUtility.cs index a757552..51d04a3 100644 --- a/src/Internal/ArrayUtility.cs +++ b/src/Internal/ArrayUtility.cs @@ -250,6 +250,8 @@ namespace DCFApixels.DragonECS.Internal new IntPtr(oldPointer), new IntPtr(MetaCache.Size * newCount))).ToPointer(); } + + } public static class CollectionUtility diff --git a/src/Internal/EcsTypeCodeManager.cs b/src/Internal/EcsTypeCodeManager.cs index 2862d11..e54d212 100644 --- a/src/Internal/EcsTypeCodeManager.cs +++ b/src/Internal/EcsTypeCodeManager.cs @@ -2,13 +2,15 @@ using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; +#if ENABLE_IL2CPP +using Unity.IL2CPP.CompilerServices; +#endif namespace DCFApixels.DragonECS.Internal { //TODO разработать возможность ручного устанавливания ID типам. //это нужно для упрощения разработки сетевух #if ENABLE_IL2CPP - using Unity.IL2CPP.CompilerServices; [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif diff --git a/src/Internal/UnsafeArray.cs b/src/Internal/UnsafeArray.cs index cf8ba0d..6e91b33 100644 --- a/src/Internal/UnsafeArray.cs +++ b/src/Internal/UnsafeArray.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Runtime.CompilerServices; #if ENABLE_IL2CPP using Unity.IL2CPP.CompilerServices; @@ -63,6 +62,8 @@ namespace DCFApixels.DragonECS.Internal return result; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] public UnsafeArray(int length) { @@ -82,6 +83,34 @@ namespace DCFApixels.DragonECS.Internal Length = length; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public UnsafeArray Slice(int start) + { + if ((uint)start > (uint)Length) + { + throw new ArgumentOutOfRangeException(); + } + return new UnsafeArray(ptr + start, Length - start); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public UnsafeArray Slice(int start, int length) + { + if ((uint)start > (uint)Length || (uint)length > (uint)(Length - start)) + { + throw new ArgumentOutOfRangeException(); + } + return new UnsafeArray(ptr + start, length); + } + + public void CopyFromArray_Unchecked(T[] array) + { + for (int i = 0; i < array.Length; i++) + { + ptr[i] = array[i]; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public UnsafeArray Clone() { @@ -101,7 +130,12 @@ namespace DCFApixels.DragonECS.Internal public override string ToString() { T* ptr = this.ptr; - return CollectionUtility.AutoToString(EnumerableInt.Range(0, Length).Select(i => ptr[i]), "ua"); + var elements = new T[Length]; + for (int i = 0; i < Length; i++) + { + elements[i] = ptr[i]; + } + return CollectionUtility.AutoToString(elements, "ua"); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } @@ -139,8 +173,12 @@ namespace DCFApixels.DragonECS.Internal public int length; public DebuggerProxy(UnsafeArray instance) { - elements = EnumerableInt.Range(0, instance.Length).Select(i => instance.ptr[i]).ToArray(); length = instance.Length; + elements = new T[length]; + for (int i = 0; i < length; i++) + { + elements[i] = instance.ptr[i]; + } } } }