From 45acde2db318e903b7b32bccf6ad460fef8da9d6 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Fri, 1 Nov 2024 12:41:10 +0800 Subject: [PATCH] refactoring --- src/EcsAspect.cs | 153 +++++---- src/EcsMask.cs | 554 ++++++++++++++---------------- src/EcsStaticMask.cs | 235 ++++++++----- src/EcsWorld.cs | 21 +- src/EcsWorld.pools.cs | 11 - src/EcsWorld.static.cs | 23 ++ src/Executors/EcsQueryExecutor.cs | 11 +- src/Executors/Queries.cs | 21 +- 8 files changed, 542 insertions(+), 487 deletions(-) diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index b5aae81..0099606 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -1,10 +1,12 @@ -using DCFApixels.DragonECS.Internal; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.PoolsCore; using System; +using System.Collections.Generic; namespace DCFApixels.DragonECS { - public abstract class EcsAspect : ITemplateNode, IEcsComponentMask + public abstract class EcsAspect : ITemplateNode, IComponentMask { #region Initialization Halpers [ThreadStatic] @@ -40,6 +42,9 @@ namespace DCFApixels.DragonECS internal EcsMask _mask; private bool _isBuilt = false; + //Инициализация аспектов проходит в синхронизированном состоянии, поэтому использование _staticMaskCache потоко безопасно. + private static Dictionary _staticMaskCache = new Dictionary(); + #region Properties public EcsMask Mask { @@ -53,6 +58,13 @@ namespace DCFApixels.DragonECS { get { return _isBuilt; } } + /// + /// Статическая инициализация означет что каждый новый эекземпляр идентичен другому, инициализация стандартным путем создает идентичные экземпляры, поэтому значение по умолчанию true. + /// + protected virtual bool IsStaticInitialization + { + get { return true; } + } #endregion #region Methods @@ -90,19 +102,14 @@ namespace DCFApixels.DragonECS #region Constructors/New private Builder() { } - private void Reset(EcsWorld world) - { - _maskBuilder = EcsStaticMask.New(); - _world = world; - } internal static unsafe TAspect New(EcsWorld world) where TAspect : EcsAspect, new() { + //Get Builder if (_constructorBuildersStack == null) { _constructorBuildersStack = new Builder[4]; _constructorBuildersStackIndex = -1; } - _constructorBuildersStackIndex++; if (_constructorBuildersStackIndex >= _constructorBuildersStack.Length) { @@ -114,16 +121,34 @@ namespace DCFApixels.DragonECS builder = new Builder(); _constructorBuildersStack[_constructorBuildersStackIndex] = builder; } - builder.Reset(world); + //Setup Builder + EcsStaticMask staticMask = null; + if (_staticMaskCache.TryGetValue(typeof(TAspect), out staticMask) == false) + { + builder._maskBuilder = EcsStaticMask.New(); + } + builder._world = world; + + //Building TAspect newAspect = new TAspect(); - newAspect.Init(builder); - _constructorBuildersStackIndex--; - newAspect._source = world; - builder.Build(out newAspect._mask); + newAspect.Init(builder); + + //Build Mask + if (staticMask == null) + { + staticMask = builder._maskBuilder.Build(); + builder._maskBuilder = default; + if (newAspect.IsStaticInitialization) + { + _staticMaskCache.Add(typeof(TAspect), staticMask); + } + } + newAspect._mask = staticMask.ToMask(world); newAspect._isBuilt = true; + _constructorBuildersStackIndex--; return newAspect; } #endregion @@ -148,34 +173,38 @@ namespace DCFApixels.DragonECS private void IncludeImplicit(Type type) { - _maskBuilder.Inc(type); + if (_maskBuilder.IsNull == false) + { + _maskBuilder.Inc(type); + } } private void ExcludeImplicit(Type type) { - _maskBuilder.Exc(type); + if (_maskBuilder.IsNull == false) + { + _maskBuilder.Exc(type); + } } - public TOtherAspect Combine(int order = 0) where TOtherAspect : EcsAspect, new() { var result = _world.GetAspect(); - _maskBuilder.Combine(result.Mask._staticMask); + if (_maskBuilder.IsNull == false) + { + _maskBuilder.Combine(result.Mask._staticMask); + } return result; } public TOtherAspect Except(int order = 0) where TOtherAspect : EcsAspect, new() { var result = _world.GetAspect(); - _maskBuilder.Except(result.Mask._staticMask); + if (_maskBuilder.IsNull == false) + { + _maskBuilder.Except(result.Mask._staticMask); + } return result; } #endregion - #region Build - private void Build(out EcsMask mask) - { - mask = _maskBuilder.Build().ToMask(_world); - } - #endregion - #region SupportReflectionHack #if UNITY_2020_3_OR_NEWER [UnityEngine.Scripting.Preserve] @@ -205,7 +234,43 @@ namespace DCFApixels.DragonECS } #endregion - #region Iterator + #region Template + public virtual void Apply(short worldID, int entityID) + { + EcsWorld world = EcsWorld.GetWorld(worldID); + foreach (var incTypeID in _mask._incs) + { + var pool = world.FindPoolInstance(incTypeID); + if (pool != null) + { + if (pool.Has(entityID) == false) + { + pool.AddRaw(entityID, null); + } + } +#if DEBUG + else + { + EcsDebug.PrintWarning("Component has not been added because the pool has not been initialized yet."); + } +#endif + } + foreach (var excTypeID in _mask._excs) + { + var pool = world.FindPoolInstance(excTypeID); + if (pool != null && pool.Has(entityID)) + { + pool.Del(entityID); + } + } + } + #endregion + + #region Other + EcsMask IComponentMask.ToMask(EcsWorld world) { return _mask; } + #endregion + + #region Obsolete [Obsolete("Use EcsMask.GetIterator()")] public Iterator GetIterator() { @@ -252,42 +317,6 @@ namespace DCFApixels.DragonECS } } #endregion - - #region Template - public virtual void Apply(short worldID, int entityID) - { - EcsWorld world = EcsWorld.GetWorld(worldID); - foreach (var incTypeID in _mask._inc) - { - var pool = world.FindPoolInstance(incTypeID); - if (pool != null) - { - if (pool.Has(entityID) == false) - { - pool.AddRaw(entityID, null); - } - } -#if DEBUG - else - { - EcsDebug.PrintWarning("Component has not been added because the pool has not been initialized yet."); - } -#endif - } - foreach (var excTypeID in _mask._exc) - { - var pool = world.FindPoolInstance(excTypeID); - if (pool != null && pool.Has(entityID)) - { - pool.Del(entityID); - } - } - } - #endregion - - #region Other - EcsMask IEcsComponentMask.ToMask(EcsWorld world) { return _mask; } - #endregion } #region EcsAspectExtensions diff --git a/src/EcsMask.cs b/src/EcsMask.cs index 5e8b051..b9920d3 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -1,6 +1,8 @@ -using DCFApixels.DragonECS.Internal; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; @@ -8,74 +10,69 @@ using System.Runtime.CompilerServices; using Unity.IL2CPP.CompilerServices; #endif -namespace DCFApixels.DragonECS +namespace DCFApixels.DragonECS.Core { - using static EcsMaskIteratorUtility; - public interface IEcsComponentMask + public interface IComponentMask { EcsMask ToMask(EcsWorld world); } +} + +namespace DCFApixels.DragonECS +{ + using static EcsMaskIteratorUtility; + #if ENABLE_IL2CPP [Il2CppSetOption (Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif [DebuggerTypeProxy(typeof(DebuggerProxy))] - public sealed class EcsMask : IEquatable, IEcsComponentMask + public sealed class EcsMask : IEquatable, IComponentMask { + public readonly int ID; + public readonly short WorldID; + internal readonly EcsStaticMask _staticMask; - internal readonly int _id; - internal readonly short _worldID; internal readonly EcsMaskChunck[] _incChunckMasks; internal readonly EcsMaskChunck[] _excChunckMasks; /// Sorted - internal readonly int[] _inc; + internal readonly int[] _incs; /// Sorted - internal readonly int[] _exc; + internal readonly int[] _excs; private EcsMaskIterator _iterator; #region Properties - public int ID - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _id; } - } - public short WorldID - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _worldID; } - } public EcsWorld World { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return EcsWorld.GetWorld(_worldID); } - } - /// Sorted set including constraints. - public ReadOnlySpan Inc - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _inc; } + get { return EcsWorld.GetWorld(WorldID); } } /// Sorted set excluding constraints. - public ReadOnlySpan Exc + public ReadOnlySpan Incs { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _exc; } + get { return _incs; } + } + /// Sorted set excluding constraints. + public ReadOnlySpan Excs + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _excs; } } public bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _inc.Length == 0 && _exc.Length == 0; } + get { return _incs.Length == 0 && _excs.Length == 0; } } public bool IsBroken { - get { return (_inc.Length & _exc.Length) == 1 && _inc[0] == _exc[0]; } + get { return (_incs.Length & _excs.Length) == 1 && _incs[0] == _excs[0]; } } #endregion #region Constructors - [Obsolete("")]//TODO написать новый сопсоб создания public static Builder New(EcsWorld world) { return new Builder(world); } internal static EcsMask CreateEmpty(int id, short worldID) { @@ -88,10 +85,10 @@ namespace DCFApixels.DragonECS private EcsMask(EcsStaticMask staticMask, int id, short worldID, int[] inc, int[] exc) { _staticMask = staticMask; - _id = id; - _inc = inc; - _exc = exc; - _worldID = worldID; + ID = id; + _incs = inc; + _excs = exc; + WorldID = worldID; _incChunckMasks = MakeMaskChuncsArray(inc); _excChunckMasks = MakeMaskChuncsArray(exc); @@ -131,114 +128,230 @@ namespace DCFApixels.DragonECS #region Checks public bool IsSubmaskOf(EcsMask otherMask) { - return IsSubmask(otherMask, this); + return _staticMask.IsSubmaskOf(otherMask._staticMask); } public bool IsSupermaskOf(EcsMask otherMask) { - return IsSubmask(this, otherMask); + return _staticMask.IsSupermaskOf(otherMask._staticMask); } public bool IsConflictWith(EcsMask otherMask) { - return OverlapsArray(_inc, otherMask._exc) || OverlapsArray(_exc, otherMask._inc); - } - - private static bool OverlapsArray(int[] l, int[] r) - { - int li = 0; - int ri = 0; - while (li < l.Length && ri < r.Length) - { - if (l[li] == r[ri]) - { - return true; - } - else if (l[li] < r[ri]) - { - li++; - } - else - { - ri++; - } - } - return false; - } - private static bool IsSubmask(EcsMask super, EcsMask sub) - { - return IsSubarray(sub._inc, super._inc) && IsSuperarray(sub._exc, super._exc); - } - private static bool IsSubarray(int[] super, int[] sub) - { - if (super.Length < sub.Length) - { - return false; - } - int superI = 0; - int subI = 0; - - while (superI < super.Length && subI < sub.Length) - { - if (super[superI] == sub[subI]) - { - superI++; - } - subI++; - } - return subI == sub.Length; - } - - private static bool IsSuperarray(int[] super, int[] sub) - { - if (super.Length < sub.Length) - { - return false; - } - int superI = 0; - int subI = 0; - - while (superI < super.Length && subI < sub.Length) - { - if (super[superI] == sub[subI]) - { - subI++; - } - superI++; - } - return subI == sub.Length; + return _staticMask.IsConflictWith(otherMask._staticMask); } #endregion #region Object public override string ToString() { - return CreateLogString(_worldID, _inc, _exc); + return CreateLogString(WorldID, _incs, _excs); } public bool Equals(EcsMask mask) { - return _id == mask._id && _worldID == mask._worldID; + return ID == mask.ID && WorldID == mask.WorldID; } public override bool Equals(object obj) { - return obj is EcsMask mask && _id == mask._id && Equals(mask); + return obj is EcsMask mask && ID == mask.ID && Equals(mask); } public override int GetHashCode() { - return unchecked(_id ^ (_worldID * EcsConsts.MAGIC_PRIME)); + return unchecked(ID ^ (WorldID * EcsConsts.MAGIC_PRIME)); } #endregion #region Other - EcsMask IEcsComponentMask.ToMask(EcsWorld world) { return this; } + public static EcsMask FromStatic(EcsWorld world, EcsStaticMask abstractMask) + { + return world.Get().ConvertFromStatic(abstractMask); + } + EcsMask IComponentMask.ToMask(EcsWorld world) { return this; } public EcsMaskIterator GetIterator() { if (_iterator == null) { - _iterator = new EcsMaskIterator(EcsWorld.GetWorld(_worldID), this); + _iterator = new EcsMaskIterator(EcsWorld.GetWorld(WorldID), this); } return _iterator; } #endregion + #region Operators + public static EcsMask operator -(EcsMask a, EcsMask b) + { + return a.World.Get().ExceptMask(a, b); + } + public static EcsMask operator -(EcsMask a, IComponentMask b) + { + return a.World.Get().ExceptMask(a, b.ToMask(a.World)); + } + public static EcsMask operator -(IComponentMask b, EcsMask a) + { + return a.World.Get().ExceptMask(b.ToMask(a.World), a); + } + public static EcsMask operator +(EcsMask a, EcsMask b) + { + return a.World.Get().CombineMask(a, b); + } + public static EcsMask operator +(EcsMask a, IComponentMask b) + { + return a.World.Get().CombineMask(a, b.ToMask(a.World)); + } + public static EcsMask operator +(IComponentMask b, EcsMask a) + { + return a.World.Get().CombineMask(b.ToMask(a.World), a); + } + public static implicit operator EcsMask((IComponentMask mask, EcsWorld world) a) + { + return a.mask.ToMask(a.world); + } + public static implicit operator EcsMask((EcsWorld world, IComponentMask mask) a) + { + return a.mask.ToMask(a.world); + } + #endregion + + #region OpMaskKey + private readonly struct OpMaskKey : IEquatable + { + public readonly int leftMaskID; + public readonly int rightMaskID; + public readonly int operation; + + public const int COMBINE_OP = 7; + public const int EXCEPT_OP = 32; + public OpMaskKey(int leftMaskID, int rightMaskID, int operation) + { + this.leftMaskID = leftMaskID; + this.rightMaskID = rightMaskID; + this.operation = operation; + } + public bool Equals(OpMaskKey other) + { + return leftMaskID == other.leftMaskID && rightMaskID == other.rightMaskID && operation == other.operation; + } + public override int GetHashCode() + { + return leftMaskID ^ (rightMaskID * operation); + } + } + #endregion + + #region Builder + private readonly struct WorldMaskComponent : IEcsWorldComponent + { + private readonly EcsWorld _world; + private readonly Dictionary _opMasks; + private readonly SparseArray _staticMasks; + + public readonly EcsMask EmptyMask; + public readonly EcsMask BrokenMask; + + #region Constructor/Destructor + public WorldMaskComponent(EcsWorld world) + { + _world = world; + _opMasks = new Dictionary(256); + _staticMasks = new SparseArray(256); + + + EmptyMask = CreateEmpty(_staticMasks.Count, world.ID); + _staticMasks.Add(EmptyMask._staticMask.ID, EmptyMask); + BrokenMask = CreateBroken(_staticMasks.Count, world.ID); + _staticMasks.Add(BrokenMask._staticMask.ID, BrokenMask); + } + public void Init(ref WorldMaskComponent component, EcsWorld world) + { + component = new WorldMaskComponent(world); + } + public void OnDestroy(ref WorldMaskComponent component, EcsWorld world) + { + component._opMasks.Clear(); + component._staticMasks.Clear(); + component = default; + } + #endregion + + #region GetMask + internal EcsMask CombineMask(EcsMask a, EcsMask b) + { + int operation = OpMaskKey.COMBINE_OP; + if (_opMasks.TryGetValue(new OpMaskKey(a.ID, b.ID, operation), out EcsMask result) == false) + { + if (a.IsConflictWith(b)) + { + return a.World.Get().BrokenMask; + } + result = ConvertFromStatic(EcsStaticMask.New().Combine(a._staticMask).Combine(b._staticMask).Build()); + _opMasks.Add(new OpMaskKey(a.ID, b.ID, operation), result); + } + 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) + { + if (a.IsConflictWith(b)) + { + return a.World.Get().BrokenMask; + } + result = ConvertFromStatic(EcsStaticMask.New().Combine(a._staticMask).Except(b._staticMask).Build()); + _opMasks.Add(new OpMaskKey(a.ID, b.ID, operation), result); + } + return result; + } + + internal EcsMask ConvertFromStatic(EcsStaticMask staticMask) + { + int[] ConvertTypeCodeToComponentTypeID(ReadOnlySpan from, EcsWorld world) + { + int[] to = new int[from.Length]; + for (int i = 0; i < to.Length; i++) + { + to[i] = world.DeclareOrGetComponentTypeID(from[i]); + } + Array.Sort(to); + return to; + } + + if (_staticMasks.TryGetValue(staticMask.ID, out EcsMask result) == false) + { + int[] incs = ConvertTypeCodeToComponentTypeID(staticMask.IncTypeCodes, _world); + int[] excs = ConvertTypeCodeToComponentTypeID(staticMask.ExcTypeCodes, _world); + + result = new EcsMask(staticMask, _staticMasks.Count, _world.ID, incs, excs); + + _staticMasks.Add(staticMask.ID, result); + } + return result; + } + #endregion + } + + public partial struct Builder + { + private readonly EcsStaticMask.Builder _builder; + private readonly EcsWorld _world; + + public Builder(EcsWorld world) + { + _world = world; + _builder = EcsStaticMask.New(); + } + + public Builder Inc() { _builder.Inc(); return this; } + public Builder Exc() { _builder.Exc(); return this; } + public Builder Inc(Type type) { _builder.Inc(type); return this; } + public Builder Exc(Type type) { _builder.Exc(type); return this; } + public Builder Inc(EcsTypeCode typeCode) { _builder.Inc(typeCode); return this; } + public Builder Exc(EcsTypeCode typeCode) { _builder.Exc(typeCode); return this; } + public Builder Combine(EcsMask mask) { _builder.Combine(mask._staticMask); return this; } + public Builder Except(EcsMask mask) { _builder.Except(mask._staticMask); return this; } + + public EcsMask Build() { return _world.Get().ConvertFromStatic(_builder.Build()); } + } + #endregion + #region Debug utils private static string CreateLogString(short worldID, int[] inc, int[] exc) { @@ -271,13 +384,13 @@ namespace DCFApixels.DragonECS { _source = mask; - ID = mask._id; - world = EcsWorld.GetWorld(mask._worldID); - _worldID = mask._worldID; + ID = mask.ID; + world = EcsWorld.GetWorld(mask.WorldID); + _worldID = mask.WorldID; includedChunkMasks = mask._incChunckMasks; excludedChunkMasks = mask._excChunckMasks; - included = mask._inc; - excluded = mask._exc; + included = mask._incs; + excluded = mask._excs; Type converter(int o) { return world.GetComponentType(o); } includedTypes = included.Select(converter).ToArray(); excludedTypes = excluded.Select(converter).ToArray(); @@ -289,200 +402,31 @@ namespace DCFApixels.DragonECS } #endregion - #region Operators - public static EcsMask operator -(EcsMask a, EcsMask b) + #region Obsolete + /// Sorted set including constraints. + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Use Incs")] + public ReadOnlySpan Inc { - return a.World.Get().ExceptMask(a, b); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _incs; } } - public static EcsMask operator -(EcsMask a, IEcsComponentMask b) + /// Sorted set excluding constraints. + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Use Excs")] + public ReadOnlySpan Exc { - return a.World.Get().ExceptMask(a, b.ToMask(a.World)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _excs; } } - public static EcsMask operator -(IEcsComponentMask b, EcsMask a) + public partial struct Builder { - return a.World.Get().ExceptMask(b.ToMask(a.World), a); - } - public static EcsMask operator +(EcsMask a, EcsMask b) - { - return a.World.Get().CombineMask(a, b); - } - public static EcsMask operator +(EcsMask a, IEcsComponentMask b) - { - return a.World.Get().CombineMask(a, b.ToMask(a.World)); - } - public static EcsMask operator +(IEcsComponentMask b, EcsMask a) - { - return a.World.Get().CombineMask(b.ToMask(a.World), a); - } - public static implicit operator EcsMask((IEcsComponentMask mask, EcsWorld world) a) - { - return a.mask.ToMask(a.world); - } - public static implicit operator EcsMask((EcsWorld world, IEcsComponentMask mask) a) - { - return a.mask.ToMask(a.world); - } - #endregion - - #region OpMaskKey - private readonly struct OpMaskKey : IEquatable - { - public readonly int leftMaskID; - public readonly int rightMaskID; - public readonly int operation; - - public const int COMBINE_OP = 7; - public const int EXCEPT_OP = 32; - public OpMaskKey(int leftMaskID, int rightMaskID, int operation) - { - this.leftMaskID = leftMaskID; - this.rightMaskID = rightMaskID; - this.operation = operation; - } - public bool Equals(OpMaskKey other) - { - return leftMaskID == other.leftMaskID && - rightMaskID == other.rightMaskID && - operation == other.operation; - } - public override int GetHashCode() - { - return leftMaskID ^ (rightMaskID * operation); - } - } - - #endregion - - #region StaticMask - public static EcsMask FromStatic(EcsWorld world, EcsStaticMask abstractMask) - { - return world.Get().ConvertFromStatic(abstractMask); - } - #endregion - - #region Builder - private readonly struct WorldMaskComponent : IEcsWorldComponent - { - private readonly EcsWorld _world; - private readonly Dictionary _opMasks; - private readonly SparseArray _staticMasks; - - public readonly EcsMask EmptyMask; - public readonly EcsMask BrokenMask; - - #region Constructor/Destructor - public WorldMaskComponent(EcsWorld world) - { - _world = world; - _opMasks = new Dictionary(256); - _staticMasks = new SparseArray(256); - - - - EmptyMask = CreateEmpty(_staticMasks.Count, world.ID); - _staticMasks.Add(EmptyMask._staticMask.ID, EmptyMask); - BrokenMask = CreateBroken(_staticMasks.Count, world.ID); - _staticMasks.Add(BrokenMask._staticMask.ID, BrokenMask); - } - public void Init(ref WorldMaskComponent component, EcsWorld world) - { - component = new WorldMaskComponent(world); - } - public void OnDestroy(ref WorldMaskComponent component, EcsWorld world) - { - component._opMasks.Clear(); - component._staticMasks.Clear(); - component = default; - } - #endregion - - #region GetMask - internal EcsMask CombineMask(EcsMask a, EcsMask b) - { - int operation = OpMaskKey.COMBINE_OP; - if (_opMasks.TryGetValue(new OpMaskKey(a._id, b._id, operation), out EcsMask result) == false) - { - if (a.IsConflictWith(b)) - { - return a.World.Get().BrokenMask; - } - result = ConvertFromStatic(EcsStaticMask.New().Combine(a._staticMask).Combine(b._staticMask).Build()); - _opMasks.Add(new OpMaskKey(a._id, b._id, operation), result); - } - 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) - { - if (a.IsConflictWith(b)) - { - return a.World.Get().BrokenMask; - } - result = ConvertFromStatic(EcsStaticMask.New().Combine(a._staticMask).Except(b._staticMask).Build()); - _opMasks.Add(new OpMaskKey(a._id, b._id, operation), result); - } - return result; - } - - internal EcsMask ConvertFromStatic(EcsStaticMask staticMask) - { - int[] ConvertTypeCodeToComponentTypeID(ReadOnlySpan from, EcsWorld world) - { - int[] to = new int[from.Length]; - for (int i = 0; i < to.Length; i++) - { - to[i] = world.DeclareOrGetComponentTypeID(from[i]); - } - Array.Sort(to); - return to; - } - - if (_staticMasks.TryGetValue(staticMask.ID, out EcsMask result) == false) - { - int[] incs = ConvertTypeCodeToComponentTypeID(staticMask.IncTypeCodes, _world); - int[] excs = ConvertTypeCodeToComponentTypeID(staticMask.ExcTypeCodes, _world); - - result = new EcsMask(staticMask, _staticMasks.Count, _world.ID, incs, excs); - - _staticMasks.Add(staticMask.ID, result); - } - return result; - } - #endregion - } - - [Obsolete("")]//TODO написать новый сопсоб создания - public struct Builder - { - private readonly EcsStaticMask.Builder _builder; - private readonly EcsWorld _world; - - public Builder(EcsWorld world) - { - _world = world; - _builder = EcsStaticMask.Builder.New(); - } - - public Builder Include() { return Inc(); } - public Builder Exclude() { return Exc(); } - public Builder Include(Type type) { return Inc(type); } - public Builder Exclude(Type type) { return Exc(type); } - - public Builder Inc() { _builder.Inc(); return this; } - public Builder Exc() { _builder.Exc(); return this; } - public Builder Inc(Type type) { _builder.Inc(type); return this; } - public Builder Exc(Type type) { _builder.Exc(type); return this; } - public Builder Inc(EcsTypeCode typeCode) { _builder.Inc(typeCode); return this; } - public Builder Exc(EcsTypeCode typeCode) { _builder.Exc(typeCode); return this; } - public Builder Combine(EcsMask mask) { _builder.Combine(mask._staticMask); return this; } - public Builder Except(EcsMask mask) { _builder.Except(mask._staticMask); return this; } - - public Builder Inc(int componentTypeID) { Inc(_world.GetComponentType(componentTypeID)); return this; } - public Builder Exc(int componentTypeID) { Exc(_world.GetComponentType(componentTypeID)); return this; } - - public EcsMask Build() { return _world.Get().ConvertFromStatic(_builder.Build()); } + [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include() { return Inc(); } + [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude() { return Exc(); } + [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include(Type type) { return Inc(type); } + [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude(Type type) { return Exc(type); } + [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Inc(int componentTypeID) { Inc(_world.GetComponentType(componentTypeID)); return this; } + [EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exc(int componentTypeID) { Exc(_world.GetComponentType(componentTypeID)); return this; } } #endregion } @@ -554,8 +498,8 @@ namespace DCFApixels.DragonECS { World = source; Mask = mask; - _sortIncBuffer = UnsafeArray.FromArray(mask._inc); - _sortExcBuffer = UnsafeArray.FromArray(mask._exc); + _sortIncBuffer = UnsafeArray.FromArray(mask._incs); + _sortExcBuffer = UnsafeArray.FromArray(mask._excs); _sortIncChunckBuffer = UnsafeArray.FromArray(mask._incChunckMasks); _sortExcChunckBuffer = UnsafeArray.FromArray(mask._excChunckMasks); _isOnlyInc = _sortExcBuffer.Length <= 0; diff --git a/src/EcsStaticMask.cs b/src/EcsStaticMask.cs index edbb639..293f4ba 100644 --- a/src/EcsStaticMask.cs +++ b/src/EcsStaticMask.cs @@ -1,4 +1,5 @@ -using DCFApixels.DragonECS.Internal; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Internal; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -16,7 +17,7 @@ namespace DCFApixels.DragonECS [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif [DebuggerTypeProxy(typeof(DebuggerProxy))] - public sealed class EcsStaticMask : IEquatable, IEcsComponentMask + public sealed class EcsStaticMask : IEquatable, IComponentMask { public static readonly EcsStaticMask Empty; public static readonly EcsStaticMask Broken; @@ -32,42 +33,50 @@ namespace DCFApixels.DragonECS Broken = CreateMask(new Key(new EcsTypeCode[1] { (EcsTypeCode)1 }, new EcsTypeCode[1] { (EcsTypeCode)1 })); } - private readonly int _id; + public readonly int ID; /// Sorted - private readonly EcsTypeCode[] _inc; + private readonly EcsTypeCode[] _incs; /// Sorted - private readonly EcsTypeCode[] _exc; + private readonly EcsTypeCode[] _excs; #region Properties - public int ID - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _id; } - } /// Sorted set including constraints presented as global type codes. public ReadOnlySpan IncTypeCodes { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _inc; } + get { return _incs; } } /// Sorted set excluding constraints presented as global type codes. public ReadOnlySpan ExcTypeCodes { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _exc; } + get { return _excs; } } public bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return _inc.Length == 0 && _exc.Length == 0; } + get { return _incs.Length == 0 && _excs.Length == 0; } } public bool IsBroken { - get { return (_inc.Length & _exc.Length) == 1 && _inc[0] == _exc[0]; } + get { return (_incs.Length & _excs.Length) == 1 && _incs[0] == _excs[0]; } } #endregion #region Constrcutors + private EcsStaticMask(int id, Key key) + { + ID = id; + _incs = key.incs; + _excs = key.excs; + } + public static Builder New() { return Builder.New(); } + public static Builder Inc() { return Builder.New().Inc(); } + public static Builder Exc() { return Builder.New().Exc(); } + public static Builder Inc(Type type) { return Builder.New().Inc(type); } + public static Builder Exc(Type type) { return Builder.New().Exc(type); } + public static Builder Inc(EcsTypeCode typeCode) { return Builder.New().Inc(typeCode); } + public static Builder Exc(EcsTypeCode typeCode) { return Builder.New().Exc(typeCode); } private static EcsStaticMask CreateMask(Key key) { if (_ids.TryGetValue(key, out EcsStaticMask result) == false) @@ -83,46 +92,110 @@ namespace DCFApixels.DragonECS } return result; } - public static Builder New() { return Builder.New(); } - public static Builder Inc() { return Builder.New().Inc(); } - public static Builder Exc() { return Builder.New().Exc(); } - public static Builder Inc(Type type) { return Builder.New().Inc(type); } - public static Builder Exc(Type type) { return Builder.New().Exc(type); } - public static Builder Inc(EcsTypeCode typeCode) { return Builder.New().Inc(typeCode); } - public static Builder Exc(EcsTypeCode typeCode) { return Builder.New().Exc(typeCode); } - private EcsStaticMask(int id, Key key) + #endregion + + #region Checks + public bool IsSubmaskOf(EcsStaticMask otherMask) { - _id = id; - _inc = key.inc; - _exc = key.exc; + return IsSubmask(otherMask, this); + } + public bool IsSupermaskOf(EcsStaticMask otherMask) + { + return IsSubmask(this, otherMask); + } + public bool IsConflictWith(EcsStaticMask otherMask) + { + return OverlapsArray(_incs, otherMask._excs) || OverlapsArray(_excs, otherMask._incs); + } + private static bool IsSubmask(EcsStaticMask super, EcsStaticMask sub) + { + return IsSubarray(sub._incs, super._incs) && IsSuperarray(sub._excs, super._excs); + } + + private static bool OverlapsArray(EcsTypeCode[] l, EcsTypeCode[] r) + { + int li = 0; + int ri = 0; + while (li < l.Length && ri < r.Length) + { + if (l[li] == r[ri]) + { + return true; + } + else if (l[li] < r[ri]) + { + li++; + } + else + { + ri++; + } + } + return false; + } + private static bool IsSubarray(EcsTypeCode[] super, EcsTypeCode[] sub) + { + if (super.Length < sub.Length) + { + return false; + } + int superI = 0; + int subI = 0; + + while (superI < super.Length && subI < sub.Length) + { + if (super[superI] == sub[subI]) + { + superI++; + } + subI++; + } + return subI == sub.Length; + } + private static bool IsSuperarray(EcsTypeCode[] super, EcsTypeCode[] sub) + { + if (super.Length < sub.Length) + { + return false; + } + int superI = 0; + int subI = 0; + + while (superI < super.Length && subI < sub.Length) + { + if (super[superI] == sub[subI]) + { + subI++; + } + superI++; + } + return subI == sub.Length; } #endregion + #region Methods - public EcsMask ToMask(EcsWorld world) - { - return EcsMask.FromStatic(world, this); - } + public EcsMask ToMask(EcsWorld world) { return EcsMask.FromStatic(world, this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(EcsStaticMask other) { return _id == other._id; } + public bool Equals(EcsStaticMask other) { return ID == other.ID; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() { return _id; } + public override int GetHashCode() { return ID; } public override bool Equals(object obj) { return Equals((EcsStaticMask)obj); } - public override string ToString() { return CreateLogString(_inc, _exc); } + public override string ToString() { return CreateLogString(_incs, _excs); } #endregion #region Builder private readonly struct Key : IEquatable { - public readonly EcsTypeCode[] inc; - public readonly EcsTypeCode[] exc; + public readonly EcsTypeCode[] incs; + public readonly EcsTypeCode[] excs; public readonly int hash; #region Constructors public Key(EcsTypeCode[] inc, EcsTypeCode[] exc) { - this.inc = inc; - this.exc = exc; + this.incs = inc; + this.excs = exc; unchecked { hash = inc.Length + exc.Length; @@ -142,15 +215,15 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Key other) { - if (inc.Length != other.inc.Length) { return false; } - if (exc.Length != other.exc.Length) { return false; } - for (int i = 0; i < inc.Length; i++) + if (incs.Length != other.incs.Length) { return false; } + if (excs.Length != other.excs.Length) { return false; } + for (int i = 0; i < incs.Length; i++) { - if (inc[i] != other.inc[i]) { return false; } + if (incs[i] != other.incs[i]) { return false; } } - for (int i = 0; i < exc.Length; i++) + for (int i = 0; i < excs.Length; i++) { - if (exc[i] != other.exc[i]) { return false; } + if (excs[i] != other.excs[i]) { return false; } } return true; } @@ -164,6 +237,19 @@ namespace DCFApixels.DragonECS private readonly BuilderInstance _builder; private readonly int _version; + #region Properties + public bool IsNull + { + get { return _builder == null || _builder._version != _version; } + } + #endregion + + #region Constrcutors + private Builder(BuilderInstance builder) + { + _builder = builder; + _version = builder._version; + } public static Builder New() { lock (_lock) @@ -175,11 +261,9 @@ namespace DCFApixels.DragonECS return new Builder(builderInstance); } } - private Builder(BuilderInstance builder) - { - _builder = builder; - _version = builder._version; - } + #endregion + + #region Inc/Exc/Combine/Except public Builder Inc() { return Inc(EcsTypeCodeManager.Get()); } public Builder Exc() { return Exc(EcsTypeCodeManager.Get()); } public Builder Inc(Type type) { return Inc(EcsTypeCodeManager.Get(type)); } @@ -208,7 +292,9 @@ namespace DCFApixels.DragonECS _builder.Except(mask); return this; } + #endregion + #region Build/Cancel public EcsStaticMask Build() { if (_version != _builder._version) { Throw.UndefinedException(); } @@ -218,6 +304,15 @@ namespace DCFApixels.DragonECS return _builder.Build(); } } + public void Cancel() + { + if (_version != _builder._version) { Throw.UndefinedException(); } + lock (_lock) + { + _buildersPool.Push(_builder); + } + } + #endregion } private class BuilderInstance { @@ -280,10 +375,10 @@ namespace DCFApixels.DragonECS foreach (var item in _combineds) { EcsStaticMask submask = item.mask; - combinedIncs.ExceptWith(submask._exc);//удаляю конфликтующие ограничения - combinedExcs.ExceptWith(submask._inc);//удаляю конфликтующие ограничения - combinedIncs.UnionWith(submask._inc); - combinedExcs.UnionWith(submask._exc); + combinedIncs.ExceptWith(submask._excs);//удаляю конфликтующие ограничения + combinedExcs.ExceptWith(submask._incs);//удаляю конфликтующие ограничения + combinedIncs.UnionWith(submask._incs); + combinedExcs.UnionWith(submask._excs); } combinedIncs.ExceptWith(_exc);//удаляю конфликтующие ограничения combinedExcs.ExceptWith(_inc);//удаляю конфликтующие ограничения @@ -305,8 +400,8 @@ namespace DCFApixels.DragonECS //{ // return _world.Get().BrokenMask; //} - combinedIncs.ExceptWith(item.mask._inc); - combinedExcs.ExceptWith(item.mask._exc); + combinedIncs.ExceptWith(item.mask._incs); + combinedExcs.ExceptWith(item.mask._excs); } _excepteds.Clear(); } @@ -372,9 +467,9 @@ namespace DCFApixels.DragonECS { _source = mask; - ID = mask._id; - included = mask._inc; - excluded = mask._exc; + ID = mask.ID; + included = mask._incs; + excluded = mask._excs; Type converter(EcsTypeCode o) { return EcsTypeCodeManager.FindTypeOfCode(o); } includedTypes = included.Select(converter).ToArray(); excludedTypes = excluded.Select(converter).ToArray(); @@ -391,33 +486,11 @@ namespace DCFApixels.DragonECS { if (CheckRepeats(incs)) { throw new EcsFrameworkException("The values in the Include constraints are repeated."); } if (CheckRepeats(excs)) { throw new EcsFrameworkException("The values in the Exclude constraints are repeated."); } - if (HasCommonElements(incs, excs)) { throw new EcsFrameworkException("Conflicting Include and Exclude constraints."); } - } - private static bool HasCommonElements(EcsTypeCode[] a, EcsTypeCode[] b) - { - int i = 0; - int j = 0; - - while (i < a.Length && j < b.Length) - { - if (a[i] == b[j]) - { - return true; - } - else if (a[i] < b[j]) - { - i++; - } - else - { - j++; - } - } - return false; + if (OverlapsArray(incs, excs)) { throw new EcsFrameworkException("Conflicting Include and Exclude constraints."); } } private static bool CheckRepeats(EcsTypeCode[] array) { - if(array.Length <= 0) + if (array.Length <= 1) { return false; } @@ -425,7 +498,7 @@ namespace DCFApixels.DragonECS for (int i = 1; i < array.Length; i++) { EcsTypeCode value = array[i]; - if(value == lastValue) + if (value == lastValue) { return true; } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 369c192..2e34c5d 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -1,4 +1,5 @@ -using DCFApixels.DragonECS.Internal; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Internal; using DCFApixels.DragonECS.PoolsCore; using System; using System.Collections.Generic; @@ -73,12 +74,6 @@ namespace DCFApixels.DragonECS private List _entityListeners = new List(); #region Properties - [Obsolete("Use EcsWorld.ID")] - public short id - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get { return ID; } - } EcsWorld IEntityStorage.World { get { return this; } @@ -391,25 +386,25 @@ namespace DCFApixels.DragonECS return _entities[entityID].componentsCount; } - public bool IsMatchesMask(IEcsComponentMask mask, int entityID) + public bool IsMatchesMask(IComponentMask mask, int entityID) { return IsMatchesMask(mask.ToMask(this), entityID); } public bool IsMatchesMask(EcsMask mask, int entityID) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (mask._worldID != ID) { Throw.World_MaskDoesntBelongWorld(); } + if (mask.WorldID != ID) { Throw.World_MaskDoesntBelongWorld(); } #endif - for (int i = 0, iMax = mask._inc.Length; i < iMax; i++) + for (int i = 0, iMax = mask._incs.Length; i < iMax; i++) { - if (!_pools[mask._inc[i]].Has(entityID)) + if (!_pools[mask._incs[i]].Has(entityID)) { return false; } } - for (int i = 0, iMax = mask._exc.Length; i < iMax; i++) + for (int i = 0, iMax = mask._excs.Length; i < iMax; i++) { - if (_pools[mask._exc[i]].Has(entityID)) + if (_pools[mask._excs[i]].Has(entityID)) { return false; } diff --git a/src/EcsWorld.pools.cs b/src/EcsWorld.pools.cs index 3964ca5..f4ac365 100644 --- a/src/EcsWorld.pools.cs +++ b/src/EcsWorld.pools.cs @@ -19,17 +19,6 @@ namespace DCFApixels.DragonECS private EcsNullPool _nullPool = EcsNullPool.instance; #region FindPoolInstance - [Obsolete("The GetPoolInstance(int componentTypeID) method will be removed in future updates, use FindPoolInstance(Type componentType)")] - public IEcsPool GetPoolInstance(int componentTypeID) - { - return FindPoolInstance(componentTypeID); - } - [Obsolete("The GetPoolInstance(Type componentType) method will be removed in future updates, use FindPoolInstance(Type componentType)")] - public IEcsPool GetPoolInstance(Type componentType) - { - return FindPoolInstance(componentType); - } - public IEcsPool FindPoolInstance(int componentTypeID) { if (IsComponentTypeDeclared(componentTypeID)) diff --git a/src/EcsWorld.static.cs b/src/EcsWorld.static.cs index 37d0d74..b91fe0a 100644 --- a/src/EcsWorld.static.cs +++ b/src/EcsWorld.static.cs @@ -1,6 +1,7 @@ using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; +using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -173,5 +174,27 @@ namespace DCFApixels.DragonECS { internal NullWorld() : base(new EcsWorldConfig(4, 4, 4, 4, 4), 0) { } } + + #region Obsolete + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Use EcsWorld.ID")] + public short id + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return ID; } + } + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("The GetPoolInstance(int componentTypeID) method will be removed in future updates, use FindPoolInstance(Type componentType)")] + public IEcsPool GetPoolInstance(int componentTypeID) + { + return FindPoolInstance(componentTypeID); + } + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("The GetPoolInstance(Type componentType) method will be removed in future updates, use FindPoolInstance(Type componentType)")] + public IEcsPool GetPoolInstance(Type componentType) + { + return FindPoolInstance(componentType); + } + #endregion } } diff --git a/src/Executors/EcsQueryExecutor.cs b/src/Executors/EcsQueryExecutor.cs index b7a13e7..3c275e0 100644 --- a/src/Executors/EcsQueryExecutor.cs +++ b/src/Executors/EcsQueryExecutor.cs @@ -1,4 +1,5 @@ -using DCFApixels.DragonECS.Internal; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -8,7 +9,7 @@ namespace DCFApixels.DragonECS public partial class EcsWorld { private readonly Dictionary<(Type, object), EcsQueryExecutor> _executorCoures = new Dictionary<(Type, object), EcsQueryExecutor>(256); - public TExecutor GetExecutor(IEcsComponentMask mask) + public TExecutor GetExecutor(IComponentMask mask) where TExecutor : EcsQueryExecutor, new() { var coreType = typeof(TExecutor); @@ -74,9 +75,9 @@ namespace DCFApixels.DragonECS public WorldStateVersionsChecker(EcsMask mask) { _world = mask.World; - _maskInc = mask._inc; - _maskExc = mask._exc; - _versions = UnmanagedArrayUtility.New(1 + mask._inc.Length + mask._exc.Length); + _maskInc = mask._incs; + _maskExc = mask._excs; + _versions = UnmanagedArrayUtility.New(1 + mask._incs.Length + mask._excs.Length); } public bool Check() { diff --git a/src/Executors/Queries.cs b/src/Executors/Queries.cs index 3e028c2..eeae60d 100644 --- a/src/Executors/Queries.cs +++ b/src/Executors/Queries.cs @@ -1,4 +1,5 @@ -using DCFApixels.DragonECS.Internal; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.Internal; using System; namespace DCFApixels.DragonECS @@ -34,7 +35,7 @@ namespace DCFApixels.DragonECS return executor.ExecuteFor(span); } - public static EcsSpan Where(this TCollection entities, IEcsComponentMask mask) + public static EcsSpan Where(this TCollection entities, IComponentMask mask) where TCollection : IEntityStorage { if (ReferenceEquals(entities, entities.World)) @@ -44,11 +45,11 @@ namespace DCFApixels.DragonECS } return entities.ToSpan().Where(mask); } - public static EcsSpan Where(this EcsReadonlyGroup group, IEcsComponentMask mask) + public static EcsSpan Where(this EcsReadonlyGroup group, IComponentMask mask) { return group.ToSpan().Where(mask); } - public static EcsSpan Where(this EcsSpan span, IEcsComponentMask mask) + public static EcsSpan Where(this EcsSpan span, IComponentMask mask) { var executor = span.World.GetExecutor(mask); return executor.ExecuteFor(span); @@ -79,7 +80,7 @@ namespace DCFApixels.DragonECS return executor.ExecuteFor(span, comparison); } - public static EcsSpan Where(this TCollection entities, IEcsComponentMask mask, Comparison comparison) + public static EcsSpan Where(this TCollection entities, IComponentMask mask, Comparison comparison) where TCollection : IEntityStorage { if (ReferenceEquals(entities, entities.World)) @@ -89,11 +90,11 @@ namespace DCFApixels.DragonECS } return entities.ToSpan().Where(mask, comparison); } - public static EcsSpan Where(this EcsReadonlyGroup group, IEcsComponentMask mask, Comparison comparison) + public static EcsSpan Where(this EcsReadonlyGroup group, IComponentMask mask, Comparison comparison) { return group.ToSpan().Where(mask, comparison); } - public static EcsSpan Where(this EcsSpan span, IEcsComponentMask mask, Comparison comparison) + public static EcsSpan Where(this EcsSpan span, IComponentMask mask, Comparison comparison) { var executor = span.World.GetExecutor(mask); return executor.ExecuteFor(span); @@ -124,7 +125,7 @@ namespace DCFApixels.DragonECS return executor.ExecuteFor(span); } - public static EcsReadonlyGroup WhereToGroup(this TCollection entities, IEcsComponentMask mask) + public static EcsReadonlyGroup WhereToGroup(this TCollection entities, IComponentMask mask) where TCollection : IEntityStorage { if (ReferenceEquals(entities, entities.World)) @@ -134,11 +135,11 @@ namespace DCFApixels.DragonECS } return entities.ToSpan().WhereToGroup(mask); } - public static EcsReadonlyGroup WhereToGroup(this EcsReadonlyGroup group, IEcsComponentMask mask) + public static EcsReadonlyGroup WhereToGroup(this EcsReadonlyGroup group, IComponentMask mask) { return group.ToSpan().WhereToGroup(mask); } - public static EcsReadonlyGroup WhereToGroup(this EcsSpan span, IEcsComponentMask mask) + public static EcsReadonlyGroup WhereToGroup(this EcsSpan span, IComponentMask mask) { var executor = span.World.GetExecutor(mask); return executor.ExecuteFor(span);