diff --git a/docs/release-notes.md b/docs/release-notes.md
index a12a5482..c4aa413e 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -16,6 +16,7 @@
* For modders:
* When a mod is blocked by SMAPI's internal compatibility list, the `TRACE` messages while loading it now indicates that and specifies the reason.
* Message data from the `ModMessageReceived` event now uses the same serializer settings as the rest of SMAPI. This mainly adds support for sending crossplatform `Color`, `Point`, `Vector2`, `Rectangle`, and `SemanticVersion` fields through network messages.
+ * Fixed how the input API handles UI scaling. This mainly affects `ICursorPosition` values returned by the API; see [the wiki docs](https://stardewvalleywiki.com/Modding:Modder_Guide/APIs/Input#ICursorPosition) for how to account for UI scaling.
## 3.8.1
Released 26 December 2020 for Stardew Valley 1.5.1 or later.
diff --git a/src/SMAPI/Framework/CursorPosition.cs b/src/SMAPI/Framework/CursorPosition.cs
index 80d89994..107481e7 100644
--- a/src/SMAPI/Framework/CursorPosition.cs
+++ b/src/SMAPI/Framework/CursorPosition.cs
@@ -1,4 +1,5 @@
using Microsoft.Xna.Framework;
+using StardewValley;
namespace StardewModdingAPI.Framework
{
@@ -25,8 +26,8 @@ namespace StardewModdingAPI.Framework
** Public methods
*********/
/// Construct an instance.
- /// The pixel position relative to the top-left corner of the in-game map, adjusted for pixel zoom.
- /// The pixel position relative to the top-left corner of the visible screen, adjusted for pixel zoom.
+ /// The pixel position relative to the top-left corner of the in-game map, adjusted for zoom but not UI scaling.
+ /// The pixel position relative to the top-left corner of the visible screen, adjusted for zoom but not UI scaling.
/// The tile position relative to the top-left corner of the map.
/// The tile position that the game considers under the cursor for purposes of clicking actions.
public CursorPosition(Vector2 absolutePixels, Vector2 screenPixels, Vector2 tile, Vector2 grabTile)
@@ -42,5 +43,21 @@ namespace StardewModdingAPI.Framework
{
return other != null && this.AbsolutePixels == other.AbsolutePixels;
}
+
+ ///
+ public Vector2 GetScaledAbsolutePixels()
+ {
+ return Game1.uiMode
+ ? Utility.ModifyCoordinatesForUIScale(this.AbsolutePixels)
+ : this.AbsolutePixels;
+ }
+
+ ///
+ public Vector2 GetScaledScreenPixels()
+ {
+ return Game1.uiMode
+ ? Utility.ModifyCoordinatesForUIScale(this.ScreenPixels)
+ : this.ScreenPixels;
+ }
}
}
diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs
index 23670202..a8d1f371 100644
--- a/src/SMAPI/Framework/Input/SInputState.cs
+++ b/src/SMAPI/Framework/Input/SInputState.cs
@@ -63,18 +63,16 @@ namespace StardewModdingAPI.Framework.Input
base.Update();
// update SMAPI extended data
+ // note: Stardew Valley is *not* in UI mode when this code runs
try
{
- float scale = Game1.options.uiScale;
+ float zoomMultiplier = (1f / Game1.options.zoomLevel);
// get real values
var controller = new GamePadStateBuilder(base.GetGamePadState());
var keyboard = new KeyboardStateBuilder(base.GetKeyboardState());
var mouse = new MouseStateBuilder(base.GetMouseState());
- Vector2 cursorAbsolutePos = new Vector2(
- x: (mouse.X / scale) + Game1.uiViewport.X,
- y: (mouse.Y / scale) + Game1.uiViewport.Y
- );
+ Vector2 cursorAbsolutePos = new Vector2((mouse.X * zoomMultiplier) + Game1.viewport.X, (mouse.Y * zoomMultiplier) + Game1.viewport.Y);
Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.getTileLocation() : (Vector2?)null;
HashSet reallyDown = new HashSet(this.GetPressedButtons(keyboard, mouse, controller));
@@ -109,7 +107,7 @@ namespace StardewModdingAPI.Framework.Input
if (cursorAbsolutePos != this.CursorPositionImpl?.AbsolutePixels || playerTilePos != this.LastPlayerTile)
{
this.LastPlayerTile = playerTilePos;
- this.CursorPositionImpl = this.GetCursorPosition(this.MouseState, cursorAbsolutePos, scale);
+ this.CursorPositionImpl = this.GetCursorPosition(this.MouseState, cursorAbsolutePos, zoomMultiplier);
}
}
catch (InvalidOperationException)
@@ -202,11 +200,11 @@ namespace StardewModdingAPI.Framework.Input
/// Get the current cursor position.
/// The current mouse state.
/// The absolute pixel position relative to the map, adjusted for pixel zoom.
- /// The UI scale applied to pixel coordinates.
- private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels, float scale)
+ /// The multiplier applied to pixel coordinates to adjust them for pixel zoom.
+ private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels, float zoomMultiplier)
{
- Vector2 screenPixels = new Vector2(mouseState.X / scale, mouseState.Y / scale);
- Vector2 tile = new Vector2((int)((Game1.uiViewport.X + screenPixels.X) / Game1.tileSize), (int)((Game1.uiViewport.Y + screenPixels.Y) / Game1.tileSize));
+ Vector2 screenPixels = new Vector2(mouseState.X * zoomMultiplier, mouseState.Y * zoomMultiplier);
+ 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();
diff --git a/src/SMAPI/ICursorPosition.cs b/src/SMAPI/ICursorPosition.cs
index 21c57db0..99c1b84d 100644
--- a/src/SMAPI/ICursorPosition.cs
+++ b/src/SMAPI/ICursorPosition.cs
@@ -1,15 +1,19 @@
using System;
using Microsoft.Xna.Framework;
+using StardewValley;
namespace StardewModdingAPI
{
/// Represents a cursor position in the different coordinate systems.
public interface ICursorPosition : IEquatable
{
- /// The pixel position relative to the top-left corner of the in-game map.
+ /*********
+ ** Accessors
+ *********/
+ /// The pixel position relative to the top-left corner of the in-game map, adjusted for zoom but not UI scaling. See also .
Vector2 AbsolutePixels { get; }
- /// The pixel position relative to the top-left corner of the visible screen.
+ /// The pixel position relative to the top-left corner of the visible screen, adjusted for zoom but not UI scaling. See also .
Vector2 ScreenPixels { get; }
/// The tile position under the cursor relative to the top-left corner of the map.
@@ -17,5 +21,15 @@ namespace StardewModdingAPI
/// The tile position that the game considers under the cursor for purposes of clicking actions. This may be different than if that's too far from the player.
Vector2 GrabTile { get; }
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Get the , adjusted for UI scaling if needed. This is only different if is true.
+ Vector2 GetScaledAbsolutePixels();
+
+ /// Get the , adjusted for UI scaling if needed. This is only different if is true.
+ Vector2 GetScaledScreenPixels();
}
}