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 : 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() ?? throw new ArgumentException( "Observer must specify ObserverAttribute", nameof(method)); var expr = method.Get()?.Value; FilterDesc filter; Action 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)Delegate.CreateDelegate( typeof(Action), 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); } }