You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
70 lines
2.4 KiB
70 lines
2.4 KiB
using System; |
|
using System.Linq; |
|
using System.Reflection; |
|
using System.Runtime.InteropServices; |
|
using gaemstone.Utility; |
|
using gaemstone.Utility.IL; |
|
using static flecs_hub.flecs; |
|
|
|
namespace gaemstone.ECS; |
|
|
|
[AttributeUsage(AttributeTargets.Method)] |
|
public class ObserverAttribute : Attribute |
|
{ |
|
public Type Event { get; } |
|
internal ObserverAttribute(Type @event) => Event = @event; // Use generic type instead. |
|
} |
|
public class ObserverAttribute<TEvent> : ObserverAttribute |
|
{ public ObserverAttribute() : base(typeof(TEvent)) { } } |
|
|
|
public static class ObserverExtensions |
|
{ |
|
public static unsafe EntityRef RegisterObserver(this Universe universe, |
|
FilterDesc filter, Entity @event, Action<Iterator> callback) |
|
{ |
|
using var alloc = TempAllocator.Use(); |
|
var desc = new ecs_observer_desc_t { |
|
filter = filter.ToFlecs(alloc), |
|
entity = universe.New((filter.Name != null) ? new(filter.Name) : null).Build(), |
|
binding_ctx = (void*)CallbackContextHelper.Create((universe, callback)), |
|
callback = new() { Data = new() { Pointer = &Callback } }, |
|
}; |
|
desc.events[0] = @event; |
|
return new(universe, new(ecs_observer_init(universe, &desc))); |
|
} |
|
|
|
public static EntityRef RegisterObserver(this Universe universe, |
|
object? instance, MethodInfo method) |
|
{ |
|
var attr = method.Get<ObserverAttribute>() ?? throw new ArgumentException( |
|
"Observer must specify ObserverAttribute", nameof(method)); |
|
var expr = method.Get<ExpressionAttribute>()?.Value; |
|
FilterDesc filter; |
|
Action<Iterator> iterAction; |
|
|
|
var param = method.GetParameters(); |
|
if ((param.Length == 1) && (param[0].ParameterType == typeof(Iterator))) { |
|
filter = new(expr ?? throw new Exception( |
|
"Observer must specify ExpressionAttribute")); |
|
if (method.IsStatic) instance = null; |
|
iterAction = (Action<Iterator>)Delegate.CreateDelegate( |
|
typeof(Action<Iterator>), instance, method); |
|
} else { |
|
var gen = IterActionGenerator.GetOrBuild(universe, method); |
|
filter = (expr != null) ? new(expr) : new(gen.Terms.ToArray()); |
|
iterAction = iter => gen.RunWithTryCatch(instance, iter); |
|
} |
|
|
|
filter.Name = method.Name; |
|
var @event = universe.LookupOrThrow(attr.Event); |
|
return universe.RegisterObserver(filter, @event, iterAction); |
|
} |
|
|
|
[UnmanagedCallersOnly] |
|
private static unsafe void Callback(ecs_iter_t* iter) |
|
{ |
|
var (universe, callback) = CallbackContextHelper |
|
.Get<(Universe, Action<Iterator>)>((nint)iter->binding_ctx); |
|
callback(new Iterator(universe, null, *iter)); |
|
} |
|
}
|
|
|