diff options
Diffstat (limited to 'src/StardewModdingAPI/Events')
36 files changed, 1854 insertions, 0 deletions
diff --git a/src/StardewModdingAPI/Events/ChangeType.cs b/src/StardewModdingAPI/Events/ChangeType.cs new file mode 100644 index 00000000..4b207f08 --- /dev/null +++ b/src/StardewModdingAPI/Events/ChangeType.cs @@ -0,0 +1,15 @@ +namespace StardewModdingAPI.Events +{ + /// <summary>Indicates how an inventory item changed.</summary> + public enum ChangeType + { + /// <summary>The entire stack was removed.</summary> + Removed, + + /// <summary>The entire stack was added.</summary> + Added, + + /// <summary>The stack size changed.</summary> + StackChange + } +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/ContentEvents.cs b/src/StardewModdingAPI/Events/ContentEvents.cs new file mode 100644 index 00000000..4b4e2ad0 --- /dev/null +++ b/src/StardewModdingAPI/Events/ContentEvents.cs @@ -0,0 +1,29 @@ +using System; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the game loads content.</summary> + public static class ContentEvents + { + + /********* + ** Events + *********/ + /// <summary>Raised after the content language changes.</summary> + public static event EventHandler<EventArgsValueChanged<string>> AfterLocaleChanged; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise an <see cref="AfterLocaleChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="oldLocale">The previous locale.</param> + /// <param name="newLocale">The current locale.</param> + internal static void InvokeAfterLocaleChanged(IMonitor monitor, string oldLocale, string newLocale) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ContentEvents)}.{nameof(ContentEvents.AfterLocaleChanged)}", ContentEvents.AfterLocaleChanged?.GetInvocationList(), null, new EventArgsValueChanged<string>(oldLocale, newLocale)); + } + } +} diff --git a/src/StardewModdingAPI/Events/ControlEvents.cs b/src/StardewModdingAPI/Events/ControlEvents.cs new file mode 100644 index 00000000..80d0f547 --- /dev/null +++ b/src/StardewModdingAPI/Events/ControlEvents.cs @@ -0,0 +1,112 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the player uses a controller, keyboard, or mouse.</summary> + public static class ControlEvents + { + /********* + ** Events + *********/ + /// <summary>Raised when the <see cref="KeyboardState"/> changes. That happens when the player presses or releases a key.</summary> + public static event EventHandler<EventArgsKeyboardStateChanged> KeyboardChanged; + + /// <summary>Raised when the player presses a keyboard key.</summary> + public static event EventHandler<EventArgsKeyPressed> KeyPressed; + + /// <summary>Raised when the player releases a keyboard key.</summary> + public static event EventHandler<EventArgsKeyPressed> KeyReleased; + + /// <summary>Raised when the <see cref="MouseState"/> changes. That happens when the player moves the mouse, scrolls the mouse wheel, or presses/releases a button.</summary> + public static event EventHandler<EventArgsMouseStateChanged> MouseChanged; + + /// <summary>The player pressed a controller button. This event isn't raised for trigger buttons.</summary> + public static event EventHandler<EventArgsControllerButtonPressed> ControllerButtonPressed; + + /// <summary>The player released a controller button. This event isn't raised for trigger buttons.</summary> + public static event EventHandler<EventArgsControllerButtonReleased> ControllerButtonReleased; + + /// <summary>The player pressed a controller trigger button.</summary> + public static event EventHandler<EventArgsControllerTriggerPressed> ControllerTriggerPressed; + + /// <summary>The player released a controller trigger button.</summary> + public static event EventHandler<EventArgsControllerTriggerReleased> ControllerTriggerReleased; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise a <see cref="KeyboardChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorState">The previous keyboard state.</param> + /// <param name="newState">The current keyboard state.</param> + internal static void InvokeKeyboardChanged(IMonitor monitor, KeyboardState priorState, KeyboardState newState) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.KeyboardChanged)}", ControlEvents.KeyboardChanged?.GetInvocationList(), null, new EventArgsKeyboardStateChanged(priorState, newState)); + } + + /// <summary>Raise a <see cref="MouseChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorState">The previous mouse state.</param> + /// <param name="newState">The current mouse state.</param> + /// <param name="priorPosition">The previous mouse position on the screen adjusted for the zoom level.</param> + /// <param name="newPosition">The current mouse position on the screen adjusted for the zoom level.</param> + internal static void InvokeMouseChanged(IMonitor monitor, MouseState priorState, MouseState newState, Point priorPosition, Point newPosition) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.MouseChanged)}", ControlEvents.MouseChanged?.GetInvocationList(), null, new EventArgsMouseStateChanged(priorState, newState, priorPosition, newPosition)); + } + + /// <summary>Raise a <see cref="KeyPressed"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="key">The keyboard button that was pressed.</param> + internal static void InvokeKeyPressed(IMonitor monitor, Keys key) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.KeyPressed)}", ControlEvents.KeyPressed?.GetInvocationList(), null, new EventArgsKeyPressed(key)); + } + + /// <summary>Raise a <see cref="KeyReleased"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="key">The keyboard button that was released.</param> + internal static void InvokeKeyReleased(IMonitor monitor, Keys key) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.KeyReleased)}", ControlEvents.KeyReleased?.GetInvocationList(), null, new EventArgsKeyPressed(key)); + } + + /// <summary>Raise a <see cref="ControllerButtonPressed"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="button">The controller button that was pressed.</param> + internal static void InvokeButtonPressed(IMonitor monitor, Buttons button) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerButtonPressed)}", ControlEvents.ControllerButtonPressed?.GetInvocationList(), null, new EventArgsControllerButtonPressed(PlayerIndex.One, button)); + } + + /// <summary>Raise a <see cref="ControllerButtonReleased"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="button">The controller button that was released.</param> + internal static void InvokeButtonReleased(IMonitor monitor, Buttons button) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerButtonReleased)}", ControlEvents.ControllerButtonReleased?.GetInvocationList(), null, new EventArgsControllerButtonReleased(PlayerIndex.One, button)); + } + + /// <summary>Raise a <see cref="ControllerTriggerPressed"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="button">The trigger button that was pressed.</param> + /// <param name="value">The current trigger value.</param> + internal static void InvokeTriggerPressed(IMonitor monitor, Buttons button, float value) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerTriggerPressed)}", ControlEvents.ControllerTriggerPressed?.GetInvocationList(), null, new EventArgsControllerTriggerPressed(PlayerIndex.One, button, value)); + } + + /// <summary>Raise a <see cref="ControllerTriggerReleased"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="button">The trigger button that was pressed.</param> + /// <param name="value">The current trigger value.</param> + internal static void InvokeTriggerReleased(IMonitor monitor, Buttons button, float value) + { + monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerTriggerReleased)}", ControlEvents.ControllerTriggerReleased?.GetInvocationList(), null, new EventArgsControllerTriggerReleased(PlayerIndex.One, button, value)); + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs b/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs new file mode 100644 index 00000000..2a2aa163 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsClickableMenuChanged.cs @@ -0,0 +1,31 @@ +using System; +using StardewValley.Menus; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="MenuEvents.MenuChanged"/> event.</summary> + public class EventArgsClickableMenuChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous menu.</summary> + public IClickableMenu NewMenu { get; } + + /// <summary>The current menu.</summary> + public IClickableMenu PriorMenu { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorMenu">The previous menu.</param> + /// <param name="newMenu">The current menu.</param> + public EventArgsClickableMenuChanged(IClickableMenu priorMenu, IClickableMenu newMenu) + { + this.NewMenu = newMenu; + this.PriorMenu = priorMenu; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs b/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs new file mode 100644 index 00000000..5e6585f0 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsClickableMenuClosed.cs @@ -0,0 +1,26 @@ +using System; +using StardewValley.Menus; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="MenuEvents.MenuClosed"/> event.</summary> + public class EventArgsClickableMenuClosed : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The menu that was closed.</summary> + public IClickableMenu PriorMenu { get; } + + + /********* + ** Accessors + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorMenu">The menu that was closed.</param> + public EventArgsClickableMenuClosed(IClickableMenu priorMenu) + { + this.PriorMenu = priorMenu; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsCommand.cs b/src/StardewModdingAPI/Events/EventArgsCommand.cs new file mode 100644 index 00000000..35370139 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsCommand.cs @@ -0,0 +1,28 @@ +#if SMAPI_1_x +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="StardewModdingAPI.Command.CommandFired"/> event.</summary> + [Obsolete("Use " + nameof(IModHelper) + "." + nameof(IModHelper.ConsoleCommands))] + public class EventArgsCommand : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The triggered command.</summary> + public Command Command { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="command">The triggered command.</param> + public EventArgsCommand(Command command) + { + this.Command = command; + } + } +} +#endif
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs b/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs new file mode 100644 index 00000000..3243b80b --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsControllerButtonPressed.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.ControllerButtonPressed"/> event.</summary> + public class EventArgsControllerButtonPressed : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player who pressed the button.</summary> + public PlayerIndex PlayerIndex { get; } + + /// <summary>The controller button that was pressed.</summary> + public Buttons ButtonPressed { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="playerIndex">The player who pressed the button.</param> + /// <param name="button">The controller button that was pressed.</param> + public EventArgsControllerButtonPressed(PlayerIndex playerIndex, Buttons button) + { + this.PlayerIndex = playerIndex; + this.ButtonPressed = button; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs b/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs new file mode 100644 index 00000000..e05a080b --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsControllerButtonReleased.cs @@ -0,0 +1,32 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.ControllerButtonReleased"/> event.</summary> + public class EventArgsControllerButtonReleased : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player who pressed the button.</summary> + public PlayerIndex PlayerIndex { get; } + + /// <summary>The controller button that was pressed.</summary> + public Buttons ButtonReleased { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="playerIndex">The player who pressed the button.</param> + /// <param name="button">The controller button that was released.</param> + public EventArgsControllerButtonReleased(PlayerIndex playerIndex, Buttons button) + { + this.PlayerIndex = playerIndex; + this.ButtonReleased = button; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs b/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs new file mode 100644 index 00000000..a2087733 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsControllerTriggerPressed.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.ControllerTriggerPressed"/> event.</summary> + public class EventArgsControllerTriggerPressed : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player who pressed the button.</summary> + public PlayerIndex PlayerIndex { get; } + + /// <summary>The controller button that was pressed.</summary> + public Buttons ButtonPressed { get; } + + /// <summary>The current trigger value.</summary> + public float Value { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="playerIndex">The player who pressed the trigger button.</param> + /// <param name="button">The trigger button that was pressed.</param> + /// <param name="value">The current trigger value.</param> + public EventArgsControllerTriggerPressed(PlayerIndex playerIndex, Buttons button, float value) + { + this.PlayerIndex = playerIndex; + this.ButtonPressed = button; + this.Value = value; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs b/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs new file mode 100644 index 00000000..d2eecbec --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsControllerTriggerReleased.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.ControllerTriggerReleased"/> event.</summary> + public class EventArgsControllerTriggerReleased : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player who pressed the button.</summary> + public PlayerIndex PlayerIndex { get; } + + /// <summary>The controller button that was released.</summary> + public Buttons ButtonReleased { get; } + + /// <summary>The current trigger value.</summary> + public float Value { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="playerIndex">The player who pressed the trigger button.</param> + /// <param name="button">The trigger button that was released.</param> + /// <param name="value">The current trigger value.</param> + public EventArgsControllerTriggerReleased(PlayerIndex playerIndex, Buttons button, float value) + { + this.PlayerIndex = playerIndex; + this.ButtonReleased = button; + this.Value = value; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs b/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs new file mode 100644 index 00000000..25d3ebf3 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsCurrentLocationChanged.cs @@ -0,0 +1,31 @@ +using System; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="LocationEvents.CurrentLocationChanged"/> event.</summary> + public class EventArgsCurrentLocationChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player's current location.</summary> + public GameLocation NewLocation { get; } + + /// <summary>The player's previous location.</summary> + public GameLocation PriorLocation { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorLocation">The player's previous location.</param> + /// <param name="newLocation">The player's current location.</param> + public EventArgsCurrentLocationChanged(GameLocation priorLocation, GameLocation newLocation) + { + this.NewLocation = newLocation; + this.PriorLocation = priorLocation; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs b/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs new file mode 100644 index 00000000..4c359939 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsFarmerChanged.cs @@ -0,0 +1,33 @@ +#if SMAPI_1_x +using System; +using SFarmer = StardewValley.Farmer; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="PlayerEvents.FarmerChanged"/> event.</summary> + public class EventArgsFarmerChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous player character.</summary> + public SFarmer NewFarmer { get; } + + /// <summary>The new player character.</summary> + public SFarmer PriorFarmer { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorFarmer">The previous player character.</param> + /// <param name="newFarmer">The new player character.</param> + public EventArgsFarmerChanged(SFarmer priorFarmer, SFarmer newFarmer) + { + this.PriorFarmer = priorFarmer; + this.NewFarmer = newFarmer; + } + } +} +#endif
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs b/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs new file mode 100644 index 00000000..fb8c821e --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsGameLocationsChanged.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="LocationEvents.LocationsChanged"/> event.</summary> + public class EventArgsGameLocationsChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The current list of game locations.</summary> + public List<GameLocation> NewLocations { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="newLocations">The current list of game locations.</param> + public EventArgsGameLocationsChanged(List<GameLocation> newLocations) + { + this.NewLocations = newLocations; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsInput.cs b/src/StardewModdingAPI/Events/EventArgsInput.cs new file mode 100644 index 00000000..31368555 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsInput.cs @@ -0,0 +1,126 @@ +#if !SMAPI_1_x +using System; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using StardewModdingAPI.Utilities; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments when a button is pressed or released.</summary> + public class EventArgsInput : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The button on the controller, keyboard, or mouse.</summary> + public SButton Button { get; } + + /// <summary>The current cursor position.</summary> + public ICursorPosition Cursor { get; set; } + + /// <summary>Whether the input is considered a 'click' by the game for enabling action.</summary> + public bool IsClick { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="button">The button on the controller, keyboard, or mouse.</param> + /// <param name="cursor">The cursor position.</param> + /// <param name="isClick">Whether the input is considered a 'click' by the game for enabling action.</param> + public EventArgsInput(SButton button, ICursorPosition cursor, bool isClick) + { + this.Button = button; + this.Cursor = cursor; + this.IsClick = isClick; + } + + /// <summary>Prevent the game from handling the vurrent button press. This doesn't prevent other mods from receiving the event.</summary> + public void SuppressButton() + { + this.SuppressButton(this.Button); + } + + /// <summary>Prevent the game from handling a button press. This doesn't prevent other mods from receiving the event.</summary> + /// <param name="button">The button to suppress.</param> + public void SuppressButton(SButton button) + { + // keyboard + if (this.Button.TryGetKeyboard(out Keys key)) + Game1.oldKBState = new KeyboardState(Game1.oldKBState.GetPressedKeys().Except(new[] { key }).ToArray()); + + // controller + else if (this.Button.TryGetController(out Buttons controllerButton)) + { + var newState = GamePad.GetState(PlayerIndex.One); + var thumbsticks = Game1.oldPadState.ThumbSticks; + var triggers = Game1.oldPadState.Triggers; + var buttons = Game1.oldPadState.Buttons; + var dpad = Game1.oldPadState.DPad; + + switch (controllerButton) + { + // d-pad + case Buttons.DPadDown: + dpad = new GamePadDPad(dpad.Up, newState.DPad.Down, dpad.Left, dpad.Right); + break; + case Buttons.DPadLeft: + dpad = new GamePadDPad(dpad.Up, dpad.Down, newState.DPad.Left, dpad.Right); + break; + case Buttons.DPadRight: + dpad = new GamePadDPad(dpad.Up, dpad.Down, dpad.Left, newState.DPad.Right); + break; + case Buttons.DPadUp: + dpad = new GamePadDPad(newState.DPad.Up, dpad.Down, dpad.Left, dpad.Right); + break; + + // trigger + case Buttons.LeftTrigger: + triggers = new GamePadTriggers(newState.Triggers.Left, triggers.Right); + break; + case Buttons.RightTrigger: + triggers = new GamePadTriggers(triggers.Left, newState.Triggers.Right); + break; + + // thumbstick + case Buttons.LeftThumbstickDown: + case Buttons.LeftThumbstickLeft: + case Buttons.LeftThumbstickRight: + case Buttons.LeftThumbstickUp: + thumbsticks = new GamePadThumbSticks(newState.ThumbSticks.Left, thumbsticks.Right); + break; + case Buttons.RightThumbstickDown: + case Buttons.RightThumbstickLeft: + case Buttons.RightThumbstickRight: + case Buttons.RightThumbstickUp: + thumbsticks = new GamePadThumbSticks(newState.ThumbSticks.Right, thumbsticks.Left); + break; + + // buttons + default: + var mask = + (buttons.A == ButtonState.Pressed ? Buttons.A : 0) + | (buttons.B == ButtonState.Pressed ? Buttons.B : 0) + | (buttons.Back == ButtonState.Pressed ? Buttons.Back : 0) + | (buttons.BigButton == ButtonState.Pressed ? Buttons.BigButton : 0) + | (buttons.LeftShoulder == ButtonState.Pressed ? Buttons.LeftShoulder : 0) + | (buttons.LeftStick == ButtonState.Pressed ? Buttons.LeftStick : 0) + | (buttons.RightShoulder == ButtonState.Pressed ? Buttons.RightShoulder : 0) + | (buttons.RightStick == ButtonState.Pressed ? Buttons.RightStick : 0) + | (buttons.Start == ButtonState.Pressed ? Buttons.Start : 0) + | (buttons.X == ButtonState.Pressed ? Buttons.X : 0) + | (buttons.Y == ButtonState.Pressed ? Buttons.Y : 0); + mask = mask ^ controllerButton; + buttons = new GamePadButtons(mask); + break; + } + + Game1.oldPadState = new GamePadState(thumbsticks, triggers, buttons, dpad); + } + } + } +} +#endif diff --git a/src/StardewModdingAPI/Events/EventArgsIntChanged.cs b/src/StardewModdingAPI/Events/EventArgsIntChanged.cs new file mode 100644 index 00000000..0c742d12 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsIntChanged.cs @@ -0,0 +1,29 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for an integer field that changed value.</summary> + public class EventArgsIntChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous value.</summary> + public int PriorInt { get; } + + /// <summary>The current value.</summary> + public int NewInt { get; } + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorInt">The previous value.</param> + /// <param name="newInt">The current value.</param> + public EventArgsIntChanged(int priorInt, int newInt) + { + this.PriorInt = priorInt; + this.NewInt = newInt; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs b/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs new file mode 100644 index 00000000..1ee02842 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsInventoryChanged.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="PlayerEvents.InventoryChanged"/> event.</summary> + public class EventArgsInventoryChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player's inventory.</summary> + public List<Item> Inventory { get; } + + /// <summary>The added items.</summary> + public List<ItemStackChange> Added { get; } + + /// <summary>The removed items.</summary> + public List<ItemStackChange> Removed { get; } + + /// <summary>The items whose stack sizes changed.</summary> + public List<ItemStackChange> QuantityChanged { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="inventory">The player's inventory.</param> + /// <param name="changedItems">The inventory changes.</param> + public EventArgsInventoryChanged(List<Item> inventory, List<ItemStackChange> changedItems) + { + this.Inventory = inventory; + this.Added = changedItems.Where(n => n.ChangeType == ChangeType.Added).ToList(); + this.Removed = changedItems.Where(n => n.ChangeType == ChangeType.Removed).ToList(); + this.QuantityChanged = changedItems.Where(n => n.ChangeType == ChangeType.StackChange).ToList(); + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs b/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs new file mode 100644 index 00000000..d9d81e10 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsKeyPressed.cs @@ -0,0 +1,26 @@ +using System; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.KeyboardChanged"/> event.</summary> + public class EventArgsKeyPressed : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The keyboard button that was pressed.</summary> + public Keys KeyPressed { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="key">The keyboard button that was pressed.</param> + public EventArgsKeyPressed(Keys key) + { + this.KeyPressed = key; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs b/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs new file mode 100644 index 00000000..14e397ce --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsKeyboardStateChanged.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.KeyboardChanged"/> event.</summary> + public class EventArgsKeyboardStateChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous keyboard state.</summary> + public KeyboardState NewState { get; } + + /// <summary>The current keyboard state.</summary> + public KeyboardState PriorState { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorState">The previous keyboard state.</param> + /// <param name="newState">The current keyboard state.</param> + public EventArgsKeyboardStateChanged(KeyboardState priorState, KeyboardState newState) + { + this.PriorState = priorState; + this.NewState = newState; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsLevelUp.cs b/src/StardewModdingAPI/Events/EventArgsLevelUp.cs new file mode 100644 index 00000000..fe6696d4 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsLevelUp.cs @@ -0,0 +1,52 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="PlayerEvents.LeveledUp"/> event.</summary> + public class EventArgsLevelUp : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The player skill that leveled up.</summary> + public LevelType Type { get; } + + /// <summary>The new skill level.</summary> + public int NewLevel { get; } + + /// <summary>The player skill types.</summary> + public enum LevelType + { + /// <summary>The combat skill.</summary> + Combat, + + /// <summary>The farming skill.</summary> + Farming, + + /// <summary>The fishing skill.</summary> + Fishing, + + /// <summary>The foraging skill.</summary> + Foraging, + + /// <summary>The mining skill.</summary> + Mining, + + /// <summary>The luck skill.</summary> + Luck + } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="type">The player skill that leveled up.</param> + /// <param name="newLevel">The new skill level.</param> + public EventArgsLevelUp(LevelType type, int newLevel) + { + this.Type = type; + this.NewLevel = newLevel; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs b/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs new file mode 100644 index 00000000..688b4b3d --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsLoadedGameChanged.cs @@ -0,0 +1,27 @@ +#if SMAPI_1_x +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="PlayerEvents.LoadedGame"/> event.</summary> + public class EventArgsLoadedGameChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>Whether the save has been loaded. This is always true.</summary> + public bool LoadedGame { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="loaded">Whether the save has been loaded. This is always true.</param> + public EventArgsLoadedGameChanged(bool loaded) + { + this.LoadedGame = loaded; + } + } +} +#endif
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs b/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs new file mode 100644 index 00000000..058999e9 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsLocationObjectsChanged.cs @@ -0,0 +1,28 @@ +using System; +using Microsoft.Xna.Framework; +using StardewValley; +using Object = StardewValley.Object; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="LocationEvents.LocationObjectsChanged"/> event.</summary> + public class EventArgsLocationObjectsChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The current list of objects in the current location.</summary> + public SerializableDictionary<Vector2, Object> NewObjects { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="newObjects">The current list of objects in the current location.</param> + public EventArgsLocationObjectsChanged(SerializableDictionary<Vector2, Object> newObjects) + { + this.NewObjects = newObjects; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs b/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs new file mode 100644 index 00000000..c82fed35 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsMineLevelChanged.cs @@ -0,0 +1,30 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="MineEvents.MineLevelChanged"/> event.</summary> + public class EventArgsMineLevelChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous mine level.</summary> + public int PreviousMineLevel { get; } + + /// <summary>The current mine level.</summary> + public int CurrentMineLevel { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="previousMineLevel">The previous mine level.</param> + /// <param name="currentMineLevel">The current mine level.</param> + public EventArgsMineLevelChanged(int previousMineLevel, int currentMineLevel) + { + this.PreviousMineLevel = previousMineLevel; + this.CurrentMineLevel = currentMineLevel; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs b/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs new file mode 100644 index 00000000..57298164 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsMouseStateChanged.cs @@ -0,0 +1,42 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="ControlEvents.MouseChanged"/> event.</summary> + public class EventArgsMouseStateChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous mouse state.</summary> + public MouseState PriorState { get; } + + /// <summary>The current mouse state.</summary> + public MouseState NewState { get; } + + /// <summary>The previous mouse position on the screen adjusted for the zoom level.</summary> + public Point PriorPosition { get; } + + /// <summary>The current mouse position on the screen adjusted for the zoom level.</summary> + public Point NewPosition { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorState">The previous mouse state.</param> + /// <param name="newState">The current mouse state.</param> + /// <param name="priorPosition">The previous mouse position on the screen adjusted for the zoom level.</param> + /// <param name="newPosition">The current mouse position on the screen adjusted for the zoom level.</param> + public EventArgsMouseStateChanged(MouseState priorState, MouseState newState, Point priorPosition, Point newPosition) + { + this.PriorState = priorState; + this.NewState = newState; + this.PriorPosition = priorPosition; + this.NewPosition = newPosition; + } + } +} diff --git a/src/StardewModdingAPI/Events/EventArgsNewDay.cs b/src/StardewModdingAPI/Events/EventArgsNewDay.cs new file mode 100644 index 00000000..b8cbe9e3 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsNewDay.cs @@ -0,0 +1,37 @@ +#if SMAPI_1_x +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a <see cref="TimeEvents.OnNewDay"/> event.</summary> + public class EventArgsNewDay : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous day value.</summary> + public int PreviousDay { get; } + + /// <summary>The current day value.</summary> + public int CurrentDay { get; } + + /// <summary>Whether the game just started the transition (<c>true</c>) or finished it (<c>false</c>).</summary> + public bool IsNewDay { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorDay">The previous day value.</param> + /// <param name="newDay">The current day value.</param> + /// <param name="isTransitioning">Whether the game just started the transition (<c>true</c>) or finished it (<c>false</c>).</param> + public EventArgsNewDay(int priorDay, int newDay, bool isTransitioning) + { + this.PreviousDay = priorDay; + this.CurrentDay = newDay; + this.IsNewDay = isTransitioning; + } + } +} +#endif
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/EventArgsStringChanged.cs b/src/StardewModdingAPI/Events/EventArgsStringChanged.cs new file mode 100644 index 00000000..f580a2ce --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsStringChanged.cs @@ -0,0 +1,31 @@ +#if SMAPI_1_x +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a string field that changed value.</summary> + public class EventArgsStringChanged : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous value.</summary> + public string NewString { get; } + + /// <summary>The current value.</summary> + public string PriorString { get; } + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorString">The previous value.</param> + /// <param name="newString">The current value.</param> + public EventArgsStringChanged(string priorString, string newString) + { + this.NewString = newString; + this.PriorString = priorString; + } + } +} +#endif
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/EventArgsValueChanged.cs b/src/StardewModdingAPI/Events/EventArgsValueChanged.cs new file mode 100644 index 00000000..1d25af49 --- /dev/null +++ b/src/StardewModdingAPI/Events/EventArgsValueChanged.cs @@ -0,0 +1,31 @@ +using System; + +namespace StardewModdingAPI.Events +{ + /// <summary>Event arguments for a field that changed value.</summary> + /// <typeparam name="T">The value type.</typeparam> + public class EventArgsValueChanged<T> : EventArgs + { + /********* + ** Accessors + *********/ + /// <summary>The previous value.</summary> + public T PriorValue { get; } + + /// <summary>The current value.</summary> + public T NewValue { get; } + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + /// <param name="priorValue">The previous value.</param> + /// <param name="newValue">The current value.</param> + public EventArgsValueChanged(T priorValue, T newValue) + { + this.PriorValue = priorValue; + this.NewValue = newValue; + } + } +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/GameEvents.cs b/src/StardewModdingAPI/Events/GameEvents.cs new file mode 100644 index 00000000..5610e67a --- /dev/null +++ b/src/StardewModdingAPI/Events/GameEvents.cs @@ -0,0 +1,216 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using StardewModdingAPI.Framework; + +#pragma warning disable 618 // Suppress obsolete-symbol errors in this file. Since several events are marked obsolete, this produces unnecessary warnings. +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the game changes state.</summary> + public static class GameEvents + { + /********* + ** Properties + *********/ +#if SMAPI_1_x + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + /// <summary>The backing field for <see cref="Initialize"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler _Initialize; + + /// <summary>The backing field for <see cref="LoadContent"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler _LoadContent; + + /// <summary>The backing field for <see cref="GameLoaded"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler _GameLoaded; + + /// <summary>The backing field for <see cref="FirstUpdateTick"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler _FirstUpdateTick; +#endif + + + /********* + ** Events + *********/ + /// <summary>Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called after <see cref="Microsoft.Xna.Framework.Game.Initialize"/>.</summary> + internal static event EventHandler InitializeInternal; + + /// <summary>Raised during launch after configuring Stardew Valley, loading it into memory, and opening the game window. The window is still blank by this point.</summary> + internal static event EventHandler GameLoadedInternal; + +#if SMAPI_1_x + /// <summary>Raised during launch after configuring XNA or MonoGame. The game window hasn't been opened by this point. Called after <see cref="Microsoft.Xna.Framework.Game.Initialize"/>.</summary> + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(GameEvents.Initialize) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] + public static event EventHandler Initialize + { + add + { + GameEvents.DeprecationManager.Warn($"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}", "1.10", DeprecationLevel.PendingRemoval); + GameEvents._Initialize += value; + } + remove => GameEvents._Initialize -= value; + } + + /// <summary>Raised before XNA loads or reloads graphics resources. Called during <see cref="Microsoft.Xna.Framework.Game.LoadContent"/>.</summary> + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the " + nameof(GameEvents.LoadContent) + " event, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] + public static event EventHandler LoadContent + { + add + { + GameEvents.DeprecationManager.Warn($"{nameof(GameEvents)}.{nameof(GameEvents.LoadContent)}", "1.10", DeprecationLevel.PendingRemoval); + GameEvents._LoadContent += value; + } + remove => GameEvents._LoadContent -= value; + } + + /// <summary>Raised during launch after configuring Stardew Valley, loading it into memory, and opening the game window. The window is still blank by this point.</summary> + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the game loads, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] + public static event EventHandler GameLoaded + { + add + { + GameEvents.DeprecationManager.Warn($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoaded)}", "1.12", DeprecationLevel.PendingRemoval); + GameEvents._GameLoaded += value; + } + remove => GameEvents._GameLoaded -= value; + } + + /// <summary>Raised during the first game update tick.</summary> + [Obsolete("The " + nameof(Mod) + "." + nameof(Mod.Entry) + " method is now called after the game loads, so any contained logic can be done directly in " + nameof(Mod.Entry) + ".")] + public static event EventHandler FirstUpdateTick + { + add + { + GameEvents.DeprecationManager.Warn($"{nameof(GameEvents)}.{nameof(GameEvents.FirstUpdateTick)}", "1.12", DeprecationLevel.PendingRemoval); + GameEvents._FirstUpdateTick += value; + } + remove => GameEvents._FirstUpdateTick -= value; + } +#endif + + /// <summary>Raised when the game updates its state (≈60 times per second).</summary> + public static event EventHandler UpdateTick; + + /// <summary>Raised every other tick (≈30 times per second).</summary> + public static event EventHandler SecondUpdateTick; + + /// <summary>Raised every fourth tick (≈15 times per second).</summary> + public static event EventHandler FourthUpdateTick; + + /// <summary>Raised every eighth tick (≈8 times per second).</summary> + public static event EventHandler EighthUpdateTick; + + /// <summary>Raised every 15th tick (≈4 times per second).</summary> + public static event EventHandler QuarterSecondTick; + + /// <summary>Raised every 30th tick (≈twice per second).</summary> + public static event EventHandler HalfSecondTick; + + /// <summary>Raised every 60th tick (≈once per second).</summary> + public static event EventHandler OneSecondTick; + + + /********* + ** Internal methods + *********/ +#if SMAPI_1_x + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + GameEvents.DeprecationManager = deprecationManager; + } +#endif + + /// <summary>Raise an <see cref="InitializeInternal"/> event.</summary> + /// <param name="monitor">Encapsulates logging and monitoring.</param> + internal static void InvokeInitialize(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.InitializeInternal)}", GameEvents.InitializeInternal?.GetInvocationList()); +#if SMAPI_1_x + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}", GameEvents._Initialize?.GetInvocationList()); +#endif + } + +#if SMAPI_1_x + /// <summary>Raise a <see cref="LoadContent"/> event.</summary> + /// <param name="monitor">Encapsulates logging and monitoring.</param> + internal static void InvokeLoadContent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.LoadContent)}", GameEvents._LoadContent?.GetInvocationList()); + } +#endif + + /// <summary>Raise a <see cref="GameLoadedInternal"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeGameLoaded(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoadedInternal)}", GameEvents.GameLoadedInternal?.GetInvocationList()); +#if SMAPI_1_x + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoaded)}", GameEvents._GameLoaded?.GetInvocationList()); +#endif + } + +#if SMAPI_1_x + /// <summary>Raise a <see cref="FirstUpdateTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeFirstUpdateTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.FirstUpdateTick)}", GameEvents._FirstUpdateTick?.GetInvocationList()); + } +#endif + + /// <summary>Raise an <see cref="UpdateTick"/> event.</summary> + /// <param name="monitor">Encapsulates logging and monitoring.</param> + internal static void InvokeUpdateTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.UpdateTick)}", GameEvents.UpdateTick?.GetInvocationList()); + } + + /// <summary>Raise a <see cref="SecondUpdateTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeSecondUpdateTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.SecondUpdateTick)}", GameEvents.SecondUpdateTick?.GetInvocationList()); + } + + /// <summary>Raise a <see cref="FourthUpdateTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeFourthUpdateTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.FourthUpdateTick)}", GameEvents.FourthUpdateTick?.GetInvocationList()); + } + + /// <summary>Raise a <see cref="EighthUpdateTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeEighthUpdateTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.EighthUpdateTick)}", GameEvents.EighthUpdateTick?.GetInvocationList()); + } + + /// <summary>Raise a <see cref="QuarterSecondTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeQuarterSecondTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.QuarterSecondTick)}", GameEvents.QuarterSecondTick?.GetInvocationList()); + } + + /// <summary>Raise a <see cref="HalfSecondTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeHalfSecondTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.HalfSecondTick)}", GameEvents.HalfSecondTick?.GetInvocationList()); + } + + /// <summary>Raise a <see cref="OneSecondTick"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOneSecondTick(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.OneSecondTick)}", GameEvents.OneSecondTick?.GetInvocationList()); + } + } +} diff --git a/src/StardewModdingAPI/Events/GraphicsEvents.cs b/src/StardewModdingAPI/Events/GraphicsEvents.cs new file mode 100644 index 00000000..fff51bed --- /dev/null +++ b/src/StardewModdingAPI/Events/GraphicsEvents.cs @@ -0,0 +1,116 @@ +using System; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised during the game's draw loop, when the game is rendering content to the window.</summary> + public static class GraphicsEvents + { + /********* + ** Events + *********/ + /**** + ** Generic events + ****/ + /// <summary>Raised after the game window is resized.</summary> + public static event EventHandler Resize; + + /**** + ** Main render events + ****/ + /// <summary>Raised before drawing the world to the screen.</summary> + public static event EventHandler OnPreRenderEvent; + + /// <summary>Raised after drawing the world to the screen.</summary> + public static event EventHandler OnPostRenderEvent; + + /**** + ** HUD events + ****/ + /// <summary>Raised before drawing the HUD (item toolbar, clock, etc) to the screen. The HUD is available at this point, but not necessarily visible. (For example, the event is raised even if a menu is open.)</summary> + public static event EventHandler OnPreRenderHudEvent; + + /// <summary>Raised after drawing the HUD (item toolbar, clock, etc) to the screen. The HUD is available at this point, but not necessarily visible. (For example, the event is raised even if a menu is open.)</summary> + public static event EventHandler OnPostRenderHudEvent; + + /**** + ** GUI events + ****/ + /// <summary>Raised before drawing a menu to the screen during a draw loop. This includes the game's internal menus like the title screen.</summary> + public static event EventHandler OnPreRenderGuiEvent; + + /// <summary>Raised after drawing a menu to the screen during a draw loop. This includes the game's internal menus like the title screen.</summary> + public static event EventHandler OnPostRenderGuiEvent; + + + /********* + ** Internal methods + *********/ + /**** + ** Generic events + ****/ + /// <summary>Raise a <see cref="Resize"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeResize(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.Resize)}", GraphicsEvents.Resize?.GetInvocationList()); + } + + /**** + ** Main render events + ****/ + /// <summary>Raise an <see cref="OnPreRenderEvent"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOnPreRenderEvent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderEvent)}", GraphicsEvents.OnPreRenderEvent?.GetInvocationList()); + } + + /// <summary>Raise an <see cref="OnPostRenderEvent"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOnPostRenderEvent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderEvent)}", GraphicsEvents.OnPostRenderEvent?.GetInvocationList()); + } + + /// <summary>Get whether there are any post-render event listeners.</summary> + internal static bool HasPostRenderListeners() + { + return GraphicsEvents.OnPostRenderEvent != null; + } + + /**** + ** GUI events + ****/ + /// <summary>Raise an <see cref="OnPreRenderGuiEvent"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOnPreRenderGuiEvent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderGuiEvent)}", GraphicsEvents.OnPreRenderGuiEvent?.GetInvocationList()); + } + + /// <summary>Raise an <see cref="OnPostRenderGuiEvent"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOnPostRenderGuiEvent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderGuiEvent)}", GraphicsEvents.OnPostRenderGuiEvent?.GetInvocationList()); + } + + /**** + ** HUD events + ****/ + /// <summary>Raise an <see cref="OnPreRenderHudEvent"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOnPreRenderHudEvent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderHudEvent)}", GraphicsEvents.OnPreRenderHudEvent?.GetInvocationList()); + } + + /// <summary>Raise an <see cref="OnPostRenderHudEvent"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeOnPostRenderHudEvent(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderHudEvent)}", GraphicsEvents.OnPostRenderHudEvent?.GetInvocationList()); + } + } +} diff --git a/src/StardewModdingAPI/Events/InputEvents.cs b/src/StardewModdingAPI/Events/InputEvents.cs new file mode 100644 index 00000000..b99b49e0 --- /dev/null +++ b/src/StardewModdingAPI/Events/InputEvents.cs @@ -0,0 +1,45 @@ +#if !SMAPI_1_x +using System; +using StardewModdingAPI.Framework; +using StardewModdingAPI.Utilities; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the player uses a controller, keyboard, or mouse button.</summary> + public static class InputEvents + { + /********* + ** Events + *********/ + /// <summary>Raised when the player presses a button on the keyboard, controller, or mouse.</summary> + public static event EventHandler<EventArgsInput> ButtonPressed; + + /// <summary>Raised when the player releases a keyboard key on the keyboard, controller, or mouse.</summary> + public static event EventHandler<EventArgsInput> ButtonReleased; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise a <see cref="ButtonPressed"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="button">The button on the controller, keyboard, or mouse.</param> + /// <param name="cursor">The cursor position.</param> + /// <param name="isClick">Whether the input is considered a 'click' by the game for enabling action.</param> + internal static void InvokeButtonPressed(IMonitor monitor, SButton button, ICursorPosition cursor, bool isClick) + { + monitor.SafelyRaiseGenericEvent($"{nameof(InputEvents)}.{nameof(InputEvents.ButtonPressed)}", InputEvents.ButtonPressed?.GetInvocationList(), null, new EventArgsInput(button, cursor, isClick)); + } + + /// <summary>Raise a <see cref="ButtonReleased"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="button">The button on the controller, keyboard, or mouse.</param> + /// <param name="cursor">The cursor position.</param> + /// <param name="isClick">Whether the input is considered a 'click' by the game for enabling action.</param> + internal static void InvokeButtonReleased(IMonitor monitor, SButton button, ICursorPosition cursor, bool isClick) + { + monitor.SafelyRaiseGenericEvent($"{nameof(InputEvents)}.{nameof(InputEvents.ButtonReleased)}", InputEvents.ButtonReleased?.GetInvocationList(), null, new EventArgsInput(button, cursor, isClick)); + } + } +} +#endif
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/ItemStackChange.cs b/src/StardewModdingAPI/Events/ItemStackChange.cs new file mode 100644 index 00000000..f9ae6df6 --- /dev/null +++ b/src/StardewModdingAPI/Events/ItemStackChange.cs @@ -0,0 +1,20 @@ +using StardewValley; + +namespace StardewModdingAPI.Events +{ + /// <summary>Represents an inventory slot that changed.</summary> + public class ItemStackChange + { + /********* + ** Accessors + *********/ + /// <summary>The item in the slot.</summary> + public Item Item { get; set; } + + /// <summary>The amount by which the item's stack size changed.</summary> + public int StackChange { get; set; } + + /// <summary>How the inventory slot changed.</summary> + public ChangeType ChangeType { get; set; } + } +}
\ No newline at end of file diff --git a/src/StardewModdingAPI/Events/LocationEvents.cs b/src/StardewModdingAPI/Events/LocationEvents.cs new file mode 100644 index 00000000..b834bc1c --- /dev/null +++ b/src/StardewModdingAPI/Events/LocationEvents.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using StardewModdingAPI.Framework; +using StardewValley; +using Object = StardewValley.Object; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the player transitions between game locations, a location is added or removed, or the objects in the current location change.</summary> + public static class LocationEvents + { + /********* + ** Events + *********/ + /// <summary>Raised after the player warps to a new location.</summary> + public static event EventHandler<EventArgsCurrentLocationChanged> CurrentLocationChanged; + + /// <summary>Raised after a game location is added or removed.</summary> + public static event EventHandler<EventArgsGameLocationsChanged> LocationsChanged; + + /// <summary>Raised after the list of objects in the current location changes (e.g. an object is added or removed).</summary> + public static event EventHandler<EventArgsLocationObjectsChanged> LocationObjectsChanged; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise a <see cref="CurrentLocationChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorLocation">The player's previous location.</param> + /// <param name="newLocation">The player's current location.</param> + internal static void InvokeCurrentLocationChanged(IMonitor monitor, GameLocation priorLocation, GameLocation newLocation) + { + monitor.SafelyRaiseGenericEvent($"{nameof(LocationEvents)}.{nameof(LocationEvents.CurrentLocationChanged)}", LocationEvents.CurrentLocationChanged?.GetInvocationList(), null, new EventArgsCurrentLocationChanged(priorLocation, newLocation)); + } + + /// <summary>Raise a <see cref="LocationsChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="newLocations">The current list of game locations.</param> + internal static void InvokeLocationsChanged(IMonitor monitor, List<GameLocation> newLocations) + { + monitor.SafelyRaiseGenericEvent($"{nameof(LocationEvents)}.{nameof(LocationEvents.LocationsChanged)}", LocationEvents.LocationsChanged?.GetInvocationList(), null, new EventArgsGameLocationsChanged(newLocations)); + } + + /// <summary>Raise a <see cref="LocationObjectsChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="newObjects">The current list of objects in the current location.</param> + internal static void InvokeOnNewLocationObject(IMonitor monitor, SerializableDictionary<Vector2, Object> newObjects) + { + monitor.SafelyRaiseGenericEvent($"{nameof(LocationEvents)}.{nameof(LocationEvents.LocationObjectsChanged)}", LocationEvents.LocationObjectsChanged?.GetInvocationList(), null, new EventArgsLocationObjectsChanged(newObjects)); + } + } +} diff --git a/src/StardewModdingAPI/Events/MenuEvents.cs b/src/StardewModdingAPI/Events/MenuEvents.cs new file mode 100644 index 00000000..bd8d897e --- /dev/null +++ b/src/StardewModdingAPI/Events/MenuEvents.cs @@ -0,0 +1,40 @@ +using System; +using StardewModdingAPI.Framework; +using StardewValley.Menus; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when a game menu is opened or closed (including internal menus like the title screen).</summary> + public static class MenuEvents + { + /********* + ** Events + *********/ + /// <summary>Raised after a game menu is opened or replaced with another menu. This event is not invoked when a menu is closed.</summary> + public static event EventHandler<EventArgsClickableMenuChanged> MenuChanged; + + /// <summary>Raised after a game menu is closed.</summary> + public static event EventHandler<EventArgsClickableMenuClosed> MenuClosed; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise a <see cref="MenuChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorMenu">The previous menu.</param> + /// <param name="newMenu">The current menu.</param> + internal static void InvokeMenuChanged(IMonitor monitor, IClickableMenu priorMenu, IClickableMenu newMenu) + { + monitor.SafelyRaiseGenericEvent($"{nameof(MenuEvents)}.{nameof(MenuEvents.MenuChanged)}", MenuEvents.MenuChanged?.GetInvocationList(), null, new EventArgsClickableMenuChanged(priorMenu, newMenu)); + } + + /// <summary>Raise a <see cref="MenuClosed"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorMenu">The menu that was closed.</param> + internal static void InvokeMenuClosed(IMonitor monitor, IClickableMenu priorMenu) + { + monitor.SafelyRaiseGenericEvent($"{nameof(MenuEvents)}.{nameof(MenuEvents.MenuClosed)}", MenuEvents.MenuClosed?.GetInvocationList(), null, new EventArgsClickableMenuClosed(priorMenu)); + } + } +} diff --git a/src/StardewModdingAPI/Events/MineEvents.cs b/src/StardewModdingAPI/Events/MineEvents.cs new file mode 100644 index 00000000..9cf7edac --- /dev/null +++ b/src/StardewModdingAPI/Events/MineEvents.cs @@ -0,0 +1,28 @@ +using System; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when something happens in the mines.</summary> + public static class MineEvents + { + /********* + ** Events + *********/ + /// <summary>Raised after the player warps to a new level of the mine.</summary> + public static event EventHandler<EventArgsMineLevelChanged> MineLevelChanged; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise a <see cref="MineLevelChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="previousMineLevel">The previous mine level.</param> + /// <param name="currentMineLevel">The current mine level.</param> + internal static void InvokeMineLevelChanged(IMonitor monitor, int previousMineLevel, int currentMineLevel) + { + monitor.SafelyRaiseGenericEvent($"{nameof(MineEvents)}.{nameof(MineEvents.MineLevelChanged)}", MineEvents.MineLevelChanged?.GetInvocationList(), null, new EventArgsMineLevelChanged(previousMineLevel, currentMineLevel)); + } + } +} diff --git a/src/StardewModdingAPI/Events/PlayerEvents.cs b/src/StardewModdingAPI/Events/PlayerEvents.cs new file mode 100644 index 00000000..72826330 --- /dev/null +++ b/src/StardewModdingAPI/Events/PlayerEvents.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using StardewModdingAPI.Framework; +using StardewValley; +using SFarmer = StardewValley.Farmer; + +#pragma warning disable 618 // Suppress obsolete-symbol errors in this file. Since several events are marked obsolete, this produces unnecessary warnings. +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the player data changes.</summary> + public static class PlayerEvents + { + /********* + ** Properties + *********/ +#if SMAPI_1_x + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + /// <summary>The backing field for <see cref="LoadedGame"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler<EventArgsLoadedGameChanged> _LoadedGame; + + /// <summary>The backing field for <see cref="FarmerChanged"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler<EventArgsFarmerChanged> _FarmerChanged; +#endif + + + /********* + ** Events + *********/ +#if SMAPI_1_x + /// <summary>Raised after the player loads a saved game.</summary> + [Obsolete("Use " + nameof(SaveEvents) + "." + nameof(SaveEvents.AfterLoad) + " instead")] + public static event EventHandler<EventArgsLoadedGameChanged> LoadedGame + { + add + { + PlayerEvents.DeprecationManager.Warn($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.LoadedGame)}", "1.6", DeprecationLevel.PendingRemoval); + PlayerEvents._LoadedGame += value; + } + remove => PlayerEvents._LoadedGame -= value; + } + + /// <summary>Raised after the game assigns a new player character. This happens just before <see cref="LoadedGame"/>; it's unclear how this would happen any other time.</summary> + [Obsolete("should no longer be used")] + public static event EventHandler<EventArgsFarmerChanged> FarmerChanged + { + add + { + PlayerEvents.DeprecationManager.Warn($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.FarmerChanged)}", "1.6", DeprecationLevel.PendingRemoval); + PlayerEvents._FarmerChanged += value; + } + remove => PlayerEvents._FarmerChanged -= value; + } +#endif + + /// <summary>Raised after the player's inventory changes in any way (added or removed item, sorted, etc).</summary> + public static event EventHandler<EventArgsInventoryChanged> InventoryChanged; + + /// <summary> Raised after the player levels up a skill. This happens as soon as they level up, not when the game notifies the player after their character goes to bed.</summary> + public static event EventHandler<EventArgsLevelUp> LeveledUp; + + + /********* + ** Internal methods + *********/ +#if SMAPI_1_x + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + PlayerEvents.DeprecationManager = deprecationManager; + } + + /// <summary>Raise a <see cref="LoadedGame"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="loaded">Whether the save has been loaded. This is always true.</param> + internal static void InvokeLoadedGame(IMonitor monitor, EventArgsLoadedGameChanged loaded) + { + monitor.SafelyRaiseGenericEvent($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.LoadedGame)}", PlayerEvents._LoadedGame?.GetInvocationList(), null, loaded); + } + + /// <summary>Raise a <see cref="FarmerChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorFarmer">The previous player character.</param> + /// <param name="newFarmer">The new player character.</param> + internal static void InvokeFarmerChanged(IMonitor monitor, SFarmer priorFarmer, SFarmer newFarmer) + { + monitor.SafelyRaiseGenericEvent($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.FarmerChanged)}", PlayerEvents._FarmerChanged?.GetInvocationList(), null, new EventArgsFarmerChanged(priorFarmer, newFarmer)); + } +#endif + + /// <summary>Raise an <see cref="InventoryChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="inventory">The player's inventory.</param> + /// <param name="changedItems">The inventory changes.</param> + internal static void InvokeInventoryChanged(IMonitor monitor, List<Item> inventory, IEnumerable<ItemStackChange> changedItems) + { + monitor.SafelyRaiseGenericEvent($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.InventoryChanged)}", PlayerEvents.InventoryChanged?.GetInvocationList(), null, new EventArgsInventoryChanged(inventory, changedItems.ToList())); + } + + /// <summary>Rase a <see cref="LeveledUp"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="type">The player skill that leveled up.</param> + /// <param name="newLevel">The new skill level.</param> + internal static void InvokeLeveledUp(IMonitor monitor, EventArgsLevelUp.LevelType type, int newLevel) + { + monitor.SafelyRaiseGenericEvent($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.LeveledUp)}", PlayerEvents.LeveledUp?.GetInvocationList(), null, new EventArgsLevelUp(type, newLevel)); + } + } +} diff --git a/src/StardewModdingAPI/Events/SaveEvents.cs b/src/StardewModdingAPI/Events/SaveEvents.cs new file mode 100644 index 00000000..50e6d729 --- /dev/null +++ b/src/StardewModdingAPI/Events/SaveEvents.cs @@ -0,0 +1,56 @@ +using System; +using StardewModdingAPI.Framework; + +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised before and after the player saves/loads the game.</summary> + public static class SaveEvents + { + /********* + ** Events + *********/ + /// <summary>Raised before the game begins writes data to the save file.</summary> + public static event EventHandler BeforeSave; + + /// <summary>Raised after the game finishes writing data to the save file.</summary> + public static event EventHandler AfterSave; + + /// <summary>Raised after the player loads a save slot.</summary> + public static event EventHandler AfterLoad; + + /// <summary>Raised after the game returns to the title screen.</summary> + public static event EventHandler AfterReturnToTitle; + + + /********* + ** Internal methods + *********/ + /// <summary>Raise a <see cref="BeforeSave"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeBeforeSave(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(SaveEvents)}.{nameof(SaveEvents.BeforeSave)}", SaveEvents.BeforeSave?.GetInvocationList(), null, EventArgs.Empty); + } + + /// <summary>Raise a <see cref="AfterSave"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeAfterSave(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(SaveEvents)}.{nameof(SaveEvents.AfterSave)}", SaveEvents.AfterSave?.GetInvocationList(), null, EventArgs.Empty); + } + + /// <summary>Raise a <see cref="AfterLoad"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeAfterLoad(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(SaveEvents)}.{nameof(SaveEvents.AfterLoad)}", SaveEvents.AfterLoad?.GetInvocationList(), null, EventArgs.Empty); + } + + /// <summary>Raise a <see cref="AfterReturnToTitle"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeAfterReturnToTitle(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(SaveEvents)}.{nameof(SaveEvents.AfterReturnToTitle)}", SaveEvents.AfterReturnToTitle?.GetInvocationList(), null, EventArgs.Empty); + } + } +} diff --git a/src/StardewModdingAPI/Events/TimeEvents.cs b/src/StardewModdingAPI/Events/TimeEvents.cs new file mode 100644 index 00000000..d5ab9fb7 --- /dev/null +++ b/src/StardewModdingAPI/Events/TimeEvents.cs @@ -0,0 +1,163 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using StardewModdingAPI.Framework; + +#pragma warning disable 618 // Suppress obsolete-symbol errors in this file. Since several events are marked obsolete, this produces unnecessary warnings. +namespace StardewModdingAPI.Events +{ + /// <summary>Events raised when the in-game date or time changes.</summary> + public static class TimeEvents + { + /********* + ** Properties + *********/ +#if SMAPI_1_x + /// <summary>Manages deprecation warnings.</summary> + private static DeprecationManager DeprecationManager; + + /// <summary>The backing field for <see cref="OnNewDay"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler<EventArgsNewDay> _OnNewDay; + + /// <summary>The backing field for <see cref="DayOfMonthChanged"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler<EventArgsIntChanged> _DayOfMonthChanged; + + /// <summary>The backing field for <see cref="SeasonOfYearChanged"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler<EventArgsStringChanged> _SeasonOfYearChanged; + + /// <summary>The backing field for <see cref="YearOfGameChanged"/>.</summary> + [SuppressMessage("ReSharper", "InconsistentNaming")] + private static event EventHandler<EventArgsIntChanged> _YearOfGameChanged; +#endif + + + /********* + ** Events + *********/ + /// <summary>Raised after the game begins a new day, including when loading a save.</summary> + public static event EventHandler AfterDayStarted; + + /// <summary>Raised after the in-game clock changes.</summary> + public static event EventHandler<EventArgsIntChanged> TimeOfDayChanged; + +#if SMAPI_1_x + /// <summary>Raised after the day-of-month value changes, including when loading a save. This may happen before save; in most cases you should use <see cref="AfterDayStarted"/> instead.</summary> + [Obsolete("Use " + nameof(TimeEvents) + "." + nameof(TimeEvents.AfterDayStarted) + " or " + nameof(SaveEvents) + " instead")] + public static event EventHandler<EventArgsIntChanged> DayOfMonthChanged + { + add + { + TimeEvents.DeprecationManager.Warn($"{nameof(TimeEvents)}.{nameof(TimeEvents.DayOfMonthChanged)}", "1.14", DeprecationLevel.PendingRemoval); + TimeEvents._DayOfMonthChanged += value; + } + remove => TimeEvents._DayOfMonthChanged -= value; + } + + /// <summary>Raised after the year value changes.</summary> + [Obsolete("Use " + nameof(TimeEvents) + "." + nameof(TimeEvents.AfterDayStarted) + " or " + nameof(SaveEvents) + " instead")] + public static event EventHandler<EventArgsIntChanged> YearOfGameChanged + { + add + { + TimeEvents.DeprecationManager.Warn($"{nameof(TimeEvents)}.{nameof(TimeEvents.YearOfGameChanged)}", "1.14", DeprecationLevel.PendingRemoval); + TimeEvents._YearOfGameChanged += value; + } + remove => TimeEvents._YearOfGameChanged -= value; + } + + /// <summary>Raised after the season value changes.</summary> + [Obsolete("Use " + nameof(TimeEvents) + "." + nameof(TimeEvents.AfterDayStarted) + " or " + nameof(SaveEvents) + " instead")] + public static event EventHandler<EventArgsStringChanged> SeasonOfYearChanged + { + add + { + TimeEvents.DeprecationManager.Warn($"{nameof(TimeEvents)}.{nameof(TimeEvents.SeasonOfYearChanged)}", "1.14", DeprecationLevel.PendingRemoval); + TimeEvents._SeasonOfYearChanged += value; + } + remove => TimeEvents._SeasonOfYearChanged -= value; + } + + /// <summary>Raised when the player is transitioning to a new day and the game is performing its day update logic. This event is triggered twice: once after the game starts transitioning, and again after it finishes.</summary> + [Obsolete("Use " + nameof(TimeEvents) + "." + nameof(TimeEvents.AfterDayStarted) + " or " + nameof(SaveEvents) + " instead")] + public static event EventHandler<EventArgsNewDay> OnNewDay + { + add + { + TimeEvents.DeprecationManager.Warn($"{nameof(TimeEvents)}.{nameof(TimeEvents.OnNewDay)}", "1.6", DeprecationLevel.PendingRemoval); + TimeEvents._OnNewDay += value; + } + remove => TimeEvents._OnNewDay -= value; + } +#endif + + + /********* + ** Internal methods + *********/ +#if SMAPI_1_x + /// <summary>Injects types required for backwards compatibility.</summary> + /// <param name="deprecationManager">Manages deprecation warnings.</param> + internal static void Shim(DeprecationManager deprecationManager) + { + TimeEvents.DeprecationManager = deprecationManager; + } +#endif + + /// <summary>Raise an <see cref="AfterDayStarted"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + internal static void InvokeAfterDayStarted(IMonitor monitor) + { + monitor.SafelyRaisePlainEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.AfterDayStarted)}", TimeEvents.AfterDayStarted?.GetInvocationList(), null, EventArgs.Empty); + } + + /// <summary>Raise a <see cref="TimeOfDayChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorTime">The previous time in military time format (e.g. 6:00pm is 1800).</param> + /// <param name="newTime">The current time in military time format (e.g. 6:10pm is 1810).</param> + internal static void InvokeTimeOfDayChanged(IMonitor monitor, int priorTime, int newTime) + { + monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.TimeOfDayChanged)}", TimeEvents.TimeOfDayChanged?.GetInvocationList(), null, new EventArgsIntChanged(priorTime, newTime)); + } + +#if SMAPI_1_x + /// <summary>Raise a <see cref="DayOfMonthChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorDay">The previous day value.</param> + /// <param name="newDay">The current day value.</param> + internal static void InvokeDayOfMonthChanged(IMonitor monitor, int priorDay, int newDay) + { + monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.DayOfMonthChanged)}", TimeEvents._DayOfMonthChanged?.GetInvocationList(), null, new EventArgsIntChanged(priorDay, newDay)); + } + + /// <summary>Raise a <see cref="YearOfGameChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorYear">The previous year value.</param> + /// <param name="newYear">The current year value.</param> + internal static void InvokeYearOfGameChanged(IMonitor monitor, int priorYear, int newYear) + { + monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.YearOfGameChanged)}", TimeEvents._YearOfGameChanged?.GetInvocationList(), null, new EventArgsIntChanged(priorYear, newYear)); + } + + /// <summary>Raise a <see cref="SeasonOfYearChanged"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorSeason">The previous season name.</param> + /// <param name="newSeason">The current season name.</param> + internal static void InvokeSeasonOfYearChanged(IMonitor monitor, string priorSeason, string newSeason) + { + monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.SeasonOfYearChanged)}", TimeEvents._SeasonOfYearChanged?.GetInvocationList(), null, new EventArgsStringChanged(priorSeason, newSeason)); + } + + /// <summary>Raise a <see cref="OnNewDay"/> event.</summary> + /// <param name="monitor">Encapsulates monitoring and logging.</param> + /// <param name="priorDay">The previous day value.</param> + /// <param name="newDay">The current day value.</param> + /// <param name="isTransitioning">Whether the game just started the transition (<c>true</c>) or finished it (<c>false</c>).</param> + internal static void InvokeOnNewDay(IMonitor monitor, int priorDay, int newDay, bool isTransitioning) + { + monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.OnNewDay)}", TimeEvents._OnNewDay?.GetInvocationList(), null, new EventArgsNewDay(priorDay, newDay, isTransitioning)); + } +#endif + } +} |