|
|
|
using System;
|
|
|
|
using System.Reflection;
|
|
|
|
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; }
|
|
|
|
public string? Expression { get; set; }
|
|
|
|
|
|
|
|
public ObserverAttribute(Type @event) => Event = @event;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class ObserverExtensions
|
|
|
|
{
|
|
|
|
public static unsafe EntityRef RegisterObserver(this Universe universe,
|
|
|
|
string name, Entity @event, FilterDesc filter, Action<Iterator> callback)
|
|
|
|
{
|
|
|
|
filter.Name = name;
|
|
|
|
var desc = new ecs_observer_desc_t {
|
|
|
|
filter = filter.ToFlecs(),
|
|
|
|
entity = universe.New(name).Build(),
|
|
|
|
binding_ctx = (void*)CallbackContextHelper.Create((universe, callback)),
|
|
|
|
callback = new() { Data = new() { Pointer = &SystemExtensions.Callback } },
|
|
|
|
};
|
|
|
|
desc.events[0] = @event;
|
|
|
|
var entity = ecs_observer_init(universe, &desc);
|
|
|
|
return new(universe, new(entity));
|
|
|
|
}
|
|
|
|
|
|
|
|
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 filter = new FilterDesc();
|
|
|
|
Action<Iterator> iterAction;
|
|
|
|
|
|
|
|
var param = method.GetParameters();
|
|
|
|
if (param.Length == 1 && param[0].ParameterType == typeof(Iterator)) {
|
|
|
|
filter.Expression = attr.Expression ?? throw new Exception(
|
|
|
|
"Observer must specify ObserverAttribute.Expression");
|
|
|
|
if (method.IsStatic) instance = null;
|
|
|
|
iterAction = (Action<Iterator>)Delegate.CreateDelegate(
|
|
|
|
typeof(Action<Iterator>), instance, method);
|
|
|
|
} else {
|
|
|
|
var gen = IterActionGenerator.GetOrBuild(universe, method);
|
|
|
|
if (attr.Expression == null) filter.Terms = gen.Terms;
|
|
|
|
else filter.Expression = attr.Expression;
|
|
|
|
iterAction = iter => gen.RunWithTryCatch(instance, iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
var @event = universe.LookupOrThrow(attr.Event);
|
|
|
|
return universe.RegisterObserver(method.Name, @event, filter, iterAction);
|
|
|
|
}
|
|
|
|
}
|