|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using gaemstone.Utility.IL;
|
|
|
|
using static flecs_hub.flecs;
|
|
|
|
|
|
|
|
namespace gaemstone.ECS;
|
|
|
|
|
|
|
|
public unsafe sealed class Filter
|
|
|
|
: IEnumerable<Iterator>
|
|
|
|
, IDisposable
|
|
|
|
{
|
|
|
|
public Universe Universe { get; }
|
|
|
|
public ecs_filter_t* Handle { get; }
|
|
|
|
|
|
|
|
private Filter(Universe universe, ecs_filter_t* handle)
|
|
|
|
{ Universe = universe; Handle = handle; }
|
|
|
|
private Filter(Universe universe, ecs_filter_desc_t desc)
|
|
|
|
: this(universe, ecs_filter_init(universe, &desc)) { }
|
|
|
|
|
|
|
|
public Filter(Universe universe, FilterDesc desc)
|
|
|
|
: this(universe, desc.ToFlecs()) { }
|
|
|
|
|
|
|
|
public static void RunOnce(Universe universe, Delegate action)
|
|
|
|
{
|
|
|
|
var gen = IterActionGenerator.GetOrBuild(universe, action.Method);
|
|
|
|
var desc = new FilterDesc(action.Method.Name, gen.Terms.ToArray());
|
|
|
|
using var filter = new Filter(universe, desc);
|
|
|
|
foreach (var iter in filter) gen.RunWithTryCatch(action.Target, iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
=> ecs_filter_fini(Handle);
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
=> ecs_filter_str(Universe, Handle).FlecsToStringAndFree()!;
|
|
|
|
|
|
|
|
public static implicit operator ecs_filter_t*(Filter q) => q.Handle;
|
|
|
|
|
|
|
|
// IEnumerable implementation
|
|
|
|
public Iterator Iter() => new(Universe, IteratorType.Filter, ecs_filter_iter(Universe, this));
|
|
|
|
public IEnumerator<Iterator> GetEnumerator() => Iter().GetEnumerator();
|
|
|
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
|
|
}
|
|
|
|
|
|
|
|
public class FilterDesc
|
|
|
|
{
|
|
|
|
public IReadOnlyList<Term> Terms { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Optional name of filter, used for debugging. If a filter is created
|
|
|
|
/// for a system, the provided name should match the system name.
|
|
|
|
/// </summary>
|
|
|
|
public string? Name { get; set; }
|
|
|
|
|
|
|
|
/// <summary> Filter expression. Should not be set at the same time as terms. </summary>
|
|
|
|
public string? Expression { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// When true, terms returned by an iterator may either contain 1 or N
|
|
|
|
/// elements, where terms with N elements are owned, and terms with 1
|
|
|
|
/// element are shared, for example from a parent or base entity. When
|
|
|
|
/// false, the iterator will at most return 1 element when the result
|
|
|
|
/// contains both owned and shared terms.
|
|
|
|
/// </summary>
|
|
|
|
public bool Instanced { get; set; }
|
|
|
|
|
|
|
|
public FilterDesc(string? name = null, params Term[] terms)
|
|
|
|
{ Name = name; Terms = terms; }
|
|
|
|
|
|
|
|
public unsafe ecs_filter_desc_t ToFlecs()
|
|
|
|
{
|
|
|
|
var desc = new ecs_filter_desc_t {
|
|
|
|
name = Name.FlecsToCString(),
|
|
|
|
expr = Expression.FlecsToCString(),
|
|
|
|
instanced = Instanced,
|
|
|
|
};
|
|
|
|
var span = desc.terms;
|
|
|
|
if (Terms.Count > desc.terms.Length) {
|
|
|
|
var byteCount = sizeof(ecs_term_t) * Terms.Count;
|
|
|
|
var ptr = (ecs_term_t*)Marshal.AllocHGlobal(byteCount);
|
|
|
|
desc.terms_buffer = ptr;
|
|
|
|
desc.terms_buffer_count = Terms.Count;
|
|
|
|
span = new(ptr, Terms.Count);
|
|
|
|
}
|
|
|
|
for (var i = 0; i < Terms.Count; i++)
|
|
|
|
span[i] = Terms[i].ToFlecs();
|
|
|
|
return desc;
|
|
|
|
}
|
|
|
|
}
|