using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using gaemstone.ECS.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS; public unsafe class Filter : IDisposable { public World World { get; } public ecs_filter_t* Handle { get; } public Variable? ThisVar { get { var index = ecs_filter_find_this_var(this); return (index >= 0) ? new(index, "This") : null; } } internal Filter(World world, ecs_filter_t* handle) { World = world; Handle = handle; } public Filter(World world, FilterDesc desc) { using var alloc = TempAllocator.Use(); var flecsDesc = desc.ToFlecs(alloc); World = world; Handle = ecs_filter_init(world, &flecsDesc); } public void Dispose() => ecs_filter_fini(this); public FilterIterator Iter() => new(ecs_filter_iter(World, this)); public override string ToString() => ecs_filter_str(World, this).FlecsToStringAndFree()!; public static implicit operator ecs_filter_t*(Filter filter) => filter.Handle; } public unsafe class FilterIterator : Iterator { internal FilterIterator(ecs_iter_t value) : base(value) { } public override bool Next() => ecs_filter_next(Handle); } public class FilterDesc { public IReadOnlyList Terms { get; } public string? Expression { get; } /// /// 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. /// public bool Instanced { get; set; } /// /// Entity associated with query (optional). /// public Entity Entity { get; set; } public FilterDesc(params Term[] terms) => Terms = terms; public FilterDesc(string expression) : this() => Expression = expression; public unsafe ecs_filter_desc_t ToFlecs(IAllocator allocator) { var desc = new ecs_filter_desc_t { _expr = allocator.AllocateCString(Expression), instanced = Instanced, entity = Entity, }; var span = desc.terms; if (Terms.Count > span.Length) { span = allocator.Allocate(Terms.Count); desc.terms_buffer = (ecs_term_t*)Unsafe.AsPointer(ref span[0]); desc.terms_buffer_count = Terms.Count; } for (var i = 0; i < Terms.Count; i++) span[i] = Terms[i].ToFlecs(allocator); return desc; } }