/// <summary> /// Add a new command with names separated by folders/namespaces, last is command name, others are holders. /// These will be made as required /// during the add. /// </summary> /// <param name="names">separated command name e.g. Physics.gravity is now {"Physics","gravity"}</param> /// <param name="callback">action of the command to add</param> /// <param name="helpText">help text to show to user about the command</param> /// <param name="command_index">used in the recursion, indicates current depth in names array</param> public void Add(string[] names, Console.CommandCallback callback, string helpText, int command_index = 0) { if (names.Length == command_index) { Command = new ConsoleCommandData { localName = names.Last(), callback = callback, help = helpText }; return; } string token = names[command_index]; string lowerToken = token.ToLowerInvariant(); if (!subCommandsLookUp.ContainsKey(lowerToken)) { ConsoleCommandData data = new ConsoleCommandData { localName = token }; subCommandsLookUp[lowerToken] = new ConsoleCommandTreeNode(this, data); } subCommandsLookUp[lowerToken].Add(names, callback, helpText, command_index + 1); }
/// <summary> /// Check for compatibility with the variable in question, generate and add the closure. If no params are given it will act as a get, /// if params are given it will attempt to use them as a set. /// /// Wrap the functionality that is DAMN NEAR identical for fields and properties so we don't have to maintain two versions in 2 locations /// </summary> /// <param name="instance"></param> /// <param name="field"></param> /// <param name="property"></param> /// <param name="finalName"></param> private static void PropAndFieldInternalHelper(object instance, FieldInfo field, PropertyInfo property, string finalName) { Type paramType; string name; ICustomAttributeProvider attrProv; if (field != null) { paramType = field.FieldType; name = field.Name; attrProv = field; } else { paramType = property.PropertyType; name = property.Name; attrProv = property; } if (!StringToType.IsSupported(paramType)) { OnErrorLogDelegate(string.Format("Cannot generate variable wrapper on {0}, type {1} is not supported.", name, paramType.Name)); return; } //fancy wrapper goes here that returns value safely on no params and tries to convert on 1 param Console.CommandCallback wrappedFunc = (string stringIn) => { //do they want to set if (!string.IsNullOrEmpty(stringIn)) { object parameter = StringToType.TryGetTypeFromString(paramType, stringIn); if (parameter != null) { //use it as a set if (field != null) { field.SetValue(instance, parameter); //log new val Console.Log("=" + field.GetValue(instance).ToString()); } else { if (property.CanWrite) { property.SetValue(instance, parameter, null); if (property.CanRead) { Console.Log("=" + property.GetValue(instance, null).ToString()); } } else { Console.Log(property.Name + " cannot be set."); } } } } else { //get only if (field != null) { Console.Log("=" + field.GetValue(instance).ToString()); } else { if (property.CanRead) { Console.Log("=" + property.GetValue(instance, null).ToString()); } else { Console.Log(property.Name + " cannot be read."); } } } }; var attrs = attrProv.GetCustomAttributes(typeof(ConsoleCommandAttribute), false) as ConsoleCommandAttribute[]; var attr = attrs.Length > 0 ? attrs[0] : null; Console.RegisterCommand(finalName, attr != null ? attr.help : "Expects " + paramType.ToString(), wrappedFunc); }