2025-03-14 16:53:25 +08:00
|
|
|
|
#if DISABLE_DEBUG
|
|
|
|
|
#undef DEBUG
|
|
|
|
|
#endif
|
|
|
|
|
using DCFApixels.DragonECS.Core;
|
2025-05-18 10:52:24 +08:00
|
|
|
|
using DCFApixels.DragonECS.Core.Internal;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
|
#if ENABLE_IL2CPP
|
|
|
|
|
using Unity.IL2CPP.CompilerServices;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
namespace DCFApixels.DragonECS
|
|
|
|
|
{
|
|
|
|
|
#if ENABLE_IL2CPP
|
2024-11-08 17:21:36 +08:00
|
|
|
|
[Il2CppSetOption(Option.NullChecks, false)]
|
2024-10-31 14:46:21 +08:00
|
|
|
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
|
|
|
|
#endif
|
|
|
|
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public sealed class EcsStaticMask : IEquatable<EcsStaticMask>, IComponentMask
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
|
|
|
|
public static readonly EcsStaticMask Empty;
|
|
|
|
|
public static readonly EcsStaticMask Broken;
|
|
|
|
|
|
|
|
|
|
private static readonly Stack<BuilderInstance> _buildersPool = new Stack<BuilderInstance>();
|
|
|
|
|
private static readonly ConcurrentDictionary<Key, EcsStaticMask> _ids = new ConcurrentDictionary<Key, EcsStaticMask>();
|
|
|
|
|
private static readonly IdDispenser _idDIspenser = new IdDispenser(nullID: 0);
|
|
|
|
|
private static readonly object _lock = new object();
|
|
|
|
|
|
|
|
|
|
static EcsStaticMask()
|
|
|
|
|
{
|
2024-11-01 13:49:29 +08:00
|
|
|
|
EcsStaticMask createMask(int id, Key key)
|
2024-11-01 12:48:53 +08:00
|
|
|
|
{
|
2024-11-01 13:49:29 +08:00
|
|
|
|
EcsStaticMask result = new EcsStaticMask(id, key);
|
2024-11-01 12:48:53 +08:00
|
|
|
|
_ids[key] = result;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2025-05-19 20:30:18 +08:00
|
|
|
|
Empty = createMask(0, new Key(new EcsTypeCode[0], new EcsTypeCode[0], new EcsTypeCode[0]));
|
|
|
|
|
Broken = createMask(_idDIspenser.UseFree(), new Key(new EcsTypeCode[1] { (EcsTypeCode)1 }, new EcsTypeCode[1] { (EcsTypeCode)1 }, new EcsTypeCode[0]));
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public readonly int ID;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
/// <summary> Sorted </summary>
|
2024-11-01 12:41:10 +08:00
|
|
|
|
private readonly EcsTypeCode[] _incs;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
/// <summary> Sorted </summary>
|
2024-11-01 12:41:10 +08:00
|
|
|
|
private readonly EcsTypeCode[] _excs;
|
2025-05-19 20:30:18 +08:00
|
|
|
|
/// <summary> Sorted </summary>
|
|
|
|
|
private readonly EcsTypeCode[] _anys;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
|
2025-05-20 11:12:30 +08:00
|
|
|
|
private readonly EcsMaskFlags _flags;
|
|
|
|
|
|
2024-10-31 14:46:21 +08:00
|
|
|
|
#region Properties
|
|
|
|
|
/// <summary> Sorted set including constraints presented as global type codes. </summary>
|
|
|
|
|
public ReadOnlySpan<EcsTypeCode> IncTypeCodes
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-01 12:41:10 +08:00
|
|
|
|
get { return _incs; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
/// <summary> Sorted set excluding constraints presented as global type codes. </summary>
|
|
|
|
|
public ReadOnlySpan<EcsTypeCode> ExcTypeCodes
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-01 12:41:10 +08:00
|
|
|
|
get { return _excs; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2025-05-19 20:30:18 +08:00
|
|
|
|
/// <summary> Sorted set excluding constraints presented as global type codes. </summary>
|
|
|
|
|
public ReadOnlySpan<EcsTypeCode> AnyTypeCodes
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get { return _anys; }
|
|
|
|
|
}
|
2025-05-20 11:12:30 +08:00
|
|
|
|
public EcsMaskFlags Flags
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
get { return _flags; }
|
|
|
|
|
}
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public bool IsEmpty
|
|
|
|
|
{
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2025-05-20 11:12:30 +08:00
|
|
|
|
get { return _flags == EcsMaskFlags.Empty; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
public bool IsBroken
|
|
|
|
|
{
|
2025-05-20 11:12:30 +08:00
|
|
|
|
get { return (_flags & EcsMaskFlags.Broken) != 0; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constrcutors
|
2024-11-01 12:41:10 +08:00
|
|
|
|
private EcsStaticMask(int id, Key key)
|
|
|
|
|
{
|
|
|
|
|
ID = id;
|
2024-11-01 12:48:53 +08:00
|
|
|
|
_incs = key.Incs;
|
|
|
|
|
_excs = key.Excs;
|
2025-05-19 20:30:18 +08:00
|
|
|
|
_anys = key.Anys;
|
2025-05-20 11:12:30 +08:00
|
|
|
|
if (_incs.Length > 0) { _flags |= EcsMaskFlags.Inc; }
|
|
|
|
|
if (_excs.Length > 0) { _flags |= EcsMaskFlags.Exc; }
|
|
|
|
|
if (_anys.Length > 0) { _flags |= EcsMaskFlags.Any; }
|
|
|
|
|
if ((_incs.Length & _excs.Length) == 1 && _incs[0] == _excs[0])
|
|
|
|
|
{
|
|
|
|
|
_flags = EcsMaskFlags.Broken;
|
|
|
|
|
}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
}
|
|
|
|
|
public static Builder New() { return Builder.New(); }
|
|
|
|
|
public static Builder Inc<T>() { return Builder.New().Inc<T>(); }
|
|
|
|
|
public static Builder Exc<T>() { return Builder.New().Exc<T>(); }
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public static Builder Any<T>() { return Builder.New().Any<T>(); }
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public static Builder Inc(Type type) { return Builder.New().Inc(type); }
|
|
|
|
|
public static Builder Exc(Type type) { return Builder.New().Exc(type); }
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public static Builder Any(Type type) { return Builder.New().Any(type); }
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public static Builder Inc(EcsTypeCode typeCode) { return Builder.New().Inc(typeCode); }
|
|
|
|
|
public static Builder Exc(EcsTypeCode typeCode) { return Builder.New().Exc(typeCode); }
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public static Builder Any(EcsTypeCode typeCode) { return Builder.New().Any(typeCode); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
private static EcsStaticMask CreateMask(Key key)
|
|
|
|
|
{
|
|
|
|
|
if (_ids.TryGetValue(key, out EcsStaticMask result) == false)
|
|
|
|
|
{
|
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
if (_ids.TryGetValue(key, out result) == false)
|
|
|
|
|
{
|
2024-11-01 12:48:53 +08:00
|
|
|
|
#if DEBUG
|
2025-05-20 11:12:30 +08:00
|
|
|
|
CheckConstraints(key.Incs, key.Excs, key.Anys);
|
2024-11-01 12:48:53 +08:00
|
|
|
|
#endif
|
2024-10-31 14:46:21 +08:00
|
|
|
|
result = new EcsStaticMask(_idDIspenser.UseFree(), key);
|
|
|
|
|
_ids[key] = result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Checks
|
2025-05-20 11:12:30 +08:00
|
|
|
|
//TODO доработать проверки с учетом Any
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public bool IsSubmaskOf(EcsStaticMask otherMask)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2024-11-01 12:41:10 +08:00
|
|
|
|
return IsSubmask(otherMask, this);
|
|
|
|
|
}
|
|
|
|
|
public bool IsSupermaskOf(EcsStaticMask otherMask)
|
|
|
|
|
{
|
|
|
|
|
return IsSubmask(this, otherMask);
|
|
|
|
|
}
|
|
|
|
|
public bool IsConflictWith(EcsStaticMask otherMask)
|
|
|
|
|
{
|
2025-05-20 11:12:30 +08:00
|
|
|
|
return OverlapsArray(_incs, otherMask._excs) || OverlapsArray(_excs, otherMask._incs) || OverlapsArray(_anys, otherMask._excs) || OverlapsArray(_anys, otherMask._incs);
|
2024-11-01 12:41:10 +08:00
|
|
|
|
}
|
|
|
|
|
private static bool IsSubmask(EcsStaticMask super, EcsStaticMask sub)
|
|
|
|
|
{
|
2025-05-20 11:12:30 +08:00
|
|
|
|
return IsSubarray(sub._incs, super._incs) && IsSuperarray(sub._excs, super._excs) && IsSubarray(sub._anys, super._anys);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 12:41:10 +08:00
|
|
|
|
private static bool OverlapsArray(EcsTypeCode[] l, EcsTypeCode[] r)
|
|
|
|
|
{
|
|
|
|
|
int li = 0;
|
|
|
|
|
int ri = 0;
|
|
|
|
|
while (li < l.Length && ri < r.Length)
|
|
|
|
|
{
|
|
|
|
|
if (l[li] == r[ri])
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else if (l[li] < r[ri])
|
|
|
|
|
{
|
|
|
|
|
li++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ri++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
private static bool IsSubarray(EcsTypeCode[] super, EcsTypeCode[] sub)
|
|
|
|
|
{
|
|
|
|
|
if (super.Length < sub.Length)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
int superI = 0;
|
|
|
|
|
int subI = 0;
|
|
|
|
|
|
|
|
|
|
while (superI < super.Length && subI < sub.Length)
|
|
|
|
|
{
|
|
|
|
|
if (super[superI] == sub[subI])
|
|
|
|
|
{
|
|
|
|
|
superI++;
|
|
|
|
|
}
|
|
|
|
|
subI++;
|
|
|
|
|
}
|
|
|
|
|
return subI == sub.Length;
|
|
|
|
|
}
|
|
|
|
|
private static bool IsSuperarray(EcsTypeCode[] super, EcsTypeCode[] sub)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2024-11-01 12:41:10 +08:00
|
|
|
|
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;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Methods
|
|
|
|
|
public EcsMask ToMask(EcsWorld world) { return EcsMask.FromStatic(world, this); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public bool Equals(EcsStaticMask other) { return ID == other.ID; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public override int GetHashCode() { return ID; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public override bool Equals(object obj) { return Equals((EcsStaticMask)obj); }
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public override string ToString() { return CreateLogString(_incs, _excs); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Builder
|
|
|
|
|
private readonly struct Key : IEquatable<Key>
|
|
|
|
|
{
|
2024-11-01 12:48:53 +08:00
|
|
|
|
public readonly EcsTypeCode[] Incs;
|
|
|
|
|
public readonly EcsTypeCode[] Excs;
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public readonly EcsTypeCode[] Anys;
|
2024-11-01 12:48:53 +08:00
|
|
|
|
public readonly int Hash;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
|
|
|
|
|
#region Constructors
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public Key(EcsTypeCode[] incs, EcsTypeCode[] excs, EcsTypeCode[] anys)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
this.Incs = incs;
|
|
|
|
|
this.Excs = excs;
|
|
|
|
|
this.Anys = anys;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
unchecked
|
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
Hash = incs.Length + excs.Length;
|
|
|
|
|
for (int i = 0, iMax = incs.Length; i < iMax; i++)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
Hash = Hash * EcsConsts.MAGIC_PRIME + (int)incs[i];
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2025-05-19 20:30:18 +08:00
|
|
|
|
for (int i = 0, iMax = excs.Length; i < iMax; i++)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
Hash = Hash * EcsConsts.MAGIC_PRIME - (int)excs[i];
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0, iMax = anys.Length; i < iMax; i++)
|
|
|
|
|
{
|
|
|
|
|
Hash = Hash * EcsConsts.MAGIC_PRIME + (int)anys[i];
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Object
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
|
public bool Equals(Key other)
|
|
|
|
|
{
|
2024-11-01 12:48:53 +08:00
|
|
|
|
if (Incs.Length != other.Incs.Length) { return false; }
|
|
|
|
|
if (Excs.Length != other.Excs.Length) { return false; }
|
2025-05-19 20:30:18 +08:00
|
|
|
|
if (Anys.Length != other.Anys.Length) { return false; }
|
2024-11-01 12:48:53 +08:00
|
|
|
|
for (int i = 0; i < Incs.Length; i++)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2024-11-01 12:48:53 +08:00
|
|
|
|
if (Incs[i] != other.Incs[i]) { return false; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2024-11-01 12:48:53 +08:00
|
|
|
|
for (int i = 0; i < Excs.Length; i++)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2024-11-01 12:48:53 +08:00
|
|
|
|
if (Excs[i] != other.Excs[i]) { return false; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2025-05-19 20:30:18 +08:00
|
|
|
|
for (int i = 0; i < Anys.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (Anys[i] != other.Anys[i]) { return false; }
|
|
|
|
|
}
|
2024-10-31 14:46:21 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
public override bool Equals(object obj) { return Equals((Key)obj); }
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
2024-11-01 12:48:53 +08:00
|
|
|
|
public override int GetHashCode() { return Hash; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
public readonly struct Builder
|
|
|
|
|
{
|
|
|
|
|
private readonly BuilderInstance _builder;
|
|
|
|
|
private readonly int _version;
|
|
|
|
|
|
2024-11-01 12:41:10 +08:00
|
|
|
|
#region Properties
|
|
|
|
|
public bool IsNull
|
|
|
|
|
{
|
|
|
|
|
get { return _builder == null || _builder._version != _version; }
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Constrcutors
|
|
|
|
|
private Builder(BuilderInstance builder)
|
|
|
|
|
{
|
|
|
|
|
_builder = builder;
|
|
|
|
|
_version = builder._version;
|
|
|
|
|
}
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public static Builder New()
|
|
|
|
|
{
|
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
if (_buildersPool.TryPop(out BuilderInstance builderInstance) == false)
|
|
|
|
|
{
|
|
|
|
|
builderInstance = new BuilderInstance();
|
|
|
|
|
}
|
|
|
|
|
return new Builder(builderInstance);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Inc/Exc/Combine/Except
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public Builder Inc<T>() { return Inc(EcsTypeCodeManager.Get<T>()); }
|
|
|
|
|
public Builder Exc<T>() { return Exc(EcsTypeCodeManager.Get<T>()); }
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public Builder Any<T>() { return Any(EcsTypeCodeManager.Get<T>()); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public Builder Inc(Type type) { return Inc(EcsTypeCodeManager.Get(type)); }
|
|
|
|
|
public Builder Exc(Type type) { return Exc(EcsTypeCodeManager.Get(type)); }
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public Builder Any(Type type) { return Any(EcsTypeCodeManager.Get(type)); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public Builder Inc(EcsTypeCode typeCode)
|
|
|
|
|
{
|
2024-11-06 19:55:33 +08:00
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
_builder.Inc(typeCode);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
public Builder Exc(EcsTypeCode typeCode)
|
|
|
|
|
{
|
2024-11-06 19:55:33 +08:00
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
_builder.Exc(typeCode);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2025-05-19 20:30:18 +08:00
|
|
|
|
public Builder Any(EcsTypeCode typeCode)
|
|
|
|
|
{
|
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
|
|
|
|
_builder.Any(typeCode);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public Builder Combine(EcsStaticMask mask)
|
|
|
|
|
{
|
2024-11-06 19:55:33 +08:00
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
_builder.Combine(mask);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
public Builder Except(EcsStaticMask mask)
|
|
|
|
|
{
|
2024-11-06 19:55:33 +08:00
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
_builder.Except(mask);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
#endregion
|
2024-10-31 14:46:21 +08:00
|
|
|
|
|
2024-11-01 12:41:10 +08:00
|
|
|
|
#region Build/Cancel
|
2024-10-31 14:46:21 +08:00
|
|
|
|
public EcsStaticMask Build()
|
|
|
|
|
{
|
2024-11-06 19:55:33 +08:00
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
_buildersPool.Push(_builder);
|
|
|
|
|
return _builder.Build();
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
public void Cancel()
|
|
|
|
|
{
|
2024-11-06 19:55:33 +08:00
|
|
|
|
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
|
2024-11-01 12:41:10 +08:00
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
_buildersPool.Push(_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
private class BuilderInstance
|
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
private readonly HashSet<EcsTypeCode> _incsSet = new HashSet<EcsTypeCode>();
|
|
|
|
|
private readonly HashSet<EcsTypeCode> _excsSet = new HashSet<EcsTypeCode>();
|
|
|
|
|
private readonly HashSet<EcsTypeCode> _anysSet = new HashSet<EcsTypeCode>();
|
2024-10-31 14:46:21 +08:00
|
|
|
|
private readonly List<Combined> _combineds = new List<Combined>();
|
|
|
|
|
private bool _sortedCombinedChecker = true;
|
|
|
|
|
private readonly List<Excepted> _excepteds = new List<Excepted>();
|
|
|
|
|
|
|
|
|
|
internal int _version;
|
|
|
|
|
|
|
|
|
|
#region Constrcutors
|
|
|
|
|
internal BuilderInstance() { }
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Inc/Exc/Combine/Except
|
|
|
|
|
public void Inc(EcsTypeCode typeCode)
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2025-05-19 20:30:18 +08:00
|
|
|
|
if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
2025-05-19 20:30:18 +08:00
|
|
|
|
if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { return; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
#endif
|
2025-05-19 20:30:18 +08:00
|
|
|
|
_incsSet.Add(typeCode);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
public void Exc(EcsTypeCode typeCode)
|
|
|
|
|
{
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#if DEBUG
|
2025-05-19 20:30:18 +08:00
|
|
|
|
if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); }
|
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
|
|
|
|
if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { return; }
|
|
|
|
|
#endif
|
|
|
|
|
_excsSet.Add(typeCode);
|
|
|
|
|
}
|
|
|
|
|
public void Any(EcsTypeCode typeCode)
|
|
|
|
|
{
|
|
|
|
|
#if DEBUG
|
|
|
|
|
if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); }
|
2025-03-15 15:00:07 +08:00
|
|
|
|
#elif DRAGONECS_STABILITY_MODE
|
2025-05-19 20:30:18 +08:00
|
|
|
|
if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { return; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
#endif
|
2025-05-19 20:30:18 +08:00
|
|
|
|
_anysSet.Add(typeCode);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
public void Combine(EcsStaticMask mask, int order = 0)
|
|
|
|
|
{
|
|
|
|
|
if (_sortedCombinedChecker && order != 0)
|
|
|
|
|
{
|
|
|
|
|
_sortedCombinedChecker = false;
|
|
|
|
|
}
|
|
|
|
|
_combineds.Add(new Combined(mask, order));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Except(EcsStaticMask mask, int order = 0)
|
|
|
|
|
{
|
|
|
|
|
_excepteds.Add(new Excepted(mask, order));
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Build
|
|
|
|
|
public EcsStaticMask Build()
|
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
HashSet<EcsTypeCode> combinedIncs = _incsSet;
|
|
|
|
|
HashSet<EcsTypeCode> combinedExcs = _excsSet;
|
|
|
|
|
HashSet<EcsTypeCode> combinedAnys = _anysSet;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
|
|
|
|
|
if (_combineds.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
combinedIncs = new HashSet<EcsTypeCode>();
|
|
|
|
|
combinedExcs = new HashSet<EcsTypeCode>();
|
2025-05-19 20:30:18 +08:00
|
|
|
|
//combinedAnys = new HashSet<EcsTypeCode>(); //TODO разработать комбинацию для any
|
2024-10-31 14:46:21 +08:00
|
|
|
|
if (_sortedCombinedChecker == false)
|
|
|
|
|
{
|
|
|
|
|
_combineds.Sort((a, b) => a.order - b.order);
|
|
|
|
|
}
|
|
|
|
|
foreach (var item in _combineds)
|
|
|
|
|
{
|
|
|
|
|
EcsStaticMask submask = item.mask;
|
2024-11-01 12:41:10 +08:00
|
|
|
|
combinedIncs.ExceptWith(submask._excs);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedExcs.ExceptWith(submask._incs);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedIncs.UnionWith(submask._incs);
|
|
|
|
|
combinedExcs.UnionWith(submask._excs);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2025-05-19 20:30:18 +08:00
|
|
|
|
combinedIncs.ExceptWith(_excsSet);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedExcs.ExceptWith(_incsSet);//удаляю конфликтующие ограничения
|
|
|
|
|
combinedIncs.UnionWith(_incsSet);
|
|
|
|
|
combinedExcs.UnionWith(_excsSet);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
_combineds.Clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
combinedIncs = _incsSet;
|
|
|
|
|
combinedExcs = _excsSet;
|
|
|
|
|
combinedAnys = _anysSet;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_excepteds.Count > 0)
|
|
|
|
|
{
|
2025-05-19 20:30:18 +08:00
|
|
|
|
//TODO разработать вычитание для any
|
2024-10-31 14:46:21 +08:00
|
|
|
|
foreach (var item in _excepteds)
|
|
|
|
|
{
|
|
|
|
|
//if (combinedIncs.Overlaps(item.mask._exc) || combinedExcs.Overlaps(item.mask._inc))
|
|
|
|
|
//{
|
|
|
|
|
// return _world.Get<WorldMaskComponent>().BrokenMask;
|
|
|
|
|
//}
|
2024-11-01 12:41:10 +08:00
|
|
|
|
combinedIncs.ExceptWith(item.mask._incs);
|
|
|
|
|
combinedExcs.ExceptWith(item.mask._excs);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
_excepteds.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var inc = combinedIncs.ToArray();
|
|
|
|
|
Array.Sort(inc);
|
|
|
|
|
var exc = combinedExcs.ToArray();
|
|
|
|
|
Array.Sort(exc);
|
2025-05-19 20:30:18 +08:00
|
|
|
|
var any = combinedAnys.ToArray();
|
|
|
|
|
Array.Sort(any);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
|
2025-05-19 20:30:18 +08:00
|
|
|
|
var key = new Key(inc, exc, any);
|
2024-10-31 14:46:21 +08:00
|
|
|
|
EcsStaticMask result = CreateMask(key);
|
|
|
|
|
|
2025-05-19 20:30:18 +08:00
|
|
|
|
_incsSet.Clear();
|
|
|
|
|
_excsSet.Clear();
|
|
|
|
|
_anysSet.Clear();
|
2024-10-31 14:46:21 +08:00
|
|
|
|
|
|
|
|
|
_version++;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Utils
|
|
|
|
|
private readonly struct Combined
|
|
|
|
|
{
|
|
|
|
|
public readonly EcsStaticMask mask;
|
|
|
|
|
public readonly int order;
|
|
|
|
|
public Combined(EcsStaticMask mask, int order) { this.mask = mask; this.order = order; }
|
|
|
|
|
}
|
|
|
|
|
private readonly struct Excepted
|
|
|
|
|
{
|
|
|
|
|
public readonly EcsStaticMask mask;
|
|
|
|
|
public readonly int order;
|
|
|
|
|
public Excepted(EcsStaticMask mask, int order) { this.mask = mask; this.order = order; }
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Debug utils
|
|
|
|
|
private static string CreateLogString(EcsTypeCode[] inc, EcsTypeCode[] exc)
|
|
|
|
|
{
|
2025-03-14 16:53:25 +08:00
|
|
|
|
#if DEBUG
|
2024-11-05 17:16:50 +08:00
|
|
|
|
string converter(EcsTypeCode o) { return EcsTypeCodeManager.FindTypeOfCode(o).ToString(); }
|
2024-10-31 14:46:21 +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
|
|
|
|
|
}
|
|
|
|
|
internal class DebuggerProxy
|
|
|
|
|
{
|
|
|
|
|
private EcsStaticMask _source;
|
|
|
|
|
|
|
|
|
|
public readonly int ID;
|
|
|
|
|
public readonly EcsTypeCode[] included;
|
|
|
|
|
public readonly EcsTypeCode[] 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(EcsStaticMask mask)
|
|
|
|
|
{
|
|
|
|
|
_source = mask;
|
|
|
|
|
|
2024-11-01 12:41:10 +08:00
|
|
|
|
ID = mask.ID;
|
|
|
|
|
included = mask._incs;
|
|
|
|
|
excluded = mask._excs;
|
2024-11-05 17:16:50 +08:00
|
|
|
|
Type converter(EcsTypeCode o) { return EcsTypeCodeManager.FindTypeOfCode(o).Type; }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
includedTypes = included.Select(converter).ToArray();
|
|
|
|
|
excludedTypes = excluded.Select(converter).ToArray();
|
|
|
|
|
}
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return CreateLogString(included, excluded);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
2025-05-20 11:12:30 +08:00
|
|
|
|
private static void CheckConstraints(EcsTypeCode[] incs, EcsTypeCode[] excs, EcsTypeCode[] anys)
|
2024-10-31 16:27:53 +08:00
|
|
|
|
{
|
2025-03-14 21:57:52 +08:00
|
|
|
|
if (CheckRepeats(incs)) { throw new ArgumentException("The values in the Include constraints are repeated."); }
|
|
|
|
|
if (CheckRepeats(excs)) { throw new ArgumentException("The values in the Exclude constraints are repeated."); }
|
2025-05-20 11:12:30 +08:00
|
|
|
|
if (CheckRepeats(anys)) { throw new ArgumentException("The values in the Any constraints are repeated."); }
|
2025-03-14 21:57:52 +08:00
|
|
|
|
if (OverlapsArray(incs, excs)) { throw new ArgumentException("Conflicting Include and Exclude constraints."); }
|
2025-05-20 11:12:30 +08:00
|
|
|
|
if (OverlapsArray(incs, anys)) { throw new ArgumentException("Conflicting Include and Any constraints."); }
|
|
|
|
|
if (OverlapsArray(anys, excs)) { throw new ArgumentException("Conflicting Any and Exclude constraints."); }
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
2024-10-31 16:27:53 +08:00
|
|
|
|
private static bool CheckRepeats(EcsTypeCode[] array)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2024-11-01 12:41:10 +08:00
|
|
|
|
if (array.Length <= 1)
|
2024-10-31 16:27:53 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
EcsTypeCode lastValue = array[0];
|
|
|
|
|
for (int i = 1; i < array.Length; i++)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
2024-10-31 16:27:53 +08:00
|
|
|
|
EcsTypeCode value = array[i];
|
2024-11-01 12:41:10 +08:00
|
|
|
|
if (value == lastValue)
|
2024-10-31 14:46:21 +08:00
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-10-31 16:27:53 +08:00
|
|
|
|
lastValue = value;
|
2024-10-31 14:46:21 +08:00
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|