static Reflector() { foreach (var type in //This is more correct but way slower //AppDomain.CurrentDomain.GetAssemblies() //.Where(a => !a.IsDynamic) //.Where(a => a.GetCustomAttributes(false).Any(c => c is ReflectAttribute)) ReflectableAssemblies .SelectMany(a => a.GetTypes())) { foreach (var ca in type.GetCustomAttributes()) { if (ca is ReflectAttribute ra) { ReflectionData.RecordPublic(type, ra.returnType); break; } } } InitializeEnumResolvers(); AllowMath <TEx <float> >(); AllowMath <TEx <bool> >(); //This will also allow stuff like (if + true false), which will error if you actually use it AllowMath <TEx <Vector2> >(); AllowMath <TEx <Vector3> >(); AllowMath <TEx <Vector4> >(); AllowMath <TEx <V2RV2> >(); void CreatePostAggregates(string method, string shortcut) { var mi = typeof(ExPostAggregators).GetMethod(method) ?? throw new Exception($"Couldn't find post-aggregator \"{method}\""); var attrs = Attribute.GetCustomAttributes(mi); var priority = 999; Type[]? types = null; foreach (var attr in attrs) { if (attr is PAPriorityAttribute pp) { priority = pp.priority; } else if (attr is PASourceTypesAttribute ps) { types = ps.types; } } void CreateAggregateMethod(MethodInfo gmi) { var prms = gmi.GetParameters(); if (prms.Length != 2) { throw new Exception($"Post-aggregator \"{method}\" doesn't have 2 arguments"); } var sourceType = prms[0].ParameterType; var searchType = prms[1].ParameterType; if (gmi.ReturnType != sourceType) { throw new Exception($"Post-aggregator \"{method}\" has a different return and first argument type"); } postAggregators.SetDefaultSet(sourceType, shortcut, new PostAggregate(priority, sourceType, searchType, gmi)); } if (types == null) { CreateAggregateMethod(mi); } else { //types = [ (float), (v2) ... ] foreach (var rt in types) { CreateAggregateMethod(mi.MakeGenericMethod(rt)); } } } CreatePostAggregates("PA_Add", "+"); CreatePostAggregates("PA_Mul", "*"); CreatePostAggregates("PA_Sub", "-"); CreatePostAggregates("PA_Div", "/"); CreatePostAggregates("PA_FDiv", "//"); CreatePostAggregates("PA_Pow", "^"); CreatePostAggregates("PA_And", "&"); CreatePostAggregates("PA_Or", "|"); void CreatePreAggregates(string method, string shortcut) { var mi = typeof(ExPreAggregators).GetMethod(method) ?? throw new Exception($"Couldn't find post-aggregator \"{method}\""); var attrs = Attribute.GetCustomAttributes(mi); var priority = 999; var types = new Type[0]; foreach (var attr in attrs) { if (attr is PAPriorityAttribute pp) { priority = pp.priority; } else if (attr is PASourceTypesAttribute ps) { types = ps.types; } } //types = [ (float), (v2) ... ] foreach (var rt in types) { var gmi = mi.MakeGenericMethod(rt); var prms = gmi.GetParameters(); if (prms.Length != 2) { throw new Exception($"Pre-aggregator \"{method}\" doesn't have 2 arguments"); } var resultType = gmi.ReturnType; var searchType1 = prms[0].ParameterType; var searchType2 = prms[1].ParameterType; if (preAggregators.TryGetValue(resultType, out var res)) { if (res.firstType != searchType1) { throw new Exception( $"Pre-aggregators currently support only one reducer type, " + $"but return type {resultType.RName()} is associated with " + $"{res.firstType.RName()} and {searchType1.RName()}."); } } else { res = new PreAggregate(searchType1); } res.AddResolver(new PreAggregateResolver(shortcut, searchType2, gmi, priority)); preAggregators[resultType] = res; } } CreatePreAggregates("PA_Mul", "*"); CreatePreAggregates("PA_GT", ">"); CreatePreAggregates("PA_LT", "<"); CreatePreAggregates("PA_GEQ", ">="); CreatePreAggregates("PA_LEQ", "<="); CreatePreAggregates("PA_EQ", "="); CreatePreAggregates("PA_NEQ", "=/="); foreach (var key in preAggregators.Keys.ToArray()) { var res = preAggregators[key]; res.SortResolvers(); preAggregators[key] = res; } }