Merge branch 'dev' of github.com:DCFApixels/DragonECS into dev

This commit is contained in:
Mikhail 2024-11-01 12:43:01 +08:00
commit 698bbad084
8 changed files with 542 additions and 487 deletions

View File

@ -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<Type, EcsStaticMask> _staticMaskCache = new Dictionary<Type, EcsStaticMask>();
#region Properties
public EcsMask Mask
{
@ -53,6 +58,13 @@ namespace DCFApixels.DragonECS
{
get { return _isBuilt; }
}
/// <summary>
/// Статическая инициализация означет что каждый новый эекземпляр идентичен другому, инициализация стандартным путем создает идентичные экземпляры, поэтому значение по умолчанию true.
/// </summary>
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<TAspect>(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<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect, new()
{
var result = _world.GetAspect<TOtherAspect>();
_maskBuilder.Combine(result.Mask._staticMask);
if (_maskBuilder.IsNull == false)
{
_maskBuilder.Combine(result.Mask._staticMask);
}
return result;
}
public TOtherAspect Except<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect, new()
{
var result = _world.GetAspect<TOtherAspect>();
_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

View File

@ -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<EcsMask>, IEcsComponentMask
public sealed class EcsMask : IEquatable<EcsMask>, 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;
/// <summary> Sorted </summary>
internal readonly int[] _inc;
internal readonly int[] _incs;
/// <summary> Sorted </summary>
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); }
}
/// <summary> Sorted set including constraints. </summary>
public ReadOnlySpan<int> Inc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _inc; }
get { return EcsWorld.GetWorld(WorldID); }
}
/// <summary> Sorted set excluding constraints. </summary>
public ReadOnlySpan<int> Exc
public ReadOnlySpan<int> Incs
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _exc; }
get { return _incs; }
}
/// <summary> Sorted set excluding constraints. </summary>
public ReadOnlySpan<int> 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<WorldMaskComponent>().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<WorldMaskComponent>().ExceptMask(a, b);
}
public static EcsMask operator -(EcsMask a, IComponentMask b)
{
return a.World.Get<WorldMaskComponent>().ExceptMask(a, b.ToMask(a.World));
}
public static EcsMask operator -(IComponentMask b, EcsMask a)
{
return a.World.Get<WorldMaskComponent>().ExceptMask(b.ToMask(a.World), a);
}
public static EcsMask operator +(EcsMask a, EcsMask b)
{
return a.World.Get<WorldMaskComponent>().CombineMask(a, b);
}
public static EcsMask operator +(EcsMask a, IComponentMask b)
{
return a.World.Get<WorldMaskComponent>().CombineMask(a, b.ToMask(a.World));
}
public static EcsMask operator +(IComponentMask b, EcsMask a)
{
return a.World.Get<WorldMaskComponent>().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<OpMaskKey>
{
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<WorldMaskComponent>
{
private readonly EcsWorld _world;
private readonly Dictionary<OpMaskKey, EcsMask> _opMasks;
private readonly SparseArray<EcsMask> _staticMasks;
public readonly EcsMask EmptyMask;
public readonly EcsMask BrokenMask;
#region Constructor/Destructor
public WorldMaskComponent(EcsWorld world)
{
_world = world;
_opMasks = new Dictionary<OpMaskKey, EcsMask>(256);
_staticMasks = new SparseArray<EcsMask>(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<WorldMaskComponent>().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<WorldMaskComponent>().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<EcsTypeCode> 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<T>() { _builder.Inc<T>(); return this; }
public Builder Exc<T>() { _builder.Exc<T>(); 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<WorldMaskComponent>().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
/// <summary> Sorted set including constraints. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use Incs")]
public ReadOnlySpan<int> Inc
{
return a.World.Get<WorldMaskComponent>().ExceptMask(a, b);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _incs; }
}
public static EcsMask operator -(EcsMask a, IEcsComponentMask b)
/// <summary> Sorted set excluding constraints. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use Excs")]
public ReadOnlySpan<int> Exc
{
return a.World.Get<WorldMaskComponent>().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<WorldMaskComponent>().ExceptMask(b.ToMask(a.World), a);
}
public static EcsMask operator +(EcsMask a, EcsMask b)
{
return a.World.Get<WorldMaskComponent>().CombineMask(a, b);
}
public static EcsMask operator +(EcsMask a, IEcsComponentMask b)
{
return a.World.Get<WorldMaskComponent>().CombineMask(a, b.ToMask(a.World));
}
public static EcsMask operator +(IEcsComponentMask b, EcsMask a)
{
return a.World.Get<WorldMaskComponent>().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<OpMaskKey>
{
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<WorldMaskComponent>().ConvertFromStatic(abstractMask);
}
#endregion
#region Builder
private readonly struct WorldMaskComponent : IEcsWorldComponent<WorldMaskComponent>
{
private readonly EcsWorld _world;
private readonly Dictionary<OpMaskKey, EcsMask> _opMasks;
private readonly SparseArray<EcsMask> _staticMasks;
public readonly EcsMask EmptyMask;
public readonly EcsMask BrokenMask;
#region Constructor/Destructor
public WorldMaskComponent(EcsWorld world)
{
_world = world;
_opMasks = new Dictionary<OpMaskKey, EcsMask>(256);
_staticMasks = new SparseArray<EcsMask>(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<WorldMaskComponent>().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<WorldMaskComponent>().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<EcsTypeCode> 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<T>() { return Inc<T>(); }
public Builder Exclude<T>() { return Exc<T>(); }
public Builder Include(Type type) { return Inc(type); }
public Builder Exclude(Type type) { return Exc(type); }
public Builder Inc<T>() { _builder.Inc<T>(); return this; }
public Builder Exc<T>() { _builder.Exc<T>(); 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<WorldMaskComponent>().ConvertFromStatic(_builder.Build()); }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include<T>() { return Inc<T>(); }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude<T>() { return Exc<T>(); }
[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<int>.FromArray(mask._inc);
_sortExcBuffer = UnsafeArray<int>.FromArray(mask._exc);
_sortIncBuffer = UnsafeArray<int>.FromArray(mask._incs);
_sortExcBuffer = UnsafeArray<int>.FromArray(mask._excs);
_sortIncChunckBuffer = UnsafeArray<EcsMaskChunck>.FromArray(mask._incChunckMasks);
_sortExcChunckBuffer = UnsafeArray<EcsMaskChunck>.FromArray(mask._excChunckMasks);
_isOnlyInc = _sortExcBuffer.Length <= 0;

View File

@ -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<EcsStaticMask>, IEcsComponentMask
public sealed class EcsStaticMask : IEquatable<EcsStaticMask>, 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;
/// <summary> Sorted </summary>
private readonly EcsTypeCode[] _inc;
private readonly EcsTypeCode[] _incs;
/// <summary> Sorted </summary>
private readonly EcsTypeCode[] _exc;
private readonly EcsTypeCode[] _excs;
#region Properties
public int ID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _id; }
}
/// <summary> Sorted set including constraints presented as global type codes. </summary>
public ReadOnlySpan<EcsTypeCode> IncTypeCodes
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _inc; }
get { return _incs; }
}
/// <summary> Sorted set excluding constraints presented as global type codes. </summary>
public ReadOnlySpan<EcsTypeCode> 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<T>() { return Builder.New().Inc<T>(); }
public static Builder Exc<T>() { return Builder.New().Exc<T>(); }
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<T>() { return Builder.New().Inc<T>(); }
public static Builder Exc<T>() { return Builder.New().Exc<T>(); }
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<Key>
{
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<T>() { return Inc(EcsTypeCodeManager.Get<T>()); }
public Builder Exc<T>() { return Exc(EcsTypeCodeManager.Get<T>()); }
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<WorldMaskComponent>().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;
}

View File

@ -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<IEcsEntityEventListener> _entityListeners = new List<IEcsEntityEventListener>();
#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;
}

View File

@ -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))

View File

@ -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
}
}

View File

@ -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<TExecutor>(IEcsComponentMask mask)
public TExecutor GetExecutor<TExecutor>(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<long>(1 + mask._inc.Length + mask._exc.Length);
_maskInc = mask._incs;
_maskExc = mask._excs;
_versions = UnmanagedArrayUtility.New<long>(1 + mask._incs.Length + mask._excs.Length);
}
public bool Check()
{

View File

@ -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<TCollection>(this TCollection entities, IEcsComponentMask mask)
public static EcsSpan Where<TCollection>(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<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span);
@ -79,7 +80,7 @@ namespace DCFApixels.DragonECS
return executor.ExecuteFor(span, comparison);
}
public static EcsSpan Where<TCollection>(this TCollection entities, IEcsComponentMask mask, Comparison<int> comparison)
public static EcsSpan Where<TCollection>(this TCollection entities, IComponentMask mask, Comparison<int> 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<int> comparison)
public static EcsSpan Where(this EcsReadonlyGroup group, IComponentMask mask, Comparison<int> comparison)
{
return group.ToSpan().Where(mask, comparison);
}
public static EcsSpan Where(this EcsSpan span, IEcsComponentMask mask, Comparison<int> comparison)
public static EcsSpan Where(this EcsSpan span, IComponentMask mask, Comparison<int> comparison)
{
var executor = span.World.GetExecutor<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span);
@ -124,7 +125,7 @@ namespace DCFApixels.DragonECS
return executor.ExecuteFor(span);
}
public static EcsReadonlyGroup WhereToGroup<TCollection>(this TCollection entities, IEcsComponentMask mask)
public static EcsReadonlyGroup WhereToGroup<TCollection>(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<EcsWhereToGroupExecutor>(mask);
return executor.ExecuteFor(span);