fix console commands being invoked asynchronously (#562)
This commit is contained in:
parent
6bd2c55a76
commit
76e1fd3905
|
@ -58,6 +58,7 @@
|
|||
* Fixed console command input not saved to the log.
|
||||
* Fixed `Context.IsPlayerFree` being false during festivals.
|
||||
* Fixed `helper.ModRegistry.GetApi` errors not always mentioning which interface caused the issue.
|
||||
* Fixed console commands being invoked asynchronously.
|
||||
* Fixed mods able to intercept other mods' assets via the internal asset keys.
|
||||
* Fixed mods able to indirectly change other mods' data through shared content caches.
|
||||
* Fixed `SemanticVersion` allowing invalid versions in some cases.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
@ -95,7 +96,7 @@ namespace StardewModdingAPI.Framework
|
|||
private bool IsInitialised;
|
||||
|
||||
/// <summary>The number of update ticks which have already executed.</summary>
|
||||
private uint TicksElapsed = 0;
|
||||
private uint TicksElapsed;
|
||||
|
||||
/// <summary>Whether the next content manager requested by the game will be for <see cref="Game1.content"/>.</summary>
|
||||
private bool NextContentManagerIsMain;
|
||||
|
@ -107,6 +108,9 @@ namespace StardewModdingAPI.Framework
|
|||
/// <summary>SMAPI's content manager.</summary>
|
||||
public ContentCoordinator ContentCore { get; private set; }
|
||||
|
||||
/// <summary>Manages console commands.</summary>
|
||||
public CommandManager CommandManager { get; } = new CommandManager();
|
||||
|
||||
/// <summary>Manages input visible to the game.</summary>
|
||||
public SInputState Input => (SInputState)Game1.input;
|
||||
|
||||
|
@ -116,6 +120,10 @@ namespace StardewModdingAPI.Framework
|
|||
/// <summary>Whether SMAPI should log more information about the game context.</summary>
|
||||
public bool VerboseLogging { get; set; }
|
||||
|
||||
/// <summary>A list of queued commands to execute.</summary>
|
||||
/// <remarks>This property must be threadsafe, since it's accessed from a separate console input thread.</remarks>
|
||||
public ConcurrentQueue<string> CommandQueue { get; } = new ConcurrentQueue<string>();
|
||||
|
||||
|
||||
/*********
|
||||
** Protected methods
|
||||
|
@ -229,7 +237,7 @@ namespace StardewModdingAPI.Framework
|
|||
{
|
||||
this.Monitor.Log("Game loader synchronising...", LogLevel.Trace);
|
||||
while (Game1.currentLoader?.MoveNext() == true)
|
||||
continue;
|
||||
;
|
||||
Game1.currentLoader = null;
|
||||
this.Monitor.Log("Game loader done.", LogLevel.Trace);
|
||||
}
|
||||
|
@ -256,6 +264,22 @@ namespace StardewModdingAPI.Framework
|
|||
return;
|
||||
}
|
||||
|
||||
/*********
|
||||
** Execute commands
|
||||
*********/
|
||||
while (this.CommandQueue.TryDequeue(out string rawInput))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.CommandManager.Trigger(rawInput))
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*********
|
||||
** Update input
|
||||
*********/
|
||||
|
|
|
@ -80,10 +80,6 @@ namespace StardewModdingAPI
|
|||
/// <remarks>This is initialised after the game starts.</remarks>
|
||||
private DeprecationManager DeprecationManager;
|
||||
|
||||
/// <summary>Manages console commands.</summary>
|
||||
/// <remarks>This is initialised after the game starts.</remarks>
|
||||
private CommandManager CommandManager;
|
||||
|
||||
/// <summary>Manages SMAPI events for mods.</summary>
|
||||
private readonly EventManager EventManager;
|
||||
|
||||
|
@ -394,7 +390,6 @@ namespace StardewModdingAPI
|
|||
|
||||
// load core components
|
||||
this.DeprecationManager = new DeprecationManager(this.Monitor, this.ModRegistry);
|
||||
this.CommandManager = new CommandManager();
|
||||
|
||||
// redirect direct console output
|
||||
{
|
||||
|
@ -485,8 +480,8 @@ namespace StardewModdingAPI
|
|||
{
|
||||
// prepare console
|
||||
this.Monitor.Log("Type 'help' for help, or 'help <cmd>' for a command's usage", LogLevel.Info);
|
||||
this.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.CommandManager.Add("SMAPI", "reload_i18n", "Reloads translation files for all mods.\n\nUsage: reload_i18n", this.HandleCommand);
|
||||
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);
|
||||
|
||||
// start handling command line input
|
||||
Thread inputThread = new Thread(() =>
|
||||
|
@ -498,19 +493,9 @@ namespace StardewModdingAPI
|
|||
if (string.IsNullOrWhiteSpace(input))
|
||||
continue;
|
||||
|
||||
// write input to log file
|
||||
// handle command
|
||||
this.Monitor.LogUserInput(input);
|
||||
|
||||
// parse input
|
||||
try
|
||||
{
|
||||
if (!this.CommandManager.Trigger(input))
|
||||
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.GameInstance.CommandQueue.Enqueue(input);
|
||||
}
|
||||
});
|
||||
inputThread.Start();
|
||||
|
@ -867,7 +852,7 @@ namespace StardewModdingAPI
|
|||
IModHelper modHelper;
|
||||
{
|
||||
IModEvents events = new ModEvents(metadata, this.EventManager);
|
||||
ICommandHelper commandHelper = new CommandHelper(manifest.UniqueID, metadata.DisplayName, this.CommandManager);
|
||||
ICommandHelper commandHelper = new CommandHelper(manifest.UniqueID, metadata.DisplayName, this.GameInstance.CommandManager);
|
||||
IContentHelper contentHelper = new ContentHelper(contentCore, metadata.DirectoryPath, manifest.UniqueID, metadata.DisplayName, monitor);
|
||||
IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, metadata.DisplayName, this.Reflection, this.DeprecationManager);
|
||||
IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry, proxyFactory, monitor);
|
||||
|
@ -1187,7 +1172,7 @@ namespace StardewModdingAPI
|
|||
case "help":
|
||||
if (arguments.Any())
|
||||
{
|
||||
Command result = this.CommandManager.Get(arguments[0]);
|
||||
Command result = this.GameInstance.CommandManager.Get(arguments[0]);
|
||||
if (result == null)
|
||||
this.Monitor.Log("There's no command with that name.", LogLevel.Error);
|
||||
else
|
||||
|
@ -1196,7 +1181,7 @@ namespace StardewModdingAPI
|
|||
else
|
||||
{
|
||||
string message = "The following commands are registered:\n";
|
||||
IGrouping<string, string>[] groups = (from command in this.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.ModName, command.Name group command.Name by command.ModName).ToArray();
|
||||
foreach (var group in groups)
|
||||
{
|
||||
string modName = group.Key;
|
||||
|
|
Loading…
Reference in New Issue