DragonECS/src/EcsMask.cs

1115 lines
42 KiB
C#
Raw Normal View History

2025-03-14 16:53:25 +08:00
#if DISABLE_DEBUG
#undef DEBUG
#endif
using DCFApixels.DragonECS.Core;
2025-05-17 14:55:31 +08:00
using DCFApixels.DragonECS.Core.Internal;
2024-01-07 18:52:54 +08:00
using System;
using System.Collections.Generic;
2024-11-01 12:41:10 +08:00
using System.ComponentModel;
2024-01-07 18:52:54 +08:00
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
2024-10-02 22:13:10 +08:00
#if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices;
#endif
2024-01-07 18:52:54 +08:00
2024-11-01 12:41:10 +08:00
namespace DCFApixels.DragonECS.Core
2024-01-07 18:52:54 +08:00
{
2024-11-01 12:41:10 +08:00
public interface IComponentMask
2024-10-05 18:05:33 +08:00
{
EcsMask ToMask(EcsWorld world);
}
2024-11-01 12:41:10 +08:00
}
namespace DCFApixels.DragonECS
{
using static EcsMaskIteratorUtility;
2024-10-02 22:13:10 +08:00
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-04-28 19:43:10 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
2024-01-07 18:52:54 +08:00
[DebuggerTypeProxy(typeof(DebuggerProxy))]
2024-11-01 12:41:10 +08:00
public sealed class EcsMask : IEquatable<EcsMask>, IComponentMask
2024-01-07 18:52:54 +08:00
{
2024-11-01 12:41:10 +08:00
public readonly int ID;
public readonly short WorldID;
2024-10-31 14:46:21 +08:00
internal readonly EcsStaticMask _staticMask;
2024-04-22 17:20:31 +08:00
internal readonly EcsMaskChunck[] _incChunckMasks;
internal readonly EcsMaskChunck[] _excChunckMasks;
2025-05-19 20:30:18 +08:00
internal readonly EcsMaskChunck[] _anyChunckMasks;
2024-10-02 22:13:10 +08:00
/// <summary> Sorted </summary>
2024-11-01 12:41:10 +08:00
internal readonly int[] _incs;
2024-10-02 22:13:10 +08:00
/// <summary> Sorted </summary>
2024-11-01 12:41:10 +08:00
internal readonly int[] _excs;
2025-05-19 20:30:18 +08:00
/// <summary> Sorted </summary>
internal readonly int[] _anys;
2024-01-07 23:19:18 +08:00
2025-05-20 11:12:30 +08:00
internal readonly EcsMaskFlags _flags;
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 EcsWorld World
{
2024-10-02 22:13:10 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-11-01 12:41:10 +08:00
get { return EcsWorld.GetWorld(WorldID); }
2024-03-02 21:45:09 +08:00
}
2024-11-01 12:41:10 +08:00
/// <summary> Sorted set excluding constraints. </summary>
public ReadOnlySpan<int> Incs
2024-03-02 21:45:09 +08:00
{
2024-10-02 22:13:10 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-11-01 12:41:10 +08:00
get { return _incs; }
2024-03-02 21:45:09 +08:00
}
2024-10-02 22:13:10 +08:00
/// <summary> Sorted set excluding constraints. </summary>
2024-11-01 12:41:10 +08:00
public ReadOnlySpan<int> Excs
2024-03-02 21:45:09 +08:00
{
2024-10-02 22:13:10 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-11-01 12:41:10 +08:00
get { return _excs; }
2024-03-02 21:45:09 +08:00
}
2025-05-20 11:12:30 +08:00
public EcsMaskFlags Flags
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _flags; }
}
2024-03-17 10:18:16 +08:00
public bool IsEmpty
{
2024-10-02 22:13:10 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2025-05-20 11:12:30 +08:00
get { return _flags == EcsMaskFlags.Empty; }
2024-03-17 10:18:16 +08:00
}
2024-04-18 22:14:50 +08:00
public bool IsBroken
{
2025-05-20 11:12:30 +08:00
get { return (_flags & EcsMaskFlags.Broken) != 0; }
2024-04-18 22:14:50 +08:00
}
2024-01-07 23:19:18 +08:00
#endregion
#region Constructors
2024-10-02 22:13:10 +08:00
public static Builder New(EcsWorld world) { return new Builder(world); }
internal static EcsMask CreateEmpty(int id, short worldID)
2024-04-18 22:14:50 +08:00
{
2025-05-20 11:12:30 +08:00
return new EcsMask(EcsStaticMask.Empty, id, worldID);
2024-04-18 22:14:50 +08:00
}
2024-10-02 22:13:10 +08:00
internal static EcsMask CreateBroken(int id, short worldID)
2024-04-18 22:14:50 +08:00
{
2025-05-20 11:12:30 +08:00
return new EcsMask(EcsStaticMask.Broken, id, worldID);
2024-04-18 22:14:50 +08:00
}
2025-05-20 11:12:30 +08:00
private EcsMask(EcsStaticMask staticMask, int id, short worldID)
2024-04-18 22:14:50 +08:00
{
2025-05-20 11:12:30 +08:00
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;
}
2024-10-31 14:46:21 +08:00
_staticMask = staticMask;
2024-11-01 12:41:10 +08:00
ID = id;
2025-05-20 11:12:30 +08:00
WorldID = worldID;
_flags = staticMask.Flags;
EcsWorld world = EcsWorld.GetWorld(worldID);
int[] incs = ConvertTypeCodeToComponentTypeID(staticMask.IncTypeCodes, world);
int[] excs = ConvertTypeCodeToComponentTypeID(staticMask.ExcTypeCodes, world);
int[] anys = ConvertTypeCodeToComponentTypeID(staticMask.AnyTypeCodes, world);
2025-05-19 20:30:18 +08:00
_incs = incs;
_excs = excs;
_anys = anys;
2024-01-07 19:32:16 +08:00
2025-05-19 20:30:18 +08:00
_incChunckMasks = MakeMaskChuncsArray(incs);
_excChunckMasks = MakeMaskChuncsArray(excs);
_anyChunckMasks = MakeMaskChuncsArray(anys);
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]);
2024-10-10 19:57:19 +08:00
if (bitJ.chunkIndex != chankIndexX)
2024-01-07 20:44:11 +08:00
{
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
{
2024-11-01 12:41:10 +08:00
return _staticMask.IsSubmaskOf(otherMask._staticMask);
2024-02-11 14:53:36 +08:00
}
2024-03-02 21:59:02 +08:00
public bool IsSupermaskOf(EcsMask otherMask)
2024-02-11 14:53:36 +08:00
{
2024-11-01 12:41:10 +08:00
return _staticMask.IsSupermaskOf(otherMask._staticMask);
2024-02-11 14:53:36 +08:00
}
2024-03-02 21:59:02 +08:00
public bool IsConflictWith(EcsMask otherMask)
2024-02-11 14:53:36 +08:00
{
2024-11-01 12:41:10 +08:00
return _staticMask.IsConflictWith(otherMask._staticMask);
2024-02-11 14:53:36 +08:00
}
#endregion
2024-01-07 18:52:54 +08:00
#region Object
2024-03-02 21:45:09 +08:00
public override string ToString()
{
2025-05-19 20:30:18 +08:00
return CreateLogString(WorldID, _incs, _excs, _anys);
2024-03-02 21:45:09 +08:00
}
2024-01-07 19:32:16 +08:00
public bool Equals(EcsMask mask)
{
2024-11-01 12:41:10 +08:00
return ID == mask.ID && WorldID == mask.WorldID;
2024-01-07 19:32:16 +08:00
}
public override bool Equals(object obj)
{
2024-11-01 12:41:10 +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-11-01 12:41:10 +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
2024-11-01 12:41:10 +08:00
public static EcsMask FromStatic(EcsWorld world, EcsStaticMask abstractMask)
{
return world.Get<WorldMaskComponent>().ConvertFromStatic(abstractMask);
}
2025-03-13 11:18:45 +08:00
public EcsStaticMask ToStatic()
{
return _staticMask;
}
2024-11-01 12:41:10 +08:00
EcsMask IComponentMask.ToMask(EcsWorld world) { return this; }
2024-08-23 22:31:43 +08:00
public EcsMaskIterator GetIterator()
{
2024-08-24 13:10:50 +08:00
if (_iterator == null)
2024-08-23 22:31:43 +08:00
{
2024-11-01 12:41:10 +08:00
_iterator = new EcsMaskIterator(EcsWorld.GetWorld(WorldID), this);
2024-08-23 22:31:43 +08:00
}
return _iterator;
}
#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);
}
2024-11-01 12:41:10 +08:00
public static EcsMask operator -(EcsMask a, IComponentMask b)
2024-10-05 20:59:16 +08:00
{
return a.World.Get<WorldMaskComponent>().ExceptMask(a, b.ToMask(a.World));
}
2024-11-01 12:41:10 +08:00
public static EcsMask operator -(IComponentMask b, EcsMask a)
2024-10-05 20:59:16 +08:00
{
return a.World.Get<WorldMaskComponent>().ExceptMask(b.ToMask(a.World), a);
}
2024-10-05 19:10:27 +08:00
public static EcsMask operator +(EcsMask a, EcsMask b)
{
return a.World.Get<WorldMaskComponent>().CombineMask(a, b);
}
2024-11-01 12:41:10 +08:00
public static EcsMask operator +(EcsMask a, IComponentMask b)
2024-10-05 20:59:16 +08:00
{
return a.World.Get<WorldMaskComponent>().CombineMask(a, b.ToMask(a.World));
}
2024-11-01 12:41:10 +08:00
public static EcsMask operator +(IComponentMask b, EcsMask a)
2024-10-05 20:59:16 +08:00
{
return a.World.Get<WorldMaskComponent>().CombineMask(b.ToMask(a.World), a);
}
2024-11-01 12:41:10 +08:00
public static implicit operator EcsMask((IComponentMask mask, EcsWorld world) a)
2024-10-05 19:10:27 +08:00
{
return a.mask.ToMask(a.world);
}
2024-11-01 12:41:10 +08:00
public static implicit operator EcsMask((EcsWorld world, IComponentMask mask) a)
2024-10-05 19:15:33 +08:00
{
return a.mask.ToMask(a.world);
}
2024-04-15 01:18:08 +08:00
#endregion
#region OpMaskKey
private readonly struct OpMaskKey : IEquatable<OpMaskKey>
{
public readonly int leftMaskID;
public readonly int rightMaskID;
public readonly int operation;
2024-10-05 19:10:27 +08:00
public const int COMBINE_OP = 7;
2024-04-15 01:18:08 +08:00
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-11-01 12:41:10 +08:00
return leftMaskID == other.leftMaskID && rightMaskID == other.rightMaskID && operation == other.operation;
2024-04-15 01:18:08 +08:00
}
public override int GetHashCode()
{
return leftMaskID ^ (rightMaskID * operation);
}
}
2024-10-02 22:13:10 +08:00
#endregion
2024-01-07 19:32:16 +08:00
#region Builder
internal readonly struct WorldMaskComponent : IEcsWorldComponent<WorldMaskComponent>
2024-01-11 00:48:39 +08:00
{
private readonly EcsWorld _world;
2024-04-15 01:18:08 +08:00
private readonly Dictionary<OpMaskKey, EcsMask> _opMasks;
2024-10-31 14:46:21 +08:00
private readonly SparseArray<EcsMask> _staticMasks;
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-10-31 14:46:21 +08:00
public WorldMaskComponent(EcsWorld world)
2024-01-11 00:48:39 +08:00
{
_world = world;
2024-10-02 22:13:10 +08:00
_opMasks = new Dictionary<OpMaskKey, EcsMask>(256);
2024-10-31 14:46:21 +08:00
_staticMasks = new SparseArray<EcsMask>(256);
2024-10-31 16:27:53 +08:00
EmptyMask = CreateEmpty(_staticMasks.Count, world.ID);
2024-10-31 14:46:21 +08:00
_staticMasks.Add(EmptyMask._staticMask.ID, EmptyMask);
2024-10-31 16:27:53 +08:00
BrokenMask = CreateBroken(_staticMasks.Count, world.ID);
2024-10-31 14:46:21 +08:00
_staticMasks.Add(BrokenMask._staticMask.ID, BrokenMask);
2024-01-11 00:48:39 +08:00
}
public void Init(ref WorldMaskComponent component, EcsWorld world)
{
2024-10-31 14:46:21 +08:00
component = new WorldMaskComponent(world);
2024-01-11 00:48:39 +08:00
}
public void OnDestroy(ref WorldMaskComponent component, EcsWorld world)
{
2024-04-15 01:18:08 +08:00
component._opMasks.Clear();
2024-10-31 14:46:21 +08:00
component._staticMasks.Clear();
2024-01-11 00:48:39 +08:00
component = default;
}
#endregion
#region GetMask
2024-10-05 19:10:27 +08:00
internal EcsMask CombineMask(EcsMask a, EcsMask b)
{
int operation = OpMaskKey.COMBINE_OP;
2024-11-01 12:41:10 +08:00
if (_opMasks.TryGetValue(new OpMaskKey(a.ID, b.ID, operation), out EcsMask result) == false)
2024-10-05 19:10:27 +08:00
{
if (a.IsConflictWith(b))
{
return a.World.Get<WorldMaskComponent>().BrokenMask;
}
2024-10-31 14:46:21 +08:00
result = ConvertFromStatic(EcsStaticMask.New().Combine(a._staticMask).Combine(b._staticMask).Build());
2024-11-01 12:41:10 +08:00
_opMasks.Add(new OpMaskKey(a.ID, b.ID, operation), result);
2024-10-05 19:10:27 +08:00
}
return result;
}
2024-04-15 01:18:08 +08:00
internal EcsMask ExceptMask(EcsMask a, EcsMask b)
{
int operation = OpMaskKey.EXCEPT_OP;
2024-11-01 12:41:10 +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-10-31 14:46:21 +08:00
result = ConvertFromStatic(EcsStaticMask.New().Combine(a._staticMask).Except(b._staticMask).Build());
2024-11-01 12:41:10 +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
2024-10-31 14:46:21 +08:00
internal EcsMask ConvertFromStatic(EcsStaticMask staticMask)
2024-01-07 18:52:54 +08:00
{
2025-05-20 11:12:30 +08:00
2024-01-11 00:48:39 +08:00
2024-10-31 14:46:21 +08:00
if (_staticMasks.TryGetValue(staticMask.ID, out EcsMask result) == false)
2024-01-07 18:52:54 +08:00
{
2025-05-20 11:12:30 +08:00
result = new EcsMask(staticMask, _staticMasks.Count, _world.ID);
2024-10-31 14:46:21 +08:00
_staticMasks.Add(staticMask.ID, result);
2024-01-07 18:52:54 +08:00
}
2024-10-31 14:46:21 +08:00
return result;
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-11-01 12:41:10 +08:00
public partial struct Builder
2024-01-07 18:52:54 +08:00
{
2024-10-31 14:46:21 +08:00
private readonly EcsStaticMask.Builder _builder;
2024-01-07 19:32:16 +08:00
private readonly EcsWorld _world;
2024-01-07 18:52:54 +08:00
2024-10-31 14:46:21 +08:00
public Builder(EcsWorld world)
2024-01-07 18:52:54 +08:00
{
_world = world;
2024-11-01 12:41:10 +08:00
_builder = EcsStaticMask.New();
2024-01-07 18:52:54 +08:00
}
2024-04-15 01:18:08 +08:00
2024-10-31 14:46:21 +08:00
public Builder Inc<T>() { _builder.Inc<T>(); return this; }
public Builder Exc<T>() { _builder.Exc<T>(); return this; }
2025-05-19 20:30:18 +08:00
public Builder Any<T>() { _builder.Any<T>(); return this; }
2024-10-31 14:46:21 +08:00
public Builder Inc(Type type) { _builder.Inc(type); return this; }
public Builder Exc(Type type) { _builder.Exc(type); return this; }
2025-05-19 20:30:18 +08:00
public Builder Any(Type type) { _builder.Any(type); return this; }
2024-10-31 14:46:21 +08:00
public Builder Inc(EcsTypeCode typeCode) { _builder.Inc(typeCode); return this; }
public Builder Exc(EcsTypeCode typeCode) { _builder.Exc(typeCode); return this; }
2025-05-19 20:30:18 +08:00
public Builder Any(EcsTypeCode typeCode) { _builder.Any(typeCode); return this; }
2024-10-31 14:46:21 +08:00
public Builder Combine(EcsMask mask) { _builder.Combine(mask._staticMask); return this; }
public Builder Except(EcsMask mask) { _builder.Except(mask._staticMask); return this; }
2024-04-18 22:14:50 +08:00
2024-10-31 14:46:21 +08:00
public EcsMask Build() { return _world.Get<WorldMaskComponent>().ConvertFromStatic(_builder.Build()); }
2024-04-18 22:14:50 +08:00
}
2024-01-07 19:32:16 +08:00
#endregion
2024-11-01 12:41:10 +08:00
#region Debug utils
2025-05-19 20:30:18 +08:00
private static string CreateLogString(short worldID, int[] incs, int[] excs, int[] anys)
2024-11-01 12:41:10 +08:00
{
2025-03-14 16:53:25 +08:00
#if DEBUG
2024-11-01 12:41:10 +08:00
string converter(int o) { return EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1); }
2025-05-20 11:12:30 +08:00
return $"Inc({string.Join(", ", incs.Select(converter))}); Exc({string.Join(", ", excs.Select(converter))}); Any({string.Join(", ", anys.Select(converter))})";
2024-11-01 12:41:10 +08:00
#else
2025-05-20 11:12:30 +08:00
return $"Inc({string.Join(", ", incs)}); Exc({string.Join(", ", excs)}; Any({string.Join(", ", anys)})"; // Release optimization
2024-11-01 12:41:10 +08:00
#endif
}
internal class DebuggerProxy
{
private EcsMask _source;
public readonly int ID;
public readonly EcsWorld world;
private readonly short _worldID;
public readonly EcsMaskChunck[] includedChunkMasks;
public readonly EcsMaskChunck[] excludedChunkMasks;
2025-05-19 20:30:18 +08:00
public readonly EcsMaskChunck[] anyChunkMasks;
2024-11-01 12:41:10 +08:00
public readonly int[] included;
public readonly int[] excluded;
2025-05-19 20:30:18 +08:00
public readonly int[] any;
2024-11-01 12:41:10 +08:00
public readonly Type[] includedTypes;
public readonly Type[] excludedTypes;
2025-05-19 20:30:18 +08:00
public readonly Type[] anyTypes;
2024-11-01 12:41:10 +08:00
public bool IsEmpty { get { return _source.IsEmpty; } }
public bool IsBroken { get { return _source.IsBroken; } }
public DebuggerProxy(EcsMask mask)
{
_source = mask;
ID = mask.ID;
world = EcsWorld.GetWorld(mask.WorldID);
_worldID = mask.WorldID;
includedChunkMasks = mask._incChunckMasks;
excludedChunkMasks = mask._excChunckMasks;
2025-05-19 20:30:18 +08:00
anyChunkMasks = mask._anyChunckMasks;
2024-11-01 12:41:10 +08:00
included = mask._incs;
excluded = mask._excs;
2025-05-19 20:30:18 +08:00
any = mask._anys;
2024-11-01 12:41:10 +08:00
Type converter(int o) { return world.GetComponentType(o); }
includedTypes = included.Select(converter).ToArray();
excludedTypes = excluded.Select(converter).ToArray();
2025-05-19 20:30:18 +08:00
anyTypes = any.Select(converter).ToArray();
2024-11-01 12:41:10 +08:00
}
public override string ToString()
{
2025-05-19 20:30:18 +08:00
return CreateLogString(_worldID, included, excluded, any);
2024-11-01 12:41:10 +08:00
}
}
#endregion
#region Obsolete
/// <summary> Sorted set including constraints. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use Incs")]
public ReadOnlySpan<int> Inc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _incs; }
}
/// <summary> Sorted set excluding constraints. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use Excs")]
public ReadOnlySpan<int> Exc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _excs; }
}
public partial struct Builder
{
[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
2024-01-07 18:52:54 +08:00
}
2025-05-20 11:12:30 +08:00
[Flags]
public enum EcsMaskFlags : byte
{
Empty = 0,
Inc = 1 << 0,
Exc = 1 << 1,
Any = 1 << 2,
IncExc = Inc | Exc,
IncAny = Inc | Any,
ExcAny = Exc | Any,
IncExcAny = Inc | Exc | Any,
Broken = IncExcAny + 1,
}
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;
2024-10-10 19:57:19 +08:00
public readonly int chunkIndex;
2024-01-07 18:52:54 +08:00
public readonly int mask;
2025-01-06 10:48:39 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsMaskChunck(int chunkIndex, int mask)
2024-01-07 18:52:54 +08:00
{
2025-01-06 10:48:39 +08:00
this.chunkIndex = chunkIndex;
2024-01-07 18:52:54 +08:00
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()
{
2024-10-10 19:57:19 +08:00
return $"mask({chunkIndex}, {mask}, {BitsUtility.CountBits(mask)})";
2024-01-07 18:52:54 +08:00
}
internal class DebuggerProxy
{
public int chunk;
public uint mask;
public int[] values = Array.Empty<int>();
public string bits;
public DebuggerProxy(EcsMaskChunck maskbits)
{
2024-10-10 19:57:19 +08:00
chunk = maskbits.chunkIndex;
2024-01-07 18:52:54 +08:00
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
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-08-24 12:29:58 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
public class EcsMaskIterator : IDisposable
2024-08-23 22:31:43 +08:00
{
2024-11-03 18:57:56 +08:00
// TODO есть идея перенести эти ChunckBuffer-ы в стек,
// для этого нужно проработать дизайн так чтобы память в стеке выделялась за пределами итератора и GetEnumerator,
// а далее передавались поинтеры, в противном случае использовался бы стандартный подход
2024-10-10 19:57:19 +08:00
public readonly EcsWorld World;
public readonly EcsMask Mask;
private readonly UnsafeArray<int> _sortIncBuffer;
private readonly UnsafeArray<int> _sortExcBuffer;
2025-05-19 20:30:18 +08:00
private readonly UnsafeArray<int> _sortAnyBuffer;
2024-11-03 18:57:56 +08:00
2024-10-10 19:57:19 +08:00
private readonly UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
private readonly UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
2025-05-19 20:30:18 +08:00
private readonly UnsafeArray<EcsMaskChunck> _sortAnyChunckBuffer;
2024-10-10 19:57:19 +08:00
2025-05-17 14:55:31 +08:00
private MemoryAllocator.Handler _bufferHandler;
private MemoryAllocator.Handler _chunckBufferHandler;
private readonly bool _isSingleIncPoolWithEntityStorage;
private readonly bool _isHasAnyEntityStorage;
2024-11-17 21:43:50 +08:00
private readonly MaskType _maskType;
2024-11-17 21:43:50 +08:00
private enum MaskType : byte
{
Empty,
OnlyInc,
IncExc,
}
2024-10-10 19:57:19 +08:00
#region Constructors/Finalizator
public unsafe EcsMaskIterator(EcsWorld source, EcsMask mask)
2024-08-23 22:31:43 +08:00
{
2024-10-10 19:57:19 +08:00
World = source;
Mask = mask;
2024-11-03 18:57:56 +08:00
2025-05-19 20:30:18 +08:00
int bufferLength = mask._incs.Length + mask._excs.Length + mask._anys.Length;
int chunckBufferLength = mask._incChunckMasks.Length + mask._excChunckMasks.Length + mask._anyChunckMasks.Length;
2025-05-17 14:55:31 +08:00
_bufferHandler = MemoryAllocator.AllocAndInit<int>(bufferLength);
_chunckBufferHandler = MemoryAllocator.AllocAndInit<EcsMaskChunck>(chunckBufferLength);
var sortBuffer = UnsafeArray<int>.Manual(_bufferHandler.As<int>(), bufferLength);
var sortChunckBuffer = UnsafeArray<EcsMaskChunck>.Manual(_chunckBufferHandler.As<EcsMaskChunck>(), chunckBufferLength);
2024-11-03 18:57:56 +08:00
_sortIncBuffer = sortBuffer.Slice(0, mask._incs.Length);
_sortIncBuffer.CopyFromArray_Unchecked(mask._incs);
_sortExcBuffer = sortBuffer.Slice(mask._incs.Length, mask._excs.Length);
_sortExcBuffer.CopyFromArray_Unchecked(mask._excs);
2025-05-19 20:30:18 +08:00
_sortAnyBuffer = sortBuffer.Slice(mask._incs.Length + mask._excs.Length, mask._anys.Length);
_sortAnyBuffer.CopyFromArray_Unchecked(mask._anys);
2024-11-03 18:57:56 +08:00
2025-05-17 14:55:31 +08:00
//EcsDebug.PrintError(_sortIncBuffer.ToArray());
//EcsDebug.PrintError(new Span<int>(_bufferHandler.GetPtrAs<int>(), _sortIncBuffer.Length).ToArray());
2024-11-03 18:57:56 +08:00
_sortIncChunckBuffer = sortChunckBuffer.Slice(0, mask._incChunckMasks.Length);
_sortIncChunckBuffer.CopyFromArray_Unchecked(mask._incChunckMasks);
_sortExcChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length, mask._excChunckMasks.Length);
_sortExcChunckBuffer.CopyFromArray_Unchecked(mask._excChunckMasks);
2025-05-19 20:30:18 +08:00
_sortAnyChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length + mask._excChunckMasks.Length, mask._anyChunckMasks.Length);
_sortAnyChunckBuffer.CopyFromArray_Unchecked(mask._anyChunckMasks);
2024-11-03 18:57:56 +08:00
_isHasAnyEntityStorage = false;
var pools = source.AllPools;
for (int i = 0; i < _sortIncBuffer.Length; i++)
{
var pool = pools[_sortIncBuffer.ptr[i]];
_isHasAnyEntityStorage |= pool is IEntityStorage;
if (_isHasAnyEntityStorage) { break; }
}
_isSingleIncPoolWithEntityStorage = Mask.Excs.Length <= 0 && Mask.Incs.Length == 1;
2025-05-19 20:30:18 +08:00
if (_sortIncBuffer.Length > 0 && _sortExcBuffer.Length == 0 && _sortAnyBuffer.Length == 0)
2024-11-17 21:43:50 +08:00
{
2025-05-19 20:30:18 +08:00
_maskType = MaskType.OnlyInc;
2024-11-17 21:43:50 +08:00
}
else
{
2025-05-19 20:30:18 +08:00
_maskType = mask.IsEmpty ? MaskType.Empty : MaskType.IncExc;
2024-11-17 21:43:50 +08:00
}
2024-08-23 22:31:43 +08:00
}
2024-10-10 19:57:19 +08:00
unsafe ~EcsMaskIterator()
{
Cleanup(false);
}
public void Dispose()
{
Cleanup(true);
GC.SuppressFinalize(this);
}
private void Cleanup(bool disposing)
2024-08-23 22:31:43 +08:00
{
2025-05-17 14:55:31 +08:00
_bufferHandler.Dispose();
_chunckBufferHandler.Dispose();
2024-08-23 22:31:43 +08:00
}
#endregion
#region SortConstraints/TryFindEntityStorage
2024-11-03 18:57:56 +08:00
private unsafe int SortConstraints_Internal()
{
UnsafeArray<int> sortIncBuffer = _sortIncBuffer;
UnsafeArray<int> sortExcBuffer = _sortExcBuffer;
2025-05-19 20:30:18 +08:00
UnsafeArray<int> sortAnyBuffer = _sortAnyBuffer;
2024-11-03 18:57:56 +08:00
EcsWorld.PoolSlot[] counts = World._poolSlots;
2025-05-19 20:30:18 +08:00
int maxBufferSize = Math.Max(Math.Max(sortIncBuffer.Length, sortExcBuffer.Length), sortAnyBuffer.Length);
2024-11-03 18:57:56 +08:00
int maxEntites = int.MaxValue;
EcsMaskChunck* preSortingBuffer;
2024-11-06 18:27:33 +08:00
if (maxBufferSize < STACK_BUFFER_THRESHOLD)
2024-11-03 18:57:56 +08:00
{
2024-11-06 18:27:33 +08:00
EcsMaskChunck* ptr = stackalloc EcsMaskChunck[maxBufferSize];
preSortingBuffer = ptr;
2024-11-03 18:57:56 +08:00
}
else
{
2025-05-18 00:49:12 +08:00
preSortingBuffer = TempBuffer<EcsMaskIterator, EcsMaskChunck>.Get(maxBufferSize);
2024-11-03 18:57:56 +08:00
}
if (_sortIncChunckBuffer.Length > 1)
{
var comparer = new IncCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(sortIncBuffer.ptr, sortIncBuffer.Length, ref comparer);
ConvertToChuncks(preSortingBuffer, sortIncBuffer, _sortIncChunckBuffer);
}
if (_sortIncChunckBuffer.Length > 0)
{
maxEntites = counts[_sortIncBuffer.ptr[0]].count;
if (maxEntites <= 0)
{
return 0;
}
}
if (_sortExcChunckBuffer.Length > 1)
{
ExcCountComparer comparer = new ExcCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(sortExcBuffer.ptr, sortExcBuffer.Length, ref comparer);
ConvertToChuncks(preSortingBuffer, sortExcBuffer, _sortExcChunckBuffer);
}
2025-05-19 20:30:18 +08:00
// Выражение IncCount < (AllEntitesCount - ExcCount) мало вероятно будет истинным.
2024-11-03 18:57:56 +08:00
// ExcCount = максимальное количество ентитей с исключеющим ограничением и IncCount = минимальоне количество ентитей с включающим ограничением
// Поэтому исключающее ограничение игнорируется для maxEntites.
2025-05-19 20:30:18 +08:00
if (_sortAnyChunckBuffer.Length > 1)
{
//TODO проверить для Any
ExcCountComparer comparer = new ExcCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(sortAnyBuffer.ptr, sortAnyBuffer.Length, ref comparer);
ConvertToChuncks(preSortingBuffer, sortAnyBuffer, _sortAnyChunckBuffer);
}
2024-11-03 18:57:56 +08:00
return maxEntites;
}
2025-05-15 11:25:18 +08:00
private unsafe bool TryGetEntityStorage(out IEntityStorage storage)
{
if (_isHasAnyEntityStorage)
{
var pools = World.AllPools;
for (int i = 0; i < _sortIncBuffer.Length; i++)
{
var pool = pools[_sortIncBuffer.ptr[i]];
storage = pool as IEntityStorage;
if (storage != null)
{
return true;
}
}
}
storage = null;
return false;
}
2024-11-03 18:57:56 +08:00
#endregion
2024-08-23 22:31:43 +08:00
2024-10-10 19:57:19 +08:00
#region IterateTo
2025-03-10 13:01:08 +08:00
//TODO Перемеиноваться в CacheTo
2024-10-10 19:57:19 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IterateTo(EcsSpan source, EcsGroup group)
2024-08-23 22:31:43 +08:00
{
2024-11-17 21:43:50 +08:00
switch (_maskType)
2024-08-24 12:29:58 +08:00
{
2024-11-17 21:43:50 +08:00
case MaskType.Empty:
group.CopyFrom(source);
break;
case MaskType.OnlyInc:
IterateOnlyInc(source).CopyTo(group);
break;
case MaskType.IncExc:
Iterate(source).CopyTo(group);
break;
default:
Throw.UndefinedException();
break;
2024-08-24 12:29:58 +08:00
}
2024-10-10 19:57:19 +08:00
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IterateTo(EcsSpan source, ref int[] array)
{
2024-11-17 21:43:50 +08:00
switch (_maskType)
2024-08-24 12:29:58 +08:00
{
2024-11-17 21:43:50 +08:00
case MaskType.Empty:
return source.ToArray(ref array);
case MaskType.OnlyInc:
return IterateOnlyInc(source).CopyTo(ref array);
case MaskType.IncExc:
return Iterate(source).CopyTo(ref array);
default:
Throw.UndefinedException();
return 0;
2024-08-24 12:29:58 +08:00
}
}
#endregion
2024-10-10 19:57:19 +08:00
#region Iterate/Enumerable
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Enumerable Iterate(EcsSpan span) { return new Enumerable(this, span); }
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
2024-08-23 22:31:43 +08:00
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
2024-10-10 19:57:19 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-08-23 22:31:43 +08:00
public void CopyTo(EcsGroup group)
{
group.Clear();
var enumerator = GetEnumerator();
while (enumerator.MoveNext())
{
group.AddUnchecked(enumerator.Current);
}
}
2024-10-10 19:57:19 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-08-23 22:31:43 +08:00
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;
}
#endregion
#region Other
2024-10-10 19:57:19 +08:00
public List<int> ToList()
2024-08-23 22:31:43 +08:00
{
List<int> ints = new List<int>();
2024-10-10 19:57:19 +08:00
foreach (var e in this) { ints.Add(e); }
return ints;
2024-08-23 22:31:43 +08:00
}
2024-10-10 19:57:19 +08:00
public override string ToString() { return CollectionUtility.EntitiesToString(ToList(), "it"); }
2024-08-23 22:31:43 +08:00
#endregion
#region Enumerator
2024-11-03 18:57:56 +08:00
public Enumerator GetEnumerator()
{
if (_iterator.Mask.IsBroken)
{
return new Enumerator(_span.Slice(0, 0), _iterator);
}
int maxEntities = _iterator.SortConstraints_Internal();
if (maxEntities <= 0)
{
return new Enumerator(_span.Slice(0, 0), _iterator);
}
2025-05-15 11:25:18 +08:00
if (_span.IsSourceEntities && _iterator.TryGetEntityStorage(out IEntityStorage storage))
{
return new Enumerator(storage.ToSpan(), _iterator);
}
else
{
return new Enumerator(_span, _iterator);
}
2024-11-03 18:57:56 +08:00
}
2024-10-10 19:57:19 +08:00
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
2025-05-15 20:41:02 +08:00
public ref struct Enumerator
2024-08-23 22:31:43 +08:00
{
private ReadOnlySpan<int>.Enumerator _span;
2024-10-10 19:57:19 +08:00
private readonly UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
private readonly UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
2025-05-19 20:30:18 +08:00
private readonly UnsafeArray<EcsMaskChunck> _sortAnyChunckBuffer;
2024-08-23 22:31:43 +08:00
2024-10-10 19:57:19 +08:00
private readonly int[] _entityComponentMasks;
2024-08-23 22:31:43 +08:00
private readonly int _entityComponentMaskLengthBitShift;
public unsafe Enumerator(EcsSpan span, EcsMaskIterator iterator)
{
_sortIncChunckBuffer = iterator._sortIncChunckBuffer;
_sortExcChunckBuffer = iterator._sortExcChunckBuffer;
2025-05-19 20:30:18 +08:00
_sortAnyChunckBuffer = iterator._sortAnyChunckBuffer;
2024-08-23 22:31:43 +08:00
2024-10-10 19:57:19 +08:00
_entityComponentMasks = iterator.World._entityComponentMasks;
2024-08-23 22:31:43 +08:00
_entityComponentMaskLengthBitShift = iterator.World._entityComponentMaskLengthBitShift;
_span = span.GetEnumerator();
}
public int Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _span.Current; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2025-05-15 20:41:02 +08:00
public unsafe bool MoveNext()
2024-08-23 22:31:43 +08:00
{
while (_span.MoveNext())
{
int entityLineStartIndex = _span.Current << _entityComponentMaskLengthBitShift;
2024-08-23 22:31:43 +08:00
for (int i = 0; i < _sortIncChunckBuffer.Length; i++)
{
var bit = _sortIncChunckBuffer.ptr[i];
if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != bit.mask)
2024-08-23 22:31:43 +08:00
{
goto skip;
}
}
for (int i = 0; i < _sortExcChunckBuffer.Length; i++)
{
var bit = _sortExcChunckBuffer.ptr[i];
if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != 0)
2024-08-23 22:31:43 +08:00
{
goto skip;
}
}
2025-05-19 20:30:18 +08:00
//можно подумать над оптимизацией через кеширование bool значения, if с bool работает быстрее прочего
if(_sortAnyChunckBuffer.Length > 0)
{
int anyCount = 0;
for (int i = 0; i < _sortAnyChunckBuffer.Length; i++)
{
var bit = _sortAnyChunckBuffer.ptr[i];
if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) == bit.mask)
{
anyCount++;
}
}
if (anyCount == 0)
{
goto skip;
}
}
2024-08-23 22:31:43 +08:00
return true;
skip: continue;
}
return false;
}
}
#endregion
}
#endregion
2024-10-10 19:57:19 +08:00
#region Iterate/Enumerable OnlyInc
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public OnlyIncEnumerable IterateOnlyInc(EcsSpan span) { return new OnlyIncEnumerable(this, span); }
2024-10-10 19:57:19 +08:00
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
public readonly ref struct OnlyIncEnumerable
{
private readonly EcsMaskIterator _iterator;
private readonly EcsSpan _span;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public OnlyIncEnumerable(EcsMaskIterator iterator, EcsSpan span)
{
_iterator = iterator;
_span = span;
}
#region CopyTo
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(EcsGroup group)
{
group.Clear();
var enumerator = GetEnumerator();
while (enumerator.MoveNext())
{
group.AddUnchecked(enumerator.Current);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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;
}
#endregion
#region Other
public List<int> ToList()
{
List<int> ints = new List<int>();
foreach (var e in this) { ints.Add(e); }
return ints;
}
public override string ToString() { return CollectionUtility.EntitiesToString(ToList(), "inc_it"); }
#endregion
#region Enumerator
2024-11-03 18:57:56 +08:00
public Enumerator GetEnumerator()
{
if (_iterator.Mask.IsBroken)
{
return new Enumerator(_span.Slice(0, 0), _iterator);
}
int maxEntities = _iterator.SortConstraints_Internal();
if (maxEntities <= 0)
{
return new Enumerator(_span.Slice(0, 0), _iterator);
}
2025-05-15 11:25:18 +08:00
if (_span.IsSourceEntities && _iterator.TryGetEntityStorage(out IEntityStorage storage))
{
return new Enumerator(storage.ToSpan(), _iterator);
}
else
{
return new Enumerator(_span, _iterator);
}
2024-11-03 18:57:56 +08:00
}
2024-10-10 19:57:19 +08:00
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
public unsafe ref struct Enumerator
{
private ReadOnlySpan<int>.Enumerator _span;
private readonly UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
private readonly int[] _entityComponentMasks;
private readonly int _entityComponentMaskLengthBitShift;
public unsafe Enumerator(EcsSpan span, EcsMaskIterator iterator)
{
_sortIncChunckBuffer = iterator._sortIncChunckBuffer;
_entityComponentMasks = iterator.World._entityComponentMasks;
_entityComponentMaskLengthBitShift = iterator.World._entityComponentMaskLengthBitShift;
_span = span.GetEnumerator();
}
public int Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _span.Current; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
while (_span.MoveNext())
{
int entityLineStartIndex = _span.Current << _entityComponentMaskLengthBitShift;
2024-10-10 19:57:19 +08:00
for (int i = 0; i < _sortIncChunckBuffer.Length; i++)
{
var bit = _sortIncChunckBuffer.ptr[i];
if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != bit.mask)
2024-10-10 19:57:19 +08:00
{
goto skip;
}
}
return true;
skip: continue;
}
return false;
}
}
#endregion
}
#endregion
}
#endregion
}
2025-05-18 10:52:24 +08:00
namespace DCFApixels.DragonECS.Core.Internal
2024-10-10 19:57:19 +08:00
{
#region EcsMaskIteratorUtility
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal unsafe class EcsMaskIteratorUtility
{
2024-11-06 18:27:33 +08:00
internal const int STACK_BUFFER_THRESHOLD = 100;
2024-10-10 19:57:19 +08:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2025-04-04 14:41:05 +08:00
internal static void ConvertToChuncks(EcsMaskChunck* bufferPtr, UnsafeArray<int> input, UnsafeArray<EcsMaskChunck> output)
2024-10-10 19:57:19 +08:00
{
for (int i = 0; i < input.Length; i++)
{
2025-04-04 14:41:05 +08:00
bufferPtr[i] = EcsMaskChunck.FromID(input.ptr[i]);
2024-10-10 19:57:19 +08:00
}
2025-04-04 14:41:05 +08:00
for (int inputI = 0, outputI = 0; outputI < output.Length; inputI++, bufferPtr++)
2024-10-10 19:57:19 +08:00
{
2025-04-04 14:41:05 +08:00
int stackingMask = bufferPtr->mask;
if (stackingMask == 0) { continue; }
int stackingChunkIndex = bufferPtr->chunkIndex;
2024-10-10 19:57:19 +08:00
2025-04-04 14:41:05 +08:00
EcsMaskChunck* bufferSpanPtr = bufferPtr + 1;
for (int j = 1; j < input.Length - inputI; j++, bufferSpanPtr++)
2024-10-10 19:57:19 +08:00
{
2025-04-04 14:41:05 +08:00
if (bufferSpanPtr->chunkIndex == stackingChunkIndex)
2024-10-10 19:57:19 +08:00
{
2025-04-04 14:41:05 +08:00
stackingMask |= bufferSpanPtr->mask;
*bufferSpanPtr = default;
2024-10-10 19:57:19 +08:00
}
}
2025-04-04 14:41:05 +08:00
output.ptr[outputI] = new EcsMaskChunck(stackingChunkIndex, stackingMask);
2024-10-10 19:57:19 +08:00
outputI++;
}
}
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct IncCountComparer : IStructComparer<int>
{
public readonly EcsWorld.PoolSlot[] counts;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public IncCountComparer(EcsWorld.PoolSlot[] counts)
{
this.counts = counts;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(int a, int b)
{
return counts[a].count - counts[b].count;
}
}
#if ENABLE_IL2CPP
2024-11-08 17:21:36 +08:00
[Il2CppSetOption(Option.NullChecks, false)]
2024-10-10 19:57:19 +08:00
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct ExcCountComparer : IStructComparer<int>
{
public readonly EcsWorld.PoolSlot[] counts;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ExcCountComparer(EcsWorld.PoolSlot[] counts)
{
this.counts = counts;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(int a, int b)
{
return counts[b].count - counts[a].count;
}
}
2024-08-23 22:31:43 +08:00
}
2024-08-24 12:29:58 +08:00
#endregion
2024-10-02 22:13:10 +08:00
}