mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-18 01:44:35 +08:00
refactoring
This commit is contained in:
parent
02834d6826
commit
45acde2db3
153
src/EcsAspect.cs
153
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<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
|
||||
|
554
src/EcsMask.cs
554
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<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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user