summaryrefslogtreecommitdiff
path: root/src/SMAPI/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'src/SMAPI/Framework')
-rw-r--r--src/SMAPI/Framework/CursorPosition.cs7
-rw-r--r--src/SMAPI/Framework/Input/SInputState.cs28
-rw-r--r--src/SMAPI/Framework/ModHelpers/InputHelper.cs54
-rw-r--r--src/SMAPI/Framework/ModHelpers/ModHelper.cs8
-rw-r--r--src/SMAPI/Framework/SGame.cs25
5 files changed, 96 insertions, 26 deletions
diff --git a/src/SMAPI/Framework/CursorPosition.cs b/src/SMAPI/Framework/CursorPosition.cs
index db02b3d1..6f716746 100644
--- a/src/SMAPI/Framework/CursorPosition.cs
+++ b/src/SMAPI/Framework/CursorPosition.cs
@@ -8,6 +8,9 @@ namespace StardewModdingAPI.Framework
/*********
** Accessors
*********/
+ /// <summary>The raw pixel position, not adjusted for the game zoom.</summary>
+ public Vector2 RawPixels { get; }
+
/// <summary>The pixel position relative to the top-left corner of the visible screen.</summary>
public Vector2 ScreenPixels { get; }
@@ -22,11 +25,13 @@ namespace StardewModdingAPI.Framework
** Public methods
*********/
/// <summary>Construct an instance.</summary>
+ /// <param name="rawPixels">The raw pixel position, not adjusted for the game zoom.</param>
/// <param name="screenPixels">The pixel position relative to the top-left corner of the visible screen.</param>
/// <param name="tile">The tile position relative to the top-left corner of the map.</param>
/// <param name="grabTile">The tile position that the game considers under the cursor for purposes of clicking actions.</param>
- public CursorPosition(Vector2 screenPixels, Vector2 tile, Vector2 grabTile)
+ public CursorPosition(Vector2 rawPixels, Vector2 screenPixels, Vector2 tile, Vector2 grabTile)
{
+ this.RawPixels = rawPixels;
this.ScreenPixels = screenPixels;
this.Tile = tile;
this.GrabTile = grabTile;
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index 27e40ab4..44fd0618 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -8,7 +8,7 @@ using StardewValley;
#pragma warning disable 809 // obsolete override of non-obsolete method (this is deliberate)
namespace StardewModdingAPI.Framework.Input
{
- /// <summary>A summary of input changes during an update frame.</summary>
+ /// <summary>Manages the game's input state.</summary>
internal sealed class SInputState : InputState
{
/*********
@@ -17,6 +17,9 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>The maximum amount of direction to ignore for the left thumbstick.</summary>
private const float LeftThumbstickDeadZone = 0.2f;
+ /// <summary>The cursor position on the screen adjusted for the zoom level.</summary>
+ private CursorPosition CursorPositionImpl;
+
/*********
** Accessors
@@ -39,8 +42,8 @@ namespace StardewModdingAPI.Framework.Input
/// <summary>A derivative of <see cref="RealMouse"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary>
public MouseState SuppressedMouse { get; private set; }
- /// <summary>The mouse position on the screen adjusted for the zoom level.</summary>
- public Point MousePosition { get; private set; }
+ /// <summary>The cursor position on the screen adjusted for the zoom level.</summary>
+ public ICursorPosition CursorPosition => this.CursorPositionImpl;
/// <summary>The buttons which were pressed, held, or released.</summary>
public IDictionary<SButton, InputStatus> ActiveButtons { get; private set; } = new Dictionary<SButton, InputStatus>();
@@ -61,7 +64,7 @@ namespace StardewModdingAPI.Framework.Input
RealController = this.RealController,
RealKeyboard = this.RealKeyboard,
RealMouse = this.RealMouse,
- MousePosition = this.MousePosition
+ CursorPositionImpl = this.CursorPositionImpl
};
}
@@ -78,15 +81,16 @@ namespace StardewModdingAPI.Framework.Input
GamePadState realController = GamePad.GetState(PlayerIndex.One);
KeyboardState realKeyboard = Keyboard.GetState();
MouseState realMouse = Mouse.GetState();
- Point mousePosition = new Point((int)(this.RealMouse.X * (1.0 / Game1.options.zoomLevel)), (int)(this.RealMouse.Y * (1.0 / Game1.options.zoomLevel))); // derived from Game1::getMouseX
var activeButtons = this.DeriveStatuses(this.ActiveButtons, realKeyboard, realMouse, realController);
+ Vector2 cursorRawPixelPos = new Vector2(this.RealMouse.X, this.RealMouse.Y);
// update real states
this.ActiveButtons = activeButtons;
this.RealController = realController;
this.RealKeyboard = realKeyboard;
this.RealMouse = realMouse;
- this.MousePosition = mousePosition;
+ if (this.CursorPositionImpl?.RawPixels != cursorRawPixelPos)
+ this.CursorPositionImpl = this.GetCursorPosition(cursorRawPixelPos);
// update suppressed states
this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown());
@@ -157,6 +161,18 @@ namespace StardewModdingAPI.Framework.Input
/*********
** Private methods
*********/
+ /// <summary>Get the current cursor position.</summary>
+ /// <remarks>The raw pixel position from the mouse state.</remarks>
+ private CursorPosition GetCursorPosition(Vector2 rawPixelPos)
+ {
+ Vector2 screenPixels = new Vector2((int)(rawPixelPos.X * (1.0 / Game1.options.zoomLevel)), (int)(rawPixelPos.Y * (1.0 / Game1.options.zoomLevel))); // derived from Game1::getMouseX
+ Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize));
+ Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton
+ ? tile
+ : Game1.player.GetGrabTile();
+ return new CursorPosition(rawPixelPos, screenPixels, tile, grabTile);
+ }
+
/// <summary>Whether input should be suppressed in the current context.</summary>
private bool ShouldSuppressNow()
{
diff --git a/src/SMAPI/Framework/ModHelpers/InputHelper.cs b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
new file mode 100644
index 00000000..f4cd12b6
--- /dev/null
+++ b/src/SMAPI/Framework/ModHelpers/InputHelper.cs
@@ -0,0 +1,54 @@
+using StardewModdingAPI.Framework.Input;
+
+namespace StardewModdingAPI.Framework.ModHelpers
+{
+ /// <summary>Provides an API for checking and changing input state.</summary>
+ internal class InputHelper : BaseHelper, IInputHelper
+ {
+ /*********
+ ** Accessors
+ *********/
+ /// <summary>Manages the game's input state.</summary>
+ private readonly SInputState InputState;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// <summary>Construct an instance.</summary>
+ /// <param name="modID">The unique ID of the relevant mod.</param>
+ /// <param name="inputState">Manages the game's input state.</param>
+ public InputHelper(string modID, SInputState inputState)
+ : base(modID)
+ {
+ this.InputState = inputState;
+ }
+
+ /// <summary>Get the current cursor position.</summary>
+ public ICursorPosition GetCursorPosition()
+ {
+ return this.InputState.CursorPosition;
+ }
+
+ /// <summary>Get whether a button is currently pressed.</summary>
+ /// <param name="button">The button.</param>
+ public bool IsDown(SButton button)
+ {
+ return this.InputState.IsDown(button);
+ }
+
+ /// <summary>Get whether a button is currently suppressed, so the game won't see it.</summary>
+ /// <param name="button">The button.</param>
+ public bool IsSuppressed(SButton button)
+ {
+ return this.InputState.SuppressButtons.Contains(button);
+ }
+
+ /// <summary>Prevent the game from handling a button press. This doesn't prevent other mods from receiving the event.</summary>
+ /// <param name="button">The button to suppress.</param>
+ public void Suppress(SButton button)
+ {
+ this.InputState.SuppressButtons.Add(button);
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/ModHelpers/ModHelper.cs b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
index 92cb9d94..1e07dafa 100644
--- a/src/SMAPI/Framework/ModHelpers/ModHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModHelper.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using StardewModdingAPI.Events;
+using StardewModdingAPI.Framework.Input;
using StardewModdingAPI.Framework.Models;
using StardewModdingAPI.Framework.Serialisation;
using StardewModdingAPI.Framework.Utilities;
@@ -40,6 +41,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <summary>An API for loading content assets.</summary>
public IContentHelper Content { get; }
+ /// <summary>An API for checking and changing input state.</summary>
+ public IInputHelper Input { get; }
+
/// <summary>An API for accessing private game code.</summary>
public IReflectionHelper Reflection { get; }
@@ -63,6 +67,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="modID">The mod's unique ID.</param>
/// <param name="modDirectory">The full path to the mod's folder.</param>
/// <param name="jsonHelper">Encapsulate SMAPI's JSON parsing.</param>
+ /// <param name="inputState">Manages the game's input state.</param>
/// <param name="events">Manages access to events raised by SMAPI.</param>
/// <param name="contentHelper">An API for loading content assets.</param>
/// <param name="commandHelper">An API for managing console commands.</param>
@@ -75,7 +80,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// <param name="deprecationManager">Manages deprecation warnings.</param>
/// <exception cref="ArgumentNullException">An argument is null or empty.</exception>
/// <exception cref="InvalidOperationException">The <paramref name="modDirectory"/> path does not exist on disk.</exception>
- public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, IModEvents events, IContentHelper contentHelper, ICommandHelper commandHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, IEnumerable<IContentPack> contentPacks, Func<string, IManifest, IContentPack> createContentPack, DeprecationManager deprecationManager)
+ public ModHelper(string modID, string modDirectory, JsonHelper jsonHelper, SInputState inputState, IModEvents events, IContentHelper contentHelper, ICommandHelper commandHelper, IModRegistry modRegistry, IReflectionHelper reflectionHelper, IMultiplayerHelper multiplayer, ITranslationHelper translationHelper, IEnumerable<IContentPack> contentPacks, Func<string, IManifest, IContentPack> createContentPack, DeprecationManager deprecationManager)
: base(modID)
{
// validate directory
@@ -88,6 +93,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.DirectoryPath = modDirectory;
this.JsonHelper = jsonHelper ?? throw new ArgumentNullException(nameof(jsonHelper));
this.Content = contentHelper ?? throw new ArgumentNullException(nameof(contentHelper));
+ this.Input = new InputHelper(modID, inputState);
this.ModRegistry = modRegistry ?? throw new ArgumentNullException(nameof(modRegistry));
this.ConsoleCommands = commandHelper ?? throw new ArgumentNullException(nameof(commandHelper));
this.Reflection = reflectionHelper ?? throw new ArgumentNullException(nameof(reflectionHelper));
diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs
index 18529728..560b54a4 100644
--- a/src/SMAPI/Framework/SGame.cs
+++ b/src/SMAPI/Framework/SGame.cs
@@ -54,9 +54,6 @@ namespace StardewModdingAPI.Framework
/// <summary>Manages SMAPI events for mods.</summary>
private readonly EventManager Events;
- /// <summary>Manages input visible to the game.</summary>
- private SInputState Input => (SInputState)Game1.input;
-
/// <summary>The maximum number of consecutive attempts SMAPI should make to recover from a draw error.</summary>
private readonly Countdown DrawCrashTimer = new Countdown(60); // 60 ticks = roughly one second
@@ -101,7 +98,7 @@ namespace StardewModdingAPI.Framework
private readonly IValueWatcher<IClickableMenu> ActiveMenuWatcher;
/// <summary>Tracks changes to the cursor position.</summary>
- private readonly IValueWatcher<Point> CursorWatcher;
+ private readonly IValueWatcher<Vector2> CursorWatcher;
/// <summary>Tracks changes to the mouse wheel scroll.</summary>
private readonly IValueWatcher<int> MouseWheelScrollWatcher;
@@ -137,6 +134,9 @@ namespace StardewModdingAPI.Framework
/// <summary>SMAPI's content manager.</summary>
public ContentCoordinator ContentCore { get; private set; }
+ /// <summary>Manages input visible to the game.</summary>
+ public SInputState Input => (SInputState)Game1.input;
+
/// <summary>The game's core multiplayer utility.</summary>
public SMultiplayer Multiplayer => (SMultiplayer)Game1.multiplayer;
@@ -174,7 +174,7 @@ namespace StardewModdingAPI.Framework
// init watchers
Game1.locations = new ObservableCollection<GameLocation>();
- this.CursorWatcher = WatcherFactory.ForEquatable(() => this.Input.MousePosition);
+ this.CursorWatcher = WatcherFactory.ForEquatable(() => this.Input.CursorPosition.ScreenPixels);
this.MouseWheelScrollWatcher = WatcherFactory.ForEquatable(() => this.Input.RealMouse.ScrollWheelValue);
this.SaveIdWatcher = WatcherFactory.ForEquatable(() => Game1.hasLoadedGame ? Game1.uniqueIDForThisGame : 0);
this.WindowSizeWatcher = WatcherFactory.ForEquatable(() => new Point(Game1.viewport.Width, Game1.viewport.Height));
@@ -452,18 +452,7 @@ namespace StardewModdingAPI.Framework
bool isChatInput = Game1.IsChatting || (Context.IsMultiplayer && Context.IsWorldReady && Game1.activeClickableMenu == null && Game1.currentMinigame == null && inputState.IsAnyDown(Game1.options.chatButton));
if (!isChatInput)
{
- // get cursor position
- ICursorPosition cursor = this.PreviousCursorPosition;
- if (this.CursorWatcher.IsChanged)
- {
- // cursor position
- Vector2 screenPixels = new Vector2(this.CursorWatcher.CurrentValue.X, this.CursorWatcher.CurrentValue.Y);
- Vector2 tile = new Vector2((int)((Game1.viewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.viewport.Y + screenPixels.Y) / Game1.tileSize));
- Vector2 grabTile = (Game1.mouseCursorTransparency > 0 && Utility.tileWithinRadiusOfPlayer((int)tile.X, (int)tile.Y, 1, Game1.player)) // derived from Game1.pressActionButton
- ? tile
- : Game1.player.GetGrabTile();
- cursor = new CursorPosition(screenPixels, tile, grabTile);
- }
+ ICursorPosition cursor = this.Input.CursorPosition;
// raise cursor moved event
if (this.CursorWatcher.IsChanged && this.PreviousCursorPosition != null)
@@ -533,7 +522,7 @@ namespace StardewModdingAPI.Framework
if (inputState.RealKeyboard != previousInputState.RealKeyboard)
this.Events.Legacy_Control_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard));
if (inputState.RealMouse != previousInputState.RealMouse)
- this.Events.Legacy_Control_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, previousInputState.MousePosition, inputState.MousePosition));
+ this.Events.Legacy_Control_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, new Point((int)previousInputState.CursorPosition.ScreenPixels.X, (int)previousInputState.CursorPosition.ScreenPixels.Y), new Point((int)inputState.CursorPosition.ScreenPixels.X, (int)inputState.CursorPosition.ScreenPixels.Y)));
}
}