diff options
| author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-03-22 19:52:42 -0400 |
|---|---|---|
| committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2020-03-22 19:52:42 -0400 |
| commit | 7ca5efbbc576f3c6c43493654b2a0ac040fd4f31 (patch) | |
| tree | fae7a4e06a14ff7f8d709e2f4d5b8b92b8784a37 /src/SMAPI | |
| parent | 5ae640dc91adff8dfb0827e2a3c3f6b54be7c612 (diff) | |
| parent | 6d1494a56c5d04e7bc1ee406810a5a53dea2229a (diff) | |
| download | SMAPI-7ca5efbbc576f3c6c43493654b2a0ac040fd4f31.tar.gz SMAPI-7ca5efbbc576f3c6c43493654b2a0ac040fd4f31.tar.bz2 SMAPI-7ca5efbbc576f3c6c43493654b2a0ac040fd4f31.zip | |
Merge branch 'develop' into stable
Diffstat (limited to 'src/SMAPI')
| -rw-r--r-- | src/SMAPI/Constants.cs | 2 | ||||
| -rw-r--r-- | src/SMAPI/Events/ButtonPressedEventArgs.cs | 6 | ||||
| -rw-r--r-- | src/SMAPI/Events/ButtonReleasedEventArgs.cs | 6 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ContentManagers/ModContentManager.cs | 7 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/GamePadStateBuilder.cs | 283 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/IInputStateBuilder.cs | 29 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/KeyboardStateBuilder.cs | 78 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/MouseStateBuilder.cs | 107 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/SInputState.cs | 347 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ModHelpers/InputHelper.cs | 4 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Monitor.cs | 13 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Rendering/SDisplayDevice.cs | 89 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Rendering/SXnaDisplayDevice.cs | 121 | ||||
| -rw-r--r-- | src/SMAPI/Framework/SGame.cs | 25 | ||||
| -rw-r--r-- | src/SMAPI/Framework/WatcherCore.cs | 2 | ||||
| -rw-r--r-- | src/SMAPI/IMonitor.cs | 5 | ||||
| -rw-r--r-- | src/SMAPI/Patches/LoadErrorPatch.cs | 25 | ||||
| -rw-r--r-- | src/SMAPI/SMAPI.csproj | 2 | ||||
| -rw-r--r-- | src/SMAPI/i18n/hu.json | 3 |
19 files changed, 793 insertions, 361 deletions
diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index 3242a12c..d66e9d6b 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -20,7 +20,7 @@ namespace StardewModdingAPI ** Public ****/ /// <summary>SMAPI's current semantic version.</summary> - public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.3.2"); + public static ISemanticVersion ApiVersion { get; } = new Toolkit.SemanticVersion("3.4.0"); /// <summary>The minimum supported version of Stardew Valley.</summary> public static ISemanticVersion MinimumGameVersion { get; } = new GameVersion("1.4.1"); diff --git a/src/SMAPI/Events/ButtonPressedEventArgs.cs b/src/SMAPI/Events/ButtonPressedEventArgs.cs index 5d922666..1b30fd23 100644 --- a/src/SMAPI/Events/ButtonPressedEventArgs.cs +++ b/src/SMAPI/Events/ButtonPressedEventArgs.cs @@ -37,17 +37,17 @@ namespace StardewModdingAPI.Events this.InputState = inputState; } - /// <summary>Whether a mod has indicated the key was already handled, so the game should handle it.</summary> + /// <summary>Get whether a mod has indicated the key was already handled, so the game shouldn't handle it.</summary> public bool IsSuppressed() { return this.IsSuppressed(this.Button); } - /// <summary>Whether a mod has indicated the key was already handled, so the game should handle it.</summary> + /// <summary>Get whether a mod has indicated the key was already handled, so the game shouldn't handle it.</summary> /// <param name="button">The button to check.</param> public bool IsSuppressed(SButton button) { - return this.InputState.SuppressButtons.Contains(button); + return this.InputState.IsSuppressed(button); } /// <summary>Get whether a given button was pressed or held.</summary> diff --git a/src/SMAPI/Events/ButtonReleasedEventArgs.cs b/src/SMAPI/Events/ButtonReleasedEventArgs.cs index f5282230..40ec1cc1 100644 --- a/src/SMAPI/Events/ButtonReleasedEventArgs.cs +++ b/src/SMAPI/Events/ButtonReleasedEventArgs.cs @@ -37,17 +37,17 @@ namespace StardewModdingAPI.Events this.InputState = inputState; } - /// <summary>Whether a mod has indicated the key was already handled, so the game should handle it.</summary> + /// <summary>Get whether a mod has indicated the key was already handled, so the game shouldn't handle it.</summary> public bool IsSuppressed() { return this.IsSuppressed(this.Button); } - /// <summary>Whether a mod has indicated the key was already handled, so the game should handle it.</summary> + /// <summary>Get whether a mod has indicated the key was already handled, so the game shouldn't handle it.</summary> /// <param name="button">The button to check.</param> public bool IsSuppressed(SButton button) { - return this.InputState.SuppressButtons.Contains(button); + return this.InputState.IsSuppressed(button); } /// <summary>Get whether a given button was pressed or held.</summary> diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index 4ffe3acd..fda80a83 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -241,13 +241,6 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <remarks>Based on <a href="https://gamedev.stackexchange.com/a/26037">code by David Gouveia</a>.</remarks> private Texture2D PremultiplyTransparency(Texture2D texture) { - // Textures loaded by Texture2D.FromStream are already premultiplied on Linux/Mac, even - // though the XNA documentation explicitly says otherwise. That's a glitch in MonoGame - // fixed in newer versions, but the game uses a bundled version that will always be - // affected. See https://github.com/MonoGame/MonoGame/issues/4820 for more info. - if (Constants.TargetPlatform != GamePlatform.Windows) - return texture; - // premultiply pixels Color[] data = new Color[texture.Width * texture.Height]; texture.GetData(data); diff --git a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs index a20e1248..36622066 100644 --- a/src/SMAPI/Framework/Input/GamePadStateBuilder.cs +++ b/src/SMAPI/Framework/Input/GamePadStateBuilder.cs @@ -4,14 +4,23 @@ using Microsoft.Xna.Framework.Input; namespace StardewModdingAPI.Framework.Input { - /// <summary>An abstraction for manipulating controller state.</summary> - internal class GamePadStateBuilder + /// <summary>Manages controller state.</summary> + internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, GamePadState> { /********* ** Fields *********/ + /// <summary>The maximum direction to ignore for the left thumbstick.</summary> + private const float LeftThumbstickDeadZone = 0.2f; + + /// <summary>The maximum direction to ignore for the right thumbstick.</summary> + private const float RightThumbstickDeadZone = 0.9f; + + /// <summary>The underlying controller state.</summary> + private GamePadState? State; + /// <summary>The current button states.</summary> - private readonly IDictionary<SButton, ButtonState> ButtonStates; + private IDictionary<SButton, ButtonState> ButtonStates; /// <summary>The left trigger value.</summary> private float LeftTrigger; @@ -27,135 +36,203 @@ namespace StardewModdingAPI.Framework.Input /********* + ** Accessors + *********/ + /// <summary>Whether the gamepad is currently connected.</summary> + public bool IsConnected { get; private set; } + + + /********* ** Public methods *********/ /// <summary>Construct an instance.</summary> - /// <param name="state">The initial controller state.</param> - public GamePadStateBuilder(GamePadState state) + /// <param name="state">The initial state, or <c>null</c> to get the latest state.</param> + public GamePadStateBuilder(GamePadState? state = null) + { + this.Reset(state); + } + + /// <summary>Reset the tracked state.</summary> + /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param> + public GamePadStateBuilder Reset(GamePadState? state = null) { + this.State = state ??= GamePad.GetState(PlayerIndex.One); + this.IsConnected = state.Value.IsConnected; + + if (!this.IsConnected) + return this; + + GamePadDPad pad = state.Value.DPad; + GamePadButtons buttons = state.Value.Buttons; + GamePadTriggers triggers = state.Value.Triggers; + GamePadThumbSticks sticks = state.Value.ThumbSticks; this.ButtonStates = new Dictionary<SButton, ButtonState> { - [SButton.DPadUp] = state.DPad.Up, - [SButton.DPadDown] = state.DPad.Down, - [SButton.DPadLeft] = state.DPad.Left, - [SButton.DPadRight] = state.DPad.Right, - - [SButton.ControllerA] = state.Buttons.A, - [SButton.ControllerB] = state.Buttons.B, - [SButton.ControllerX] = state.Buttons.X, - [SButton.ControllerY] = state.Buttons.Y, - [SButton.LeftStick] = state.Buttons.LeftStick, - [SButton.RightStick] = state.Buttons.RightStick, - [SButton.LeftShoulder] = state.Buttons.LeftShoulder, - [SButton.RightShoulder] = state.Buttons.RightShoulder, - [SButton.ControllerBack] = state.Buttons.Back, - [SButton.ControllerStart] = state.Buttons.Start, - [SButton.BigButton] = state.Buttons.BigButton + [SButton.DPadUp] = pad.Up, + [SButton.DPadDown] = pad.Down, + [SButton.DPadLeft] = pad.Left, + [SButton.DPadRight] = pad.Right, + + [SButton.ControllerA] = buttons.A, + [SButton.ControllerB] = buttons.B, + [SButton.ControllerX] = buttons.X, + [SButton.ControllerY] = buttons.Y, + [SButton.LeftStick] = buttons.LeftStick, + [SButton.RightStick] = buttons.RightStick, + [SButton.LeftShoulder] = buttons.LeftShoulder, + [SButton.RightShoulder] = buttons.RightShoulder, + [SButton.ControllerBack] = buttons.Back, + [SButton.ControllerStart] = buttons.Start, + [SButton.BigButton] = buttons.BigButton }; - this.LeftTrigger = state.Triggers.Left; - this.RightTrigger = state.Triggers.Right; - this.LeftStickPos = state.ThumbSticks.Left; - this.RightStickPos = state.ThumbSticks.Right; + this.LeftTrigger = triggers.Left; + this.RightTrigger = triggers.Right; + this.LeftStickPos = sticks.Left; + this.RightStickPos = sticks.Right; + + return this; } - /// <summary>Mark all matching buttons unpressed.</summary> - /// <param name="buttons">The buttons.</param> - public void SuppressButtons(IEnumerable<SButton> buttons) + /// <summary>Override the states for a set of buttons.</summary> + /// <param name="overrides">The button state overrides.</param> + public GamePadStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides) { - foreach (SButton button in buttons) - this.SuppressButton(button); + if (!this.IsConnected) + return this; + + foreach (var pair in overrides) + { + bool changed = true; + + bool isDown = pair.Value.IsDown(); + switch (pair.Key) + { + // left thumbstick + case SButton.LeftThumbstickUp: + this.LeftStickPos.Y = isDown ? 1 : 0; + break; + case SButton.LeftThumbstickDown: + this.LeftStickPos.Y = isDown ? 1 : 0; + break; + case SButton.LeftThumbstickLeft: + this.LeftStickPos.X = isDown ? 1 : 0; + break; + case SButton.LeftThumbstickRight: + this.LeftStickPos.X = isDown ? 1 : 0; + break; + + // right thumbstick + case SButton.RightThumbstickUp: + this.RightStickPos.Y = isDown ? 1 : 0; + break; + case SButton.RightThumbstickDown: + this.RightStickPos.Y = isDown ? 1 : 0; + break; + case SButton.RightThumbstickLeft: + this.RightStickPos.X = isDown ? 1 : 0; + break; + case SButton.RightThumbstickRight: + this.RightStickPos.X = isDown ? 1 : 0; + break; + + // triggers + case SButton.LeftTrigger: + this.LeftTrigger = isDown ? 1 : 0; + break; + case SButton.RightTrigger: + this.RightTrigger = isDown ? 1 : 0; + break; + + // buttons + default: + if (this.ButtonStates.ContainsKey(pair.Key)) + this.ButtonStates[pair.Key] = isDown ? ButtonState.Pressed : ButtonState.Released; + else + changed = false; + break; + } + + if (changed) + this.State = null; + } + + return this; } - /// <summary>Mark a button unpressed.</summary> - /// <param name="button">The button.</param> - public void SuppressButton(SButton button) + /// <summary>Get the currently pressed buttons.</summary> + public IEnumerable<SButton> GetPressedButtons() { - switch (button) + if (!this.IsConnected) + yield break; + + // buttons + foreach (var pair in this.ButtonStates) + { + if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button)) + yield return button.ToSButton(); + } + + // triggers + if (this.LeftTrigger > 0.2f) + yield return SButton.LeftTrigger; + if (this.RightTrigger > 0.2f) + yield return SButton.RightTrigger; + + // left thumbstick direction + if (this.LeftStickPos.Y > GamePadStateBuilder.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickUp; + if (this.LeftStickPos.Y < -GamePadStateBuilder.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickDown; + if (this.LeftStickPos.X > GamePadStateBuilder.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickRight; + if (this.LeftStickPos.X < -GamePadStateBuilder.LeftThumbstickDeadZone) + yield return SButton.LeftThumbstickLeft; + + // right thumbstick direction + if (this.RightStickPos.Length() > GamePadStateBuilder.RightThumbstickDeadZone) { - // left thumbstick - case SButton.LeftThumbstickUp: - if (this.LeftStickPos.Y > 0) - this.LeftStickPos.Y = 0; - break; - case SButton.LeftThumbstickDown: - if (this.LeftStickPos.Y < 0) - this.LeftStickPos.Y = 0; - break; - case SButton.LeftThumbstickLeft: - if (this.LeftStickPos.X < 0) - this.LeftStickPos.X = 0; - break; - case SButton.LeftThumbstickRight: - if (this.LeftStickPos.X > 0) - this.LeftStickPos.X = 0; - break; - - // right thumbstick - case SButton.RightThumbstickUp: - if (this.RightStickPos.Y > 0) - this.RightStickPos.Y = 0; - break; - case SButton.RightThumbstickDown: - if (this.RightStickPos.Y < 0) - this.RightStickPos.Y = 0; - break; - case SButton.RightThumbstickLeft: - if (this.RightStickPos.X < 0) - this.RightStickPos.X = 0; - break; - case SButton.RightThumbstickRight: - if (this.RightStickPos.X > 0) - this.RightStickPos.X = 0; - break; - - // triggers - case SButton.LeftTrigger: - this.LeftTrigger = 0; - break; - case SButton.RightTrigger: - this.RightTrigger = 0; - break; - - // buttons - default: - if (this.ButtonStates.ContainsKey(button)) - this.ButtonStates[button] = ButtonState.Released; - break; + if (this.RightStickPos.Y > 0) + yield return SButton.RightThumbstickUp; + if (this.RightStickPos.Y < 0) + yield return SButton.RightThumbstickDown; + if (this.RightStickPos.X > 0) + yield return SButton.RightThumbstickRight; + if (this.RightStickPos.X < 0) + yield return SButton.RightThumbstickLeft; } } - /// <summary>Construct an equivalent gamepad state.</summary> - public GamePadState ToGamePadState() + /// <summary>Get the equivalent state.</summary> + public GamePadState GetState() { - return new GamePadState( - leftThumbStick: this.LeftStickPos, - rightThumbStick: this.RightStickPos, - leftTrigger: this.LeftTrigger, - rightTrigger: this.RightTrigger, - buttons: this.GetBitmask(this.GetPressedButtons()) // MonoDevelop requires one bitmask here; don't specify multiple values - ); + if (this.State == null) + { + this.State = new GamePadState( + leftThumbStick: this.LeftStickPos, + rightThumbStick: this.RightStickPos, + leftTrigger: this.LeftTrigger, + rightTrigger: this.RightTrigger, + buttons: this.GetButtonBitmask() // MonoGame requires one bitmask here; don't specify multiple values + ); + } + + return this.State.Value; } + /********* ** Private methods *********/ - /// <summary>Get all pressed buttons.</summary> - private IEnumerable<Buttons> GetPressedButtons() + /// <summary>Get a bitmask representing the pressed buttons.</summary> + private Buttons GetButtonBitmask() { + Buttons flag = 0; foreach (var pair in this.ButtonStates) { if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button)) - yield return button; + flag |= button; } - } - /// <summary>Get a bitmask representing the given buttons.</summary> - /// <param name="buttons">The buttons to represent.</param> - private Buttons GetBitmask(IEnumerable<Buttons> buttons) - { - Buttons flag = 0; - foreach (Buttons button in buttons) - flag |= button; return flag; } } diff --git a/src/SMAPI/Framework/Input/IInputStateBuilder.cs b/src/SMAPI/Framework/Input/IInputStateBuilder.cs new file mode 100644 index 00000000..193e5216 --- /dev/null +++ b/src/SMAPI/Framework/Input/IInputStateBuilder.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace StardewModdingAPI.Framework.Input +{ + /// <summary>Manages input state.</summary> + /// <typeparam name="THandler">The handler type.</typeparam> + /// <typeparam name="TState">The state type.</typeparam> + internal interface IInputStateBuilder<out THandler, TState> + where TState : struct + where THandler : IInputStateBuilder<THandler, TState> + { + /********* + ** Methods + *********/ + /// <summary>Reset the tracked state.</summary> + /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param> + THandler Reset(TState? state = null); + + /// <summary>Override the states for a set of buttons.</summary> + /// <param name="overrides">The button state overrides.</param> + THandler OverrideButtons(IDictionary<SButton, SButtonState> overrides); + + /// <summary>Get the currently pressed buttons.</summary> + IEnumerable<SButton> GetPressedButtons(); + + /// <summary>Get the equivalent state.</summary> + TState GetState(); + } +} diff --git a/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs b/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs new file mode 100644 index 00000000..f95a28bf --- /dev/null +++ b/src/SMAPI/Framework/Input/KeyboardStateBuilder.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Framework.Input +{ + /// <summary>Manages keyboard state.</summary> + internal class KeyboardStateBuilder : IInputStateBuilder<KeyboardStateBuilder, KeyboardState> + { + /********* + ** Fields + *********/ + /// <summary>The underlying keyboard state.</summary> + private KeyboardState? State; + + /// <summary>The pressed buttons.</summary> + private readonly HashSet<Keys> PressedButtons = new HashSet<Keys>(); + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="state">The initial state, or <c>null</c> to get the latest state.</param> + public KeyboardStateBuilder(KeyboardState? state = null) + { + this.Reset(state); + } + + /// <summary>Reset the tracked state.</summary> + /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param> + public KeyboardStateBuilder Reset(KeyboardState? state = null) + { + this.State = state ??= Keyboard.GetState(); + + this.PressedButtons.Clear(); + foreach (var button in state.Value.GetPressedKeys()) + this.PressedButtons.Add(button); + + return this; + } + + /// <summary>Override the states for a set of buttons.</summary> + /// <param name="overrides">The button state overrides.</param> + public KeyboardStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides) + { + foreach (var pair in overrides) + { + if (pair.Key.TryGetKeyboard(out Keys key)) + { + this.State = null; + + if (pair.Value.IsDown()) + this.PressedButtons.Add(key); + else + this.PressedButtons.Remove(key); + } + } + + return this; + } + + /// <summary>Get the currently pressed buttons.</summary> + public IEnumerable<SButton> GetPressedButtons() + { + foreach (Keys key in this.PressedButtons) + yield return key.ToSButton(); + } + + /// <summary>Get the equivalent state.</summary> + public KeyboardState GetState() + { + return + this.State + ?? (this.State = new KeyboardState(this.PressedButtons.ToArray())).Value; + } + } +} diff --git a/src/SMAPI/Framework/Input/MouseStateBuilder.cs b/src/SMAPI/Framework/Input/MouseStateBuilder.cs new file mode 100644 index 00000000..cff3e05e --- /dev/null +++ b/src/SMAPI/Framework/Input/MouseStateBuilder.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Framework.Input +{ + /// <summary>Manages mouse state.</summary> + internal class MouseStateBuilder : IInputStateBuilder<MouseStateBuilder, MouseState> + { + /********* + ** Fields + *********/ + /// <summary>The underlying mouse state.</summary> + private MouseState? State; + + /// <summary>The current button states.</summary> + private IDictionary<SButton, ButtonState> ButtonStates; + + /// <summary>The mouse wheel scroll value.</summary> + private int ScrollWheelValue; + + + /********* + ** Accessors + *********/ + /// <summary>The X cursor position.</summary> + public int X { get; private set; } + + /// <summary>The Y cursor position.</summary> + public int Y { get; private set; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="state">The initial state, or <c>null</c> to get the latest state.</param> + public MouseStateBuilder(MouseState? state = null) + { + this.Reset(state); + } + + /// <summary>Reset the tracked state.</summary> + /// <param name="state">The state from which to reset, or <c>null</c> to get the latest state.</param> + public MouseStateBuilder Reset(MouseState? state = null) + { + this.State = state ??= Mouse.GetState(); + + this.ButtonStates = new Dictionary<SButton, ButtonState> + { + [SButton.MouseLeft] = state.Value.LeftButton, + [SButton.MouseMiddle] = state.Value.MiddleButton, + [SButton.MouseRight] = state.Value.RightButton, + [SButton.MouseX1] = state.Value.XButton1, + [SButton.MouseX2] = state.Value.XButton2 + }; + this.X = state.Value.X; + this.Y = state.Value.Y; + this.ScrollWheelValue = state.Value.ScrollWheelValue; + + return this; + } + + /// <summary>Override the states for a set of buttons.</summary> + /// <param name="overrides">The button state overrides.</param> + public MouseStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides) + { + foreach (var pair in overrides) + { + bool isDown = pair.Value.IsDown(); + if (this.ButtonStates.ContainsKey(pair.Key)) + this.ButtonStates[pair.Key] = isDown ? ButtonState.Pressed : ButtonState.Released; + } + + return this; + } + + /// <summary>Get the currently pressed buttons.</summary> + public IEnumerable<SButton> GetPressedButtons() + { + foreach (var pair in this.ButtonStates) + { + if (pair.Value == ButtonState.Pressed) + yield return pair.Key; + } + } + + /// <summary>Get the equivalent state.</summary> + public MouseState GetState() + { + if (this.State == null) + { + this.State = new MouseState( + x: this.X, + y: this.Y, + scrollWheel: this.ScrollWheelValue, + leftButton: this.ButtonStates[SButton.MouseLeft], + middleButton: this.ButtonStates[SButton.MouseMiddle], + rightButton: this.ButtonStates[SButton.MouseRight], + xButton1: this.ButtonStates[SButton.MouseX1], + xButton2: this.ButtonStates[SButton.MouseX2] + ); + } + + return this.State.Value; + } + } +} diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs index 4eaa9ca6..333f5726 100644 --- a/src/SMAPI/Framework/Input/SInputState.cs +++ b/src/SMAPI/Framework/Input/SInputState.cs @@ -14,46 +14,40 @@ namespace StardewModdingAPI.Framework.Input /********* ** Accessors *********/ - /// <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; /// <summary>The player's last known tile position.</summary> private Vector2? LastPlayerTile; + /// <summary>The buttons to press until the game next handles input.</summary> + private readonly HashSet<SButton> CustomPressedKeys = new HashSet<SButton>(); + + /// <summary>The buttons to consider released until the actual button is released.</summary> + private readonly HashSet<SButton> CustomReleasedKeys = new HashSet<SButton>(); + + /// <summary>Whether there are new overrides in <see cref="CustomPressedKeys"/> or <see cref="CustomReleasedKeys"/> that haven't been applied to the previous state.</summary> + private bool HasNewOverrides; + /********* ** Accessors *********/ /// <summary>The controller state as of the last update.</summary> - public GamePadState RealController { get; private set; } + public GamePadState LastController { get; private set; } /// <summary>The keyboard state as of the last update.</summary> - public KeyboardState RealKeyboard { get; private set; } + public KeyboardState LastKeyboard { get; private set; } /// <summary>The mouse state as of the last update.</summary> - public MouseState RealMouse { get; private set; } + public MouseState LastMouse { get; private set; } - /// <summary>A derivative of <see cref="RealController"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary> - public GamePadState SuppressedController { get; private set; } - - /// <summary>A derivative of <see cref="RealKeyboard"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary> - public KeyboardState SuppressedKeyboard { get; private set; } - - /// <summary>A derivative of <see cref="RealMouse"/> which suppresses the buttons in <see cref="SuppressButtons"/>.</summary> - public MouseState SuppressedMouse { get; private set; } + /// <summary>The buttons which were pressed, held, or released as of the last update.</summary> + public IDictionary<SButton, SButtonState> LastButtonStates { get; private set; } = new Dictionary<SButton, SButtonState>(); /// <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, SButtonState> ActiveButtons { get; private set; } = new Dictionary<SButton, SButtonState>(); - - /// <summary>The buttons to suppress when the game next handles input. Each button is suppressed until it's released.</summary> - public HashSet<SButton> SuppressButtons { get; } = new HashSet<SButton>(); - /********* ** Public methods @@ -63,14 +57,34 @@ namespace StardewModdingAPI.Framework.Input { return new SInputState { - ActiveButtons = this.ActiveButtons, - RealController = this.RealController, - RealKeyboard = this.RealKeyboard, - RealMouse = this.RealMouse, + LastButtonStates = this.LastButtonStates, + LastController = this.LastController, + LastKeyboard = this.LastKeyboard, + LastMouse = this.LastMouse, CursorPositionImpl = this.CursorPositionImpl }; } + /// <summary>Override the state for a button.</summary> + /// <param name="button">The button to over |
