diff options
-rw-r--r-- | docs/release-notes.md | 1 | ||||
-rw-r--r-- | src/SMAPI/Framework/CursorPosition.cs | 21 | ||||
-rw-r--r-- | src/SMAPI/Framework/Input/SInputState.cs | 18 | ||||
-rw-r--r-- | src/SMAPI/ICursorPosition.cs | 18 |
4 files changed, 44 insertions, 14 deletions
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 *********/ /// <summary>Construct an instance.</summary> - /// <param name="absolutePixels">The pixel position relative to the top-left corner of the in-game map, adjusted for pixel zoom.</param> - /// <param name="screenPixels">The pixel position relative to the top-left corner of the visible screen, adjusted for pixel zoom.</param> + /// <param name="absolutePixels">The pixel position relative to the top-left corner of the in-game map, adjusted for zoom but not UI scaling.</param> + /// <param name="screenPixels">The pixel position relative to the top-left corner of the visible screen, adjusted for zoom but not UI scaling.</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 absolutePixels, Vector2 screenPixels, Vector2 tile, Vector2 grabTile) @@ -42,5 +43,21 @@ namespace StardewModdingAPI.Framework { return other != null && this.AbsolutePixels == other.AbsolutePixels; } + + /// <inheritdoc /> + public Vector2 GetScaledAbsolutePixels() + { + return Game1.uiMode + ? Utility.ModifyCoordinatesForUIScale(this.AbsolutePixels) + : this.AbsolutePixels; + } + + /// <inheritdoc /> + 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<SButton> reallyDown = new HashSet<SButton>(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 /// <summary>Get the current cursor position.</summary> /// <param name="mouseState">The current mouse state.</param> /// <param name="absolutePixels">The absolute pixel position relative to the map, adjusted for pixel zoom.</param> - /// <param name="scale">The UI scale applied to pixel coordinates.</param> - private CursorPosition GetCursorPosition(MouseState mouseState, Vector2 absolutePixels, float scale) + /// <param name="zoomMultiplier">The multiplier applied to pixel coordinates to adjust them for pixel zoom.</param> + 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 { /// <summary>Represents a cursor position in the different coordinate systems.</summary> public interface ICursorPosition : IEquatable<ICursorPosition> { - /// <summary>The pixel position relative to the top-left corner of the in-game map.</summary> + /********* + ** Accessors + *********/ + /// <summary>The pixel position relative to the top-left corner of the in-game map, adjusted for zoom but not UI scaling. See also <see cref="GetScaledAbsolutePixels"/>.</summary> Vector2 AbsolutePixels { get; } - /// <summary>The pixel position relative to the top-left corner of the visible screen.</summary> + /// <summary>The pixel position relative to the top-left corner of the visible screen, adjusted for zoom but not UI scaling. See also <see cref="GetScaledScreenPixels"/>.</summary> Vector2 ScreenPixels { get; } /// <summary>The tile position under the cursor relative to the top-left corner of the map.</summary> @@ -17,5 +21,15 @@ namespace StardewModdingAPI /// <summary>The tile position that the game considers under the cursor for purposes of clicking actions. This may be different than <see cref="Tile"/> if that's too far from the player.</summary> Vector2 GrabTile { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Get the <see cref="AbsolutePixels"/>, adjusted for UI scaling if needed. This is only different if <see cref="Game1.uiMode"/> is true.</summary> + Vector2 GetScaledAbsolutePixels(); + + /// <summary>Get the <see cref="ScreenPixels"/>, adjusted for UI scaling if needed. This is only different if <see cref="Game1.uiMode"/> is true.</summary> + Vector2 GetScaledScreenPixels(); } } |