From f2238cd33adf504594a57fbe69fd521e6f0262c3 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 18 Apr 2024 22:14:50 +0800 Subject: [PATCH] add EcsMask.Builder.Except --- src/EcsAspect.cs | 21 ++++++++--- src/EcsMask.cs | 94 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 95 insertions(+), 20 deletions(-) diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index fb48e88..eca92f6 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -168,7 +168,7 @@ namespace DCFApixels.DragonECS return (TAspect)newAspect; } - #region Include/Exclude/Optional/Combine + #region Include/Exclude/Optional/Combine/Except public TPool IncludePool() where TPool : IEcsPoolImplementation, new() { var pool = _world.GetPoolInstance(); @@ -199,6 +199,12 @@ namespace DCFApixels.DragonECS _maskBuilder.Combine(result.Mask); return result; } + public TOtherAspect Except(int order = 0) where TOtherAspect : EcsAspect + { + var result = _world.GetAspect(); + _maskBuilder.Except(result.Mask); + return result; + } #endregion private void Build(out EcsMask mask) @@ -364,9 +370,14 @@ namespace DCFApixels.DragonECS _sortIncChunckBuffer = aspect._sortIncChunckBuffer; _sortExcChunckBuffer = aspect._sortExcChunckBuffer; - //_entityComponentMaskBitShift = BitsUtility.GetHighBitNumber(aspect.World._entityComponentMaskLength); _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; @@ -388,9 +399,9 @@ namespace DCFApixels.DragonECS } for (int i = 0, ii = 0; ii < _sortIncChunckBuffer.Length; ii++) { - EcsMaskChunck bas = _preSortedIncBuffer[i]; - int chankIndexX = bas.chankIndex; - int maskX = bas.mask; + EcsMaskChunck chunkX = _preSortedIncBuffer[i]; + int chankIndexX = chunkX.chankIndex; + int maskX = chunkX.mask; for (int j = i + 1; j < _sortIncBuffer.Length; j++) { diff --git a/src/EcsMask.cs b/src/EcsMask.cs index fe6562c..9d08815 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -44,6 +44,10 @@ namespace DCFApixels.DragonECS { get { return inc.Length == 0 && exc.Length == 0; } } + public bool IsBroken + { + get { return (inc.Length & exc.Length) == 1 && inc[0] == exc[0]; } + } #endregion #region Constructors @@ -51,11 +55,24 @@ namespace DCFApixels.DragonECS { return new Builder(world); } - internal EcsMask(int id, short worldID, int[] inc, int[] exc) + + internal static EcsMask New(int id, short worldID, int[] inc, int[] exc) { #if DEBUG CheckConstraints(inc, exc); #endif + return new EcsMask(id, worldID, inc, exc); + } + internal static EcsMask NewEmpty(int id, short worldID) + { + return new EcsMask(id, worldID, new int[0], new int[0]); + } + internal static EcsMask NewBroken(int id, short worldID) + { + return new EcsMask(id, worldID, new int[1] { 1 }, new int[1] { 1 }); + } + private EcsMask(int id, short worldID, int[] inc, int[] exc) + { this.id = id; this.inc = inc; this.exc = exc; @@ -198,7 +215,7 @@ namespace DCFApixels.DragonECS #region Debug utils #if DEBUG private static HashSet _dummyHashSet = new HashSet(); - private void CheckConstraints(int[] inc, int[] exc) + private static void CheckConstraints(int[] inc, int[] exc) { lock (_dummyHashSet) { @@ -209,7 +226,7 @@ namespace DCFApixels.DragonECS if (_dummyHashSet.Overlaps(exc)) { throw new EcsFrameworkException("Conflicting Include and Exclude constraints."); } } } - private bool CheckRepeats(int[] array) + private static bool CheckRepeats(int[] array) { _dummyHashSet.Clear(); foreach (var item in array) @@ -235,6 +252,8 @@ namespace DCFApixels.DragonECS internal class DebuggerProxy { + private EcsMask _source; + public readonly int ID; public readonly EcsWorld world; private readonly short _worldID; @@ -245,8 +264,13 @@ namespace DCFApixels.DragonECS public readonly Type[] includedTypes; public readonly Type[] excludedTypes; + public bool IsEmpty { get { return _source.IsEmpty; } } + public bool IsBroken { get { return _source.IsBroken; } } + public DebuggerProxy(EcsMask mask) { + _source = mask; + ID = mask.id; world = EcsWorld.GetWorld(mask.worldID); _worldID = mask.worldID; @@ -308,16 +332,26 @@ namespace DCFApixels.DragonECS private readonly Dictionary _masks; private readonly Dictionary _opMasks; + public readonly EcsMask EmptyMask; + public readonly EcsMask BrokenMask; + #region Constructor/Destructor - public WorldMaskComponent(EcsWorld world, Dictionary masks, Dictionary opMasks) + public WorldMaskComponent(EcsWorld world, Dictionary masks, Dictionary opMasks, EcsMask emptyMask, EcsMask brokenMask) { _world = world; _masks = masks; _opMasks = opMasks; + EmptyMask = emptyMask; + BrokenMask = brokenMask; } public void Init(ref WorldMaskComponent component, EcsWorld world) { - component = new WorldMaskComponent(world, new Dictionary(256), new Dictionary(256)); + var masks = new Dictionary(256); + EcsMask emptyMask = NewEmpty(0, world.id); + EcsMask brokenMask = NewBroken(1, world.id); + masks.Add(new Key(emptyMask.inc, emptyMask.exc), emptyMask); + masks.Add(new Key(brokenMask.inc, brokenMask.exc), brokenMask); + component = new WorldMaskComponent(world, masks, new Dictionary(256), emptyMask, brokenMask); } public void OnDestroy(ref WorldMaskComponent component, EcsWorld world) { @@ -336,7 +370,7 @@ namespace DCFApixels.DragonECS var builder = New(a.World); if (a.IsConflictWith(b)) { - return a.World.GetAspect().Mask; + return a.World.Get().BrokenMask; } ExceptMaskConstraint(builder, a.inc, b.inc, true); ExceptMaskConstraint(builder, a.exc, b.exc, false); @@ -376,7 +410,7 @@ namespace DCFApixels.DragonECS { if (!_masks.TryGetValue(maskKey, out EcsMask result)) { - result = new EcsMask(_masks.Count, _world.id, maskKey.inc, maskKey.exc); + result = EcsMask.New(_masks.Count, _world.id, maskKey.inc, maskKey.exc); _masks.Add(maskKey, result); } return result; @@ -447,7 +481,8 @@ namespace DCFApixels.DragonECS private readonly EcsWorld _world; private readonly HashSet _inc = new HashSet(); private readonly HashSet _exc = new HashSet(); - private readonly List _combined = new List(); + private readonly List _combineds = new List(); + private readonly List _excepteds = new List(); #region Constrcutors internal Builder(EcsWorld world) @@ -493,7 +528,13 @@ namespace DCFApixels.DragonECS public Builder Combine(EcsMask mask, int order = 0) { - _combined.Add(new Combined(mask, order)); + _combineds.Add(new Combined(mask, order)); + return this; + } + + public Builder Except(EcsMask mask, int order = 0) + { + _excepteds.Add(new Excepted(mask, order)); return this; } #endregion @@ -503,12 +544,12 @@ namespace DCFApixels.DragonECS { HashSet combinedInc; HashSet combinedExc; - if (_combined.Count > 0) + if (_combineds.Count > 0) { combinedInc = new HashSet(); combinedExc = new HashSet(); - _combined.Sort((a, b) => a.order - b.order); - foreach (var item in _combined) + _combineds.Sort((a, b) => a.order - b.order); + foreach (var item in _combineds) { EcsMask submask = item.mask; combinedInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения @@ -526,15 +567,28 @@ namespace DCFApixels.DragonECS combinedInc = _inc; combinedExc = _exc; } + if (_excepteds.Count > 0) + { + foreach (var item in _excepteds) + { + if(combinedInc.Overlaps(item.mask.exc) || combinedExc.Overlaps(item.mask.inc)) + { + _combineds.Clear(); + _excepteds.Clear(); + return _world.Get().BrokenMask; + } + combinedInc.ExceptWith(item.mask.inc); + combinedExc.ExceptWith(item.mask.exc); + } + } var inc = combinedInc.ToArray(); Array.Sort(inc); - _inc.Clear(); var exc = combinedExc.ToArray(); Array.Sort(exc); - _exc.Clear(); - _combined.Clear(); + _combineds.Clear(); + _excepteds.Clear(); return _world.Get().GetMask(new Key(inc, exc)); } @@ -551,6 +605,16 @@ namespace DCFApixels.DragonECS this.order = order; } } + private readonly struct Excepted + { + public readonly EcsMask mask; + public readonly int order; + public Excepted(EcsMask mask, int order) + { + this.mask = mask; + this.order = order; + } + } #endregion }