oecs-sharp/OECS/WorldQueryExtensions.cs

720 lines
27 KiB
C#
Raw Normal View History

using System.Runtime.CompilerServices;
namespace OECS;
/// <summary>
/// Provides zero-allocation ref struct iterators and entity-finding
/// extension methods for querying a <see cref="World"/>.
/// </summary>
public static class WorldQueryExtensions
{
// ── Select (ref struct enumerators) ──────────────────────────────
public static Select1<T1> Select<T1>(this World world, Query<T1> query = default)
where T1 : struct
{
return new Select1<T1>(world, query);
}
public static Select2<T1, T2> Select<T1, T2>(this World world, Query<T1, T2> query = default)
where T1 : struct where T2 : struct
{
return new Select2<T1, T2>(world, query);
}
public static Select3<T1, T2, T3> Select<T1, T2, T3>(this World world, Query<T1, T2, T3> query = default)
where T1 : struct where T2 : struct where T3 : struct
{
return new Select3<T1, T2, T3>(world, query);
}
public static Select4<T1, T2, T3, T4> Select<T1, T2, T3, T4>(this World world, Query<T1, T2, T3, T4> query = default)
where T1 : struct where T2 : struct where T3 : struct where T4 : struct
{
return new Select4<T1, T2, T3, T4>(world, query);
}
public static Select5<T1, T2, T3, T4, T5> Select<T1, T2, T3, T4, T5>(this World world, Query<T1, T2, T3, T4, T5> query = default)
where T1 : struct where T2 : struct where T3 : struct where T4 : struct where T5 : struct
{
return new Select5<T1, T2, T3, T4, T5>(world, query);
}
public static Select6<T1, T2, T3, T4, T5, T6> Select<T1, T2, T3, T4, T5, T6>(this World world, Query<T1, T2, T3, T4, T5, T6> query = default)
where T1 : struct where T2 : struct where T3 : struct where T4 : struct where T5 : struct where T6 : struct
{
return new Select6<T1, T2, T3, T4, T5, T6>(world, query);
}
// ── FindEntity ──────────────────────────────────────────────────
public static Entity FindEntity<T1>(this World world, Query<T1> query = default)
where T1 : struct
{
using var iter = new Select1<T1>(world, query);
return iter.MoveNext() ? iter.Entity : Entity.Null;
}
public static Entity FindEntity<T1, T2>(this World world, Query<T1, T2> query = default)
where T1 : struct where T2 : struct
{
using var iter = new Select2<T1, T2>(world, query);
return iter.MoveNext() ? iter.Entity : Entity.Null;
}
public static Entity FindEntity<T1, T2, T3>(this World world, Query<T1, T2, T3> query = default)
where T1 : struct where T2 : struct where T3 : struct
{
using var iter = new Select3<T1, T2, T3>(world, query);
return iter.MoveNext() ? iter.Entity : Entity.Null;
}
}
// ── Ref struct enumerators ───────────────────────────────────────────
/// <summary>Ref struct iterator for queries with one component type.</summary>
public ref struct Select1<T1> where T1 : struct
{
private readonly World _world;
private readonly SparseSet<T1>? _set;
private readonly ComponentStore _store;
private readonly HashSet<Type>? _without;
private int _index;
private readonly int _count;
internal Select1(World world, Query<T1> query)
{
_world = world;
_store = world.Components;
_without = query.WithoutTypes;
_set = _store.GetSet(typeof(T1)) as SparseSet<T1>;
_count = _set?.Count ?? 0;
_index = -1;
_world.BeginBatching();
}
/// <summary>The current entity handle.</summary>
public Entity Entity { get; private set; }
/// <summary>The current enumerator (required for foreach duck-typing).</summary>
public Select1<T1> Current => this;
/// <summary>
/// Mutable reference to the current entity's component of type <typeparamref name="T1"/>.
/// Access is tracked for auto-dirty-marking during a batching scope.
/// </summary>
public ref T1 Ref1
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
_world.TrackAccess(Entity, typeof(T1));
return ref _set!.Get(Entity);
}
}
/// <summary>
/// Read-only reference to the current entity's component of type <typeparamref name="T1"/>.
/// Access is NOT tracked for auto-dirty-marking.
/// </summary>
public ref readonly T1 Val1 => ref _set!.Get(Entity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_set == null) return false;
while (++_index < _count)
{
Entity = _set.DenseEntities[_index];
if (!PassesWithout()) continue;
if (_world.IsSingletonEntity(Entity)) continue;
return true;
}
return false;
}
public Select1<T1> GetEnumerator() => this;
public void Dispose()
{
_world.EndBatching();
}
private bool PassesWithout()
{
if (_without == null) return true;
foreach (var type in _without)
{
var set = _store.GetSet(type);
if (set != null && set.Contains(Entity))
return false;
}
return true;
}
}
/// <summary>Ref struct iterator for queries with two component types. Drives from the smaller set.</summary>
public ref struct Select2<T1, T2> where T1 : struct where T2 : struct
{
private readonly World _world;
private readonly SparseSet<T1>? _set1;
private readonly SparseSet<T2>? _set2;
private readonly ComponentStore _store;
private readonly HashSet<Type>? _without;
private int _index;
private readonly int _count;
private readonly bool _swapped;
internal Select2(World world, Query<T1, T2> query)
{
_world = world;
_store = world.Components;
_without = query.WithoutTypes;
_set1 = _store.GetSet(typeof(T1)) as SparseSet<T1>;
_set2 = _store.GetSet(typeof(T2)) as SparseSet<T2>;
int c1 = _set1?.Count ?? 0;
int c2 = _set2?.Count ?? 0;
_swapped = c2 < c1;
_count = _swapped ? c2 : c1;
_index = -1;
_world.BeginBatching();
}
public Entity Entity { get; private set; }
public Select2<T1, T2> Current => this;
public ref T1 Ref1
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
_world.TrackAccess(Entity, typeof(T1));
return ref _set1!.Get(Entity);
}
}
public ref T2 Ref2
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
_world.TrackAccess(Entity, typeof(T2));
return ref _set2!.Get(Entity);
}
}
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_set1 == null || _set2 == null) return false;
while (++_index < _count)
{
if (_swapped)
{
Entity = _set2!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
}
else
{
Entity = _set1.DenseEntities[_index];
if (!_set2.Contains(Entity)) continue;
}
if (!PassesWithout()) continue;
if (_world.IsSingletonEntity(Entity)) continue;
return true;
}
return false;
}
public Select2<T1, T2> GetEnumerator() => this;
public void Dispose() => _world.EndBatching();
private bool PassesWithout()
{
if (_without == null) return true;
foreach (var type in _without)
{
var set = _store.GetSet(type);
if (set != null && set.Contains(Entity))
return false;
}
return true;
}
}
/// <summary>Ref struct iterator for queries with three component types. Drives from the smallest set.</summary>
public ref struct Select3<T1, T2, T3>
where T1 : struct where T2 : struct where T3 : struct
{
private readonly World _world;
private readonly SparseSet<T1>? _set1;
private readonly SparseSet<T2>? _set2;
private readonly SparseSet<T3>? _set3;
private readonly ComponentStore _store;
private readonly HashSet<Type>? _without;
private int _index;
private readonly int _count;
private readonly int _driver; // 0 = set1, 1 = set2, 2 = set3
internal Select3(World world, Query<T1, T2, T3> query)
{
_world = world;
_store = world.Components;
_without = query.WithoutTypes;
_set1 = _store.GetSet(typeof(T1)) as SparseSet<T1>;
_set2 = _store.GetSet(typeof(T2)) as SparseSet<T2>;
_set3 = _store.GetSet(typeof(T3)) as SparseSet<T3>;
int c1 = _set1?.Count ?? 0;
int c2 = _set2?.Count ?? 0;
int c3 = _set3?.Count ?? 0;
if (c2 <= c1 && c2 <= c3) { _driver = 1; _count = c2; }
else if (c3 <= c1 && c3 <= c2) { _driver = 2; _count = c3; }
else { _driver = 0; _count = c1; }
_index = -1;
_world.BeginBatching();
}
public Entity Entity { get; private set; }
public Select3<T1, T2, T3> Current => this;
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_set1 == null || _set2 == null || _set3 == null) return false;
while (++_index < _count)
{
switch (_driver)
{
case 0:
Entity = _set1.DenseEntities[_index];
if (!_set2.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
break;
case 1:
Entity = _set2!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
break;
case 2:
Entity = _set3!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set2.Contains(Entity)) continue;
break;
}
if (!PassesWithout()) continue;
if (_world.IsSingletonEntity(Entity)) continue;
return true;
}
return false;
}
public Select3<T1, T2, T3> GetEnumerator() => this;
public void Dispose() => _world.EndBatching();
private bool PassesWithout()
{
if (_without == null) return true;
foreach (var type in _without)
{
var set = _store.GetSet(type);
if (set != null && set.Contains(Entity))
return false;
}
return true;
}
}
/// <summary>Ref struct iterator for queries with four component types.</summary>
public ref struct Select4<T1, T2, T3, T4>
where T1 : struct where T2 : struct where T3 : struct where T4 : struct
{
private readonly World _world;
private readonly SparseSet<T1>? _set1;
private readonly SparseSet<T2>? _set2;
private readonly SparseSet<T3>? _set3;
private readonly SparseSet<T4>? _set4;
private readonly ComponentStore _store;
private readonly HashSet<Type>? _without;
private int _index;
private readonly int _count;
private readonly int _driver;
internal Select4(World world, Query<T1, T2, T3, T4> query)
{
_world = world;
_store = world.Components;
_without = query.WithoutTypes;
_set1 = _store.GetSet(typeof(T1)) as SparseSet<T1>;
_set2 = _store.GetSet(typeof(T2)) as SparseSet<T2>;
_set3 = _store.GetSet(typeof(T3)) as SparseSet<T3>;
_set4 = _store.GetSet(typeof(T4)) as SparseSet<T4>;
int c1 = _set1?.Count ?? 0, c2 = _set2?.Count ?? 0;
int c3 = _set3?.Count ?? 0, c4 = _set4?.Count ?? 0;
int min = c1;
_driver = 0;
if (c2 < min) { min = c2; _driver = 1; }
if (c3 < min) { min = c3; _driver = 2; }
if (c4 < min) { min = c4; _driver = 3; }
_count = min;
_index = -1;
_world.BeginBatching();
}
public Entity Entity { get; private set; }
public Select4<T1, T2, T3, T4> Current => this;
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
public ref T4 Ref4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T4)); return ref _set4!.Get(Entity); } }
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
public ref readonly T4 Val4 => ref _set4!.Get(Entity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_set1 == null || _set2 == null || _set3 == null || _set4 == null) return false;
while (++_index < _count)
{
switch (_driver)
{
case 0:
Entity = _set1.DenseEntities[_index];
if (!_set2.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
break;
case 1:
Entity = _set2!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
break;
case 2:
Entity = _set3!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set2.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
break;
case 3:
Entity = _set4!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set2.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
break;
}
if (!PassesWithout()) continue;
if (_world.IsSingletonEntity(Entity)) continue;
return true;
}
return false;
}
public Select4<T1, T2, T3, T4> GetEnumerator() => this;
public void Dispose() => _world.EndBatching();
private bool PassesWithout()
{
if (_without == null) return true;
foreach (var type in _without)
{
var set = _store.GetSet(type);
if (set != null && set.Contains(Entity))
return false;
}
return true;
}
}
/// <summary>Ref struct iterator for queries with five component types.</summary>
public ref struct Select5<T1, T2, T3, T4, T5>
where T1 : struct where T2 : struct where T3 : struct where T4 : struct where T5 : struct
{
private readonly World _world;
private readonly SparseSet<T1>? _set1;
private readonly SparseSet<T2>? _set2;
private readonly SparseSet<T3>? _set3;
private readonly SparseSet<T4>? _set4;
private readonly SparseSet<T5>? _set5;
private readonly ComponentStore _store;
private readonly HashSet<Type>? _without;
private int _index;
private readonly int _count;
private readonly int _driver;
internal Select5(World world, Query<T1, T2, T3, T4, T5> query)
{
_world = world;
_store = world.Components;
_without = query.WithoutTypes;
_set1 = _store.GetSet(typeof(T1)) as SparseSet<T1>;
_set2 = _store.GetSet(typeof(T2)) as SparseSet<T2>;
_set3 = _store.GetSet(typeof(T3)) as SparseSet<T3>;
_set4 = _store.GetSet(typeof(T4)) as SparseSet<T4>;
_set5 = _store.GetSet(typeof(T5)) as SparseSet<T5>;
int c1 = _set1?.Count ?? 0, c2 = _set2?.Count ?? 0;
int c3 = _set3?.Count ?? 0, c4 = _set4?.Count ?? 0;
int c5 = _set5?.Count ?? 0;
int min = c1;
_driver = 0;
if (c2 < min) { min = c2; _driver = 1; }
if (c3 < min) { min = c3; _driver = 2; }
if (c4 < min) { min = c4; _driver = 3; }
if (c5 < min) { min = c5; _driver = 4; }
_count = min;
_index = -1;
_world.BeginBatching();
}
public Entity Entity { get; private set; }
public Select5<T1, T2, T3, T4, T5> Current => this;
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
public ref T4 Ref4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T4)); return ref _set4!.Get(Entity); } }
public ref T5 Ref5 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T5)); return ref _set5!.Get(Entity); } }
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
public ref readonly T4 Val4 => ref _set4!.Get(Entity);
public ref readonly T5 Val5 => ref _set5!.Get(Entity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_set1 == null || _set2 == null || _set3 == null || _set4 == null || _set5 == null) return false;
while (++_index < _count)
{
switch (_driver)
{
case 0:
Entity = _set1.DenseEntities[_index];
if (!_set2.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
if (!_set5.Contains(Entity)) continue;
break;
case 1:
Entity = _set2!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
if (!_set5.Contains(Entity)) continue;
break;
case 2:
Entity = _set3!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set2.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
if (!_set5.Contains(Entity)) continue;
break;
case 3:
Entity = _set4!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set2.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
if (!_set5.Contains(Entity)) continue;
break;
case 4:
Entity = _set5!.DenseEntities[_index];
if (!_set1.Contains(Entity)) continue;
if (!_set2.Contains(Entity)) continue;
if (!_set3.Contains(Entity)) continue;
if (!_set4.Contains(Entity)) continue;
break;
}
if (!PassesWithout()) continue;
if (_world.IsSingletonEntity(Entity)) continue;
return true;
}
return false;
}
public Select5<T1, T2, T3, T4, T5> GetEnumerator() => this;
public void Dispose() => _world.EndBatching();
private bool PassesWithout()
{
if (_without == null) return true;
foreach (var type in _without)
{
var set = _store.GetSet(type);
if (set != null && set.Contains(Entity))
return false;
}
return true;
}
}
/// <summary>Ref struct iterator for queries with six component types.</summary>
public ref struct Select6<T1, T2, T3, T4, T5, T6>
where T1 : struct where T2 : struct where T3 : struct
where T4 : struct where T5 : struct where T6 : struct
{
private readonly World _world;
private readonly SparseSet<T1>? _set1;
private readonly SparseSet<T2>? _set2;
private readonly SparseSet<T3>? _set3;
private readonly SparseSet<T4>? _set4;
private readonly SparseSet<T5>? _set5;
private readonly SparseSet<T6>? _set6;
private readonly ComponentStore _store;
private readonly HashSet<Type>? _without;
private int _index;
private readonly int _count;
private readonly int _driver;
internal Select6(World world, Query<T1, T2, T3, T4, T5, T6> query)
{
_world = world;
_store = world.Components;
_without = query.WithoutTypes;
_set1 = _store.GetSet(typeof(T1)) as SparseSet<T1>;
_set2 = _store.GetSet(typeof(T2)) as SparseSet<T2>;
_set3 = _store.GetSet(typeof(T3)) as SparseSet<T3>;
_set4 = _store.GetSet(typeof(T4)) as SparseSet<T4>;
_set5 = _store.GetSet(typeof(T5)) as SparseSet<T5>;
_set6 = _store.GetSet(typeof(T6)) as SparseSet<T6>;
int c1 = _set1?.Count ?? 0, c2 = _set2?.Count ?? 0;
int c3 = _set3?.Count ?? 0, c4 = _set4?.Count ?? 0;
int c5 = _set5?.Count ?? 0, c6 = _set6?.Count ?? 0;
int min = c1;
_driver = 0;
if (c2 < min) { min = c2; _driver = 1; }
if (c3 < min) { min = c3; _driver = 2; }
if (c4 < min) { min = c4; _driver = 3; }
if (c5 < min) { min = c5; _driver = 4; }
if (c6 < min) { min = c6; _driver = 5; }
_count = min;
_index = -1;
_world.BeginBatching();
}
public Entity Entity { get; private set; }
public Select6<T1, T2, T3, T4, T5, T6> Current => this;
public ref T1 Ref1 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T1)); return ref _set1!.Get(Entity); } }
public ref T2 Ref2 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T2)); return ref _set2!.Get(Entity); } }
public ref T3 Ref3 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T3)); return ref _set3!.Get(Entity); } }
public ref T4 Ref4 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T4)); return ref _set4!.Get(Entity); } }
public ref T5 Ref5 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T5)); return ref _set5!.Get(Entity); } }
public ref T6 Ref6 { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { _world.TrackAccess(Entity, typeof(T6)); return ref _set6!.Get(Entity); } }
public ref readonly T1 Val1 => ref _set1!.Get(Entity);
public ref readonly T2 Val2 => ref _set2!.Get(Entity);
public ref readonly T3 Val3 => ref _set3!.Get(Entity);
public ref readonly T4 Val4 => ref _set4!.Get(Entity);
public ref readonly T5 Val5 => ref _set5!.Get(Entity);
public ref readonly T6 Val6 => ref _set6!.Get(Entity);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
if (_set1 == null || _set2 == null || _set3 == null || _set4 == null || _set5 == null || _set6 == null) return false;
while (++_index < _count)
{
switch (_driver)
{
case 0:
Entity = _set1.DenseEntities[_index];
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;
break;
case 1:
Entity = _set2!.DenseEntities[_index];
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;
break;
case 2:
Entity = _set3!.DenseEntities[_index];
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;
break;
case 3:
Entity = _set4!.DenseEntities[_index];
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;
break;
case 4:
Entity = _set5!.DenseEntities[_index];
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;
break;
case 5:
Entity = _set6!.DenseEntities[_index];
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;
break;
}
if (!PassesWithout()) continue;
if (_world.IsSingletonEntity(Entity)) continue;
return true;
}
return false;
}
public Select6<T1, T2, T3, T4, T5, T6> GetEnumerator() => this;
public void Dispose() => _world.EndBatching();
private bool PassesWithout()
{
if (_without == null) return true;
foreach (var type in _without)
{
var set = _store.GetSet(type);
if (set != null && set.Contains(Entity))
return false;
}
return true;
}
}