From e9cdfbfb5104b1c2270ef8acc7d1665a620713ec Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sun, 7 Jan 2024 19:32:16 +0800 Subject: [PATCH] update mask building --- src/Collections/EcsGroup.cs | 2 +- src/Collections/EcsSpan.cs | 2 +- src/Consts.cs | 2 + src/EcsAspect.cs | 98 ++++-------------------------- src/EcsMask.cs | 117 +++++++++++++++++++----------------- src/EcsWorld.cache.cs | 2 +- src/EcsWorld.cs | 2 +- src/EcsWorld.static.cs | 2 +- 8 files changed, 82 insertions(+), 145 deletions(-) diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index 7d8d441..2909f45 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -514,7 +514,7 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException(); #endif - if(group.Count > Count) + if (group.Count > Count) { foreach (var item in this) if (group.Has(item)) diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs index be3e2e7..579d916 100644 --- a/src/Collections/EcsSpan.cs +++ b/src/Collections/EcsSpan.cs @@ -37,7 +37,7 @@ namespace DCFApixels.DragonECS { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _values.IsEmpty; - } + } #endregion #region Constructors diff --git a/src/Consts.cs b/src/Consts.cs index 8100e90..5ab4b62 100644 --- a/src/Consts.cs +++ b/src/Consts.cs @@ -17,5 +17,7 @@ public const string POST_END_LAYER = nameof(POST_END_LAYER); public const string META_HIDDEN_TAG = "HiddenInDebagging"; + + public const int MAGIC_PRIME = 314159; } } diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 924a081..cbcbb0c 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -2,7 +2,6 @@ using DCFApixels.DragonECS.Utils; using System; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -34,20 +33,16 @@ namespace DCFApixels.DragonECS public sealed class Builder : EcsAspectBuilderBase { private EcsWorld _world; - private HashSet _inc; - private HashSet _exc; - private List _combined; + private EcsMask.Builder _maskBuilder; public EcsWorld World => _world; private Builder(EcsWorld world) { _world = world; - _combined = new List(); - _inc = new HashSet(); - _exc = new HashSet(); + _maskBuilder = new EcsMask.Builder(world); } - internal static unsafe TAspect Build(EcsWorld world) where TAspect : EcsAspect + internal static unsafe TAspect New(EcsWorld world) where TAspect : EcsAspect { Builder builder = new Builder(world); Type aspectType = typeof(TAspect); @@ -63,7 +58,7 @@ namespace DCFApixels.DragonECS newAspect.Init(builder); } newAspect._source = world; - builder.End(out newAspect._mask); + builder.Build(out newAspect._mask); newAspect._isInit = true; newAspect._sortIncBuffer = new UnsafeArray(newAspect._mask.inc.Length, true); @@ -92,7 +87,7 @@ namespace DCFApixels.DragonECS return (TAspect)newAspect; } - #region Include/Exclude/Optional + #region Include/Exclude/Optional/Combine public sealed override TPool Include() { IncludeImplicit(typeof(TPool).GetGenericArguments()[0]); @@ -109,27 +104,16 @@ namespace DCFApixels.DragonECS } private void IncludeImplicit(Type type) { - int id = _world.GetComponentID(type); -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type); -#endif - _inc.Add(id); + _maskBuilder.Include(type); } private void ExcludeImplicit(Type type) { - int id = _world.GetComponentID(type); -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type); -#endif - _exc.Add(id); + _maskBuilder.Exclude(type); } - #endregion - - #region Combine public TOtherAspect Combine(int order = 0) where TOtherAspect : EcsAspect { var result = _world.GetAspect(); - _combined.Add(new Combined(result, order)); + _maskBuilder.CombineWith(result.Mask); return result; } #endregion @@ -139,60 +123,9 @@ namespace DCFApixels.DragonECS return new EcsWorldCmp(_world.id); } - private void End(out EcsMask mask) + private void Build(out EcsMask mask) { - HashSet maskInc; - HashSet maskExc; - if (_combined.Count > 0) - { - maskInc = new HashSet(); - maskExc = new HashSet(); - _combined.Sort((a, b) => a.order - b.order); - 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(_exc);//удаляю конфликтующие ограничения - maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения - maskInc.UnionWith(_inc); - maskExc.UnionWith(_exc); - } - else - { - maskInc = _inc; - maskExc = _exc; - } - - Dictionary r = new Dictionary(); - foreach (var id in maskInc) - { - var bit = EcsMaskChunck.FromID(id); - if (!r.TryAdd(bit.chankIndex, bit.mask)) - r[bit.chankIndex] = r[bit.chankIndex] | bit.mask; - } - EcsMaskChunck[] incMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray(); - r.Clear(); - foreach (var id in maskExc) - { - var bit = EcsMaskChunck.FromID(id); - if (!r.TryAdd(bit.chankIndex, bit.mask)) - r[bit.chankIndex] = r[bit.chankIndex] | bit.mask; - } - EcsMaskChunck[] excMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray(); - - var inc = maskInc.ToArray(); - Array.Sort(inc); - var exc = maskExc.ToArray(); - Array.Sort(exc); - - mask = new EcsMask(0, _world.id, inc, exc, incMasks, excMasks); - _world = null; - _inc = null; - _exc = null; + mask = _maskBuilder.Build(); } #region SupportReflectionHack @@ -281,7 +214,7 @@ namespace DCFApixels.DragonECS int count = 0; while (enumerator.MoveNext()) { - if(array.Length <= count) + if (array.Length <= count) Array.Resize(ref array, array.Length << 1); array[count++] = enumerator.Current; } @@ -365,15 +298,11 @@ namespace DCFApixels.DragonECS UnsafeArray _sortExcBuffer = aspect._sortExcBuffer; _sortIncChunckBuffer = aspect._sortIncChunckBuffer; _sortExcChunckBuffer = aspect._sortExcChunckBuffer; - int[] counts = mask.World._poolComponentCounts; - - + #region Sort IncCountComparer incComparer = new IncCountComparer(counts); ExcCountComparer excComparer = new ExcCountComparer(counts); - - #region Sort UnsafeArraySortHalperX.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer); UnsafeArraySortHalperX.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer); @@ -476,9 +405,6 @@ namespace DCFApixels.DragonECS _preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]); } - //int _sortedIncBufferLength = mask.inc.Length; - //int _sortedExcBufferLength = mask.exc.Length; - //if (_sortIncChunckBuffer.Length > 1)//перенести этот чек в начала сортировки, для _incChunckMasks.Length == 1 сортировка не нужна if (_sortIncBuffer.Length > 1) { diff --git a/src/EcsMask.cs b/src/EcsMask.cs index f3da598..10b2b71 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; -using static Leopotam.EcsLite.EcsWorld; namespace DCFApixels.DragonECS { @@ -13,38 +12,17 @@ namespace DCFApixels.DragonECS private Dictionary _masks = new Dictionary(256); internal EcsMask GetMask_Internal(EcsMask.BuilderMaskKey maskKey) { - if(!_masks.TryGetValue(maskKey, out EcsMask result)) + if (!_masks.TryGetValue(maskKey, out EcsMask result)) { - int[] combinedInc = maskKey.inc; - int[] combinedExc = maskKey.exc; - Dictionary r = new Dictionary(); - foreach (var id in combinedInc) - { - var bit = EcsMaskChunck.FromID(id); - if (!r.TryAdd(bit.chankIndex, bit.mask)) - r[bit.chankIndex] = r[bit.chankIndex] | bit.mask; - } - EcsMaskChunck[] incMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray(); - r.Clear(); - foreach (var id in combinedExc) - { - var bit = EcsMaskChunck.FromID(id); - if (!r.TryAdd(bit.chankIndex, bit.mask)) - r[bit.chankIndex] = r[bit.chankIndex] | bit.mask; - } - EcsMaskChunck[] excMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray(); - - result = new EcsMask(_masks.Count, id, combinedInc, combinedExc, incMasks, excMasks); + result = new EcsMask(_masks.Count, id, maskKey.inc, maskKey.exc); _masks.Add(maskKey, result); } return result; } } - - [DebuggerTypeProxy(typeof(DebuggerProxy))] - public sealed class EcsMask + public sealed class EcsMask : IEquatable { internal readonly int id; internal readonly int worldID; @@ -58,7 +36,7 @@ namespace DCFApixels.DragonECS public ReadOnlySpan Inc => inc; /// Excluding constraints public ReadOnlySpan Exc => exc; - internal EcsMask(int id, int worldID, int[] inc, int[] exc, EcsMaskChunck[] incChunckMasks, EcsMaskChunck[] excChunckMasks) + internal EcsMask(int id, int worldID, int[] inc, int[] exc) { #if DEBUG CheckConstraints(inc, exc); @@ -67,12 +45,43 @@ namespace DCFApixels.DragonECS this.inc = inc; this.exc = exc; this.worldID = worldID; - this.incChunckMasks = incChunckMasks; - this.excChunckMasks = excChunckMasks; + + //TODO пересесть с дикта на подсчет в цикле. + Dictionary r = new Dictionary(); + foreach (var cmpID in inc) + { + var bit = EcsMaskChunck.FromID(cmpID); + if (!r.TryAdd(bit.chankIndex, bit.mask)) + r[bit.chankIndex] = r[bit.chankIndex] | bit.mask; + } + EcsMaskChunck[] incMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray(); + r.Clear(); + foreach (var cmpID in exc) + { + var bit = EcsMaskChunck.FromID(cmpID); + if (!r.TryAdd(bit.chankIndex, bit.mask)) + r[bit.chankIndex] = r[bit.chankIndex] | bit.mask; + } + EcsMaskChunck[] excMasks = r.Select(o => new EcsMaskChunck(o.Key, o.Value)).ToArray(); + + incChunckMasks = incMasks; + excChunckMasks = excMasks; } #region Object public override string ToString() => CreateLogString(worldID, inc, exc); + public bool Equals(EcsMask mask) + { + return id == mask.id && worldID == mask.worldID; + } + public override bool Equals(object obj) + { + return obj is EcsMask mask && id == mask.id && Equals(mask); + } + public override int GetHashCode() + { + return unchecked(id ^ (worldID * EcsConsts.MAGIC_PRIME)); + } #endregion #region Debug utils @@ -109,10 +118,12 @@ namespace DCFApixels.DragonECS return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization #endif } + internal class DebuggerProxy { + public readonly int ID; public readonly EcsWorld world; - public readonly int worldID; + private readonly int _worldID; public readonly EcsMaskChunck[] includedChunkMasks; public readonly EcsMaskChunck[] excludedChunkMasks; public readonly int[] included; @@ -122,8 +133,9 @@ namespace DCFApixels.DragonECS public DebuggerProxy(EcsMask mask) { + ID = mask.id; world = EcsWorld.GetWorld(mask.worldID); - worldID = mask.worldID; + _worldID = mask.worldID; includedChunkMasks = mask.incChunckMasks; excludedChunkMasks = mask.excChunckMasks; included = mask.inc; @@ -132,10 +144,11 @@ namespace DCFApixels.DragonECS includedTypes = included.Select(converter).ToArray(); excludedTypes = excluded.Select(converter).ToArray(); } - public override string ToString() => CreateLogString(worldID, included, excluded); + public override string ToString() => CreateLogString(_worldID, included, excluded); } #endregion + #region Builder public readonly struct BuilderMaskKey : IEquatable { public readonly int[] inc; @@ -173,7 +186,7 @@ namespace DCFApixels.DragonECS } } #if DEBUG - if(other.hash != hash) + if (other.hash != hash) { throw new Exception("other.hash != hash"); } @@ -186,16 +199,14 @@ namespace DCFApixels.DragonECS public class Builder { - private EcsWorld _world; - private HashSet _inc; - private HashSet _exc; - private List _combined; + private readonly EcsWorld _world; + private readonly HashSet _inc = new HashSet(); + private readonly HashSet _exc = new HashSet(); + private readonly List _combined = new List(); internal Builder(EcsWorld world) { _world = world; - _inc = new HashSet(); - _exc = new HashSet(); } public void Include() @@ -269,26 +280,23 @@ namespace DCFApixels.DragonECS var exc = combinedExc.ToArray(); Array.Sort(exc); - int keyHash = inc.Length + exc.Length; - for (int i = 0, iMax = inc.Length; i < iMax; i++) + unchecked { - keyHash = unchecked(keyHash * 314159 + inc[i]); + int keyHash = inc.Length + exc.Length; + for (int i = 0, iMax = inc.Length; i < iMax; i++) + { + keyHash = keyHash * EcsConsts.MAGIC_PRIME + inc[i]; + } + for (int i = 0, iMax = exc.Length; i < iMax; i++) + { + keyHash = keyHash * EcsConsts.MAGIC_PRIME - exc[i]; + } + BuilderMaskKey key = new BuilderMaskKey(inc, exc, keyHash); + return _world.GetMask_Internal(key); } - for (int i = 0, iMax = exc.Length; i < iMax; i++) - { - keyHash = unchecked(keyHash * 314159 - exc[i]); - } - BuilderMaskKey key = new BuilderMaskKey(inc, exc, keyHash); - - _world = null; - _inc = null; - _exc = null; - _combined = null; - - return _world.GetMask_Internal(key); } } - + private readonly struct Combined { public readonly EcsMask mask; @@ -299,6 +307,7 @@ namespace DCFApixels.DragonECS this.order = order; } } + #endregion } [DebuggerTypeProxy(typeof(DebuggerProxy))] diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs index 8729c4b..a964ce5 100644 --- a/src/EcsWorld.cache.cs +++ b/src/EcsWorld.cache.cs @@ -23,7 +23,7 @@ public AspectCache(T instance) => this.instance = instance; void IEcsWorldComponent>.Init(ref AspectCache component, EcsWorld world) { - component = new AspectCache(EcsAspect.Builder.Build(world)); + component = new AspectCache(EcsAspect.Builder.New(world)); } void IEcsWorldComponent>.OnDestroy(ref AspectCache component, EcsWorld world) { diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 6561464..137665c 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -142,7 +142,7 @@ namespace DCFApixels.DragonECS #region Where Query public EcsReadonlyGroup WhereToGroupFor(EcsSpan span, out TAspect aspect) where TAspect : EcsAspect { - if(_isEnableReleaseDelEntBuffer) + if (_isEnableReleaseDelEntBuffer) { ReleaseDelEntityBufferAll(); } diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 10c18e9..dd52fea 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS { itemIndex = ++_count; } - if(_items.Length <= itemIndex) + if (_items.Length <= itemIndex) { Array.Resize(ref _items, _items.Length << 1); }