summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/release-notes.md1
-rw-r--r--src/SMAPI/Framework/Command.cs12
-rw-r--r--src/SMAPI/Framework/CommandManager.cs31
-rw-r--r--src/SMAPI/Framework/ModHelpers/CommandHelper.cs15
-rw-r--r--src/SMAPI/Framework/SCore.cs12
-rw-r--r--src/SMAPI/Framework/SGame.cs22
6 files changed, 61 insertions, 32 deletions
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 7c25eba6..f4bce8c8 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -16,6 +16,7 @@
* Fixed transparency issues on Linux/Mac for some mod images.
* Fixed translation issues not shown as warnings.
* Fixed dependencies not correctly enforced if the dependency is installed but failed to load.
+ * Fixed some errors logged as SMAPI instead of the affected mod.
* Updated compatibility list.
* For modders:
diff --git a/src/SMAPI/Framework/Command.cs b/src/SMAPI/Framework/Command.cs
index 943e018d..8c9df47d 100644
--- a/src/SMAPI/Framework/Command.cs
+++ b/src/SMAPI/Framework/Command.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
namespace StardewModdingAPI.Framework
{
@@ -8,8 +8,8 @@ namespace StardewModdingAPI.Framework
/*********
** Accessor
*********/
- /// <summary>The friendly name for the mod that registered the command.</summary>
- public string ModName { get; }
+ /// <summary>The mod that registered the command (or <c>null</c> if registered by SMAPI).</summary>
+ public IModMetadata Mod { get; }
/// <summary>The command name, which the user must type to trigger it.</summary>
public string Name { get; }
@@ -25,13 +25,13 @@ namespace StardewModdingAPI.Framework
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="modName">The friendly name for the mod that registered the command.</param>
+ /// <param name="mod">The mod that registered the command (or <c>null</c> if registered by SMAPI).</param>
/// <param name="name">The command name, which the user must type to trigger it.</param>
/// <param name="documentation">The human-readable documentation shown when the player runs the built-in 'help' command.</param>
/// <param name="callback">The method to invoke when the command is triggered. This method is passed the command name and arguments submitted by the user.</param>
- public Command(string modName, string name, string documentation, Action<string, string[]> callback)
+ public Command(IModMetadata mod, string name, string documentation, Action<string, string[]> callback)
{
- this.ModName = modName;
+ this.Mod = mod;
this.Name = name;
this.Documentation = documentation;
this.Callback = callback;
diff --git a/src/SMAPI/Framework/CommandManager.cs b/src/SMAPI/Framework/CommandManager.cs
index f9651ed9..aabe99c3 100644
--- a/src/SMAPI/Framework/CommandManager.cs
+++ b/src/SMAPI/Framework/CommandManager.cs
@@ -19,7 +19,7 @@ namespace StardewModdingAPI.Framework
** Public methods
*********/
/// <summary>Add a console command.</summary>
- /// <param name="modName">The friendly mod name for this instance.</param>
+ /// <param name="mod">The mod adding the command (or <c>null</c> for a SMAPI command).</param>
/// <param name="name">The command name, which the user must type to trigger it.</param>
/// <param name="documentation">The human-readable documentation shown when the player runs the built-in 'help' command.</param>
/// <param name="callback">The method to invoke when the command is triggered. This method is passed the command name and arguments submitted by the user.</param>
@@ -27,7 +27,7 @@ namespace StardewModdingAPI.Framework
/// <exception cref="ArgumentNullException">The <paramref name="name"/> or <paramref name="callback"/> is null or empty.</exception>
/// <exception cref="FormatException">The <paramref name="name"/> is not a valid format.</exception>
/// <exception cref="ArgumentException">There's already a command with that name.</exception>
- public void Add(string modName, string name, string documentation, Action<string, string[]> callback, bool allowNullCallback = false)
+ public void Add(IModMetadata mod, string name, string documentation, Action<string, string[]> callback, bool allowNullCallback = false)
{
name = this.GetNormalisedName(name);
@@ -44,7 +44,7 @@ namespace StardewModdingAPI.Framework
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));
+ this.Commands.Add(name, new Command(mod, name, documentation, callback));
}
/// <summary>Get a command by its unique name.</summary>
@@ -65,19 +65,30 @@ namespace StardewModdingAPI.Framework
.OrderBy(p => p.Name);
}
- /// <summary>Trigger a command.</summary>
- /// <param name="input">The raw command input.</param>
- /// <returns>Returns whether a matching command was triggered.</returns>
- public bool Trigger(string input)
+ /// <summary>Try to parse a raw line of user input into an executable command.</summary>
+ /// <param name="input">The raw user input.</param>
+ /// <param name="name">The parsed command name.</param>
+ /// <param name="args">The parsed command arguments.</param>
+ /// <param name="command">The command which can handle the input.</param>
+ /// <returns>Returns true if the input was successfully parsed and matched to a command; else false.</returns>
+ public bool TryParse(string input, out string name, out string[] args, out Command command)
{
+ // ignore if blank
if (string.IsNullOrWhiteSpace(input))
+ {
+ name = null;
+ args = null;
+ command = null;
return false;
+ }
- string[] args = this.ParseArgs(input);
- string name = args[0];
+ // parse input
+ args = this.ParseArgs(input);
+ name = this.GetNormalisedName(args[0]);
args = args.Skip(1).ToArray();
- return this.Trigger(name, args);
+ // get command
+ return this.Commands.TryGetValue(name, out command);
}
/// <summary>Trigger a command.</summary>
diff --git a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
index bdedb07c..5a3304f3 100644
--- a/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/CommandHelper.cs
@@ -8,8 +8,8 @@ namespace StardewModdingAPI.Framework.ModHelpers
/*********
** Accessors
*********/
- /// <summary>The friendly mod name for this instance.</summary>
- private readonly string ModName;
+ /// <summary>The mod using this instance.</summary>
+ private readonly IModMetadata Mod;
/// <summary>Manages console commands.</summary>
private readonly CommandManager CommandManager;
@@ -19,13 +19,12 @@ namespace StardewModdingAPI.Framework.ModHelpers
** Public methods
*********/
/// <summary>Construct an instance.</summary>
- /// <param name="modID">The unique ID of the relevant mod.</param>
- /// <param name="modName">The friendly mod name for this instance.</param>
+ /// <param name="mod">The mod using this instance.</param>
/// <param name="commandManager">Manages console commands.</param>
- public CommandHelper(string modID, string modName, CommandManager commandManager)
- : base(modID)
+ public CommandHelper(IModMetadata mod, CommandManager commandManager)
+ : base(mod?.Manifest?.UniqueID ?? "SMAPI")
{
- this.ModName = modName;
+ this.Mod = mod;
this.CommandManager = commandManager;
}
@@ -38,7 +37,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <exception cref="ArgumentException">There's already a command with that name.</exception>
public ICommandHelper Add(string name, string documentation, Action<string, string[]> callback)
{
- this.CommandManager.Add(this.ModName, name, documentation, callback);
+ this.CommandManager.Add(this.Mod, name, documentation, callback);
return this;
}
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 5f30c9ef..0594c793 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -427,8 +427,8 @@ namespace StardewModdingAPI.Framework
{
// prepare console
this.Monitor.Log("Type 'help' for help, or 'help <cmd>' for a command's usage", LogLevel.Info);
- this.GameInstance.CommandManager.Add("SMAPI", "help", "Lists command documentation.\n\nUsage: help\nLists all available commands.\n\nUsage: help <cmd>\n- cmd: The name of a command whose documentation to display.", this.HandleCommand);
- this.GameInstance.CommandManager.Add("SMAPI", "reload_i18n", "Reloads translation files for all mods.\n\nUsage: reload_i18n", this.HandleCommand);
+ this.GameInstance.CommandManager.Add(null, "help", "Lists command documentation.\n\nUsage: help\nLists all available commands.\n\nUsage: help <cmd>\n- cmd: The name of a command whose documentation to display.", this.HandleCommand);
+ this.GameInstance.CommandManager.Add(null, "reload_i18n", "Reloads translation files for all mods.\n\nUsage: reload_i18n", this.HandleCommand);
// start handling command line input
Thread inputThread = new Thread(() =>
@@ -973,7 +973,7 @@ namespace StardewModdingAPI.Framework
IModHelper modHelper;
{
IModEvents events = new ModEvents(mod, this.EventManager);
- ICommandHelper commandHelper = new CommandHelper(manifest.UniqueID, mod.DisplayName, this.GameInstance.CommandManager);
+ ICommandHelper commandHelper = new CommandHelper(mod, this.GameInstance.CommandManager);
IContentHelper contentHelper = new ContentHelper(contentCore, mod.DirectoryPath, manifest.UniqueID, mod.DisplayName, monitor);
IDataHelper dataHelper = new DataHelper(manifest.UniqueID, mod.DirectoryPath, jsonHelper);
IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, mod.DisplayName, this.Reflection, this.DeprecationManager);
@@ -1216,15 +1216,15 @@ namespace StardewModdingAPI.Framework
if (result == null)
this.Monitor.Log("There's no command with that name.", LogLevel.Error);
else
- this.Monitor.Log($"{result.Name}: {result.Documentation}\n(Added by {result.ModName}.)", LogLevel.Info);
+ this.Monitor.Log($"{result.Name}: {result.Documentation}{(result.Mod != null ? $"\n(Added by {result.Mod.DisplayName}.)" : "")}", LogLevel.Info);
}
else
{
string message = "The following commands are registered:\n";
- IGrouping<string, string>[] groups = (from command in this.GameInstance.CommandManager.GetAll() orderby command.ModName, command.Name group command.Name by command.ModName).ToArray();
+ IGrouping<string, string>[] groups = (from command in this.GameInstance.CommandManager.GetAll() orderby command.Mod?.DisplayName, command.Name group command.Name by command.Mod?.DisplayName).ToArray();
foreach (var group in groups)
{
- string modName = group.Key;
+ string modName = group.Key ?? "SMAPI";
string[] commandNames = group.ToArray();
message += $"{modName}:\n {string.Join("\n ", commandNames)}\n\n";
}
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 1bd583bf..a9b80bc7 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -268,14 +268,32 @@ namespace StardewModdingAPI.Framework
*********/
while (this.CommandQueue.TryDequeue(out string rawInput))
{
+ // parse command
+ string name;
+ string[] args;
+ Command command;
try
{
- if (!this.CommandManager.Trigger(rawInput))
+ if (!this.CommandManager.TryParse(rawInput, out name, out args, out command))
this.Monitor.Log("Unknown command; type 'help' for a list of available commands.", LogLevel.Error);
}
catch (Exception ex)
{
- this.Monitor.Log($"The handler registered for that command failed:\n{ex.GetLogSummary()}", LogLevel.Error);
+ this.Monitor.Log($"Failed parsing that command:\n{ex.GetLogSummary()}", LogLevel.Error);
+ continue;
+ }
+
+ // execute command
+ try
+ {
+ command.Callback.Invoke(name, args);
+ }
+ catch (Exception ex)
+ {
+ if (command.Mod != null)
+ command.Mod.LogAsMod($"Mod failed handling that command:\n{ex.GetLogSummary()}", LogLevel.Error);
+ else
+ this.Monitor.Log($"Failed handling that command:\n{ex.GetLogSummary()}", LogLevel.Error);
}
}