|
|
|
using System;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Reflection;
|
|
|
|
using gaemstone.Utility;
|
|
|
|
using gaemstone.Utility.IL;
|
|
|
|
|
|
|
|
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 EntityRef InitObserver(this World world,
|
|
|
|
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(world, method);
|
|
|
|
filter = (expr != null) ? new(expr) : new(gen.Terms.ToArray());
|
|
|
|
iterAction = iter => gen.RunWithTryCatch(instance, iter);
|
|
|
|
}
|
|
|
|
|
|
|
|
var @event = world.LookupByTypeOrThrow(attr.Event);
|
|
|
|
return world.New(method.Name).Build().InitObserver(@event, filter, iterAction);
|
|
|
|
}
|
|
|
|
}
|