diff --git a/docs/release-notes.md b/docs/release-notes.md
index b7bd7b53..8dac1d0c 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -10,6 +10,9 @@
* Fixed update-check error if a mod's Chucklefish page has no version.
* Fixed SMAPI beta versions not showing update alert on next launch (thanks to danvolchek!).
+For the Console Commands mod:
+ * Added `test_input` command to view button codes in the console.
+
For modders:
* Asset propagation for player sprites now affects other players' sprites, and updates recolor maps (e.g. sleeves).
* Removed invalid-schedule validation which had false positives.
@@ -31,13 +34,14 @@ Released 05 January 2019 for Stardew Valley 1.4 or later.
* Fixed compatibility with Linux Mint 18 (thanks to techge!), Arch Linux, and Linux systems with libhybris-utils installed.
* Fixed memory leak when repeatedly loading a save and returning to title.
* Fixed memory leak when mods reload assets.
- * Fixes for Console Commands mod:
- * added new clothing items;
- * fixed spawning new flooring and rings (thanks to Mizzion!);
- * fixed spawning custom rings added by mods;
- * Fixed errors when some item data is invalid.
* Updated translations. Thanks to L30Bola (added Portuguese), PlussRolf (added Spanish), and shirutan (added Japanese)!
+* For the Console Commands mod:
+ * Added new clothing items.
+ * Fixed spawning new flooring and rings (thanks to Mizzion!).
+ * Fixed spawning custom rings added by mods.
+ * Fixed errors when some item data is invalid.
+
* For the web UI:
* Added option to edit & reupload in the JSON validator.
* File uploads are now stored in Azure storage instead of Pastebin, due to ongoing Pastebin perfomance issues.
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ITrainerCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ITrainerCommand.cs
index a0b739f8..d4d36e5d 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ITrainerCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/ITrainerCommand.cs
@@ -12,8 +12,11 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// The command description.
string Description { get; }
- /// Whether the command needs to perform logic when the game updates.
- bool NeedsUpdate { get; }
+ /// Whether the command may need to perform logic when the game updates. This value shouldn't change.
+ bool MayNeedUpdate { get; }
+
+ /// Whether the command may need to perform logic when the player presses a button. This value shouldn't change.
+ bool MayNeedInput { get; }
/*********
@@ -27,6 +30,11 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// Perform any logic needed on update tick.
/// Writes messages to the console and log file.
- void Update(IMonitor monitor);
+ void OnUpdated(IMonitor monitor);
+
+ /// Perform any logic when input is received.
+ /// Writes messages to the console and log file.
+ /// The button that was pressed.
+ void OnButtonPressed(IMonitor monitor, SButton button);
}
}
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/TestInputCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/TestInputCommand.cs
new file mode 100644
index 00000000..11aa10c3
--- /dev/null
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Other/TestInputCommand.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Other
+{
+ /// A command which logs the keys being pressed for 30 seconds once enabled.
+ internal class TestInputCommand : TrainerCommand
+ {
+ /*********
+ ** Fields
+ *********/
+ /// The number of seconds for which to log input.
+ private readonly int LogSeconds = 30;
+
+ /// When the command should stop printing input, or null if currently disabled.
+ private long? ExpiryTicks;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ public TestInputCommand()
+ : base("test_input", "Prints all input to the console for 30 seconds.", mayNeedUpdate: true, mayNeedInput: true) { }
+
+ /// Handle the command.
+ /// Writes messages to the console and log file.
+ /// The command name.
+ /// The command arguments.
+ public override void Handle(IMonitor monitor, string command, ArgumentParser args)
+ {
+ this.ExpiryTicks = DateTime.UtcNow.Add(TimeSpan.FromSeconds(this.LogSeconds)).Ticks;
+ monitor.Log($"OK, logging all player input for {this.LogSeconds} seconds.", LogLevel.Info);
+ }
+
+ /// Perform any logic needed on update tick.
+ /// Writes messages to the console and log file.
+ public override void OnUpdated(IMonitor monitor)
+ {
+ // handle expiry
+ if (this.ExpiryTicks == null)
+ return;
+ if (this.ExpiryTicks <= DateTime.UtcNow.Ticks)
+ {
+ monitor.Log("No longer logging input.", LogLevel.Info);
+ this.ExpiryTicks = null;
+ return;
+ }
+ }
+
+ /// Perform any logic when input is received.
+ /// Writes messages to the console and log file.
+ /// The button that was pressed.
+ public override void OnButtonPressed(IMonitor monitor, SButton button)
+ {
+ if (this.ExpiryTicks != null)
+ monitor.Log($"Pressed {button}", LogLevel.Info);
+ }
+ }
+}
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs
index 1abb82b5..59bda5dd 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetHealthCommand.cs
@@ -1,4 +1,4 @@
-using System.Linq;
+using System.Linq;
using StardewValley;
namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
@@ -13,19 +13,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
private bool InfiniteHealth;
- /*********
- ** Accessors
- *********/
- /// Whether the command needs to perform logic when the game updates.
- public override bool NeedsUpdate => this.InfiniteHealth;
-
-
/*********
** Public methods
*********/
/// Construct an instance.
public SetHealthCommand()
- : base("player_sethealth", "Sets the player's health.\n\nUsage: player_sethealth [value]\n- value: an integer amount, or 'inf' for infinite health.") { }
+ : base("player_sethealth", "Sets the player's health.\n\nUsage: player_sethealth [value]\n- value: an integer amount, or 'inf' for infinite health.", mayNeedUpdate: true) { }
/// Handle the command.
/// Writes messages to the console and log file.
@@ -62,9 +55,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// Perform any logic needed on update tick.
/// Writes messages to the console and log file.
- public override void Update(IMonitor monitor)
+ public override void OnUpdated(IMonitor monitor)
{
- if (this.InfiniteHealth)
+ if (this.InfiniteHealth && Context.IsWorldReady)
Game1.player.health = Game1.player.maxHealth;
}
}
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs
index 1706bbc1..6e3d68b6 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetMoneyCommand.cs
@@ -13,19 +13,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
private bool InfiniteMoney;
- /*********
- ** Accessors
- *********/
- /// Whether the command needs to perform logic when the game updates.
- public override bool NeedsUpdate => this.InfiniteMoney;
-
-
/*********
** Public methods
*********/
/// Construct an instance.
public SetMoneyCommand()
- : base("player_setmoney", "Sets the player's money.\n\nUsage: player_setmoney \n- value: an integer amount, or 'inf' for infinite money.") { }
+ : base("player_setmoney", "Sets the player's money.\n\nUsage: player_setmoney \n- value: an integer amount, or 'inf' for infinite money.", mayNeedUpdate: true) { }
/// Handle the command.
/// Writes messages to the console and log file.
@@ -62,9 +55,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// Perform any logic needed on update tick.
/// Writes messages to the console and log file.
- public override void Update(IMonitor monitor)
+ public override void OnUpdated(IMonitor monitor)
{
- if (this.InfiniteMoney)
+ if (this.InfiniteMoney && Context.IsWorldReady)
Game1.player.Money = 999999;
}
}
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs
index 009cb1de..60a1dcb1 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/Player/SetStaminaCommand.cs
@@ -1,4 +1,4 @@
-using System.Linq;
+using System.Linq;
using StardewValley;
namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
@@ -13,19 +13,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
private bool InfiniteStamina;
- /*********
- ** Accessors
- *********/
- /// Whether the command needs to perform logic when the game updates.
- public override bool NeedsUpdate => this.InfiniteStamina;
-
-
/*********
** Public methods
*********/
/// Construct an instance.
public SetStaminaCommand()
- : base("player_setstamina", "Sets the player's stamina.\n\nUsage: player_setstamina [value]\n- value: an integer amount, or 'inf' for infinite stamina.") { }
+ : base("player_setstamina", "Sets the player's stamina.\n\nUsage: player_setstamina [value]\n- value: an integer amount, or 'inf' for infinite stamina.", mayNeedUpdate: true) { }
/// Handle the command.
/// Writes messages to the console and log file.
@@ -62,9 +55,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// Perform any logic needed on update tick.
/// Writes messages to the console and log file.
- public override void Update(IMonitor monitor)
+ public override void OnUpdated(IMonitor monitor)
{
- if (this.InfiniteStamina)
+ if (this.InfiniteStamina && Context.IsWorldReady)
Game1.player.stamina = Game1.player.MaxStamina;
}
}
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/TrainerCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/TrainerCommand.cs
index 466b8f6e..6d5cae97 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/TrainerCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/TrainerCommand.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
@@ -16,8 +16,11 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// The command description.
public string Description { get; }
- /// Whether the command needs to perform logic when the game updates.
- public virtual bool NeedsUpdate { get; } = false;
+ /// Whether the command may need to perform logic when the player presses a button. This value shouldn't change.
+ public bool MayNeedInput { get; }
+
+ /// Whether the command may need to perform logic when the game updates. This value shouldn't change.
+ public bool MayNeedUpdate { get; }
/*********
@@ -31,7 +34,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// Perform any logic needed on update tick.
/// Writes messages to the console and log file.
- public virtual void Update(IMonitor monitor) { }
+ public virtual void OnUpdated(IMonitor monitor) { }
+
+ /// Perform any logic when input is received.
+ /// Writes messages to the console and log file.
+ /// The button that was pressed.
+ public virtual void OnButtonPressed(IMonitor monitor, SButton button) { }
/*********
@@ -40,10 +48,14 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// Construct an instance.
/// The command name the user must type.
/// The command description.
- protected TrainerCommand(string name, string description)
+ /// Whether the command may need to perform logic when the player presses a button.
+ /// Whether the command may need to perform logic when the game updates.
+ protected TrainerCommand(string name, string description, bool mayNeedInput = false, bool mayNeedUpdate = false)
{
this.Name = name;
this.Description = description;
+ this.MayNeedInput = mayNeedInput;
+ this.MayNeedUpdate = mayNeedUpdate;
}
/// Log an error indicating incorrect usage.
diff --git a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs
index 6a7ab162..736a93a0 100644
--- a/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/Framework/Commands/World/FreezeTimeCommand.cs
@@ -1,4 +1,4 @@
-using System.Linq;
+using System.Linq;
using StardewValley;
namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World
@@ -16,19 +16,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World
private bool FreezeTime;
- /*********
- ** Accessors
- *********/
- /// Whether the command needs to perform logic when the game updates.
- public override bool NeedsUpdate => this.FreezeTime;
-
-
/*********
** Public methods
*********/
/// Construct an instance.
public FreezeTimeCommand()
- : base("world_freezetime", "Freezes or resumes time.\n\nUsage: world_freezetime [value]\n- value: one of 0 (resume), 1 (freeze), or blank (toggle).") { }
+ : base("world_freezetime", "Freezes or resumes time.\n\nUsage: world_freezetime [value]\n- value: one of 0 (resume), 1 (freeze), or blank (toggle).", mayNeedUpdate: true) { }
/// Handle the command.
/// Writes messages to the console and log file.
@@ -57,9 +50,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World
/// Perform any logic needed on update tick.
/// Writes messages to the console and log file.
- public override void Update(IMonitor monitor)
+ public override void OnUpdated(IMonitor monitor)
{
- if (this.FreezeTime)
+ if (this.FreezeTime && Context.IsWorldReady)
Game1.timeOfDay = FreezeTimeCommand.FrozenTime;
}
}
diff --git a/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs b/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs
index 4807c46d..5c4f3bba 100644
--- a/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs
+++ b/src/SMAPI.Mods.ConsoleCommands/ModEntry.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using StardewModdingAPI.Events;
using StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands;
namespace StardewModdingAPI.Mods.ConsoleCommands
@@ -14,6 +15,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands
/// The commands to handle.
private ITrainerCommand[] Commands;
+ /// The commands which may need to handle update ticks.
+ private ITrainerCommand[] UpdateHandlers;
+
+ /// The commands which may need to handle input.
+ private ITrainerCommand[] InputHandlers;
+
/*********
** Public methods
@@ -27,27 +34,35 @@ namespace StardewModdingAPI.Mods.ConsoleCommands
foreach (ITrainerCommand command in this.Commands)
helper.ConsoleCommands.Add(command.Name, command.Description, (name, args) => this.HandleCommand(command, name, args));
+ // cache commands
+ this.InputHandlers = this.Commands.Where(p => p.MayNeedInput).ToArray();
+ this.UpdateHandlers = this.Commands.Where(p => p.MayNeedUpdate).ToArray();
+
// hook events
helper.Events.GameLoop.UpdateTicked += this.OnUpdateTicked;
+ helper.Events.Input.ButtonPressed += this.OnButtonPressed;
}
/*********
** Private methods
*********/
+ /// The method invoked when a button is pressed.
+ /// The event sender.
+ /// The event arguments.
+ private void OnButtonPressed(object sender, ButtonPressedEventArgs e)
+ {
+ foreach (ITrainerCommand command in this.InputHandlers)
+ command.OnButtonPressed(this.Monitor, e.Button);
+ }
+
/// The method invoked when the game updates its state.
/// The event sender.
/// The event arguments.
private void OnUpdateTicked(object sender, EventArgs e)
{
- if (!Context.IsWorldReady)
- return;
-
- foreach (ITrainerCommand command in this.Commands)
- {
- if (command.NeedsUpdate)
- command.Update(this.Monitor);
- }
+ foreach (ITrainerCommand command in this.UpdateHandlers)
+ command.OnUpdated(this.Monitor);
}
/// Handle a console command.