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.

61 lines
2.0 KiB

2 years ago
using System;
using System.Linq;
using System.Reflection;
using gaemstone.Utility;
using gaemstone.Utility.IL;
using static flecs_hub.flecs;
2 years ago
namespace gaemstone.ECS;
[AttributeUsage(AttributeTargets.Method)]
public class ObserverAttribute : Attribute
2 years ago
{
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,
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 = &SystemExtensions.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));
FilterDesc filter;
Action<Iterator> iterAction;
var param = method.GetParameters();
if (param.Length == 1 && param[0].ParameterType == typeof(Iterator)) {
filter = new(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);
filter = (attr.Expression != null) ? new(attr.Expression) : 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);
}
2 years ago
}