using System; using System.Linq; using System.Reflection; using gaemstone.Flecs; using gaemstone.Utility; using gaemstone.Utility.IL; namespace gaemstone.ECS; [AttributeUsage(AttributeTargets.Method)] public class SystemAttribute : Attribute { public Type Phase { get; } public SystemAttribute() : this(typeof(SystemPhase.OnUpdate)) { } internal SystemAttribute(Type phase) => Phase = phase; // Use generic type instead. } public class SystemAttribute : SystemAttribute { public SystemAttribute() : base(typeof(TPhase)) { } } [AttributeUsage(AttributeTargets.Method)] public class ExpressionAttribute : Attribute { public string Value { get; } public ExpressionAttribute(string value) => Value = value; } public static class SystemExtensions { public static EntityRef InitSystem(this World world, Delegate action) { var attr = action.Method.Get(); var expr = action.Method.Get()?.Value; QueryDesc query; if (action is Action callback) { query = new(expr ?? throw new ArgumentException( "System must specify ExpressionAttribute", nameof(action))); } else { var gen = IterActionGenerator.GetOrBuild(world, action.Method); query = (expr != null) ? new(expr) : new(gen.Terms.ToArray()); callback = iter => gen.RunWithTryCatch(action.Target, iter); } var phase = world.LookupByTypeOrThrow(attr?.Phase ?? typeof(SystemPhase.OnUpdate)); return world.New(action.Method.Name).Build().InitSystem(phase, query, callback); } public static EntityRef InitSystem(this World world, object? instance, MethodInfo method) { var attr = method.Get(); var expr = method.Get()?.Value; QueryDesc query; Action callback; var param = method.GetParameters(); if ((param.Length == 1) && (param[0].ParameterType == typeof(Iterator))) { query = new(expr ?? throw new ArgumentException( "System must specify ExpressionAttribute", nameof(method))); callback = (Action)Delegate.CreateDelegate(typeof(Action), instance, method); } else { var gen = IterActionGenerator.GetOrBuild(world, method); query = (expr != null) ? new(expr) : new(gen.Terms.ToArray()); callback = iter => gen.RunWithTryCatch(instance, iter); } var phase = world.LookupByTypeOrThrow(attr?.Phase ?? typeof(SystemPhase.OnUpdate)); return world.New(method.Name).Build().InitSystem(phase, query, callback); } }