add test_input console command

This commit is contained in:
Jesse Plamondon-Willard 2020-01-22 20:36:24 -05:00
parent 1670a2f3a6
commit 381de5eba9
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
9 changed files with 134 additions and 64 deletions

View File

@ -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.

View File

@ -12,8 +12,11 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// <summary>The command description.</summary>
string Description { get; }
/// <summary>Whether the command needs to perform logic when the game updates.</summary>
bool NeedsUpdate { get; }
/// <summary>Whether the command may need to perform logic when the game updates. This value shouldn't change.</summary>
bool MayNeedUpdate { get; }
/// <summary>Whether the command may need to perform logic when the player presses a button. This value shouldn't change.</summary>
bool MayNeedInput { get; }
/*********
@ -27,6 +30,11 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
void Update(IMonitor monitor);
void OnUpdated(IMonitor monitor);
/// <summary>Perform any logic when input is received.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
/// <param name="button">The button that was pressed.</param>
void OnButtonPressed(IMonitor monitor, SButton button);
}
}

View File

@ -0,0 +1,59 @@
using System;
namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Other
{
/// <summary>A command which logs the keys being pressed for 30 seconds once enabled.</summary>
internal class TestInputCommand : TrainerCommand
{
/*********
** Fields
*********/
/// <summary>The number of seconds for which to log input.</summary>
private readonly int LogSeconds = 30;
/// <summary>When the command should stop printing input, or <c>null</c> if currently disabled.</summary>
private long? ExpiryTicks;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
public TestInputCommand()
: base("test_input", "Prints all input to the console for 30 seconds.", mayNeedUpdate: true, mayNeedInput: true) { }
/// <summary>Handle the command.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
/// <param name="command">The command name.</param>
/// <param name="args">The command arguments.</param>
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);
}
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
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;
}
}
/// <summary>Perform any logic when input is received.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
/// <param name="button">The button that was pressed.</param>
public override void OnButtonPressed(IMonitor monitor, SButton button)
{
if (this.ExpiryTicks != null)
monitor.Log($"Pressed {button}", LogLevel.Info);
}
}
}

View File

@ -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
*********/
/// <summary>Whether the command needs to perform logic when the game updates.</summary>
public override bool NeedsUpdate => this.InfiniteHealth;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
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) { }
/// <summary>Handle the command.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
@ -62,9 +55,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
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;
}
}

View File

@ -13,19 +13,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
private bool InfiniteMoney;
/*********
** Accessors
*********/
/// <summary>Whether the command needs to perform logic when the game updates.</summary>
public override bool NeedsUpdate => this.InfiniteMoney;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
public SetMoneyCommand()
: base("player_setmoney", "Sets the player's money.\n\nUsage: player_setmoney <value>\n- value: an integer amount, or 'inf' for infinite money.") { }
: base("player_setmoney", "Sets the player's money.\n\nUsage: player_setmoney <value>\n- value: an integer amount, or 'inf' for infinite money.", mayNeedUpdate: true) { }
/// <summary>Handle the command.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
@ -62,9 +55,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
public override void Update(IMonitor monitor)
public override void OnUpdated(IMonitor monitor)
{
if (this.InfiniteMoney)
if (this.InfiniteMoney && Context.IsWorldReady)
Game1.player.Money = 999999;
}
}

View File

@ -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
*********/
/// <summary>Whether the command needs to perform logic when the game updates.</summary>
public override bool NeedsUpdate => this.InfiniteStamina;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
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) { }
/// <summary>Handle the command.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
@ -62,9 +55,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.Player
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
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;
}
}

View File

@ -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
/// <summary>The command description.</summary>
public string Description { get; }
/// <summary>Whether the command needs to perform logic when the game updates.</summary>
public virtual bool NeedsUpdate { get; } = false;
/// <summary>Whether the command may need to perform logic when the player presses a button. This value shouldn't change.</summary>
public bool MayNeedInput { get; }
/// <summary>Whether the command may need to perform logic when the game updates. This value shouldn't change.</summary>
public bool MayNeedUpdate { get; }
/*********
@ -31,7 +34,12 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
public virtual void Update(IMonitor monitor) { }
public virtual void OnUpdated(IMonitor monitor) { }
/// <summary>Perform any logic when input is received.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
/// <param name="button">The button that was pressed.</param>
public virtual void OnButtonPressed(IMonitor monitor, SButton button) { }
/*********
@ -40,10 +48,14 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands
/// <summary>Construct an instance.</summary>
/// <param name="name">The command name the user must type.</param>
/// <param name="description">The command description.</param>
protected TrainerCommand(string name, string description)
/// <param name="mayNeedInput">Whether the command may need to perform logic when the player presses a button.</param>
/// <param name="mayNeedUpdate">Whether the command may need to perform logic when the game updates.</param>
protected TrainerCommand(string name, string description, bool mayNeedInput = false, bool mayNeedUpdate = false)
{
this.Name = name;
this.Description = description;
this.MayNeedInput = mayNeedInput;
this.MayNeedUpdate = mayNeedUpdate;
}
/// <summary>Log an error indicating incorrect usage.</summary>

View File

@ -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
*********/
/// <summary>Whether the command needs to perform logic when the game updates.</summary>
public override bool NeedsUpdate => this.FreezeTime;
/*********
** Public methods
*********/
/// <summary>Construct an instance.</summary>
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) { }
/// <summary>Handle the command.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
@ -57,9 +50,9 @@ namespace StardewModdingAPI.Mods.ConsoleCommands.Framework.Commands.World
/// <summary>Perform any logic needed on update tick.</summary>
/// <param name="monitor">Writes messages to the console and log file.</param>
public override void Update(IMonitor monitor)
public override void OnUpdated(IMonitor monitor)
{
if (this.FreezeTime)
if (this.FreezeTime && Context.IsWorldReady)
Game1.timeOfDay = FreezeTimeCommand.FrozenTime;
}
}

View File

@ -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
/// <summary>The commands to handle.</summary>
private ITrainerCommand[] Commands;
/// <summary>The commands which may need to handle update ticks.</summary>
private ITrainerCommand[] UpdateHandlers;
/// <summary>The commands which may need to handle input.</summary>
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
*********/
/// <summary>The method invoked when a button is pressed.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
private void OnButtonPressed(object sender, ButtonPressedEventArgs e)
{
foreach (ITrainerCommand command in this.InputHandlers)
command.OnButtonPressed(this.Monitor, e.Button);
}
/// <summary>The method invoked when the game updates its state.</summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event arguments.</param>
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);
}
/// <summary>Handle a console command.</summary>