using System; using System.Collections.Generic; using System.Linq; namespace StardewModdingAPI.Framework { /// Manages console commands. internal class CommandManager { /********* ** Properties *********/ /// The commands registered with SMAPI. private readonly IDictionary Commands = new Dictionary(StringComparer.InvariantCultureIgnoreCase); /********* ** Public methods *********/ /// Add a console command. /// The friendly mod name for this instance. /// The command name, which the user must type to trigger it. /// The human-readable documentation shown when the player runs the built-in 'help' command. /// The method to invoke when the command is triggered. This method is passed the command name and arguments submitted by the user. /// Whether to allow a null argument; this should only used for backwards compatibility. /// The or is null or empty. /// The is not a valid format. /// There's already a command with that name. public void Add(string modName, string name, string documentation, Action callback, bool allowNullCallback = false) { name = this.GetNormalisedName(name); // validate format if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name), "Can't register a command with no name."); if (name.Any(char.IsWhiteSpace)) throw new FormatException($"Can't register the '{name}' command because the name can't contain whitespace."); if (callback == null && !allowNullCallback) throw new ArgumentNullException(nameof(callback), $"Can't register the '{name}' command because without a callback."); // ensure uniqueness if (this.Commands.ContainsKey(name)) throw new ArgumentException(nameof(callback), $"Can't register the '{name}' command because there's already a command with that name."); // add command this.Commands.Add(name, new Command(modName, name, documentation, callback)); } /// Get a command by its unique name. /// The command name. /// Returns the matching command, or null if not found. public Command Get(string name) { name = this.GetNormalisedName(name); this.Commands.TryGetValue(name, out Command command); return command; } /// Get all registered commands. public IEnumerable GetAll() { return this.Commands .Values .OrderBy(p => p.Name); } /// Trigger a command. /// The raw command input. /// Returns whether a matching command was triggered. public bool Trigger(string input) { if (string.IsNullOrWhiteSpace(input)) return false; string[] args = input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); string name = args[0]; args = args.Skip(1).ToArray(); return this.Trigger(name, args); } /// Trigger a command. /// The command name. /// The command arguments. /// Returns whether a matching command was triggered. public bool Trigger(string name, string[] arguments) { // get normalised name name = this.GetNormalisedName(name); if (name == null) return false; // get command if (this.Commands.TryGetValue(name, out Command command)) { command.Callback.Invoke(name, arguments); return true; } return false; } /********* ** Private methods *********/ /// Get a normalised command name. /// The command name. private string GetNormalisedName(string name) { name = name?.Trim().ToLower(); return !string.IsNullOrWhiteSpace(name) ? name : null; } } }