using System; using System.Runtime.InteropServices; using gaemstone.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS; public static class SystemExtensions { public static unsafe EntityRef InitSystem(this EntityRef entity, Entity phase, QueryDesc query, Action callback) { var world = entity.World; entity.Add(world.DependsOn, phase); using var alloc = TempAllocator.Use(); var desc = new ecs_system_desc_t { entity = entity, query = query.ToFlecs(alloc), binding_ctx = (void*)CallbackContextHelper.Create((world, callback)), binding_ctx_free = new() { Data = new() { Pointer = &FreeContext } }, callback = new() { Data = new() { Pointer = &Callback } }, }; return new(world, new(ecs_system_init(world, &desc))); } [UnmanagedCallersOnly] private static unsafe void Callback(ecs_iter_t* iter) { var (world, callback) = CallbackContextHelper .Get<(World, Action)>((nint)iter->binding_ctx); callback(new Iterator(world, null, *iter)); } // [UnmanagedCallersOnly] // private static unsafe void Run(ecs_iter_t* flecsIter) // { // var (world, callback) = CallbackContextHelper // .Get<(World, Action)>((nint)flecsIter->binding_ctx); // // This is what flecs does, so I guess we'll do it too! // var type = (&flecsIter->next == (delegate*)&ecs_query_next) // ? IteratorType.Query : (IteratorType?)null; // using var iter = new Iterator(world, type, *flecsIter); // If the method is marked with [Source], set the $This variable. // if (Method.Get()?.Type is Type sourceType) // iter.SetThis(World.LookupOrThrow(sourceType)); // if (flecsIter->field_count == 0) callback(iter); // else while (iter.Next()) callback(iter); // } [UnmanagedCallersOnly] private static unsafe void FreeContext(void* context) => CallbackContextHelper.Free((nint)context); }