2024-01-07 18:52:54 +08:00
|
|
|
|
using DCFApixels.DragonECS.Internal;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
|
|
|
|
|
namespace DCFApixels.DragonECS
|
|
|
|
|
{
|
2024-04-28 19:43:10 +08:00
|
|
|
|
#if ENABLE_IL2CPP
|
|
|
|
|
using Unity.IL2CPP.CompilerServices;
|
|
|
|
|
[Il2CppSetOption (Option.NullChecks, false)]
|
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
#endif
|
2024-01-07 18:52:54 +08:00
|
|
|
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
2024-01-07 19:32:16 +08:00
|
|
|
|
public sealed class EcsMask : IEquatable<EcsMask>
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
internal readonly int _id;
|
|
|
|
|
internal readonly short _worldID;
|
|
|
|
|
internal readonly EcsMaskChunck[] _incChunckMasks;
|
|
|
|
|
internal readonly EcsMaskChunck[] _excChunckMasks;
|
|
|
|
|
internal readonly int[] _inc; //Sorted
|
|
|
|
|
internal readonly int[] _exc; //Sorted
|
2024-01-07 23:19:18 +08:00
|
|
|
|
|
2024-08-23 22:31:43 +08:00
|
|
|
|
private EcsMaskIterator _iterator;
|
|
|
|
|
|
2024-01-07 23:19:18 +08:00
|
|
|
|
#region Properties
|
2024-03-02 21:45:09 +08:00
|
|
|
|
public int ID
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return _id; }
|
2024-03-02 21:45:09 +08:00
|
|
|
|
}
|
2024-04-16 12:46:09 +08:00
|
|
|
|
public short WorldID
|
2024-03-02 21:45:09 +08:00
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return _worldID; }
|
2024-03-02 21:45:09 +08:00
|
|
|
|
}
|
|
|
|
|
public EcsWorld World
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return EcsWorld.GetWorld(_worldID); }
|
2024-03-02 21:45:09 +08:00
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
/// <summary>Including constraints</summary>
|
2024-03-02 21:45:09 +08:00
|
|
|
|
public ReadOnlySpan<int> Inc
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return _inc; }
|
2024-03-02 21:45:09 +08:00
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
/// <summary>Excluding constraints</summary>
|
2024-03-02 21:45:09 +08:00
|
|
|
|
public ReadOnlySpan<int> Exc
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return _exc; }
|
2024-03-02 21:45:09 +08:00
|
|
|
|
}
|
2024-03-17 10:18:16 +08:00
|
|
|
|
public bool IsEmpty
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return _inc.Length == 0 && _exc.Length == 0; }
|
2024-03-17 10:18:16 +08:00
|
|
|
|
}
|
2024-04-18 22:14:50 +08:00
|
|
|
|
public bool IsBroken
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
get { return (_inc.Length & _exc.Length) == 1 && _inc[0] == _exc[0]; }
|
2024-04-18 22:14:50 +08:00
|
|
|
|
}
|
2024-01-07 23:19:18 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
2024-01-11 00:48:39 +08:00
|
|
|
|
public static Builder New(EcsWorld world)
|
|
|
|
|
{
|
|
|
|
|
return new Builder(world);
|
|
|
|
|
}
|
2024-04-18 22:14:50 +08:00
|
|
|
|
|
|
|
|
|
internal static EcsMask New(int id, short worldID, int[] inc, int[] exc)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
#if DEBUG
|
|
|
|
|
CheckConstraints(inc, exc);
|
|
|
|
|
#endif
|
2024-04-18 22:14:50 +08:00
|
|
|
|
return new EcsMask(id, worldID, inc, exc);
|
|
|
|
|
}
|
|
|
|
|
internal static EcsMask NewEmpty(int id, short worldID)
|
|
|
|
|
{
|
|
|
|
|
return new EcsMask(id, worldID, new int[0], new int[0]);
|
|
|
|
|
}
|
|
|
|
|
internal static EcsMask NewBroken(int id, short worldID)
|
|
|
|
|
{
|
|
|
|
|
return new EcsMask(id, worldID, new int[1] { 1 }, new int[1] { 1 });
|
|
|
|
|
}
|
|
|
|
|
private EcsMask(int id, short worldID, int[] inc, int[] exc)
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
this._id = id;
|
|
|
|
|
this._inc = inc;
|
|
|
|
|
this._exc = exc;
|
|
|
|
|
this._worldID = worldID;
|
2024-01-07 19:32:16 +08:00
|
|
|
|
|
2024-04-22 17:20:31 +08:00
|
|
|
|
_incChunckMasks = MakeMaskChuncsArray(inc);
|
|
|
|
|
_excChunckMasks = MakeMaskChuncsArray(exc);
|
2024-01-07 20:44:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private unsafe EcsMaskChunck[] MakeMaskChuncsArray(int[] sortedArray)
|
|
|
|
|
{
|
|
|
|
|
EcsMaskChunck* buffer = stackalloc EcsMaskChunck[sortedArray.Length];
|
|
|
|
|
|
|
|
|
|
int resultLength = 0;
|
|
|
|
|
for (int i = 0; i < sortedArray.Length;)
|
2024-01-07 19:32:16 +08:00
|
|
|
|
{
|
2024-01-07 20:44:11 +08:00
|
|
|
|
int chankIndexX = sortedArray[i] >> EcsMaskChunck.DIV_SHIFT;
|
|
|
|
|
int maskX = 0;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
EcsMaskChunck bitJ = EcsMaskChunck.FromID(sortedArray[i]);
|
|
|
|
|
if (bitJ.chankIndex != chankIndexX)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
maskX |= bitJ.mask;
|
|
|
|
|
i++;
|
|
|
|
|
} while (i < sortedArray.Length);
|
|
|
|
|
buffer[resultLength++] = new EcsMaskChunck(chankIndexX, maskX);
|
2024-01-07 19:32:16 +08:00
|
|
|
|
}
|
2024-01-07 20:44:11 +08:00
|
|
|
|
|
|
|
|
|
EcsMaskChunck[] result = new EcsMaskChunck[resultLength];
|
|
|
|
|
for (int i = 0; i < resultLength; i++)
|
2024-01-07 19:32:16 +08:00
|
|
|
|
{
|
2024-01-07 20:44:11 +08:00
|
|
|
|
result[i] = buffer[i];
|
2024-01-07 19:32:16 +08:00
|
|
|
|
}
|
2024-01-07 20:44:11 +08:00
|
|
|
|
return result;
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-07 23:19:18 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
|
2024-02-11 14:53:36 +08:00
|
|
|
|
#region Checks
|
2024-03-02 21:59:02 +08:00
|
|
|
|
public bool IsSubmaskOf(EcsMask otherMask)
|
2024-02-11 14:53:36 +08:00
|
|
|
|
{
|
|
|
|
|
return IsSubmask(otherMask, this);
|
|
|
|
|
}
|
2024-03-02 21:59:02 +08:00
|
|
|
|
public bool IsSupermaskOf(EcsMask otherMask)
|
2024-02-11 14:53:36 +08:00
|
|
|
|
{
|
|
|
|
|
return IsSubmask(this, otherMask);
|
|
|
|
|
}
|
2024-03-02 21:59:02 +08:00
|
|
|
|
public bool IsConflictWith(EcsMask otherMask)
|
2024-02-11 14:53:36 +08:00
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
return OverlapsArray(_inc, otherMask._exc) || OverlapsArray(_exc, otherMask._inc);
|
2024-02-11 14:53:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
return IsSubarray(sub._inc, super._inc) && IsSuperarray(sub._exc, super._exc);
|
2024-02-11 14:53:36 +08:00
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-01-07 18:52:54 +08:00
|
|
|
|
#region Object
|
2024-03-02 21:45:09 +08:00
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
return CreateLogString(_worldID, _inc, _exc);
|
2024-03-02 21:45:09 +08:00
|
|
|
|
}
|
2024-01-07 19:32:16 +08:00
|
|
|
|
public bool Equals(EcsMask mask)
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
return _id == mask._id && _worldID == mask._worldID;
|
2024-01-07 19:32:16 +08:00
|
|
|
|
}
|
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
return obj is EcsMask mask && _id == mask._id && Equals(mask);
|
2024-01-07 19:32:16 +08:00
|
|
|
|
}
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
2024-04-22 17:20:31 +08:00
|
|
|
|
return unchecked(_id ^ (_worldID * EcsConsts.MAGIC_PRIME));
|
2024-01-07 19:32:16 +08:00
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
2024-08-23 22:31:43 +08:00
|
|
|
|
#region Other
|
|
|
|
|
public EcsMaskIterator GetIterator()
|
|
|
|
|
{
|
|
|
|
|
if(_iterator == null)
|
|
|
|
|
{
|
|
|
|
|
_iterator = new EcsMaskIterator(EcsWorld.GetWorld(_worldID), this);
|
|
|
|
|
}
|
|
|
|
|
return _iterator;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-01-07 18:52:54 +08:00
|
|
|
|
#region Debug utils
|
|
|
|
|
#if DEBUG
|
|
|
|
|
private static HashSet<int> _dummyHashSet = new HashSet<int>();
|
2024-04-18 22:14:50 +08:00
|
|
|
|
private static void CheckConstraints(int[] inc, int[] exc)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
lock (_dummyHashSet)
|
|
|
|
|
{
|
2024-03-02 21:45:09 +08:00
|
|
|
|
if (CheckRepeats(inc)) { throw new EcsFrameworkException("The values in the Include constraints are repeated."); }
|
|
|
|
|
if (CheckRepeats(exc)) { throw new EcsFrameworkException("The values in the Exclude constraints are repeated."); }
|
2024-01-07 18:52:54 +08:00
|
|
|
|
_dummyHashSet.Clear();
|
|
|
|
|
_dummyHashSet.UnionWith(inc);
|
2024-03-02 21:45:09 +08:00
|
|
|
|
if (_dummyHashSet.Overlaps(exc)) { throw new EcsFrameworkException("Conflicting Include and Exclude constraints."); }
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-18 22:14:50 +08:00
|
|
|
|
private static bool CheckRepeats(int[] array)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
_dummyHashSet.Clear();
|
|
|
|
|
foreach (var item in array)
|
|
|
|
|
{
|
2024-03-02 21:45:09 +08:00
|
|
|
|
if (_dummyHashSet.Contains(item))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
_dummyHashSet.Add(item);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2024-04-16 12:46:09 +08:00
|
|
|
|
private static string CreateLogString(short worldID, int[] inc, int[] exc)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
#if (DEBUG && !DISABLE_DEBUG)
|
2024-03-02 21:45:09 +08:00
|
|
|
|
string converter(int o) { return EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1); }
|
2024-01-07 18:52:54 +08:00
|
|
|
|
return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})";
|
|
|
|
|
#else
|
|
|
|
|
return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2024-01-07 19:32:16 +08:00
|
|
|
|
|
2024-01-07 18:52:54 +08:00
|
|
|
|
internal class DebuggerProxy
|
|
|
|
|
{
|
2024-04-18 22:14:50 +08:00
|
|
|
|
private EcsMask _source;
|
|
|
|
|
|
2024-01-07 19:32:16 +08:00
|
|
|
|
public readonly int ID;
|
2024-01-07 18:52:54 +08:00
|
|
|
|
public readonly EcsWorld world;
|
2024-04-16 12:46:09 +08:00
|
|
|
|
private readonly short _worldID;
|
2024-01-07 18:52:54 +08:00
|
|
|
|
public readonly EcsMaskChunck[] includedChunkMasks;
|
|
|
|
|
public readonly EcsMaskChunck[] excludedChunkMasks;
|
|
|
|
|
public readonly int[] included;
|
|
|
|
|
public readonly int[] excluded;
|
|
|
|
|
public readonly Type[] includedTypes;
|
|
|
|
|
public readonly Type[] excludedTypes;
|
|
|
|
|
|
2024-04-18 22:14:50 +08:00
|
|
|
|
public bool IsEmpty { get { return _source.IsEmpty; } }
|
|
|
|
|
public bool IsBroken { get { return _source.IsBroken; } }
|
|
|
|
|
|
2024-01-07 18:52:54 +08:00
|
|
|
|
public DebuggerProxy(EcsMask mask)
|
|
|
|
|
{
|
2024-04-18 22:14:50 +08:00
|
|
|
|
_source = mask;
|
|
|
|
|
|
2024-04-22 17:20:31 +08:00
|
|
|
|
ID = mask._id;
|
|
|
|
|
world = EcsWorld.GetWorld(mask._worldID);
|
|
|
|
|
_worldID = mask._worldID;
|
|
|
|
|
includedChunkMasks = mask._incChunckMasks;
|
|
|
|
|
excludedChunkMasks = mask._excChunckMasks;
|
|
|
|
|
included = mask._inc;
|
|
|
|
|
excluded = mask._exc;
|
2024-03-02 21:45:09 +08:00
|
|
|
|
Type converter(int o) { return world.GetComponentType(o); }
|
2024-01-07 18:52:54 +08:00
|
|
|
|
includedTypes = included.Select(converter).ToArray();
|
|
|
|
|
excludedTypes = excluded.Select(converter).ToArray();
|
|
|
|
|
}
|
2024-03-02 21:45:09 +08:00
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return CreateLogString(_worldID, included, excluded);
|
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-04-15 01:18:08 +08:00
|
|
|
|
#region Operators
|
|
|
|
|
public static EcsMask operator -(EcsMask a, EcsMask b)
|
|
|
|
|
{
|
|
|
|
|
return a.World.Get<WorldMaskComponent>().ExceptMask(a, b);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region OpMaskKey
|
|
|
|
|
private readonly struct OpMaskKey : IEquatable<OpMaskKey>
|
|
|
|
|
{
|
|
|
|
|
public readonly int leftMaskID;
|
|
|
|
|
public readonly int rightMaskID;
|
|
|
|
|
public readonly int operation;
|
|
|
|
|
|
|
|
|
|
public const int UNION_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)
|
|
|
|
|
{
|
2024-04-28 18:36:24 +08:00
|
|
|
|
return leftMaskID == other.leftMaskID &&
|
|
|
|
|
rightMaskID == other.rightMaskID &&
|
2024-04-15 01:18:08 +08:00
|
|
|
|
operation == other.operation;
|
|
|
|
|
}
|
|
|
|
|
public override int GetHashCode()
|
|
|
|
|
{
|
|
|
|
|
return leftMaskID ^ (rightMaskID * operation);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-01-07 19:32:16 +08:00
|
|
|
|
#region Builder
|
2024-01-11 00:48:39 +08:00
|
|
|
|
private readonly struct WorldMaskComponent : IEcsWorldComponent<WorldMaskComponent>
|
|
|
|
|
{
|
|
|
|
|
private readonly EcsWorld _world;
|
|
|
|
|
private readonly Dictionary<Key, EcsMask> _masks;
|
2024-04-15 01:18:08 +08:00
|
|
|
|
private readonly Dictionary<OpMaskKey, EcsMask> _opMasks;
|
2024-01-11 00:48:39 +08:00
|
|
|
|
|
2024-04-18 22:14:50 +08:00
|
|
|
|
public readonly EcsMask EmptyMask;
|
|
|
|
|
public readonly EcsMask BrokenMask;
|
|
|
|
|
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#region Constructor/Destructor
|
2024-04-18 22:14:50 +08:00
|
|
|
|
public WorldMaskComponent(EcsWorld world, Dictionary<Key, EcsMask> masks, Dictionary<OpMaskKey, EcsMask> opMasks, EcsMask emptyMask, EcsMask brokenMask)
|
2024-01-11 00:48:39 +08:00
|
|
|
|
{
|
|
|
|
|
_world = world;
|
|
|
|
|
_masks = masks;
|
2024-04-15 01:18:08 +08:00
|
|
|
|
_opMasks = opMasks;
|
2024-04-18 22:14:50 +08:00
|
|
|
|
EmptyMask = emptyMask;
|
|
|
|
|
BrokenMask = brokenMask;
|
2024-01-11 00:48:39 +08:00
|
|
|
|
}
|
|
|
|
|
public void Init(ref WorldMaskComponent component, EcsWorld world)
|
|
|
|
|
{
|
2024-04-18 22:14:50 +08:00
|
|
|
|
var masks = new Dictionary<Key, EcsMask>(256);
|
|
|
|
|
EcsMask emptyMask = NewEmpty(0, world.id);
|
|
|
|
|
EcsMask brokenMask = NewBroken(1, world.id);
|
2024-04-22 17:20:31 +08:00
|
|
|
|
masks.Add(new Key(emptyMask._inc, emptyMask._exc), emptyMask);
|
|
|
|
|
masks.Add(new Key(brokenMask._inc, brokenMask._exc), brokenMask);
|
2024-04-18 22:14:50 +08:00
|
|
|
|
component = new WorldMaskComponent(world, masks, new Dictionary<OpMaskKey, EcsMask>(256), emptyMask, brokenMask);
|
2024-01-11 00:48:39 +08:00
|
|
|
|
}
|
|
|
|
|
public void OnDestroy(ref WorldMaskComponent component, EcsWorld world)
|
|
|
|
|
{
|
|
|
|
|
component._masks.Clear();
|
2024-04-15 01:18:08 +08:00
|
|
|
|
component._opMasks.Clear();
|
2024-01-11 00:48:39 +08:00
|
|
|
|
component = default;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region GetMask
|
2024-04-15 01:18:08 +08:00
|
|
|
|
internal EcsMask ExceptMask(EcsMask a, EcsMask b)
|
|
|
|
|
{
|
|
|
|
|
int operation = OpMaskKey.EXCEPT_OP;
|
2024-04-22 17:20:31 +08:00
|
|
|
|
if (_opMasks.TryGetValue(new OpMaskKey(a._id, b._id, operation), out EcsMask result) == false)
|
2024-04-15 01:18:08 +08:00
|
|
|
|
{
|
|
|
|
|
if (a.IsConflictWith(b))
|
|
|
|
|
{
|
2024-04-18 22:14:50 +08:00
|
|
|
|
return a.World.Get<WorldMaskComponent>().BrokenMask;
|
2024-04-15 01:18:08 +08:00
|
|
|
|
}
|
2024-04-18 22:21:15 +08:00
|
|
|
|
result = New(a.World).Combine(a).Except(b).Build();
|
2024-04-22 17:20:31 +08:00
|
|
|
|
_opMasks.Add(new OpMaskKey(a._id, b._id, operation), result);
|
2024-04-15 01:18:08 +08:00
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
internal EcsMask GetMask(Key maskKey)
|
|
|
|
|
{
|
|
|
|
|
if (!_masks.TryGetValue(maskKey, out EcsMask result))
|
|
|
|
|
{
|
2024-04-18 22:21:15 +08:00
|
|
|
|
result = New(_masks.Count, _world.id, maskKey.inc, maskKey.exc);
|
2024-01-11 00:48:39 +08:00
|
|
|
|
_masks.Add(maskKey, result);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
private readonly struct Key : IEquatable<Key>
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
public readonly int[] inc;
|
|
|
|
|
public readonly int[] exc;
|
|
|
|
|
public readonly int hash;
|
2024-01-11 00:48:39 +08:00
|
|
|
|
|
|
|
|
|
#region Constructors
|
|
|
|
|
public Key(int[] inc, int[] exc)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
this.inc = inc;
|
|
|
|
|
this.exc = exc;
|
2024-01-11 00:48:39 +08:00
|
|
|
|
unchecked
|
|
|
|
|
{
|
|
|
|
|
hash = inc.Length + exc.Length;
|
|
|
|
|
for (int i = 0, iMax = inc.Length; i < iMax; i++)
|
|
|
|
|
{
|
|
|
|
|
hash = hash * EcsConsts.MAGIC_PRIME + inc[i];
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0, iMax = exc.Length; i < iMax; i++)
|
|
|
|
|
{
|
|
|
|
|
hash = hash * EcsConsts.MAGIC_PRIME - exc[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Object
|
2024-01-07 18:52:54 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-01-11 00:48:39 +08:00
|
|
|
|
public bool Equals(Key other)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
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 (inc[i] != other.inc[i])
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < exc.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (exc[i] != other.exc[i])
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public override int GetHashCode() => hash;
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class Builder
|
|
|
|
|
{
|
2024-01-07 19:32:16 +08:00
|
|
|
|
private readonly EcsWorld _world;
|
|
|
|
|
private readonly HashSet<int> _inc = new HashSet<int>();
|
|
|
|
|
private readonly HashSet<int> _exc = new HashSet<int>();
|
2024-04-18 22:14:50 +08:00
|
|
|
|
private readonly List<Combined> _combineds = new List<Combined>();
|
|
|
|
|
private readonly List<Excepted> _excepteds = new List<Excepted>();
|
2024-01-07 18:52:54 +08:00
|
|
|
|
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#region Constrcutors
|
2024-01-07 18:52:54 +08:00
|
|
|
|
internal Builder(EcsWorld world)
|
|
|
|
|
{
|
|
|
|
|
_world = world;
|
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#region Include/Exclude/Combine
|
|
|
|
|
public Builder Include<T>()
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
2024-04-15 01:18:08 +08:00
|
|
|
|
return Include(_world.GetComponentTypeID<T>());
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
public Builder Exclude<T>()
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
2024-04-15 01:18:08 +08:00
|
|
|
|
return Exclude(_world.GetComponentTypeID<T>());
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
public Builder Include(Type type)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
2024-04-15 01:18:08 +08:00
|
|
|
|
return Include(_world.GetComponentTypeID(type));
|
|
|
|
|
}
|
|
|
|
|
public Builder Exclude(Type type)
|
|
|
|
|
{
|
|
|
|
|
return Exclude(_world.GetComponentTypeID(type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Builder Include(int compponentTypeID)
|
|
|
|
|
{
|
2024-01-07 18:52:54 +08:00
|
|
|
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
2024-04-15 01:18:08 +08:00
|
|
|
|
if (_inc.Contains(compponentTypeID) || _exc.Contains(compponentTypeID)) Throw.ConstraintIsAlreadyContainedInMask(_world.GetComponentType(compponentTypeID));
|
2024-01-07 18:52:54 +08:00
|
|
|
|
#endif
|
2024-04-15 01:18:08 +08:00
|
|
|
|
_inc.Add(compponentTypeID);
|
2024-01-11 00:48:39 +08:00
|
|
|
|
return this;
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-04-15 01:18:08 +08:00
|
|
|
|
public Builder Exclude(int compponentTypeID)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
2024-04-15 01:18:08 +08:00
|
|
|
|
if (_inc.Contains(compponentTypeID) || _exc.Contains(compponentTypeID)) Throw.ConstraintIsAlreadyContainedInMask(_world.GetComponentType(compponentTypeID));
|
2024-01-07 18:52:54 +08:00
|
|
|
|
#endif
|
2024-04-15 01:18:08 +08:00
|
|
|
|
_exc.Add(compponentTypeID);
|
2024-01-11 00:48:39 +08:00
|
|
|
|
return this;
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-04-15 01:18:08 +08:00
|
|
|
|
|
2024-01-11 00:48:39 +08:00
|
|
|
|
public Builder Combine(EcsMask mask, int order = 0)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
2024-04-18 22:14:50 +08:00
|
|
|
|
_combineds.Add(new Combined(mask, order));
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Builder Except(EcsMask mask, int order = 0)
|
|
|
|
|
{
|
|
|
|
|
_excepteds.Add(new Excepted(mask, order));
|
2024-01-11 00:48:39 +08:00
|
|
|
|
return this;
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#region Build
|
2024-01-07 18:52:54 +08:00
|
|
|
|
public EcsMask Build()
|
|
|
|
|
{
|
|
|
|
|
HashSet<int> combinedInc;
|
|
|
|
|
HashSet<int> combinedExc;
|
2024-04-18 22:14:50 +08:00
|
|
|
|
if (_combineds.Count > 0)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
combinedInc = new HashSet<int>();
|
|
|
|
|
combinedExc = new HashSet<int>();
|
2024-04-18 22:14:50 +08:00
|
|
|
|
_combineds.Sort((a, b) => a.order - b.order);
|
|
|
|
|
foreach (var item in _combineds)
|
2024-01-07 18:52:54 +08:00
|
|
|
|
{
|
|
|
|
|
EcsMask submask = item.mask;
|
2024-04-22 17:20:31 +08:00
|
|
|
|
combinedInc.ExceptWith(submask._exc);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedExc.ExceptWith(submask._inc);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedInc.UnionWith(submask._inc);
|
|
|
|
|
combinedExc.UnionWith(submask._exc);
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
|
|
|
|
combinedInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedInc.UnionWith(_inc);
|
|
|
|
|
combinedExc.UnionWith(_exc);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
combinedInc = _inc;
|
|
|
|
|
combinedExc = _exc;
|
|
|
|
|
}
|
2024-04-18 22:14:50 +08:00
|
|
|
|
if (_excepteds.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in _excepteds)
|
|
|
|
|
{
|
2024-04-28 18:36:24 +08:00
|
|
|
|
if (combinedInc.Overlaps(item.mask._exc) || combinedExc.Overlaps(item.mask._inc))
|
2024-04-18 22:14:50 +08:00
|
|
|
|
{
|
|
|
|
|
_combineds.Clear();
|
|
|
|
|
_excepteds.Clear();
|
|
|
|
|
return _world.Get<WorldMaskComponent>().BrokenMask;
|
|
|
|
|
}
|
2024-04-22 17:20:31 +08:00
|
|
|
|
combinedInc.ExceptWith(item.mask._inc);
|
|
|
|
|
combinedExc.ExceptWith(item.mask._exc);
|
2024-04-18 22:14:50 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-07 18:52:54 +08:00
|
|
|
|
|
|
|
|
|
var inc = combinedInc.ToArray();
|
|
|
|
|
Array.Sort(inc);
|
|
|
|
|
var exc = combinedExc.ToArray();
|
|
|
|
|
Array.Sort(exc);
|
|
|
|
|
|
2024-04-18 22:14:50 +08:00
|
|
|
|
_combineds.Clear();
|
|
|
|
|
_excepteds.Clear();
|
2024-01-11 00:48:39 +08:00
|
|
|
|
|
|
|
|
|
return _world.Get<WorldMaskComponent>().GetMask(new Key(inc, exc));
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-11 00:48:39 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
2024-01-07 19:32:16 +08:00
|
|
|
|
|
2024-01-07 18:52:54 +08:00
|
|
|
|
private readonly struct Combined
|
|
|
|
|
{
|
|
|
|
|
public readonly EcsMask mask;
|
|
|
|
|
public readonly int order;
|
|
|
|
|
public Combined(EcsMask mask, int order)
|
|
|
|
|
{
|
|
|
|
|
this.mask = mask;
|
|
|
|
|
this.order = order;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-04-18 22:14:50 +08:00
|
|
|
|
private readonly struct Excepted
|
|
|
|
|
{
|
|
|
|
|
public readonly EcsMask mask;
|
|
|
|
|
public readonly int order;
|
|
|
|
|
public Excepted(EcsMask mask, int order)
|
|
|
|
|
{
|
|
|
|
|
this.mask = mask;
|
|
|
|
|
this.order = order;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-07 19:32:16 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-01-07 23:19:18 +08:00
|
|
|
|
#region EcsMaskChunck
|
2024-01-07 18:52:54 +08:00
|
|
|
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
|
|
|
|
public readonly struct EcsMaskChunck
|
|
|
|
|
{
|
|
|
|
|
internal const int BITS = 32;
|
|
|
|
|
internal const int DIV_SHIFT = 5;
|
|
|
|
|
internal const int MOD_MASK = BITS - 1;
|
|
|
|
|
|
|
|
|
|
public readonly int chankIndex;
|
|
|
|
|
public readonly int mask;
|
|
|
|
|
public EcsMaskChunck(int chankIndex, int mask)
|
|
|
|
|
{
|
|
|
|
|
this.chankIndex = chankIndex;
|
|
|
|
|
this.mask = mask;
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public static EcsMaskChunck FromID(int id)
|
|
|
|
|
{
|
|
|
|
|
return new EcsMaskChunck(id >> DIV_SHIFT, 1 << (id & MOD_MASK));
|
|
|
|
|
}
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return $"mask({chankIndex}, {mask}, {BitsUtility.CountBits(mask)})";
|
|
|
|
|
}
|
|
|
|
|
internal class DebuggerProxy
|
|
|
|
|
{
|
|
|
|
|
public int chunk;
|
|
|
|
|
public uint mask;
|
|
|
|
|
public int[] values = Array.Empty<int>();
|
|
|
|
|
public string bits;
|
|
|
|
|
public DebuggerProxy(EcsMaskChunck maskbits)
|
|
|
|
|
{
|
|
|
|
|
chunk = maskbits.chankIndex;
|
|
|
|
|
mask = (uint)maskbits.mask;
|
|
|
|
|
BitsUtility.GetBitNumbersNoAlloc(mask, ref values);
|
|
|
|
|
for (int i = 0; i < values.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
values[i] += (chunk) << 5;
|
|
|
|
|
}
|
|
|
|
|
bits = BitsUtility.ToBitsString(mask, '_', 8);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-01-07 23:19:18 +08:00
|
|
|
|
#endregion
|
2024-08-23 22:31:43 +08:00
|
|
|
|
|
2024-08-24 12:29:58 +08:00
|
|
|
|
#region EcsMaskIterator
|
|
|
|
|
#if ENABLE_IL2CPP
|
|
|
|
|
[Il2CppSetOption (Option.NullChecks, false)]
|
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
#endif
|
2024-08-23 22:31:43 +08:00
|
|
|
|
public class EcsMaskIterator
|
|
|
|
|
{
|
|
|
|
|
#region CountStructComparers
|
|
|
|
|
private readonly struct IncCountComparer : IStructComparer<int>
|
|
|
|
|
{
|
|
|
|
|
public readonly EcsWorld.PoolSlot[] counts;
|
|
|
|
|
public IncCountComparer(EcsWorld.PoolSlot[] counts)
|
|
|
|
|
{
|
|
|
|
|
this.counts = counts;
|
|
|
|
|
}
|
|
|
|
|
public int Compare(int a, int b)
|
|
|
|
|
{
|
|
|
|
|
return counts[a].count - counts[b].count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
private readonly struct ExcCountComparer : IStructComparer<int>
|
|
|
|
|
{
|
|
|
|
|
public readonly EcsWorld.PoolSlot[] counts;
|
|
|
|
|
public ExcCountComparer(EcsWorld.PoolSlot[] counts)
|
|
|
|
|
{
|
|
|
|
|
this.counts = counts;
|
|
|
|
|
}
|
|
|
|
|
public int Compare(int a, int b)
|
|
|
|
|
{
|
|
|
|
|
return counts[b].count - counts[a].count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
internal EcsWorld _source;
|
|
|
|
|
internal EcsMask _mask;
|
|
|
|
|
|
|
|
|
|
private UnsafeArray<int> _sortIncBuffer;
|
|
|
|
|
private UnsafeArray<int> _sortExcBuffer;
|
|
|
|
|
private UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
|
|
|
|
|
private UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
|
|
|
|
|
|
|
|
|
#region Constructors
|
2024-08-24 12:29:58 +08:00
|
|
|
|
public unsafe EcsMaskIterator(EcsWorld source, EcsMask mask)
|
2024-08-23 22:31:43 +08:00
|
|
|
|
{
|
|
|
|
|
_source = source;
|
|
|
|
|
_mask = mask;
|
2024-08-24 12:29:58 +08:00
|
|
|
|
|
|
|
|
|
_sortIncBuffer = new UnsafeArray<int>(_mask._inc.Length, true);
|
|
|
|
|
_sortExcBuffer = new UnsafeArray<int>(_mask._exc.Length, true);
|
|
|
|
|
_sortIncChunckBuffer = new UnsafeArray<EcsMaskChunck>(_mask._incChunckMasks.Length, true);
|
|
|
|
|
_sortExcChunckBuffer = new UnsafeArray<EcsMaskChunck>(_mask._excChunckMasks.Length, true);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < _sortIncBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
_sortIncBuffer.ptr[i] = _mask._inc[i];
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < _sortExcBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
_sortExcBuffer.ptr[i] = _mask._exc[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < _sortIncChunckBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
_sortIncChunckBuffer.ptr[i] = _mask._incChunckMasks[i];
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < _sortExcChunckBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
_sortExcChunckBuffer.ptr[i] = _mask._excChunckMasks[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Finalizator
|
|
|
|
|
unsafe ~EcsMaskIterator()
|
|
|
|
|
{
|
|
|
|
|
_sortIncBuffer.Dispose();
|
|
|
|
|
_sortExcBuffer.Dispose();
|
|
|
|
|
_sortIncChunckBuffer.Dispose();
|
|
|
|
|
_sortExcChunckBuffer.Dispose();
|
2024-08-23 22:31:43 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Properties
|
|
|
|
|
public EcsWorld World
|
|
|
|
|
{
|
|
|
|
|
get { return _source; }
|
|
|
|
|
}
|
|
|
|
|
public EcsMask Mask
|
|
|
|
|
{
|
|
|
|
|
get { return _mask; }
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Enumerable
|
|
|
|
|
public Enumerable Iterate(EcsSpan span)
|
|
|
|
|
{
|
|
|
|
|
return new Enumerable();
|
|
|
|
|
}
|
|
|
|
|
public readonly ref struct Enumerable
|
|
|
|
|
{
|
|
|
|
|
private readonly EcsMaskIterator _iterator;
|
|
|
|
|
private readonly EcsSpan _span;
|
|
|
|
|
|
|
|
|
|
public Enumerable(EcsMaskIterator iterator, EcsSpan span)
|
|
|
|
|
{
|
|
|
|
|
_iterator = iterator;
|
|
|
|
|
_span = span;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region CopyTo
|
|
|
|
|
public void CopyTo(EcsGroup group)
|
|
|
|
|
{
|
|
|
|
|
group.Clear();
|
|
|
|
|
var enumerator = GetEnumerator();
|
|
|
|
|
while (enumerator.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
group.AddUnchecked(enumerator.Current);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public int CopyTo(ref int[] array)
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
var enumerator = GetEnumerator();
|
|
|
|
|
while (enumerator.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
if (array.Length <= count)
|
|
|
|
|
{
|
|
|
|
|
Array.Resize(ref array, array.Length << 1);
|
|
|
|
|
}
|
|
|
|
|
array[count++] = enumerator.Current;
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
public EcsSpan CopyToSpan(ref int[] array)
|
|
|
|
|
{
|
|
|
|
|
int count = CopyTo(ref array);
|
|
|
|
|
return new EcsSpan(_iterator.World.id, array, count);
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Other
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
List<int> ints = new List<int>();
|
|
|
|
|
foreach (var e in this)
|
|
|
|
|
{
|
|
|
|
|
ints.Add(e);
|
|
|
|
|
}
|
|
|
|
|
return CollectionUtility.EntitiesToString(ints, "it");
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Enumerator
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public Enumerator GetEnumerator() { return new Enumerator(_span, _iterator); }
|
|
|
|
|
|
|
|
|
|
public unsafe ref struct Enumerator
|
|
|
|
|
{
|
|
|
|
|
private ReadOnlySpan<int>.Enumerator _span;
|
|
|
|
|
private readonly int[] _entityComponentMasks;
|
|
|
|
|
|
|
|
|
|
private static EcsMaskChunck* _preSortedIncBuffer;
|
|
|
|
|
private static EcsMaskChunck* _preSortedExcBuffer;
|
|
|
|
|
|
|
|
|
|
private UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
|
|
|
|
|
private UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
|
|
|
|
|
|
|
|
|
private readonly int _entityComponentMaskLengthBitShift;
|
|
|
|
|
|
|
|
|
|
public unsafe Enumerator(EcsSpan span, EcsMaskIterator iterator)
|
|
|
|
|
{
|
|
|
|
|
_entityComponentMasks = iterator.World._entityComponentMasks;
|
|
|
|
|
_sortIncChunckBuffer = iterator._sortIncChunckBuffer;
|
|
|
|
|
_sortExcChunckBuffer = iterator._sortExcChunckBuffer;
|
|
|
|
|
|
|
|
|
|
_entityComponentMaskLengthBitShift = iterator.World._entityComponentMaskLengthBitShift;
|
|
|
|
|
|
|
|
|
|
if (iterator.Mask.IsBroken)
|
|
|
|
|
{
|
|
|
|
|
_span = span.Slice(0, 0).GetEnumerator();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region Sort
|
|
|
|
|
UnsafeArray<int> _sortIncBuffer = iterator._sortIncBuffer;
|
|
|
|
|
UnsafeArray<int> _sortExcBuffer = iterator._sortExcBuffer;
|
|
|
|
|
EcsWorld.PoolSlot[] counts = iterator.World._poolSlots;
|
|
|
|
|
|
|
|
|
|
if (_preSortedIncBuffer == null)
|
|
|
|
|
{
|
|
|
|
|
_preSortedIncBuffer = UnmanagedArrayUtility.New<EcsMaskChunck>(256);
|
|
|
|
|
_preSortedExcBuffer = UnmanagedArrayUtility.New<EcsMaskChunck>(256);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_sortIncChunckBuffer.Length > 1)
|
|
|
|
|
{
|
|
|
|
|
IncCountComparer incComparer = new IncCountComparer(counts);
|
|
|
|
|
UnsafeArraySortHalperX<int>.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer);
|
|
|
|
|
for (int i = 0; i < _sortIncBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
_preSortedIncBuffer[i] = EcsMaskChunck.FromID(_sortIncBuffer.ptr[i]);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0, ii = 0; ii < _sortIncChunckBuffer.Length; ii++)
|
|
|
|
|
{
|
|
|
|
|
EcsMaskChunck chunkX = _preSortedIncBuffer[i];
|
|
|
|
|
int chankIndexX = chunkX.chankIndex;
|
|
|
|
|
int maskX = chunkX.mask;
|
|
|
|
|
|
|
|
|
|
for (int j = i + 1; j < _sortIncBuffer.Length; j++)
|
|
|
|
|
{
|
|
|
|
|
if (_preSortedIncBuffer[j].chankIndex == chankIndexX)
|
|
|
|
|
{
|
|
|
|
|
maskX |= _preSortedIncBuffer[j].mask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_sortIncChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX);
|
|
|
|
|
while (++i < _sortIncBuffer.Length && _preSortedIncBuffer[i].chankIndex == chankIndexX)
|
|
|
|
|
{
|
|
|
|
|
// skip
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (_sortIncChunckBuffer.Length > 0 && counts[_sortIncBuffer.ptr[0]].count <= 0)
|
|
|
|
|
{
|
|
|
|
|
_span = span.Slice(0, 0).GetEnumerator();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (_sortExcChunckBuffer.Length > 1)
|
|
|
|
|
{
|
|
|
|
|
ExcCountComparer excComparer = new ExcCountComparer(counts);
|
|
|
|
|
UnsafeArraySortHalperX<int>.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer);
|
|
|
|
|
for (int i = 0; i < _sortExcBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
_preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int i = 0, ii = 0; ii < _sortExcChunckBuffer.Length; ii++)
|
|
|
|
|
{
|
|
|
|
|
EcsMaskChunck bas = _preSortedExcBuffer[i];
|
|
|
|
|
int chankIndexX = bas.chankIndex;
|
|
|
|
|
int maskX = bas.mask;
|
|
|
|
|
|
|
|
|
|
for (int j = i + 1; j < _sortExcBuffer.Length; j++)
|
|
|
|
|
{
|
|
|
|
|
if (_preSortedExcBuffer[j].chankIndex == chankIndexX)
|
|
|
|
|
{
|
|
|
|
|
maskX |= _preSortedExcBuffer[j].mask;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_sortExcChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX);
|
|
|
|
|
while (++i < _sortExcBuffer.Length && _preSortedExcBuffer[i].chankIndex == chankIndexX)
|
|
|
|
|
{
|
|
|
|
|
// skip
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
_span = span.GetEnumerator();
|
|
|
|
|
}
|
|
|
|
|
public int Current
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get { return _span.Current; }
|
|
|
|
|
}
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool MoveNext()
|
|
|
|
|
{
|
|
|
|
|
while (_span.MoveNext())
|
|
|
|
|
{
|
|
|
|
|
int chunck = _span.Current << _entityComponentMaskLengthBitShift;
|
|
|
|
|
for (int i = 0; i < _sortIncChunckBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var bit = _sortIncChunckBuffer.ptr[i];
|
|
|
|
|
if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != bit.mask)
|
|
|
|
|
{
|
|
|
|
|
goto skip;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < _sortExcChunckBuffer.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var bit = _sortExcChunckBuffer.ptr[i];
|
|
|
|
|
if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != 0)
|
|
|
|
|
{
|
|
|
|
|
goto skip;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
skip: continue;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
2024-08-24 12:29:58 +08:00
|
|
|
|
#endregion
|
2024-01-07 18:52:54 +08:00
|
|
|
|
}
|