2024-11-01 12:41:10 +08:00
|
|
|
|
using DCFApixels.DragonECS.Core;
|
|
|
|
|
using DCFApixels.DragonECS.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;
|
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;
|
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 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
|
|
|
|
}
|
2024-03-17 10:18:16 +08:00
|
|
|
|
public bool IsEmpty
|
|
|
|
|
{
|
2024-10-02 22:13:10 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-01 12:41:10 +08:00
|
|
|
|
get { return _incs.Length == 0 && _excs.Length == 0; }
|
2024-03-17 10:18:16 +08:00
|
|
|
|
}
|
2024-04-18 22:14:50 +08:00
|
|
|
|
public bool IsBroken
|
|
|
|
|
{
|
2024-11-01 12:41:10 +08:00
|
|
|
|
get { return (_incs.Length & _excs.Length) == 1 && _incs[0] == _excs[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
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
return new EcsMask(EcsStaticMask.Empty, id, worldID, new int[0], new int[0]);
|
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
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
return new EcsMask(EcsStaticMask.Broken, id, worldID, new int[1] { 1 }, new int[1] { 1 });
|
2024-04-18 22:14:50 +08:00
|
|
|
|
}
|
2024-10-31 14:46:21 +08:00
|
|
|
|
private EcsMask(EcsStaticMask staticMask, int id, short worldID, int[] inc, int[] exc)
|
2024-04-18 22:14:50 +08:00
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
_staticMask = staticMask;
|
2024-11-01 12:41:10 +08:00
|
|
|
|
ID = id;
|
|
|
|
|
_incs = inc;
|
|
|
|
|
_excs = exc;
|
|
|
|
|
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]);
|
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()
|
|
|
|
|
{
|
2024-11-01 12:41:10 +08:00
|
|
|
|
return CreateLogString(WorldID, _incs, _excs);
|
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
|
2024-12-04 16:09:52 +08:00
|
|
|
|
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
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
int[] ConvertTypeCodeToComponentTypeID(ReadOnlySpan<EcsTypeCode> from, EcsWorld world)
|
2024-01-11 00:48:39 +08:00
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
int[] to = new int[from.Length];
|
|
|
|
|
for (int i = 0; i < to.Length; i++)
|
2024-01-11 00:48:39 +08:00
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
to[i] = world.DeclareOrGetComponentTypeID(from[i]);
|
2024-01-11 00:48:39 +08:00
|
|
|
|
}
|
2024-10-31 14:46:21 +08:00
|
|
|
|
Array.Sort(to);
|
|
|
|
|
return to;
|
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
|
|
|
|
{
|
2024-10-31 14:46:21 +08:00
|
|
|
|
int[] incs = ConvertTypeCodeToComponentTypeID(staticMask.IncTypeCodes, _world);
|
|
|
|
|
int[] excs = ConvertTypeCodeToComponentTypeID(staticMask.ExcTypeCodes, _world);
|
|
|
|
|
|
2024-10-31 16:27:53 +08:00
|
|
|
|
result = new EcsMask(staticMask, _staticMasks.Count, _world.ID, incs, excs);
|
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; }
|
|
|
|
|
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; }
|
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
|
|
|
|
|
private static string CreateLogString(short worldID, int[] inc, int[] exc)
|
|
|
|
|
{
|
|
|
|
|
#if (DEBUG && !DISABLE_DEBUG)
|
|
|
|
|
string converter(int o) { return EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1); }
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
public readonly int[] included;
|
|
|
|
|
public readonly int[] excluded;
|
|
|
|
|
public readonly Type[] includedTypes;
|
|
|
|
|
public readonly Type[] excludedTypes;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
included = mask._incs;
|
|
|
|
|
excluded = mask._excs;
|
|
|
|
|
Type converter(int o) { return world.GetComponentType(o); }
|
|
|
|
|
includedTypes = included.Select(converter).ToArray();
|
|
|
|
|
excludedTypes = excluded.Select(converter).ToArray();
|
|
|
|
|
}
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return CreateLogString(_worldID, included, excluded);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#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
|
|
|
|
}
|
|
|
|
|
|
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
|
2024-08-23 22:31:43 +08:00
|
|
|
|
public class EcsMaskIterator
|
|
|
|
|
{
|
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;
|
2024-11-03 18:57:56 +08:00
|
|
|
|
/// <summary> slised _sortIncBuffer </summary>
|
2024-10-10 19:57:19 +08:00
|
|
|
|
private readonly UnsafeArray<int> _sortExcBuffer;
|
2024-11-03 18:57:56 +08:00
|
|
|
|
|
2024-10-10 19:57:19 +08:00
|
|
|
|
private readonly UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
|
2024-11-03 18:57:56 +08:00
|
|
|
|
/// <summary> slised _sortIncChunckBuffer </summary>
|
2024-10-10 19:57:19 +08:00
|
|
|
|
private readonly UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
|
|
|
|
|
2025-03-11 14:30:33 +08:00
|
|
|
|
private readonly bool _isSingleIncPoolWithEntityStorage;
|
|
|
|
|
private readonly bool _isHasAnyEntityStorage;
|
2024-11-17 21:43:50 +08:00
|
|
|
|
private readonly MaskType _maskType;
|
2025-03-11 14:30:33 +08:00
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
var sortBuffer = new UnsafeArray<int>(mask._incs.Length + mask._excs.Length);
|
|
|
|
|
var sortChunckBuffer = new UnsafeArray<EcsMaskChunck>(mask._incChunckMasks.Length + mask._excChunckMasks.Length);
|
|
|
|
|
|
|
|
|
|
_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);
|
|
|
|
|
|
|
|
|
|
_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-03-11 14:30:33 +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;
|
2024-11-17 21:43:50 +08:00
|
|
|
|
if (_sortExcBuffer.Length <= 0)
|
|
|
|
|
{
|
|
|
|
|
_maskType = mask.IsEmpty ? MaskType.Empty : MaskType.OnlyInc;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_maskType = MaskType.IncExc;
|
|
|
|
|
}
|
2024-08-23 22:31:43 +08:00
|
|
|
|
}
|
2024-10-10 19:57:19 +08:00
|
|
|
|
unsafe ~EcsMaskIterator()
|
2024-08-23 22:31:43 +08:00
|
|
|
|
{
|
2024-10-10 19:57:19 +08:00
|
|
|
|
_sortIncBuffer.ReadonlyDispose();
|
2024-11-03 18:57:56 +08:00
|
|
|
|
//_sortExcBuffer.ReadonlyDispose();// использует общую памяять с _sortIncBuffer;
|
2024-10-10 19:57:19 +08:00
|
|
|
|
_sortIncChunckBuffer.ReadonlyDispose();
|
2024-11-03 18:57:56 +08:00
|
|
|
|
//_sortExcChunckBuffer.ReadonlyDispose();// использует общую памяять с _sortIncChunckBuffer;
|
2024-08-23 22:31:43 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
2024-11-03 18:57:56 +08:00
|
|
|
|
#region SortConstraints
|
|
|
|
|
private unsafe int SortConstraints_Internal()
|
|
|
|
|
{
|
|
|
|
|
UnsafeArray<int> sortIncBuffer = _sortIncBuffer;
|
|
|
|
|
UnsafeArray<int> sortExcBuffer = _sortExcBuffer;
|
|
|
|
|
|
|
|
|
|
EcsWorld.PoolSlot[] counts = World._poolSlots;
|
|
|
|
|
int maxBufferSize = sortIncBuffer.Length > sortExcBuffer.Length ? sortIncBuffer.Length : sortExcBuffer.Length;
|
|
|
|
|
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
|
|
|
|
|
{
|
2024-11-06 18:27:33 +08:00
|
|
|
|
preSortingBuffer = TempBuffer<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);
|
|
|
|
|
}
|
|
|
|
|
// Выражение мало IncCount < (AllEntitesCount - ExcCount) вероятно будет истинным.
|
|
|
|
|
// ExcCount = максимальное количество ентитей с исключеющим ограничением и IncCount = минимальоне количество ентитей с включающим ограничением
|
|
|
|
|
// Поэтому исключающее ограничение игнорируется для maxEntites.
|
|
|
|
|
return maxEntites;
|
|
|
|
|
}
|
2025-03-11 14:30:33 +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-03-11 14:30:33 +08:00
|
|
|
|
if (_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
|
2024-08-23 22:31:43 +08:00
|
|
|
|
public unsafe ref struct Enumerator
|
|
|
|
|
{
|
|
|
|
|
private ReadOnlySpan<int>.Enumerator _span;
|
|
|
|
|
|
2024-10-10 19:57:19 +08:00
|
|
|
|
private readonly UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
|
|
|
|
|
private readonly UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
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;
|
|
|
|
|
|
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)]
|
|
|
|
|
public bool MoveNext()
|
|
|
|
|
{
|
|
|
|
|
while (_span.MoveNext())
|
|
|
|
|
{
|
2024-11-06 13:46:20 +08:00
|
|
|
|
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];
|
2024-11-06 13:46:20 +08:00
|
|
|
|
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];
|
2024-11-06 13:46:20 +08:00
|
|
|
|
if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) != 0)
|
2024-08-23 22:31:43 +08:00
|
|
|
|
{
|
|
|
|
|
goto skip;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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); }
|
|
|
|
|
#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-03-12 15:29:16 +08:00
|
|
|
|
if (_span.IsSourceEntities && _iterator.TryGetEntityStorage(out IEntityStorage storage))
|
2025-03-11 14:30:33 +08:00
|
|
|
|
{
|
|
|
|
|
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())
|
|
|
|
|
{
|
2024-11-06 13:46:20 +08:00
|
|
|
|
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];
|
2024-11-06 13:46:20 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace DCFApixels.DragonECS.Internal
|
|
|
|
|
{
|
|
|
|
|
#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)]
|
|
|
|
|
internal static void ConvertToChuncks(EcsMaskChunck* ptr, UnsafeArray<int> input, UnsafeArray<EcsMaskChunck> output)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < input.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
ptr[i] = EcsMaskChunck.FromID(input.ptr[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int inputI = 0, outputI = 0; outputI < output.Length; inputI++, ptr++)
|
|
|
|
|
{
|
|
|
|
|
int maskX = ptr->mask;
|
|
|
|
|
if (maskX == 0) { continue; }
|
|
|
|
|
int chunkIndexX = ptr->chunkIndex;
|
|
|
|
|
|
|
|
|
|
EcsMaskChunck* subptr = ptr;
|
|
|
|
|
for (int j = 1; j < input.Length - inputI; j++, subptr++)
|
|
|
|
|
{
|
|
|
|
|
if (subptr->chunkIndex == chunkIndexX)
|
|
|
|
|
{
|
|
|
|
|
maskX |= subptr->mask;
|
|
|
|
|
*subptr = default;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
output.ptr[outputI] = new EcsMaskChunck(chunkIndexX, maskX);
|
|
|
|
|
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
|
|
|
|
}
|