using System; using System.Runtime.InteropServices; using gaemstone.ECS.Utility; using static flecs_hub.flecs; namespace gaemstone.ECS; public static class ObserverExtensions { public static unsafe Entity InitObserver(this Entity entity, FilterDesc filter, Action> callback, params Entity[] events) { if (events.Length == 0) throw new ArgumentException("Must specify at least 1 event", nameof(events)); if (events.Length > 8) throw new ArgumentException("Must specify at most 8 events", nameof(events)); var world = entity.World; var internalCallback = (nint iterPtr) => callback(new((ecs_iter_t*)iterPtr)); using var alloc = TempAllocator.Use(); var desc = new ecs_observer_desc_t { entity = entity, filter = filter.ToFlecs(alloc), binding_ctx = (void*)CallbackContextHelper.Create(internalCallback), binding_ctx_free = new() { Data = new() { Pointer = &FreeContext } }, callback = new() { Data = new() { Pointer = &Callback } }, }; var span = desc.events; for (var i = 0; i < events.Length; i++) span[i] = events[i]; if (ecs_observer_init(world, &desc).Data == default) throw new InvalidOperationException(); return entity; } [UnmanagedCallersOnly] private static unsafe void Callback(ecs_iter_t* iter) => CallbackContextHelper .Get>((nint)iter->binding_ctx) .Invoke((nint)iter); [UnmanagedCallersOnly] private static unsafe void FreeContext(void* context) => CallbackContextHelper.Free((nint)context); }