private object[] MakeArgs(Type[] types, string[] text, out string error) { int expected = 0; VarConverter[] converters = new VarConverter[types.Length]; for (int i = 0; i < types.Length; i++) { var c = GameVar.GetConverter(types[i]); if (c == null) { error = $"Could not find parser for type '{types[i].FullName}'."; return(null); } converters[i] = c; expected += c.ExpectedArgCount; } if (expected != text.Length) { error = $"Incorrect number of input parts.\nExpected: {expected} parts from {types.Length} parameters, got {text.Length} parts."; return(null); } object[] output = new object[types.Length]; int readIndex = 0; for (int i = 0; i < types.Length; i++) { var c = converters[i]; string[] args = new string[c.ExpectedArgCount]; System.Array.Copy(text, readIndex, args, 0, c.ExpectedArgCount); readIndex += c.ExpectedArgCount; object obj = c.Convert(args, out string oops); if (oops != null) { error = $"Failed to parse argument #{i} ({types[i].Name}):\n{oops}";; return(null); } output[i] = obj; } error = null; return(output); }
public static void LoadCommands() { System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch(); s.Start(); Assembly a = typeof(CommandUI).Assembly; Debug.Log($"Searching for custom commands and variables in assembly '{a.FullName}'"); // Partition on the type list initially. var def = typeof(CommandAttribute); var found = from t in a.GetTypes().AsParallel() let methods = t.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) from m in methods where m.IsDefined(def, true) select new { Type = t, Method = m, Attribute = m.GetCustomAttribute <CommandAttribute>() }; var gameVarDef = typeof(GameVarAttribute); var gameF = from t in a.GetTypes().AsParallel() let fields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) from f in fields where f.IsDefined(gameVarDef, true) select new { Type = t, Field = f, Attribute = f.GetCustomAttribute <GameVarAttribute>() }; var gameP = from t in a.GetTypes().AsParallel() let properties = t.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance) from p in properties where p.IsDefined(gameVarDef, true) select new { Type = t, Property = p, Attribute = p.GetCustomAttribute <GameVarAttribute>() }; foreach (var gv in gameF) { var thing = new GameVar(gv.Attribute, gv.Field, null); GameVars.Add(thing.Name, thing); } foreach (var gv in gameP) { var thing = new GameVar(gv.Attribute, null, gv.Property); GameVars.Add(thing.Name, thing); } for (int i = 0; i < GameVars.Count; i++) { var gv = GameVars.ElementAt(i).Value; if (!gv.IsValid) { Debug.LogWarning($"{gv.Name} is not a valid game variable, ignoring."); GameVars.Remove(gv.Name); i--; } } int count = 0; StringBuilder str = new StringBuilder(); foreach (var cmd in found) { var type = cmd.Type; var method = cmd.Method; var attr = cmd.Attribute; if (!method.IsStatic) { Debug.LogError($"Currently non-static commands are not supported: {type.FullName}.{method.Name}"); continue; } Command c = new Command(attr, method); Commands.Add(c.Name, c); str.Append($"Class: {type.FullName}, Method: {method.Name}\n"); count++; } s.Stop(); Debug.Log($"Took {s.Elapsed.TotalMilliseconds:F1}ms. Found {count} commands:\n{str.ToString()}\n"); }