update EcsMask api / add ExceptMask

This commit is contained in:
Mikhail 2024-04-15 01:18:08 +08:00
parent a06fcfc7be
commit d414915465

View File

@ -14,8 +14,8 @@ namespace DCFApixels.DragonECS
internal readonly int worldID; internal readonly int worldID;
internal readonly EcsMaskChunck[] incChunckMasks; internal readonly EcsMaskChunck[] incChunckMasks;
internal readonly EcsMaskChunck[] excChunckMasks; internal readonly EcsMaskChunck[] excChunckMasks;
internal readonly int[] inc; internal readonly int[] inc; //Sorted
internal readonly int[] exc; internal readonly int[] exc; //Sorted
#region Properties #region Properties
public int ID public int ID
@ -265,30 +265,113 @@ namespace DCFApixels.DragonECS
} }
#endregion #endregion
#region Operators
public static EcsMask operator -(EcsMask a, EcsMask b)
{
return a.World.Get<WorldMaskComponent>().ExceptMask(a, b);
}
#endregion
#region OpMaskKey
private readonly struct OpMaskKey : IEquatable<OpMaskKey>
{
public readonly int leftMaskID;
public readonly int rightMaskID;
public readonly int operation;
public const int UNION_OP = 7;
public const int EXCEPT_OP = 32;
public OpMaskKey(int leftMaskID, int rightMaskID, int operation)
{
this.leftMaskID = leftMaskID;
this.rightMaskID = rightMaskID;
this.operation = operation;
}
public bool Equals(OpMaskKey other)
{
return leftMaskID == other.leftMaskID &&
rightMaskID == other.rightMaskID &&
operation == other.operation;
}
public override int GetHashCode()
{
return leftMaskID ^ (rightMaskID * operation);
}
}
#endregion
#region Builder #region Builder
private readonly struct WorldMaskComponent : IEcsWorldComponent<WorldMaskComponent> private readonly struct WorldMaskComponent : IEcsWorldComponent<WorldMaskComponent>
{ {
private readonly EcsWorld _world; private readonly EcsWorld _world;
private readonly Dictionary<Key, EcsMask> _masks; private readonly Dictionary<Key, EcsMask> _masks;
private readonly Dictionary<OpMaskKey, EcsMask> _opMasks;
#region Constructor/Destructor #region Constructor/Destructor
public WorldMaskComponent(EcsWorld world, Dictionary<Key, EcsMask> masks) public WorldMaskComponent(EcsWorld world, Dictionary<Key, EcsMask> masks, Dictionary<OpMaskKey, EcsMask> opMasks)
{ {
_world = world; _world = world;
_masks = masks; _masks = masks;
_opMasks = opMasks;
} }
public void Init(ref WorldMaskComponent component, EcsWorld world) public void Init(ref WorldMaskComponent component, EcsWorld world)
{ {
component = new WorldMaskComponent(world, new Dictionary<Key, EcsMask>(256)); component = new WorldMaskComponent(world, new Dictionary<Key, EcsMask>(256), new Dictionary<OpMaskKey, EcsMask>(256));
} }
public void OnDestroy(ref WorldMaskComponent component, EcsWorld world) public void OnDestroy(ref WorldMaskComponent component, EcsWorld world)
{ {
component._masks.Clear(); component._masks.Clear();
component._opMasks.Clear();
component = default; component = default;
} }
#endregion #endregion
#region GetMask #region GetMask
internal EcsMask ExceptMask(EcsMask a, EcsMask b)
{
int operation = OpMaskKey.EXCEPT_OP;
if (_opMasks.TryGetValue(new OpMaskKey(a.id, b.id, operation), out EcsMask result) == false)
{
var builder = New(a.World);
if (a.IsConflictWith(b))
{
return a.World.GetAspect<EmptyAspect>().Mask;
}
ExceptMaskConstraint(builder, a.inc, b.inc, true);
ExceptMaskConstraint(builder, a.exc, b.exc, false);
result = builder.Build();
_opMasks.Add(new OpMaskKey(a.id, b.id, operation), result);
}
return result;
}
private void ExceptMaskConstraint(Builder b, int[] acnstrs, int[] bcnstrs, bool isInc)
{
for (int i = 0, ii = 0; i < acnstrs.Length; i++)
{
int acnst = acnstrs[i];
while (ii < bcnstrs.Length && acnst > bcnstrs[ii])
{
ii++;
}
if (ii >= bcnstrs.Length)
{
break;
}
int binc = bcnstrs[ii];
if (acnst == binc)
{
if (isInc)
{
b.Include(acnst);
}
else
{
b.Exclude(acnst);
}
}
}
}
internal EcsMask GetMask(Key maskKey) internal EcsMask GetMask(Key maskKey)
{ {
if (!_masks.TryGetValue(maskKey, out EcsMask result)) if (!_masks.TryGetValue(maskKey, out EcsMask result))
@ -376,40 +459,38 @@ namespace DCFApixels.DragonECS
#region Include/Exclude/Combine #region Include/Exclude/Combine
public Builder Include<T>() public Builder Include<T>()
{ {
int id = _world.GetComponentTypeID<T>(); return Include(_world.GetComponentTypeID<T>());
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(typeof(T));
#endif
_inc.Add(id);
return this;
} }
public Builder Exclude<T>() public Builder Exclude<T>()
{ {
int id = _world.GetComponentTypeID<T>(); return Exclude(_world.GetComponentTypeID<T>());
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(typeof(T));
#endif
_exc.Add(id);
return this;
} }
public Builder Include(Type type) public Builder Include(Type type)
{ {
int id = _world.GetComponentTypeID(type); return Include(_world.GetComponentTypeID(type));
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
#endif
_inc.Add(id);
return this;
} }
public Builder Exclude(Type type) public Builder Exclude(Type type)
{ {
int id = _world.GetComponentTypeID(type); return Exclude(_world.GetComponentTypeID(type));
}
public Builder Include(int compponentTypeID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type); if (_inc.Contains(compponentTypeID) || _exc.Contains(compponentTypeID)) Throw.ConstraintIsAlreadyContainedInMask(_world.GetComponentType(compponentTypeID));
#endif #endif
_exc.Add(id); _inc.Add(compponentTypeID);
return this; return this;
} }
public Builder Exclude(int compponentTypeID)
{
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(compponentTypeID) || _exc.Contains(compponentTypeID)) Throw.ConstraintIsAlreadyContainedInMask(_world.GetComponentType(compponentTypeID));
#endif
_exc.Add(compponentTypeID);
return this;
}
public Builder Combine(EcsMask mask, int order = 0) public Builder Combine(EcsMask mask, int order = 0)
{ {
_combined.Add(new Combined(mask, order)); _combined.Add(new Combined(mask, order));