1
0
Fork 0

More strongly-typed Filters

Requires some very repetitive constructs (no variable-count generics) but simplifies filter iteration for the simplest cases.
This commit is contained in:
Sage Vaillancourt 2025-03-25 15:49:18 -04:00
parent 76b18a6ba9
commit 50d1ee6035
2 changed files with 175 additions and 4 deletions

View File

@ -1,11 +1,166 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MoonTools.ECS.Collections;
namespace MoonTools.ECS;
public class Filter<T> where T : unmanaged
{
private readonly Filter _underlying;
internal Filter(Filter underlying)
{
_underlying = underlying;
}
public TypedEntityEnum<T> GetEnumerator()
{
return new TypedEntityEnum<T>(_underlying.Entities, _underlying.World);
}
}
public ref struct TypedEntityEnum<T> : IEnumerator<(Entity entity, T)> where T : unmanaged
{
private ReverseSpanEnumerator<Entity> _underlying;
private readonly World _world;
public TypedEntityEnum(ReverseSpanEnumerator<Entity> underlying, World world)
{
_underlying = underlying;
_world = world;
}
public bool MoveNext()
{
if (!_underlying.MoveNext())
{
return false;
}
Entity currentEntity = _underlying.Current;
Current = (currentEntity, _world.Get<T>(currentEntity));
return true;
}
public void Reset()
{
throw new NotImplementedException();
}
public (Entity, T) Current { get; private set; }
object IEnumerator.Current => Current;
public void Dispose()
{
}
}
public class Filter<T1, T2> where T1 : unmanaged where T2 : unmanaged
{
private readonly Filter _underlying;
internal Filter(Filter underlying)
{
_underlying = underlying;
}
public TypedEntityEnum<T1, T2> GetEnumerator()
{
return new TypedEntityEnum<T1, T2>(_underlying.Entities, _underlying.World);
}
}
public ref struct TypedEntityEnum<T1, T2> : IEnumerator<(Entity entity, T1, T2)> where T1 : unmanaged where T2 : unmanaged
{
private ReverseSpanEnumerator<Entity> _underlying;
private readonly World _world;
public TypedEntityEnum(ReverseSpanEnumerator<Entity> underlying, World world)
{
_underlying = underlying;
_world = world;
}
public bool MoveNext()
{
if (!_underlying.MoveNext())
{
return false;
}
Entity currentEntity = _underlying.Current;
Current = (currentEntity, _world.Get<T1>(currentEntity), _world.Get<T2>(currentEntity));
return true;
}
public void Reset()
{
throw new NotImplementedException();
}
public (Entity, T1, T2) Current { get; private set; }
object IEnumerator.Current => Current;
public void Dispose()
{
}
}
public class Filter<T1, T2, T3> where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged
{
private readonly Filter _underlying;
internal Filter(Filter underlying)
{
_underlying = underlying;
}
public TypedEntityEnum<T1, T2, T3> GetEnumerator()
{
return new TypedEntityEnum<T1, T2, T3>(_underlying.Entities, _underlying.World);
}
}
public ref struct TypedEntityEnum<T1, T2, T3> : IEnumerator<(Entity entity, T1, T2, T3)> where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged
{
private ReverseSpanEnumerator<Entity> _underlying;
private readonly World _world;
public TypedEntityEnum(ReverseSpanEnumerator<Entity> underlying, World world)
{
_underlying = underlying;
_world = world;
}
public bool MoveNext()
{
if (!_underlying.MoveNext())
{
return false;
}
Entity currentEntity = _underlying.Current;
Current = (currentEntity, _world.Get<T1>(currentEntity), _world.Get<T2>(currentEntity), _world.Get<T3>(currentEntity));
return true;
}
public void Reset()
{
throw new NotImplementedException();
}
public (Entity, T1, T2, T3) Current { get; private set; }
object IEnumerator.Current => Current;
public void Dispose()
{
}
}
public class Filter
{
private World World;
internal World World;
internal FilterSignature Signature;
internal IndexableSet<Entity> EntitySet = new IndexableSet<Entity>();
@ -17,10 +172,10 @@ public class Filter
public bool Empty => EntitySet.Count == 0;
public int Count => EntitySet.Count;
// WARNING: this WILL crash if the index is out of range!
/// WARNING: this WILL crash if the index is out of range!
public Entity NthEntity(int index) => EntitySet[index];
// WARNING: this WILL crash if the filter is empty!
/// WARNING: this WILL crash if the filter is empty!
public Entity RandomEntity => EntitySet[RandomManager.Next(EntitySet.Count)];
public RandomEntityEnumerator EntitiesInRandomOrder => new RandomEntityEnumerator(this);

View File

@ -1,4 +1,5 @@
using MoonTools.ECS.Collections;
using System;
using MoonTools.ECS.Collections;
namespace MoonTools.ECS
{
@ -39,5 +40,20 @@ namespace MoonTools.ECS
var signature = new FilterSignature(Included, Excluded);
return World.GetFilter(signature);
}
public Filter<T> Of<T>() where T : unmanaged
{
return new Filter<T>(Include<T>().Build());
}
public Filter<T1, T2> Of<T1, T2>() where T1 : unmanaged where T2 : unmanaged
{
return new Filter<T1, T2>(Include<T1>().Include<T2>().Build());
}
public Filter<T1, T2, T3> Of<T1, T2, T3>() where T1 : unmanaged where T2 : unmanaged where T3 : unmanaged
{
return new Filter<T1, T2, T3>(Include<T1>().Include<T2>().Include<T3>().Build());
}
}
}