507 lines
21 KiB
C#
507 lines
21 KiB
C#
using System.Runtime.CompilerServices;
|
|
|
|
namespace OECS;
|
|
|
|
/// <summary>
|
|
/// Provides query execution logic for <see cref="World"/>.
|
|
/// Iterates one sparse set as the driver and probes the remaining sets
|
|
/// for membership. The "without" filter is checked after all "with" probes.
|
|
///
|
|
/// The singleton entity (ID 1) is automatically excluded from all queries.
|
|
/// </summary>
|
|
internal static class QueryExecutor
|
|
{
|
|
private const uint SingletonId = 1;
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
private static bool PassesWithoutFilter(ComponentStore store, Entity entity, IReadOnlySet<Type> withoutTypes)
|
|
{
|
|
foreach (var type in withoutTypes)
|
|
{
|
|
var set = store.GetSet(type);
|
|
if (set != null && set.Contains(entity))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// ── ForEach overloads ──────────────────────────────────────────────
|
|
|
|
public static void ForEach<T1>(
|
|
ComponentStore store,
|
|
QueryDescriptor query,
|
|
ForEachAction<T1> action)
|
|
where T1 : struct
|
|
{
|
|
var set = store.GetSet(typeof(T1)) as SparseSet<T1>;
|
|
if (set == null) return;
|
|
|
|
var dense = set.Dense;
|
|
var denseEntities = set.DenseEntities;
|
|
var count = set.Count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without))
|
|
continue;
|
|
action(entity, ref dense[i]);
|
|
}
|
|
}
|
|
|
|
public static void ForEach<T1, T2>(
|
|
ComponentStore store,
|
|
QueryDescriptor query,
|
|
ForEachAction<T1, T2> action)
|
|
where T1 : struct where T2 : struct
|
|
{
|
|
var set1 = store.GetSet(typeof(T1)) as SparseSet<T1>;
|
|
if (set1 == null) return;
|
|
var set2 = store.GetSet(typeof(T2)) as SparseSet<T2>;
|
|
if (set2 == null) return;
|
|
|
|
if (set1.Count <= set2.Count)
|
|
{
|
|
IterateTwo(set1, set2, store, query.Without, action);
|
|
}
|
|
else
|
|
{
|
|
IterateTwoSwapped(set2, set1, store, query.Without, action);
|
|
}
|
|
}
|
|
|
|
private static void IterateTwo<TDriver, TOther>(
|
|
SparseSet<TDriver> driveSet,
|
|
SparseSet<TOther> otherSet,
|
|
ComponentStore store,
|
|
IReadOnlySet<Type> withoutTypes,
|
|
ForEachAction<TDriver, TOther> action)
|
|
where TDriver : struct where TOther : struct
|
|
{
|
|
var dense = driveSet.Dense;
|
|
var denseEntities = driveSet.DenseEntities;
|
|
var count = driveSet.Count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!otherSet.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, withoutTypes))
|
|
continue;
|
|
action(entity, ref dense[i], ref otherSet.Get(entity));
|
|
}
|
|
}
|
|
|
|
private static void IterateTwoSwapped<TOther, TDriver>(
|
|
SparseSet<TDriver> driveSet,
|
|
SparseSet<TOther> otherSet,
|
|
ComponentStore store,
|
|
IReadOnlySet<Type> withoutTypes,
|
|
ForEachAction<TOther, TDriver> action)
|
|
where TDriver : struct where TOther : struct
|
|
{
|
|
var dense = driveSet.Dense;
|
|
var denseEntities = driveSet.DenseEntities;
|
|
var count = driveSet.Count;
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!otherSet.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, withoutTypes))
|
|
continue;
|
|
action(entity, ref otherSet.Get(entity), ref dense[i]);
|
|
}
|
|
}
|
|
|
|
public static void ForEach<T1, T2, T3>(
|
|
ComponentStore store,
|
|
QueryDescriptor query,
|
|
ForEachAction<T1, T2, T3> action)
|
|
where T1 : struct where T2 : struct where T3 : struct
|
|
{
|
|
var set1 = store.GetSet(typeof(T1)) as SparseSet<T1>;
|
|
if (set1 == null) return;
|
|
var set2 = store.GetSet(typeof(T2)) as SparseSet<T2>;
|
|
if (set2 == null) return;
|
|
var set3 = store.GetSet(typeof(T3)) as SparseSet<T3>;
|
|
if (set3 == null) return;
|
|
|
|
// Pick the smallest set as the driver.
|
|
int c1 = set1.Count, c2 = set2.Count, c3 = set3.Count;
|
|
|
|
if (c2 <= c1 && c2 <= c3)
|
|
{
|
|
var dense = set2.Dense;
|
|
var denseEntities = set2.DenseEntities;
|
|
var count = set2.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref dense[i], ref set3.Get(entity));
|
|
}
|
|
}
|
|
else if (c3 <= c1 && c3 <= c2)
|
|
{
|
|
var dense = set3.Dense;
|
|
var denseEntities = set3.DenseEntities;
|
|
var count = set3.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref dense[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dense = set1.Dense;
|
|
var denseEntities = set1.DenseEntities;
|
|
var count = set1.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref dense[i], ref set2.Get(entity), ref set3.Get(entity));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ForEach<T1, T2, T3, T4>(
|
|
ComponentStore store,
|
|
QueryDescriptor query,
|
|
ForEachAction<T1, T2, T3, T4> action)
|
|
where T1 : struct where T2 : struct where T3 : struct where T4 : struct
|
|
{
|
|
var set1 = store.GetSet(typeof(T1)) as SparseSet<T1>;
|
|
if (set1 == null) return;
|
|
var set2 = store.GetSet(typeof(T2)) as SparseSet<T2>;
|
|
if (set2 == null) return;
|
|
var set3 = store.GetSet(typeof(T3)) as SparseSet<T3>;
|
|
if (set3 == null) return;
|
|
var set4 = store.GetSet(typeof(T4)) as SparseSet<T4>;
|
|
if (set4 == null) return;
|
|
|
|
// Pick the smallest set as the driver.
|
|
int c1 = set1.Count, c2 = set2.Count, c3 = set3.Count, c4 = set4.Count;
|
|
int min = Math.Min(Math.Min(c1, c2), Math.Min(c3, c4));
|
|
|
|
if (min == c2)
|
|
{
|
|
var dense = set2.Dense;
|
|
var denseEntities = set2.DenseEntities;
|
|
var count = set2.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref dense[i], ref set3.Get(entity), ref set4.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c3)
|
|
{
|
|
var dense = set3.Dense;
|
|
var denseEntities = set3.DenseEntities;
|
|
var count = set3.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref dense[i], ref set4.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c4)
|
|
{
|
|
var dense = set4.Dense;
|
|
var denseEntities = set4.DenseEntities;
|
|
var count = set4.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref set3.Get(entity), ref dense[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dense = set1.Dense;
|
|
var denseEntities = set1.DenseEntities;
|
|
var count = set1.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref dense[i], ref set2.Get(entity), ref set3.Get(entity), ref set4.Get(entity));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ForEach<T1, T2, T3, T4, T5>(
|
|
ComponentStore store,
|
|
QueryDescriptor query,
|
|
ForEachAction<T1, T2, T3, T4, T5> action)
|
|
where T1 : struct where T2 : struct where T3 : struct where T4 : struct where T5 : struct
|
|
{
|
|
var set1 = store.GetSet(typeof(T1)) as SparseSet<T1>;
|
|
if (set1 == null) return;
|
|
var set2 = store.GetSet(typeof(T2)) as SparseSet<T2>;
|
|
if (set2 == null) return;
|
|
var set3 = store.GetSet(typeof(T3)) as SparseSet<T3>;
|
|
if (set3 == null) return;
|
|
var set4 = store.GetSet(typeof(T4)) as SparseSet<T4>;
|
|
if (set4 == null) return;
|
|
var set5 = store.GetSet(typeof(T5)) as SparseSet<T5>;
|
|
if (set5 == null) return;
|
|
|
|
// Pick the smallest set as the driver.
|
|
int c1 = set1.Count, c2 = set2.Count, c3 = set3.Count, c4 = set4.Count, c5 = set5.Count;
|
|
int min = Math.Min(Math.Min(Math.Min(c1, c2), Math.Min(c3, c4)), c5);
|
|
|
|
if (min == c2)
|
|
{
|
|
var dense = set2.Dense;
|
|
var denseEntities = set2.DenseEntities;
|
|
var count = set2.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref dense[i], ref set3.Get(entity), ref set4.Get(entity), ref set5.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c3)
|
|
{
|
|
var dense = set3.Dense;
|
|
var denseEntities = set3.DenseEntities;
|
|
var count = set3.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref dense[i], ref set4.Get(entity), ref set5.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c4)
|
|
{
|
|
var dense = set4.Dense;
|
|
var denseEntities = set4.DenseEntities;
|
|
var count = set4.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref set3.Get(entity), ref dense[i], ref set5.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c5)
|
|
{
|
|
var dense = set5.Dense;
|
|
var denseEntities = set5.DenseEntities;
|
|
var count = set5.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref set3.Get(entity), ref set4.Get(entity), ref dense[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dense = set1.Dense;
|
|
var denseEntities = set1.DenseEntities;
|
|
var count = set1.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref dense[i], ref set2.Get(entity), ref set3.Get(entity), ref set4.Get(entity), ref set5.Get(entity));
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ForEach<T1, T2, T3, T4, T5, T6>(
|
|
ComponentStore store,
|
|
QueryDescriptor query,
|
|
ForEachAction<T1, T2, T3, T4, T5, T6> action)
|
|
where T1 : struct where T2 : struct where T3 : struct where T4 : struct where T5 : struct where T6 : struct
|
|
{
|
|
var set1 = store.GetSet(typeof(T1)) as SparseSet<T1>;
|
|
if (set1 == null) return;
|
|
var set2 = store.GetSet(typeof(T2)) as SparseSet<T2>;
|
|
if (set2 == null) return;
|
|
var set3 = store.GetSet(typeof(T3)) as SparseSet<T3>;
|
|
if (set3 == null) return;
|
|
var set4 = store.GetSet(typeof(T4)) as SparseSet<T4>;
|
|
if (set4 == null) return;
|
|
var set5 = store.GetSet(typeof(T5)) as SparseSet<T5>;
|
|
if (set5 == null) return;
|
|
var set6 = store.GetSet(typeof(T6)) as SparseSet<T6>;
|
|
if (set6 == null) return;
|
|
|
|
// Pick the smallest set as the driver.
|
|
int c1 = set1.Count, c2 = set2.Count, c3 = set3.Count, c4 = set4.Count, c5 = set5.Count, c6 = set6.Count;
|
|
int min = Math.Min(Math.Min(Math.Min(c1, c2), Math.Min(c3, c4)), Math.Min(c5, c6));
|
|
|
|
if (min == c2)
|
|
{
|
|
var dense = set2.Dense;
|
|
var denseEntities = set2.DenseEntities;
|
|
var count = set2.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!set6.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref dense[i], ref set3.Get(entity), ref set4.Get(entity), ref set5.Get(entity), ref set6.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c3)
|
|
{
|
|
var dense = set3.Dense;
|
|
var denseEntities = set3.DenseEntities;
|
|
var count = set3.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!set6.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref dense[i], ref set4.Get(entity), ref set5.Get(entity), ref set6.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c4)
|
|
{
|
|
var dense = set4.Dense;
|
|
var denseEntities = set4.DenseEntities;
|
|
var count = set4.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!set6.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref set3.Get(entity), ref dense[i], ref set5.Get(entity), ref set6.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c5)
|
|
{
|
|
var dense = set5.Dense;
|
|
var denseEntities = set5.DenseEntities;
|
|
var count = set5.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set6.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref set3.Get(entity), ref set4.Get(entity), ref dense[i], ref set6.Get(entity));
|
|
}
|
|
}
|
|
else if (min == c6)
|
|
{
|
|
var dense = set6.Dense;
|
|
var denseEntities = set6.DenseEntities;
|
|
var count = set6.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set1.Contains(entity)) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref set1.Get(entity), ref set2.Get(entity), ref set3.Get(entity), ref set4.Get(entity), ref set5.Get(entity), ref dense[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var dense = set1.Dense;
|
|
var denseEntities = set1.DenseEntities;
|
|
var count = set1.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var entity = denseEntities[i];
|
|
if (entity.Id == SingletonId) continue;
|
|
if (!set2.Contains(entity)) continue;
|
|
if (!set3.Contains(entity)) continue;
|
|
if (!set4.Contains(entity)) continue;
|
|
if (!set5.Contains(entity)) continue;
|
|
if (!set6.Contains(entity)) continue;
|
|
if (!PassesWithoutFilter(store, entity, query.Without)) continue;
|
|
action(entity, ref dense[i], ref set2.Get(entity), ref set3.Get(entity), ref set4.Get(entity), ref set5.Get(entity), ref set6.Get(entity));
|
|
}
|
|
}
|
|
}
|
|
} |