diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs | 4 | ||||
| -rw-r--r-- | src/SMAPI.ModBuildConfig/build/smapi.targets | 1 | ||||
| -rw-r--r-- | src/SMAPI.ModBuildConfig/package.nuspec | 2 | ||||
| -rw-r--r-- | src/SMAPI/Framework/IModMetadata.cs | 3 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/InputState.cs | 220 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Input/SInputState.cs | 359 | ||||
| -rw-r--r-- | src/SMAPI/Framework/ModLoading/ModMetadata.cs | 9 | ||||
| -rw-r--r-- | src/SMAPI/Framework/Monitor.cs | 32 | ||||
| -rw-r--r-- | src/SMAPI/Framework/SGame.cs | 113 | ||||
| -rw-r--r-- | src/SMAPI/Program.cs | 41 | ||||
| -rw-r--r-- | src/SMAPI/SModHooks.cs | 48 | ||||
| -rw-r--r-- | src/SMAPI/StardewModdingAPI.csproj | 3 | 
12 files changed, 426 insertions, 409 deletions
| diff --git a/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs b/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs index 96bd29f4..d6f8dd7f 100644 --- a/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs +++ b/src/SMAPI.ModBuildConfig/Properties/AssemblyInfo.cs @@ -2,5 +2,5 @@ using System.Reflection;  [assembly: AssemblyTitle("SMAPI.ModBuildConfig")]  [assembly: AssemblyDescription("")] -[assembly: AssemblyVersion("2.0.2.0")] -[assembly: AssemblyFileVersion("2.0.2.0")] +[assembly: AssemblyVersion("2.1.0.0")] +[assembly: AssemblyFileVersion("2.1.0.0")] diff --git a/src/SMAPI.ModBuildConfig/build/smapi.targets b/src/SMAPI.ModBuildConfig/build/smapi.targets index 78afa7da..d33a9637 100644 --- a/src/SMAPI.ModBuildConfig/build/smapi.targets +++ b/src/SMAPI.ModBuildConfig/build/smapi.targets @@ -45,6 +45,7 @@      <When Condition="$(OS) == 'Windows_NT'">        <PropertyGroup>          <GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\GalaxyClient\Games\Stardew Valley</GamePath> +        <GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\GOG Galaxy\Games\Stardew Valley</GamePath>          <GamePath Condition="!Exists('$(GamePath)')">C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley</GamePath>          <GamePath Condition="!Exists('$(GamePath)')">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\GOG.com\Games\1453375253', 'PATH', null, RegistryView.Registry32))</GamePath>          <GamePath Condition="!Exists('$(GamePath)')">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 413150', 'InstallLocation', null, RegistryView.Registry64, RegistryView.Registry32))</GamePath> diff --git a/src/SMAPI.ModBuildConfig/package.nuspec b/src/SMAPI.ModBuildConfig/package.nuspec index 2512c4d6..66d02537 100644 --- a/src/SMAPI.ModBuildConfig/package.nuspec +++ b/src/SMAPI.ModBuildConfig/package.nuspec @@ -2,7 +2,7 @@  <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">    <metadata>      <id>Pathoschild.Stardew.ModBuildConfig</id> -    <version>2.1-alpha20180414</version> +    <version>2.1</version>      <title>Build package for SMAPI mods</title>      <authors>Pathoschild</authors>      <owners>Pathoschild</owners> diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs index 248809df..b7972fe1 100644 --- a/src/SMAPI/Framework/IModMetadata.cs +++ b/src/SMAPI/Framework/IModMetadata.cs @@ -65,6 +65,9 @@ namespace StardewModdingAPI.Framework          /// <param name="api">The mod-provided API.</param>          IModMetadata SetApi(object api); +        /// <summary>Whether the mod manifest was loaded (regardless of whether the mod itself was loaded).</summary> +        bool HasManifest(); +          /// <summary>Whether the mod has at least one update key set.</summary>          bool HasUpdateKeys();      } diff --git a/src/SMAPI/Framework/Input/InputState.cs b/src/SMAPI/Framework/Input/InputState.cs deleted file mode 100644 index 62337a6c..00000000 --- a/src/SMAPI/Framework/Input/InputState.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Input; -using StardewValley; - -namespace StardewModdingAPI.Framework.Input -{ -    /// <summary>A summary of input changes during an update frame.</summary> -    internal class InputState -    { -        /********* -        ** Accessors -        *********/ -        /// <summary>The maximum amount of direction to ignore for the left thumbstick.</summary> -        private const float LeftThumbstickDeadZone = 0.2f; - -        /// <summary>The maximum amount of direction to ignore for the right thumbstick.</summary> -        private const float RightThumbstickDeadZone = 0f; - - -        /********* -        ** Accessors -        *********/ -        /// <summary>The underlying controller state.</summary> -        public GamePadState ControllerState { get; } - -        /// <summary>The underlying keyboard state.</summary> -        public KeyboardState KeyboardState { get; } - -        /// <summary>The underlying mouse state.</summary> -        public MouseState MouseState { get; } - -        /// <summary>The mouse position on the screen adjusted for the zoom level.</summary> -        public Point MousePosition { get; } - -        /// <summary>The buttons which were pressed, held, or released.</summary> -        public IDictionary<SButton, InputStatus> ActiveButtons { get; } = new Dictionary<SButton, InputStatus>(); - - -        /********* -        ** Public methods -        *********/ -        /// <summary>Construct an empty instance.</summary> -        public InputState() { } - -        /// <summary>Construct an instance.</summary> -        /// <param name="previousState">The previous input state.</param> -        /// <param name="controllerState">The current controller state.</param> -        /// <param name="keyboardState">The current keyboard state.</param> -        /// <param name="mouseState">The current mouse state.</param> -        public InputState(InputState previousState, GamePadState controllerState, KeyboardState keyboardState, MouseState mouseState) -        { -            // init properties -            this.ControllerState = controllerState; -            this.KeyboardState = keyboardState; -            this.MouseState = mouseState; -            this.MousePosition = new Point((int)(mouseState.X * (1.0 / Game1.options.zoomLevel)), (int)(mouseState.Y * (1.0 / Game1.options.zoomLevel))); // derived from Game1::getMouseX - -            // get button states -            SButton[] down = this.GetPressedButtons(keyboardState, mouseState, controllerState).ToArray(); -            foreach (SButton button in down) -                this.ActiveButtons[button] = this.GetStatus(previousState.GetStatus(button), isDown: true); -            foreach (KeyValuePair<SButton, InputStatus> prev in previousState.ActiveButtons) -            { -                if (prev.Value.IsDown() && !this.ActiveButtons.ContainsKey(prev.Key)) -                    this.ActiveButtons[prev.Key] = InputStatus.Released; -            } -        } - -        /// <summary>Get the status of a button.</summary> -        /// <param name="button">The button to check.</param> -        public InputStatus GetStatus(SButton button) -        { -            return this.ActiveButtons.TryGetValue(button, out InputStatus status) ? status : InputStatus.None; -        } - -        /// <summary>Get whether a given button was pressed or held.</summary> -        /// <param name="button">The button to check.</param> -        public bool IsDown(SButton button) -        { -            return this.GetStatus(button).IsDown(); -        } - -        /// <summary>Get whether any of the given buttons were pressed or held.</summary> -        /// <param name="buttons">The buttons to check.</param> -        public bool IsAnyDown(InputButton[] buttons) -        { -            return buttons.Any(button => this.IsDown(button.ToSButton())); -        } - -        /// <summary>Get the current input state.</summary> -        /// <param name="previousState">The previous input state.</param> -        public static InputState GetState(InputState previousState) -        { -            GamePadState controllerState = GamePad.GetState(PlayerIndex.One); -            KeyboardState keyboardState = Keyboard.GetState(); -            MouseState mouseState = Mouse.GetState(); - -            return new InputState(previousState, controllerState, keyboardState, mouseState); -        } - -        /********* -        ** Private methods -        *********/ -        /// <summary>Get the status of a button.</summary> -        /// <param name="oldStatus">The previous button status.</param> -        /// <param name="isDown">Whether the button is currently down.</param> -        public InputStatus GetStatus(InputStatus oldStatus, bool isDown) -        { -            if (isDown && oldStatus.IsDown()) -                return InputStatus.Held; -            if (isDown) -                return InputStatus.Pressed; -            return InputStatus.Released; -        } - -        /// <summary>Get the buttons pressed in the given stats.</summary> -        /// <param name="keyboard">The keyboard state.</param> -        /// <param name="mouse">The mouse state.</param> -        /// <param name="controller">The controller state.</param> -        /// <remarks>Thumbstick direction logic derived from <see cref="ButtonCollection"/>.</remarks> -        private IEnumerable<SButton> GetPressedButtons(KeyboardState keyboard, MouseState mouse, GamePadState controller) -        { -            // keyboard -            foreach (Keys key in keyboard.GetPressedKeys()) -                yield return key.ToSButton(); - -            // mouse -            if (mouse.LeftButton == ButtonState.Pressed) -                yield return SButton.MouseLeft; -            if (mouse.RightButton == ButtonState.Pressed) -                yield return SButton.MouseRight; -            if (mouse.MiddleButton == ButtonState.Pressed) -                yield return SButton.MouseMiddle; -            if (mouse.XButton1 == ButtonState.Pressed) -                yield return SButton.MouseX1; -            if (mouse.XButton2 == ButtonState.Pressed) -                yield return SButton.MouseX2; - -            // controller -            if (controller.IsConnected) -            { -                // main buttons -                if (controller.Buttons.A == ButtonState.Pressed) -                    yield return SButton.ControllerA; -                if (controller.Buttons.B == ButtonState.Pressed) -                    yield return SButton.ControllerB; -                if (controller.Buttons.X == ButtonState.Pressed) -                    yield return SButton.ControllerX; -                if (controller.Buttons.Y == ButtonState.Pressed) -                    yield return SButton.ControllerY; -                if (controller.Buttons.LeftStick == ButtonState.Pressed) -                    yield return SButton.LeftStick; -                if (controller.Buttons.RightStick == ButtonState.Pressed) -                    yield return SButton.RightStick; -                if (controller.Buttons.Start == ButtonState.Pressed) -                    yield return SButton.ControllerStart; - -                // directional pad -                if (controller.DPad.Up == ButtonState.Pressed) -                    yield return SButton.DPadUp; -                if (controller.DPad.Down == ButtonState.Pressed) -                    yield return SButton.DPadDown; -                if (controller.DPad.Left == ButtonState.Pressed) -                    yield return SButton.DPadLeft; -                if (controller.DPad.Right == ButtonState.Pressed) -                    yield return SButton.DPadRight; - -                // secondary buttons -                if (controller.Buttons.Back == ButtonState.Pressed) -                    yield return SButton.ControllerBack; -                if (controller.Buttons.BigButton == ButtonState.Pressed) -                    yield return SButton.BigButton; - -                // shoulders -                if (controller.Buttons.LeftShoulder == ButtonState.Pressed) -                    yield return SButton.LeftShoulder; -                if (controller.Buttons.RightShoulder == ButtonState.Pressed) -                    yield return SButton.RightShoulder; - -                // triggers -                if (controller.Triggers.Left > 0.2f) -                    yield return SButton.LeftTrigger; -                if (controller.Triggers.Right > 0.2f) -                    yield return SButton.RightTrigger; - -                // left thumbstick direction -                if (controller.ThumbSticks.Left.Y > InputState.LeftThumbstickDeadZone) -                    yield return SButton.LeftThumbstickUp; -                if (controller.ThumbSticks.Left.Y < -InputState.LeftThumbstickDeadZone) -                    yield return SButton.LeftThumbstickDown; -                if (controller.ThumbSticks.Left.X > InputState.LeftThumbstickDeadZone) -                    yield return SButton.LeftThumbstickRight; -                if (controller.ThumbSticks.Left.X < -InputState.LeftThumbstickDeadZone) -                    yield return SButton.LeftThumbstickLeft; - -                // right thumbstick direction -                if (this.IsRightThumbstickOutsideDeadZone(controller.ThumbSticks.Right)) -                { -                    if (controller.ThumbSticks.Right.Y > 0) -                        yield return SButton.RightThumbstickUp; -                    if (controller.ThumbSticks.Right.Y < 0) -                        yield return SButton.RightThumbstickDown; -                    if (controller.ThumbSticks.Right.X > 0) -                        yield return SButton.RightThumbstickRight; -                    if (controller.ThumbSticks.Right.X < 0) -                        yield return SButton.RightThumbstickLeft; -                } -            } -        } - -        /// <summary>Get whether the right thumbstick should be considered outside the dead zone.</summary> -        /// <param name="direction">The right thumbstick value.</param> -        private bool IsRightThumbstickOutsideDeadZone(Vector2 direction) -        { -            return direction.Length() > 0.9f; -        } -    } -} diff --git a/src/SMAPI/Framework/Input/SInputState.cs b/src/SMAPI/Framework/Input/SInputState.cs new file mode 100644 index 00000000..62defa9f --- /dev/null +++ b/src/SMAPI/Framework/Input/SInputState.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +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> +    internal sealed class SInputState : InputState +    { +        /********* +        ** Accessors +        *********/ +        /// <summary>The maximum amount of direction to ignore for the left thumbstick.</summary> +        private const float LeftThumbstickDeadZone = 0.2f; + + +        /********* +        ** Accessors +        *********/ +        /// <summary>The controller state as of the last update.</summary> +        public GamePadState RealController { get; private set; } + +        /// <summary>The keyboard state as of the last update.</summary> +        public KeyboardState RealKeyboard { get; private set; } + +        /// <summary>The mouse state as of the last update.</summary> +        public MouseState RealMouse { 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 mouse position on the screen adjusted for the zoom level.</summary> +        public Point MousePosition { get; private set; } + +        /// <summary>The buttons which were pressed, held, or released.</summary> +        public IDictionary<SButton, InputStatus> ActiveButtons { get; private set; } = new Dictionary<SButton, InputStatus>(); + +        /// <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 +        *********/ +        /// <summary>Get a copy of the current state.</summary> +        public SInputState Clone() +        { +            return new SInputState +            { +                ActiveButtons = this.ActiveButtons, +                RealController = this.RealController, +                RealKeyboard = this.RealKeyboard, +                RealMouse = this.RealMouse, +                MousePosition = this.MousePosition +            }; +        } + +        /// <summary>This method is called by the game, and does nothing since SMAPI will already have updated by that point.</summary> +        [Obsolete("This method should only be called by the game itself.")] +        public override void Update() { } + +        /// <summary>Update the current button statuses for the given tick.</summary> +        public void TrueUpdate() +        { +            try +            { +                // get new states +                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); + +                // get suppressed states +                GamePadState suppressedController = realController; +                KeyboardState suppressedKeyboard = realKeyboard; +                MouseState suppressedMouse = realMouse; +                if (this.SuppressButtons.Count > 0) +                    this.UpdateSuppression(activeButtons, ref suppressedKeyboard, ref suppressedMouse, ref suppressedController); + +                // update +                this.ActiveButtons = activeButtons; +                this.RealController = realController; +                this.RealKeyboard = realKeyboard; +                this.RealMouse = realMouse; +                this.SuppressedController = suppressedController; +                this.SuppressedKeyboard = suppressedKeyboard; +                this.SuppressedMouse = suppressedMouse; +                this.MousePosition = mousePosition; +            } +            catch (InvalidOperationException) +            { +                // GetState() may crash for some players if window doesn't have focus but game1.IsActive == true +            } +        } + +        /// <summary>Get the gamepad state visible to the game.</summary> +        [Obsolete("This method should only be called by the game itself.")] +        public override GamePadState GetGamePadState() +        { +            return this.ShouldSuppressNow() +                ? this.SuppressedController +                : this.RealController; +        } + +        /// <summary>Get the keyboard state visible to the game.</summary> +        [Obsolete("This method should only be called by the game itself.")] +        public override KeyboardState GetKeyboardState() +        { +            return this.ShouldSuppressNow() +                ? this.SuppressedKeyboard +                : this.RealKeyboard; +        } + +        /// <summary>Get the keyboard state visible to the game.</summary> +        [Obsolete("This method should only be called by the game itself.")] +        public override MouseState GetMouseState() +        { +            return this.ShouldSuppressNow() +                ? this.SuppressedMouse +                : this.RealMouse; +        } + +        /// <summary>Get whether a given button was pressed or held.</summary> +        /// <param name="button">The button to check.</param> +        public bool IsDown(SButton button) +        { +            return this.GetStatus(this.ActiveButtons, button).IsDown(); +        } + +        /// <summary>Get whether any of the given buttons were pressed or held.</summary> +        /// <param name="buttons">The buttons to check.</param> +        public bool IsAnyDown(InputButton[] buttons) +        { +            return buttons.Any(button => this.IsDown(button.ToSButton())); +        } + +        /// <summary>Apply input suppression for the given input states.</summary> +        /// <param name="activeButtons">The current button states to check.</param> +        /// <param name="keyboardState">The game's keyboard state for the current tick.</param> +        /// <param name="mouseState">The game's mouse state for the current tick.</param> +        /// <param name="gamePadState">The game's controller state for the current tick.</param> +        public void UpdateSuppression(IDictionary<SButton, InputStatus> activeButtons, ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState) +        { +            // stop suppressing buttons once released +            if (this.SuppressButtons.Count != 0) +                this.SuppressButtons.RemoveWhere(p => !this.GetStatus(activeButtons, p).IsDown()); +            if (this.SuppressButtons.Count == 0) +                return; + +            // gather info +            HashSet<Keys> keyboardButtons = new HashSet<Keys>(); +            HashSet<SButton> controllerButtons = new HashSet<SButton>(); +            HashSet<SButton> mouseButtons = new HashSet<SButton>(); +            foreach (SButton button in this.SuppressButtons) +            { +                if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2) +                    mouseButtons.Add(button); +                else if (button.TryGetKeyboard(out Keys key)) +                    keyboardButtons.Add(key); +                else if (gamePadState.IsConnected && button.TryGetController(out Buttons _)) +                    controllerButtons.Add(button); +            } + +            // suppress keyboard keys +            if (keyboardState.GetPressedKeys().Any() && keyboardButtons.Any()) +                keyboardState = new KeyboardState(keyboardState.GetPressedKeys().Except(keyboardButtons).ToArray()); + +            // suppress controller keys +            if (gamePadState.IsConnected && controllerButtons.Any()) +            { +                GamePadStateBuilder builder = new GamePadStateBuilder(gamePadState); +                builder.SuppressButtons(controllerButtons); +                gamePadState = builder.ToGamePadState(); +            } + +            // suppress mouse buttons +            if (mouseButtons.Any()) +            { +                mouseState = new MouseState( +                    x: mouseState.X, +                    y: mouseState.Y, +                    scrollWheel: mouseState.ScrollWheelValue, +                    leftButton: mouseButtons.Contains(SButton.MouseLeft) ? ButtonState.Pressed : mouseState.LeftButton, +                    middleButton: mouseButtons.Contains(SButton.MouseMiddle) ? ButtonState.Pressed : mouseState.MiddleButton, +                    rightButton: mouseButtons.Contains(SButton.MouseRight) ? ButtonState.Pressed : mouseState.RightButton, +                    xButton1: mouseButtons.Contains(SButton.MouseX1) ? ButtonState.Pressed : mouseState.XButton1, +                    xButton2: mouseButtons.Contains(SButton.MouseX2) ? ButtonState.Pressed : mouseState.XButton2 +                ); +            } +        } + + +        /********* +        ** Private methods +        *********/ +        /// <summary>Whether input should be suppressed in the current context.</summary> +        private bool ShouldSuppressNow() +        { +            return Game1.chatBox != null && !Game1.chatBox.isActive(); +        } + +        /// <summary>Get the status of all pressed or released buttons relative to their previous status.</summary> +        /// <param name="previousStatuses">The previous button statuses.</param> +        /// <param name="keyboard">The keyboard state.</param> +        /// <param name="mouse">The mouse state.</param> +        /// <param name="controller">The controller state.</param> +        private IDictionary<SButton, InputStatus> DeriveStatuses(IDictionary<SButton, InputStatus> previousStatuses, KeyboardState keyboard, MouseState mouse, GamePadState controller) +        { +            IDictionary<SButton, InputStatus> activeButtons = new Dictionary<SButton, InputStatus>(); + +            // handle pressed keys +            SButton[] down = this.GetPressedButtons(keyboard, mouse, controller).ToArray(); +            foreach (SButton button in down) +                activeButtons[button] = this.DeriveStatus(this.GetStatus(previousStatuses, button), isDown: true); + +            // handle released keys +            foreach (KeyValuePair<SButton, InputStatus> prev in activeButtons) +            { +                if (prev.Value.IsDown() && !activeButtons.ContainsKey(prev.Key)) +                    activeButtons[prev.Key] = InputStatus.Released; +            } + +            return activeButtons; +        } + +        /// <summary>Get the status of a button relative to its previous status.</summary> +        /// <param name="oldStatus">The previous button status.</param> +        /// <param name="isDown">Whether the button is currently down.</param> +        private InputStatus DeriveStatus(InputStatus oldStatus, bool isDown) +        { +            if (isDown && oldStatus.IsDown()) +                return InputStatus.Held; +            if (isDown) +                return InputStatus.Pressed; +            return InputStatus.Released; +        } + +        /// <summary>Get the status of a button.</summary> +        /// <param name="activeButtons">The current button states to check.</param> +        /// <param name="button">The button to check.</param> +        private InputStatus GetStatus(IDictionary<SButton, InputStatus> activeButtons, SButton button) +        { +            return activeButtons.TryGetValue(button, out InputStatus status) ? status : InputStatus.None; +        } + +        /// <summary>Get the buttons pressed in the given stats.</summary> +        /// <param name="keyboard">The keyboard state.</param> +        /// <param name="mouse">The mouse state.</param> +        /// <param name="controller">The controller state.</param> +        /// <remarks>Thumbstick direction logic derived from <see cref="ButtonCollection"/>.</remarks> +        private IEnumerable<SButton> GetPressedButtons(KeyboardState keyboard, MouseState mouse, GamePadState controller) +        { +            // keyboard +            foreach (Keys key in keyboard.GetPressedKeys()) +                yield return key.ToSButton(); + +            // mouse +            if (mouse.LeftButton == ButtonState.Pressed) +                yield return SButton.MouseLeft; +            if (mouse.RightButton == ButtonState.Pressed) +                yield return SButton.MouseRight; +            if (mouse.MiddleButton == ButtonState.Pressed) +                yield return SButton.MouseMiddle; +            if (mouse.XButton1 == ButtonState.Pressed) +                yield return SButton.MouseX1; +            if (mouse.XButton2 == ButtonState.Pressed) +                yield return SButton.MouseX2; + +            // controller +            if (controller.IsConnected) +            { +                // main buttons +                if (controller.Buttons.A == ButtonState.Pressed) +                    yield return SButton.ControllerA; +                if (controller.Buttons.B == ButtonState.Pressed) +                    yield return SButton.ControllerB; +                if (controller.Buttons.X == ButtonState.Pressed) +                    yield return SButton.ControllerX; +                if (controller.Buttons.Y == ButtonState.Pressed) +                    yield return SButton.ControllerY; +                if (controller.Buttons.LeftStick == ButtonState.Pressed) +                    yield return SButton.LeftStick; +                if (controller.Buttons.RightStick == ButtonState.Pressed) +                    yield return SButton.RightStick; +                if (controller.Buttons.Start == ButtonState.Pressed) +                    yield return SButton.ControllerStart; + +                // directional pad +                if (controller.DPad.Up == ButtonState.Pressed) +                    yield return SButton.DPadUp; +                if (controller.DPad.Down == ButtonState.Pressed) +                    yield return SButton.DPadDown; +                if (controller.DPad.Left == ButtonState.Pressed) +                    yield return SButton.DPadLeft; +                if (controller.DPad.Right == ButtonState.Pressed) +                    yield return SButton.DPadRight; + +                // secondary buttons +                if (controller.Buttons.Back == ButtonState.Pressed) +                    yield return SButton.ControllerBack; +                if (controller.Buttons.BigButton == ButtonState.Pressed) +                    yield return SButton.BigButton; + +                // shoulders +                if (controller.Buttons.LeftShoulder == ButtonState.Pressed) +                    yield return SButton.LeftShoulder; +                if (controller.Buttons.RightShoulder == ButtonState.Pressed) +                    yield return SButton.RightShoulder; + +                // triggers +                if (controller.Triggers.Left > 0.2f) +                    yield return SButton.LeftTrigger; +                if (controller.Triggers.Right > 0.2f) +                    yield return SButton.RightTrigger; + +                // left thumbstick direction +                if (controller.ThumbSticks.Left.Y > SInputState.LeftThumbstickDeadZone) +                    yield return SButton.LeftThumbstickUp; +                if (controller.ThumbSticks.Left.Y < -SInputState.LeftThumbstickDeadZone) +                    yield return SButton.LeftThumbstickDown; +                if (controller.ThumbSticks.Left.X > SInputState.LeftThumbstickDeadZone) +                    yield return SButton.LeftThumbstickRight; +                if (controller.ThumbSticks.Left.X < -SInputState.LeftThumbstickDeadZone) +                    yield return SButton.LeftThumbstickLeft; + +                // right thumbstick direction +                if (this.IsRightThumbstickOutsideDeadZone(controller.ThumbSticks.Right)) +                { +                    if (controller.ThumbSticks.Right.Y > 0) +                        yield return SButton.RightThumbstickUp; +                    if (controller.ThumbSticks.Right.Y < 0) +                        yield return SButton.RightThumbstickDown; +                    if (controller.ThumbSticks.Right.X > 0) +                        yield return SButton.RightThumbstickRight; +                    if (controller.ThumbSticks.Right.X < 0) +                        yield return SButton.RightThumbstickLeft; +                } +            } +        } + +        /// <summary>Get whether the right thumbstick should be considered outside the dead zone.</summary> +        /// <param name="direction">The right thumbstick value.</param> +        private bool IsRightThumbstickOutsideDeadZone(Vector2 direction) +        { +            return direction.Length() > 0.9f; +        } +    } +} diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs index af888b71..d3a33e7a 100644 --- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs +++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs @@ -104,11 +104,18 @@ namespace StardewModdingAPI.Framework.ModLoading              return this;          } +        /// <summary>Whether the mod manifest was loaded (regardless of whether the mod itself was loaded).</summary> +        public bool HasManifest() +        { +            return this.Manifest != null; +        } +          /// <summary>Whether the mod has at least one update key set.</summary>          public bool HasUpdateKeys()          {              return -                this.Manifest?.UpdateKeys != null +                this.HasManifest() +                && this.Manifest.UpdateKeys != null                  && this.Manifest.UpdateKeys.Any(key => !string.IsNullOrWhiteSpace(key));          }      } diff --git a/src/SMAPI/Framework/Monitor.cs b/src/SMAPI/Framework/Monitor.cs index a76afc3c..cc511ed4 100644 --- a/src/SMAPI/Framework/Monitor.cs +++ b/src/SMAPI/Framework/Monitor.cs @@ -48,9 +48,6 @@ namespace StardewModdingAPI.Framework          /// <summary>Whether to write anything to the console. This should be disabled if no console is available.</summary>          internal bool WriteToConsole { get; set; } = true; -        /// <summary>Whether to write anything to the log file. This should almost always be enabled.</summary> -        internal bool WriteToFile { get; set; } = true; -          /*********          ** Public methods @@ -96,8 +93,16 @@ namespace StardewModdingAPI.Framework          {              if (this.WriteToConsole)                  this.ConsoleManager.ExclusiveWriteWithoutInterception(Console.WriteLine); -            if (this.WriteToFile) -                this.LogFile.WriteLine(""); +            this.LogFile.WriteLine(""); +        } + +        /// <summary>Log console input from the user.</summary> +        /// <param name="input">The user input to log.</param> +        internal void LogUserInput(string input) +        { +            // user input already appears in the console, so just need to write to file +            string prefix = this.GenerateMessagePrefix(this.Source, LogLevel.Info); +            this.LogFile.WriteLine($"{prefix} $>{input}");          } @@ -120,9 +125,8 @@ namespace StardewModdingAPI.Framework          private void LogImpl(string source, string message, LogLevel level, ConsoleColor color, ConsoleColor? background = null)          {              // generate message -            string levelStr = level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength); - -            string fullMessage = $"[{DateTime.Now:HH:mm:ss} {levelStr} {source}] {message}"; +            string prefix = this.GenerateMessagePrefix(source, level); +            string fullMessage = $"{prefix} {message}";              string consoleMessage = this.ShowFullStampInConsole ? fullMessage : $"[{source}] {message}";              // write to console @@ -144,8 +148,16 @@ namespace StardewModdingAPI.Framework              }              // write to log file -            if (this.WriteToFile) -                this.LogFile.WriteLine(fullMessage); +            this.LogFile.WriteLine(fullMessage); +        } + +        /// <summary>Generate a message prefix for the current time.</summary> +        /// <param name="source">The name of the mod logging the message.</param> +        /// <param name="level">The log level.</param> +        private string GenerateMessagePrefix(string source, LogLevel level) +        { +            string levelStr = level.ToString().ToUpper().PadRight(Monitor.MaxLevelLength); +            return $"[{DateTime.Now:HH:mm:ss} {levelStr} {source}]";          }          /// <summary>Get the color scheme to use for the current console.</summary> diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index 4f5bd96b..182b90fc 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -53,6 +53,9 @@ 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 @@ -78,9 +81,6 @@ namespace StardewModdingAPI.Framework          /****          ** Game state          ****/ -        /// <summary>The player input as of the previous tick.</summary> -        private InputState PreviousInput = new InputState(); -          /// <summary>The underlying watchers for convenience. These are accessible individually as separate properties.</summary>          private readonly List<IWatcher> Watchers = new List<IWatcher>(); @@ -120,9 +120,6 @@ namespace StardewModdingAPI.Framework          /// <summary>Simplifies access to private game code.</summary>          private readonly Reflector Reflection; -        /// <summary>The buttons to suppress when the game next handles input. Each button is suppressed until it's released.</summary> -        private readonly HashSet<SButton> SuppressButtons = new HashSet<SButton>(); -          /*********          ** Accessors @@ -157,7 +154,7 @@ namespace StardewModdingAPI.Framework              this.OnGameExiting = onGameExiting;              if (this.ContentCore == null) // shouldn't happen since CreateContentManager is called first, but let's init here just in case                  this.ContentCore = new ContentCore(this.Content.ServiceProvider, this.Content.RootDirectory, Thread.CurrentThread.CurrentUICulture, this.Monitor, reflection); -            Game1.hooks = new SModHooks(this.UpdateControlInput); +            Game1.input = new SInputState();              // init watchers              Game1.locations = new ObservableCollection<GameLocation>(); @@ -289,7 +286,7 @@ namespace StardewModdingAPI.Framework                  if (this.FirstUpdate)                      this.OnGameInitialised(); -                 +                  /*********                  ** Update context                  *********/ @@ -390,16 +387,9 @@ namespace StardewModdingAPI.Framework                  *********/                  if (Game1.game1.IsActive)                  { -                    // get input state -                    InputState inputState; -                    try -                    { -                        inputState = InputState.GetState(this.PreviousInput); -                    } -                    catch (InvalidOperationException) // GetState() may crash for some players if window doesn't have focus but game1.IsActive == true -                    { -                        inputState = this.PreviousInput; -                    } +                    SInputState previousInputState = this.Input.Clone(); +                    SInputState inputState = this.Input; +                    inputState.TrueUpdate();                      // raise events                      bool isChatInput = Game1.IsChatting || (Context.IsMultiplayer && Context.IsWorldReady && Game1.activeClickableMenu == null && Game1.currentMinigame == null && inputState.IsAnyDown(Game1.options.chatButton)); @@ -425,7 +415,7 @@ namespace StardewModdingAPI.Framework                              if (status == InputStatus.Pressed)                              { -                                this.Events.Input_ButtonPressed.Raise(new EventArgsInput(button, cursor, button.IsActionButton(), button.IsUseToolButton(), this.SuppressButtons)); +                                this.Events.Input_ButtonPressed.Raise(new EventArgsInput(button, cursor, button.IsActionButton(), button.IsUseToolButton(), inputState.SuppressButtons));                                  // legacy events                                  if (button.TryGetKeyboard(out Keys key)) @@ -436,14 +426,14 @@ namespace StardewModdingAPI.Framework                                  else if (button.TryGetController(out Buttons controllerButton))                                  {                                      if (controllerButton == Buttons.LeftTrigger || controllerButton == Buttons.RightTrigger) -                                        this.Events.Control_ControllerTriggerPressed.Raise(new EventArgsControllerTriggerPressed(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.ControllerState.Triggers.Left : inputState.ControllerState.Triggers.Right)); +                                        this.Events.Control_ControllerTriggerPressed.Raise(new EventArgsControllerTriggerPressed(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right));                                      else                                          this.Events.Control_ControllerButtonPressed.Raise(new EventArgsControllerButtonPressed(PlayerIndex.One, controllerButton));                                  }                              }                              else if (status == InputStatus.Released)                              { -                                this.Events.Input_ButtonReleased.Raise(new EventArgsInput(button, cursor, button.IsActionButton(), button.IsUseToolButton(), this.SuppressButtons)); +                                this.Events.Input_ButtonReleased.Raise(new EventArgsInput(button, cursor, button.IsActionButton(), button.IsUseToolButton(), inputState.SuppressButtons));                                  // legacy events                                  if (button.TryGetKeyboard(out Keys key)) @@ -454,7 +444,7 @@ namespace StardewModdingAPI.Framework                                  else if (button.TryGetController(out Buttons controllerButton))                                  {                                      if (controllerButton == Buttons.LeftTrigger || controllerButton == Buttons.RightTrigger) -                                        this.Events.Control_ControllerTriggerReleased.Raise(new EventArgsControllerTriggerReleased(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.ControllerState.Triggers.Left : inputState.ControllerState.Triggers.Right)); +                                        this.Events.Control_ControllerTriggerReleased.Raise(new EventArgsControllerTriggerReleased(PlayerIndex.One, controllerButton, controllerButton == Buttons.LeftTrigger ? inputState.RealController.Triggers.Left : inputState.RealController.Triggers.Right));                                      else                                          this.Events.Control_ControllerButtonReleased.Raise(new EventArgsControllerButtonReleased(PlayerIndex.One, controllerButton));                                  } @@ -462,14 +452,11 @@ namespace StardewModdingAPI.Framework                          }                          // raise legacy state-changed events -                        if (inputState.KeyboardState != this.PreviousInput.KeyboardState) -                            this.Events.Control_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(this.PreviousInput.KeyboardState, inputState.KeyboardState)); -                        if (inputState.MouseState != this.PreviousInput.MouseState) -                            this.Events.Control_MouseChanged.Raise(new EventArgsMouseStateChanged(this.PreviousInput.MouseState, inputState.MouseState, this.PreviousInput.MousePosition, inputState.MousePosition)); +                        if (inputState.RealKeyboard != previousInputState.RealKeyboard) +                            this.Events.Control_KeyboardChanged.Raise(new EventArgsKeyboardStateChanged(previousInputState.RealKeyboard, inputState.RealKeyboard)); +                        if (inputState.RealMouse != previousInputState.RealMouse) +                            this.Events.Control_MouseChanged.Raise(new EventArgsMouseStateChanged(previousInputState.RealMouse, inputState.RealMouse, previousInputState.MousePosition, inputState.MousePosition));                      } - -                    // track state -                    this.PreviousInput = inputState;                  }                  /********* @@ -624,17 +611,6 @@ namespace StardewModdingAPI.Framework              }          } -        /// <summary>Read the current input state for handling.</summary> -        /// <param name="keyboardState">The game's keyboard state for the current tick.</param> -        /// <param name="mouseState">The game's mouse state for the current tick.</param> -        /// <param name="gamePadState">The game's controller state for the current tick.</param> -        /// <param name="defaultLogic">The game's default logic.</param> -        public void UpdateControlInput(ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState, Action defaultLogic) -        { -            this.ApplySuppression(ref keyboardState, ref mouseState, ref gamePadState); -            defaultLogic(); -        } -          /// <summary>The method called to draw everything to the screen.</summary>          /// <param name="gameTime">A snapshot of the game timing state.</param>          protected override void Draw(GameTime gameTime) @@ -1256,63 +1232,6 @@ namespace StardewModdingAPI.Framework          /****          ** Methods          ****/ -        /// <summary>Apply input suppression for the given input states.</summary> -        /// <param name="keyboardState">The game's keyboard state for the current tick.</param> -        /// <param name="mouseState">The game's mouse state for the current tick.</param> -        /// <param name="gamePadState">The game's controller state for the current tick.</param> -        private void ApplySuppression(ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState) -        { -            // stop suppressing buttons once released -            if (this.SuppressButtons.Count != 0) -            { -                InputState inputState = new InputState(this.PreviousInput, gamePadState, keyboardState, mouseState); -                this.SuppressButtons.RemoveWhere(p => !inputState.IsDown(p)); -            } -            if (this.SuppressButtons.Count == 0) -                return; - -            // gather info -            HashSet<Keys> keyboardButtons = new HashSet<Keys>(); -            HashSet<SButton> controllerButtons = new HashSet<SButton>(); -            HashSet<SButton> mouseButtons = new HashSet<SButton>(); -            foreach (SButton button in this.SuppressButtons) -            { -                if (button == SButton.MouseLeft || button == SButton.MouseMiddle || button == SButton.MouseRight || button == SButton.MouseX1 || button == SButton.MouseX2) -                    mouseButtons.Add(button); -                else if (button.TryGetKeyboard(out Keys key)) -                    keyboardButtons.Add(key); -                else if (gamePadState.IsConnected && button.TryGetController(out Buttons _)) -                    controllerButtons.Add(button); -            } - -            // suppress keyboard keys -            if (keyboardState.GetPressedKeys().Any() && keyboardButtons.Any()) -                keyboardState = new KeyboardState(keyboardState.GetPressedKeys().Except(keyboardButtons).ToArray()); - -            // suppress controller keys -            if (gamePadState.IsConnected && controllerButtons.Any()) -            { -                GamePadStateBuilder builder = new GamePadStateBuilder(gamePadState); -                builder.SuppressButtons(controllerButtons); -                gamePadState = builder.ToGamePadState(); -            } - -            // suppress mouse buttons -            if (mouseButtons.Any()) -            { -                mouseState = new MouseState( -                    x: mouseState.X, -                    y: mouseState.Y, -                    scrollWheel: mouseState.ScrollWheelValue, -                    leftButton: mouseButtons.Contains(SButton.MouseLeft) ? ButtonState.Pressed : mouseState.LeftButton, -                    middleButton: mouseButtons.Contains(SButton.MouseMiddle) ? ButtonState.Pressed : mouseState.MiddleButton, -                    rightButton: mouseButtons.Contains(SButton.MouseRight) ? ButtonState.Pressed : mouseState.RightButton, -                    xButton1: mouseButtons.Contains(SButton.MouseX1) ? ButtonState.Pressed : mouseState.XButton1, -                    xButton2: mouseButtons.Contains(SButton.MouseX2) ? ButtonState.Pressed : mouseState.XButton2 -                ); -            } -        } -          /// <summary>Perform any cleanup needed when the player unloads a save and returns to the title screen.</summary>          private void CleanupAfterReturnToTitle()          { diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs index 3c6b1cf6..f1152d82 100644 --- a/src/SMAPI/Program.cs +++ b/src/SMAPI/Program.cs @@ -448,6 +448,9 @@ namespace StardewModdingAPI                      if (string.IsNullOrWhiteSpace(input))                          continue; +                    // write input to log file +                    this.Monitor.LogUserInput(input); +                      // parse input                      try                      { @@ -582,25 +585,8 @@ namespace StardewModdingAPI                                  StringComparer.InvariantCultureIgnoreCase                              ); -                        // report update keys -                        { -                            IModMetadata[] modsWithoutKeys = ( -                                from mod in mods -                                where -                                    mod.Manifest != null -                                    && (mod.Manifest.UpdateKeys == null || !mod.Manifest.UpdateKeys.Any()) -                                    && (mod.Manifest?.UniqueID != "SMAPI.ConsoleCommands" && mod.Manifest?.UniqueID != "SMAPI.TrainerMod") -                                orderby mod.DisplayName -                                select mod -                            ).ToArray(); - -                            string message = $"Checking {modsByKey.Count} mod update keys."; -                            if (modsWithoutKeys.Any()) -                                message += $" {modsWithoutKeys.Length} mods have no update keys: {string.Join(", ", modsWithoutKeys.Select(p => p.DisplayName))}."; -                            this.Monitor.Log($"   {message}", LogLevel.Trace); -                        } -                          // fetch results +                        this.Monitor.Log($"   Checking {modsByKey.Count} mod update keys.", LogLevel.Trace);                          var results =                              (                                  from entry in client.GetModInfo(modsByKey.Keys.ToArray()) @@ -714,10 +700,12 @@ namespace StardewModdingAPI              // load content packs              foreach (IModMetadata metadata in mods.Where(p => p.IsContentPack))              { -                // get basic info -                IManifest manifest = metadata.Manifest;                  this.Monitor.Log($"   {metadata.DisplayName} (content pack, {PathUtilities.GetRelativePath(Constants.ModPath, metadata.DirectoryPath)})...", LogLevel.Trace); +                // show warning for missing update key +                if (metadata.HasManifest() && !metadata.HasUpdateKeys()) +                    this.Monitor.Log($"      {metadata.DisplayName} has no {nameof(IManifest.UpdateKeys)} in its manifest. You may not see update alerts for this mod.", LogLevel.Warn); +                  // validate status                  if (metadata.Status == ModMetadataStatus.Failed)                  { @@ -726,11 +714,8 @@ namespace StardewModdingAPI                      continue;                  } -                // show warnings -                if (this.Settings.DeveloperMode && !metadata.HasUpdateKeys()) -                    this.Monitor.Log($"      {metadata.DisplayName} has no {nameof(IManifest.UpdateKeys)} in its manifest. You may not see update alerts for this mod.", LogLevel.Warn); -                  // load mod as content pack +                IManifest manifest = metadata.Manifest;                  IMonitor monitor = this.GetSecondaryMonitor(metadata.DisplayName);                  ContentManagerShim contentManager = this.ContentCore.CreateContentManager($"Mods.{metadata.Manifest.UniqueID}", metadata.DirectoryPath);                  IContentHelper contentHelper = new ContentHelper(this.ContentCore, contentManager, metadata.DirectoryPath, manifest.UniqueID, metadata.DisplayName, monitor); @@ -766,6 +751,10 @@ namespace StardewModdingAPI                          ? $"   {metadata.DisplayName} ({PathUtilities.GetRelativePath(Constants.ModPath, metadata.DirectoryPath)}{Path.DirectorySeparatorChar}{metadata.Manifest.EntryDll})..." // don't use Path.Combine here, since EntryDLL might not be valid                          : $"   {metadata.DisplayName}...", LogLevel.Trace); +                    // show warnings +                    if (metadata.HasManifest() && !metadata.HasUpdateKeys() && metadata.Manifest.UniqueID != "SMAPI.ConsoleCommands") +                        this.Monitor.Log($"      {metadata.DisplayName} has no {nameof(IManifest.UpdateKeys)} in its manifest. You may not see update alerts for this mod.", LogLevel.Warn); +                      // validate status                      if (metadata.Status == ModMetadataStatus.Failed)                      { @@ -774,10 +763,6 @@ namespace StardewModdingAPI                          continue;                      } -                    // show warnings -                    if (this.Settings.DeveloperMode && !metadata.HasUpdateKeys() && metadata.Manifest.UniqueID != "SMAPI.ConsoleCommands") -                        this.Monitor.Log($"      {metadata.DisplayName} has no {nameof(IManifest.UpdateKeys)} in its manifest. You may not see update alerts for this mod.", LogLevel.Warn); -                      // load mod                      string assemblyPath = metadata.Manifest?.EntryDll != null                          ? Path.Combine(metadata.DirectoryPath, metadata.Manifest.EntryDll) diff --git a/src/SMAPI/SModHooks.cs b/src/SMAPI/SModHooks.cs deleted file mode 100644 index 1b88d606..00000000 --- a/src/SMAPI/SModHooks.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using Microsoft.Xna.Framework.Input; -using StardewValley; - -namespace StardewModdingAPI -{ -    /// <summary>Intercepts predefined Stardew Valley mod hooks.</summary> -    internal class SModHooks : ModHooks -    { -        /********* -        ** Delegates -        *********/ -        /// <summary>A delegate invoked by the <see cref="SModHooks.OnGame1_UpdateControlInput"/> hook.</summary> -        /// <param name="keyboardState">The game's keyboard state for the current tick.</param> -        /// <param name="mouseState">The game's mouse state for the current tick.</param> -        /// <param name="gamePadState">The game's controller state for the current tick.</param> -        /// <param name="action">The game's default logic.</param> -        public delegate void UpdateControlInputDelegate(ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState, Action action); - - -        /********* -        ** Properties -        *********/ -        /// <summary>The callback for <see cref="OnGame1_UpdateControlInput"/>.</summary> -        private readonly UpdateControlInputDelegate UpdateControlInputHandler; - - -        /********* -        ** Public methods -        *********/ -        /// <summary>Construct an instance.</summary> -        /// <param name="updateControlInputHandler">The callback for <see cref="OnGame1_UpdateControlInput"/>.</param> -        public SModHooks(UpdateControlInputDelegate updateControlInputHandler) -        { -            this.UpdateControlInputHandler = updateControlInputHandler; -        } - -        /// <summary>A hook invoked before the game processes player input.</summary> -        /// <param name="keyboardState">The game's keyboard state for the current tick.</param> -        /// <param name="mouseState">The game's mouse state for the current tick.</param> -        /// <param name="gamePadState">The game's controller state for the current tick.</param> -        /// <param name="action">The game's default logic.</param> -        public override void OnGame1_UpdateControlInput(ref KeyboardState keyboardState, ref MouseState mouseState, ref GamePadState gamePadState, Action action) -        { -            this.UpdateControlInputHandler(ref keyboardState, ref mouseState, ref gamePadState, action); -        } -    } -} diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index d7719e27..560d7bf4 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -92,7 +92,7 @@      <Compile Include="Framework\Content\ContentCache.cs" />      <Compile Include="Framework\Events\ManagedEventBase.cs" />      <Compile Include="Framework\Input\GamePadStateBuilder.cs" /> -    <Compile Include="Framework\Input\InputState.cs" /> +    <Compile Include="Framework\Input\SInputState.cs" />      <Compile Include="Framework\Input\InputStatus.cs" />      <Compile Include="Framework\LegacyManifestVersion.cs" />      <Compile Include="Framework\ModData\ModDatabase.cs" /> @@ -263,7 +263,6 @@      <Compile Include="Framework\SGame.cs" />      <Compile Include="IReflectionHelper.cs" />      <Compile Include="SemanticVersion.cs" /> -    <Compile Include="SModHooks.cs" />      <Compile Include="Translation.cs" />      <Compile Include="ICursorPosition.cs" />      <Compile Include="Utilities\SDate.cs" /> | 
