summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/StardewModdingAPI/Events/ControlEvents.cs41
-rw-r--r--src/StardewModdingAPI/Events/GameEvents.cs68
-rw-r--r--src/StardewModdingAPI/Events/GraphicsEvents.cs97
-rw-r--r--src/StardewModdingAPI/Events/LocationEvents.cs16
-rw-r--r--src/StardewModdingAPI/Events/MenuEvents.cs11
-rw-r--r--src/StardewModdingAPI/Events/MineEvents.cs6
-rw-r--r--src/StardewModdingAPI/Events/PlayerEvents.cs21
-rw-r--r--src/StardewModdingAPI/Events/TimeEvents.cs26
-rw-r--r--src/StardewModdingAPI/Framework/InternalExtensions.cs65
-rw-r--r--src/StardewModdingAPI/Inheritance/SGame.cs100
-rw-r--r--src/StardewModdingAPI/Program.cs2
-rw-r--r--src/StardewModdingAPI/StardewModdingAPI.csproj1
12 files changed, 261 insertions, 193 deletions
diff --git a/src/StardewModdingAPI/Events/ControlEvents.cs b/src/StardewModdingAPI/Events/ControlEvents.cs
index b7f69805..790bf193 100644
--- a/src/StardewModdingAPI/Events/ControlEvents.cs
+++ b/src/StardewModdingAPI/Events/ControlEvents.cs
@@ -1,6 +1,7 @@
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
+using StardewModdingAPI.Framework;
namespace StardewModdingAPI.Events
{
@@ -39,69 +40,77 @@ namespace StardewModdingAPI.Events
** 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(KeyboardState priorState, KeyboardState newState)
+ internal static void InvokeKeyboardChanged(IMonitor monitor, KeyboardState priorState, KeyboardState newState)
{
- ControlEvents.KeyboardChanged?.Invoke(null, new EventArgsKeyboardStateChanged(priorState, 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(MouseState priorState, MouseState newState, Point priorPosition, Point newPosition)
+ internal static void InvokeMouseChanged(IMonitor monitor, MouseState priorState, MouseState newState, Point priorPosition, Point newPosition)
{
- ControlEvents.MouseChanged?.Invoke(null, new EventArgsMouseStateChanged(priorState, newState, priorPosition, 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(Keys key)
+ internal static void InvokeKeyPressed(IMonitor monitor, Keys key)
{
- ControlEvents.KeyPressed?.Invoke(null, new EventArgsKeyPressed(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(Keys key)
+ internal static void InvokeKeyReleased(IMonitor monitor, Keys key)
{
- ControlEvents.KeyReleased?.Invoke(null, new EventArgsKeyPressed(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="playerIndex">The player who pressed the button.</param>
/// <param name="button">The controller button that was pressed.</param>
- internal static void InvokeButtonPressed(PlayerIndex playerIndex, Buttons button)
+ internal static void InvokeButtonPressed(IMonitor monitor, PlayerIndex playerIndex, Buttons button)
{
- ControlEvents.ControllerButtonPressed?.Invoke(null, new EventArgsControllerButtonPressed(playerIndex, button));
+ monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerButtonPressed)}", ControlEvents.ControllerButtonPressed?.GetInvocationList(), null, new EventArgsControllerButtonPressed(playerIndex, button));
}
/// <summary>Raise a <see cref="ControllerButtonReleased"/> event.</summary>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
/// <param name="playerIndex">The player who released the button.</param>
/// <param name="button">The controller button that was released.</param>
- internal static void InvokeButtonReleased(PlayerIndex playerIndex, Buttons button)
+ internal static void InvokeButtonReleased(IMonitor monitor, PlayerIndex playerIndex, Buttons button)
{
- ControlEvents.ControllerButtonReleased?.Invoke(null, new EventArgsControllerButtonReleased(playerIndex, button));
+ monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerButtonReleased)}", ControlEvents.ControllerButtonReleased?.GetInvocationList(), null, new EventArgsControllerButtonReleased(playerIndex, button));
}
/// <summary>Raise a <see cref="ControllerTriggerPressed"/> event.</summary>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
/// <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>
- internal static void InvokeTriggerPressed(PlayerIndex playerIndex, Buttons button, float value)
+ internal static void InvokeTriggerPressed(IMonitor monitor, PlayerIndex playerIndex, Buttons button, float value)
{
- ControlEvents.ControllerTriggerPressed?.Invoke(null, new EventArgsControllerTriggerPressed(playerIndex, button, value));
+ monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerTriggerPressed)}", ControlEvents.ControllerTriggerPressed?.GetInvocationList(), null, new EventArgsControllerTriggerPressed(playerIndex, button, value));
}
/// <summary>Raise a <see cref="ControllerTriggerReleased"/> event.</summary>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
/// <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>
- internal static void InvokeTriggerReleased(PlayerIndex playerIndex, Buttons button, float value)
+ internal static void InvokeTriggerReleased(IMonitor monitor, PlayerIndex playerIndex, Buttons button, float value)
{
- ControlEvents.ControllerTriggerReleased?.Invoke(null, new EventArgsControllerTriggerReleased(playerIndex, button, value));
+ monitor.SafelyRaiseGenericEvent($"{nameof(ControlEvents)}.{nameof(ControlEvents.ControllerTriggerReleased)}", ControlEvents.ControllerTriggerReleased?.GetInvocationList(), null, new EventArgsControllerTriggerReleased(playerIndex, button, value));
}
}
}
diff --git a/src/StardewModdingAPI/Events/GameEvents.cs b/src/StardewModdingAPI/Events/GameEvents.cs
index 46505d14..715083b9 100644
--- a/src/StardewModdingAPI/Events/GameEvents.cs
+++ b/src/StardewModdingAPI/Events/GameEvents.cs
@@ -1,4 +1,5 @@
using System;
+using StardewModdingAPI.Framework;
namespace StardewModdingAPI.Events
{
@@ -46,93 +47,80 @@ namespace StardewModdingAPI.Events
** Internal methods
*********/
/// <summary>Raise a <see cref="GameLoaded"/> event.</summary>
- internal static void InvokeGameLoaded()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeGameLoaded(IMonitor monitor)
{
- GameEvents.GameLoaded?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.GameLoaded)}", GameEvents.GameLoaded?.GetInvocationList());
}
/// <summary>Raise an <see cref="Initialize"/> event.</summary>
/// <param name="monitor">Encapsulates logging and monitoring.</param>
internal static void InvokeInitialize(IMonitor monitor)
{
- try
- {
- GameEvents.Initialize?.Invoke(null, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- monitor.Log($"A mod crashed handling an event.\n{ex}", LogLevel.Error);
- }
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.Initialize)}", GameEvents.Initialize?.GetInvocationList());
}
/// <summary>Raise a <see cref="LoadContent"/> event.</summary>
/// <param name="monitor">Encapsulates logging and monitoring.</param>
internal static void InvokeLoadContent(IMonitor monitor)
{
- try
- {
- GameEvents.LoadContent?.Invoke(null, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- monitor.Log($"A mod crashed handling an event.\n{ex}", LogLevel.Error);
- }
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.LoadContent)}", GameEvents.LoadContent?.GetInvocationList());
}
/// <summary>Raise an <see cref="UpdateTick"/> event.</summary>
/// <param name="monitor">Encapsulates logging and monitoring.</param>
internal static void InvokeUpdateTick(IMonitor monitor)
{
- try
- {
- GameEvents.UpdateTick?.Invoke(null, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- monitor.Log($"A mod crashed handling an event.\n{ex}", LogLevel.Error);
- }
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.UpdateTick)}", GameEvents.UpdateTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="SecondUpdateTick"/> event.</summary>
- internal static void InvokeSecondUpdateTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeSecondUpdateTick(IMonitor monitor)
{
- GameEvents.SecondUpdateTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.SecondUpdateTick)}", GameEvents.SecondUpdateTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="FourthUpdateTick"/> event.</summary>
- internal static void InvokeFourthUpdateTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeFourthUpdateTick(IMonitor monitor)
{
- GameEvents.FourthUpdateTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.FourthUpdateTick)}", GameEvents.FourthUpdateTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="EighthUpdateTick"/> event.</summary>
- internal static void InvokeEighthUpdateTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeEighthUpdateTick(IMonitor monitor)
{
- GameEvents.EighthUpdateTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.EighthUpdateTick)}", GameEvents.EighthUpdateTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="QuarterSecondTick"/> event.</summary>
- internal static void InvokeQuarterSecondTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeQuarterSecondTick(IMonitor monitor)
{
- GameEvents.QuarterSecondTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.QuarterSecondTick)}", GameEvents.QuarterSecondTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="HalfSecondTick"/> event.</summary>
- internal static void InvokeHalfSecondTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeHalfSecondTick(IMonitor monitor)
{
- GameEvents.HalfSecondTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.HalfSecondTick)}", GameEvents.HalfSecondTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="OneSecondTick"/> event.</summary>
- internal static void InvokeOneSecondTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOneSecondTick(IMonitor monitor)
{
- GameEvents.OneSecondTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.OneSecondTick)}", GameEvents.OneSecondTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="FirstUpdateTick"/> event.</summary>
- internal static void InvokeFirstUpdateTick()
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeFirstUpdateTick(IMonitor monitor)
{
- GameEvents.FirstUpdateTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GameEvents)}.{nameof(GameEvents.FirstUpdateTick)}", GameEvents.FirstUpdateTick?.GetInvocationList());
}
}
}
diff --git a/src/StardewModdingAPI/Events/GraphicsEvents.cs b/src/StardewModdingAPI/Events/GraphicsEvents.cs
index 3f52212b..5f4feeac 100644
--- a/src/StardewModdingAPI/Events/GraphicsEvents.cs
+++ b/src/StardewModdingAPI/Events/GraphicsEvents.cs
@@ -1,4 +1,5 @@
using System;
+using StardewModdingAPI.Framework;
namespace StardewModdingAPI.Events
{
@@ -72,19 +73,19 @@ namespace StardewModdingAPI.Events
** Generic events
****/
/// <summary>Raise a <see cref="Resize"/> event.</summary>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
/// <param name="sender">The object which raised the event.</param>
/// <param name="e">The event arguments.</param>
- internal static void InvokeResize(object sender, EventArgs e)
+ internal static void InvokeResize(IMonitor monitor, object sender, EventArgs e)
{
- GraphicsEvents.Resize?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.Resize)}", GraphicsEvents.Resize?.GetInvocationList(), sender, e);
}
/// <summary>Raise a <see cref="DrawDebug"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeDrawDebug(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeDrawDebug(IMonitor monitor)
{
- GraphicsEvents.DrawDebug?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.DrawDebug)}", GraphicsEvents.DrawDebug?.GetInvocationList());
}
/// <summary>Raise a <see cref="DrawTick"/> event.</summary>
@@ -92,110 +93,94 @@ namespace StardewModdingAPI.Events
[Obsolete("Should not be used.")]
public static void InvokeDrawTick(IMonitor monitor)
{
- try
- {
- GraphicsEvents.DrawTick?.Invoke(null, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- monitor.Log($"A mod crashed handling an event.\n{ex}", LogLevel.Error);
- }
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.DrawTick)}", GraphicsEvents.DrawTick?.GetInvocationList());
}
/// <summary>Raise a <see cref="DrawInRenderTargetTick"/> event.</summary>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
[Obsolete("Should not be used.")]
- public static void InvokeDrawInRenderTargetTick()
+ public static void InvokeDrawInRenderTargetTick(IMonitor monitor)
{
- GraphicsEvents.DrawInRenderTargetTick?.Invoke(null, EventArgs.Empty);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.DrawInRenderTargetTick)}", GraphicsEvents.DrawInRenderTargetTick?.GetInvocationList());
}
/****
** Main render events
****/
/// <summary>Raise an <see cref="OnPreRenderEvent"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPreRenderEvent(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPreRenderEvent(IMonitor monitor)
{
- GraphicsEvents.OnPreRenderEvent?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderEvent)}", GraphicsEvents.OnPreRenderEvent?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPostRenderEvent"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPostRenderEvent(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPostRenderEvent(IMonitor monitor)
{
- GraphicsEvents.OnPostRenderEvent?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderEvent)}", GraphicsEvents.OnPostRenderEvent?.GetInvocationList());
}
/****
** HUD events
****/
/// <summary>Raise an <see cref="OnPreRenderGuiEvent"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPreRenderGuiEvent(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPreRenderGuiEvent(IMonitor monitor)
{
- GraphicsEvents.OnPreRenderGuiEvent?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderGuiEvent)}", GraphicsEvents.OnPreRenderGuiEvent?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPreRenderGuiEventNoCheck"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPreRenderGuiEventNoCheck(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPreRenderGuiEventNoCheck(IMonitor monitor)
{
- GraphicsEvents.OnPreRenderGuiEventNoCheck?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderGuiEventNoCheck)}", GraphicsEvents.OnPreRenderGuiEventNoCheck?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPostRenderGuiEvent"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPostRenderGuiEvent(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPostRenderGuiEvent(IMonitor monitor)
{
- GraphicsEvents.OnPostRenderGuiEvent?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderGuiEvent)}", GraphicsEvents.OnPostRenderGuiEvent?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPostRenderGuiEventNoCheck"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPostRenderGuiEventNoCheck(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPostRenderGuiEventNoCheck(IMonitor monitor)
{
- GraphicsEvents.OnPostRenderGuiEventNoCheck?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderGuiEventNoCheck)}", GraphicsEvents.OnPostRenderGuiEventNoCheck?.GetInvocationList());
}
/****
** GUI events
****/
/// <summary>Raise an <see cref="OnPreRenderHudEvent"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPreRenderHudEvent(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPreRenderHudEvent(IMonitor monitor)
{
- GraphicsEvents.OnPreRenderHudEvent?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderHudEvent)}", GraphicsEvents.OnPreRenderHudEvent?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPreRenderHudEventNoCheck"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPreRenderHudEventNoCheck(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPreRenderHudEventNoCheck(IMonitor monitor)
{
- GraphicsEvents.OnPreRenderHudEventNoCheck?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPreRenderHudEventNoCheck)}", GraphicsEvents.OnPreRenderHudEventNoCheck?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPostRenderHudEvent"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPostRenderHudEvent(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPostRenderHudEvent(IMonitor monitor)
{
- GraphicsEvents.OnPostRenderHudEvent?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderHudEvent)}", GraphicsEvents.OnPostRenderHudEvent?.GetInvocationList());
}
/// <summary>Raise an <see cref="OnPostRenderHudEventNoCheck"/> event.</summary>
- /// <param name="sender">The object which raised the event.</param>
- /// <param name="e">The event arguments.</param>
- internal static void InvokeOnPostRenderHudEventNoCheck(object sender, EventArgs e)
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ internal static void InvokeOnPostRenderHudEventNoCheck(IMonitor monitor)
{
- GraphicsEvents.OnPostRenderHudEventNoCheck?.Invoke(sender, e);
+ monitor.SafelyRaisePlainEvent($"{nameof(GraphicsEvents)}.{nameof(GraphicsEvents.OnPostRenderHudEventNoCheck)}", GraphicsEvents.OnPostRenderHudEventNoCheck?.GetInvocationList());
}
}
}
diff --git a/src/StardewModdingAPI/Events/LocationEvents.cs b/src/StardewModdingAPI/Events/LocationEvents.cs
index 3c28f541..b834bc1c 100644
--- a/src/StardewModdingAPI/Events/LocationEvents.cs
+++ b/src/StardewModdingAPI/Events/LocationEvents.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
+using StardewModdingAPI.Framework;
using StardewValley;
using Object = StardewValley.Object;
@@ -26,25 +27,28 @@ namespace StardewModdingAPI.Events
** 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(GameLocation priorLocation, GameLocation newLocation)
+ internal static void InvokeCurrentLocationChanged(IMonitor monitor, GameLocation priorLocation, GameLocation newLocation)
{
- LocationEvents.CurrentLocationChanged?.Invoke(null, new EventArgsCurrentLocationChanged(priorLocation, 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(List<GameLocation> newLocations)
+ internal static void InvokeLocationsChanged(IMonitor monitor, List<GameLocation> newLocations)
{
- LocationEvents.LocationsChanged?.Invoke(null, new EventArgsGameLocationsChanged(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(SerializableDictionary<Vector2, Object> newObjects)
+ internal static void InvokeOnNewLocationObject(IMonitor monitor, SerializableDictionary<Vector2, Object> newObjects)
{
- LocationEvents.LocationObjectsChanged?.Invoke(null, new EventArgsLocationObjectsChanged(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
index 4cb68cbb..bd8d897e 100644
--- a/src/StardewModdingAPI/Events/MenuEvents.cs
+++ b/src/StardewModdingAPI/Events/MenuEvents.cs
@@ -1,4 +1,5 @@
using System;
+using StardewModdingAPI.Framework;
using StardewValley.Menus;
namespace StardewModdingAPI.Events
@@ -20,18 +21,20 @@ namespace StardewModdingAPI.Events
** 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(IClickableMenu priorMenu, IClickableMenu newMenu)
+ internal static void InvokeMenuChanged(IMonitor monitor, IClickableMenu priorMenu, IClickableMenu newMenu)
{
- MenuEvents.MenuChanged?.Invoke(null, new EventArgsClickableMenuChanged(priorMenu, 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(IClickableMenu priorMenu)
+ internal static void InvokeMenuClosed(IMonitor monitor, IClickableMenu priorMenu)
{
- MenuEvents.MenuClosed?.Invoke(null, new EventArgsClickableMenuClosed(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
index 8b91d7d7..9cf7edac 100644
--- a/src/StardewModdingAPI/Events/MineEvents.cs
+++ b/src/StardewModdingAPI/Events/MineEvents.cs
@@ -1,4 +1,5 @@
using System;
+using StardewModdingAPI.Framework;
namespace StardewModdingAPI.Events
{
@@ -16,11 +17,12 @@ namespace StardewModdingAPI.Events
** 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(int previousMineLevel, int currentMineLevel)
+ internal static void InvokeMineLevelChanged(IMonitor monitor, int previousMineLevel, int currentMineLevel)
{
- MineEvents.MineLevelChanged?.Invoke(null, new EventArgsMineLevelChanged(previousMineLevel, 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
index c92ab7ce..3f301b07 100644
--- a/src/StardewModdingAPI/Events/PlayerEvents.cs
+++ b/src/StardewModdingAPI/Events/PlayerEvents.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using StardewModdingAPI.Framework;
using StardewModdingAPI.Inheritance;
using StardewValley;
@@ -29,34 +30,38 @@ namespace StardewModdingAPI.Events
** Internal methods
*********/
/// <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(EventArgsLoadedGameChanged loaded)
+ internal static void InvokeLoadedGame(IMonitor monitor, EventArgsLoadedGameChanged loaded)
{
- PlayerEvents.LoadedGame?.Invoke(null, 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(Farmer priorFarmer, Farmer newFarmer)
+ internal static void InvokeFarmerChanged(IMonitor monitor, Farmer priorFarmer, Farmer newFarmer)
{
- PlayerEvents.FarmerChanged?.Invoke(null, new EventArgsFarmerChanged(priorFarmer, newFarmer));
+ monitor.SafelyRaiseGenericEvent($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.FarmerChanged)}", PlayerEvents.FarmerChanged?.GetInvocationList(), null, new EventArgsFarmerChanged(priorFarmer, newFarmer));
}
/// <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(List<Item> inventory, IEnumerable<ItemStackChange> changedItems)
+ internal static void InvokeInventoryChanged(IMonitor monitor, List<Item> inventory, IEnumerable<ItemStackChange> changedItems)
{
- PlayerEvents.InventoryChanged?.Invoke(null, new EventArgsInventoryChanged(inventory, changedItems.ToList()));
+ 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(EventArgsLevelUp.LevelType type, int newLevel)
+ internal static void InvokeLeveledUp(IMonitor monitor, EventArgsLevelUp.LevelType type, int newLevel)
{
- PlayerEvents.LeveledUp?.Invoke(null, new EventArgsLevelUp(type, newLevel));
+ monitor.SafelyRaiseGenericEvent($"{nameof(PlayerEvents)}.{nameof(PlayerEvents.LeveledUp)}", PlayerEvents.LeveledUp?.GetInvocationList(), null, new EventArgsLevelUp(type, newLevel));
}
}
}
diff --git a/src/StardewModdingAPI/Events/TimeEvents.cs b/src/StardewModdingAPI/Events/TimeEvents.cs
index 0481ad48..1b367230 100644
--- a/src/StardewModdingAPI/Events/TimeEvents.cs
+++ b/src/StardewModdingAPI/Events/TimeEvents.cs
@@ -1,4 +1,5 @@
using System;
+using StardewModdingAPI.Framework;
namespace StardewModdingAPI.Events
{
@@ -28,44 +29,49 @@ namespace StardewModdingAPI.Events
** Internal methods
*********/
/// <summary>Raise a <see cref="InvokeDayOfMonthChanged"/> 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(int priorTime, int newTime)
+ internal static void InvokeTimeOfDayChanged(IMonitor monitor, int priorTime, int newTime)
{
- TimeEvents.TimeOfDayChanged?.Invoke(null, new EventArgsIntChanged(priorTime, newTime));
+ monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.TimeOfDayChanged)}", TimeEvents.TimeOfDayChanged?.GetInvocationList(), null, new EventArgsIntChanged(priorTime, newTime));
}
/// <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(int priorDay, int newDay)
+ internal static void InvokeDayOfMonthChanged(IMonitor monitor, int priorDay, int newDay)
{
- TimeEvents.DayOfMonthChanged?.Invoke(null, new EventArgsIntChanged(priorDay, 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(int priorYear, int newYear)
+ internal static void InvokeYearOfGameChanged(IMonitor monitor, int priorYear, int newYear)
{
- TimeEvents.YearOfGameChanged?.Invoke(null, new EventArgsIntChanged(priorYear, 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(string priorSeason, string newSeason)
+ internal static void InvokeSeasonOfYearChanged(IMonitor monitor, string priorSeason, string newSeason)
{
- TimeEvents.SeasonOfYearChanged?.Invoke(null, new EventArgsStringChanged(priorSeason, 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(int priorDay, int newDay, bool isTransitioning)
+ internal static void InvokeOnNewDay(IMonitor monitor, int priorDay, int newDay, bool isTransitioning)
{
- TimeEvents.OnNewDay?.Invoke(null, new EventArgsNewDay(priorDay, newDay, isTransitioning));
+ monitor.SafelyRaiseGenericEvent($"{nameof(TimeEvents)}.{nameof(TimeEvents.OnNewDay)}", TimeEvents.OnNewDay?.GetInvocationList(), null, new EventArgsNewDay(priorDay, newDay, isTransitioning));
}
}
}
diff --git a/src/StardewModdingAPI/Framework/InternalExtensions.cs b/src/StardewModdingAPI/Framework/InternalExtensions.cs
new file mode 100644
index 00000000..d08d12f3
--- /dev/null
+++ b/src/StardewModdingAPI/Framework/InternalExtensions.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace StardewModdingAPI.Framework
+{
+ /// <summary>Provides extension methods for SMAPI's internal use.</summary>
+ internal static class InternalExtensions
+ {
+ /*********
+ ** Public methods
+ *********/
+ /****
+ ** IMonitor
+ ****/
+ /// <summary>Safely raise an <see cref="EventHandler"/> event, and intercept any exceptions thrown by its handlers.</summary>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ /// <param name="name">The event name for error messages.</param>
+ /// <param name="handlers">The event handlers.</param>
+ /// <param name="sender">The event sender.</param>
+ /// <param name="args">The event arguments (or <c>null</c> to pass <see cref="EventArgs.Empty"/>).</param>
+ public static void SafelyRaisePlainEvent(this IMonitor monitor, string name, IEnumerable<Delegate> handlers, object sender = null, EventArgs args = null)
+ {
+ if (handlers == null)
+ return;
+
+ foreach (EventHandler handler in Enumerable.Cast<EventHandler>(handlers))
+ {
+ try
+ {
+ handler.Invoke(sender, args ?? EventArgs.Empty);
+ }
+ catch (Exception ex)
+ {
+ monitor.Log($"A mod failed handling the {name} event:\n{ex}", LogLevel.Error);
+ }
+ }
+ }
+
+ /// <summary>Safely raise an <see cref="EventHandler{TEventArgs}"/> event, and intercept any exceptions thrown by its handlers.</summary>
+ /// <typeparam name="TEventArgs">The event argument object type.</typeparam>
+ /// <param name="monitor">Encapsulates monitoring and logging.</param>
+ /// <param name="name">The event name for error messages.</param>
+ /// <param name="handlers">The event handlers.</param>
+ /// <param name="sender">The event sender.</param>
+ /// <param name="args">The event arguments.</param>
+ public static void SafelyRaiseGenericEvent<TEventArgs>(this IMonitor monitor, string name, IEnumerable<Delegate> handlers, object sender, TEventArgs args)
+ {
+ if (handlers == null)
+ return;
+
+ foreach (EventHandler<TEventArgs> handler in Enumerable.Cast<EventHandler<TEventArgs>>(handlers))
+ {
+ try
+ {
+ handler.Invoke(sender, args);
+ }
+ catch (Exception ex)
+ {
+ monitor.Log($"A mod failed handling the {name} event:\n{ex}", LogLevel.Error);
+ }
+ }
+ }
+ }
+}
diff --git a/src/StardewModdingAPI/Inheritance/SGame.cs b/src/StardewModdingAPI/Inheritance/SGame.cs
index ed5df125..5484bfc2 100644
--- a/src/StardewModdingAPI/Inheritance/SGame.cs
+++ b/src/StardewModdingAPI/Inheritance/SGame.cs
@@ -318,7 +318,7 @@ namespace StardewModdingAPI.Inheritance
// raise game loaded
if (this.FirstUpdate)
- GameEvents.InvokeGameLoaded();
+ GameEvents.InvokeGameLoaded(this.Monitor);
// update SMAPI events
this.UpdateEventCalls();
@@ -342,21 +342,21 @@ namespace StardewModdingAPI.Inheritance
GameEvents.InvokeUpdateTick(this.Monitor);
if (this.FirstUpdate)
{
- GameEvents.InvokeFirstUpdateTick();
+ GameEvents.InvokeFirstUpdateTick(this.Monitor);
this.FirstUpdate = false;
}
if (this.CurrentUpdateTick % 2 == 0)
- GameEvents.InvokeSecondUpdateTick();
+ GameEvents.InvokeSecondUpdateTick(this.Monitor);
if (this.CurrentUpdateTick % 4 == 0)
- GameEvents.InvokeFourthUpdateTick();
+ GameEvents.InvokeFourthUpdateTick(this.Monitor);
if (this.CurrentUpdateTick % 8 == 0)
- GameEvents.InvokeEighthUpdateTick();
+ GameEvents.InvokeEighthUpdateTick(this.Monitor);
if (this.CurrentUpdateTick % 15 == 0)
- GameEvents.InvokeQuarterSecondTick();
+ GameEvents.InvokeQuarterSecondTick(this.Monitor);
if (this.CurrentUpdateTick % 30 == 0)
- GameEvents.InvokeHalfSecondTick();
+ GameEvents.InvokeHalfSecondTick(this.Monitor);
if (this.CurrentUpdateTick % 60 == 0)
- GameEvents.InvokeOneSecondTick();
+ GameEvents.InvokeOneSecondTick(this.Monitor);
this.CurrentUpdateTick += 1;
if (this.CurrentUpdateTick >= 60)
this.CurrentUpdateTick = 0;
@@ -388,9 +388,9 @@ namespace StardewModdingAPI.Inheritance
{
Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
Game1.activeClickableMenu.drawBackground(Game1.spriteBatch);
- GraphicsEvents.InvokeOnPreRenderGuiEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor);
Game1.activeClickableMenu.draw(Game1.spriteBatch);
- GraphicsEvents.InvokeOnPostRenderGuiEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor);
Game1.spriteBatch.End();
if (!this.ZoomLevelIsOne)
{
@@ -489,7 +489,7 @@ namespace StardewModdingAPI.Inheritance
Game1.bloom?.BeginDraw();
this.GraphicsDevice.Clear(this.BgColour);
Game1.spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, null, null);
- GraphicsEvents.InvokeOnPreRenderEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPreRenderEvent(this.Monitor);
Game1.background?.draw(Game1.spriteBatch);
Game1.mapDisplayDevice.BeginScene(Game1.spriteBatch);
Game1.currentLocation.Map.GetLayer("Back").Draw(Game1.mapDisplayDevice, Game1.viewport, Location.Origin, false, Game1.pixelZoom);
@@ -679,16 +679,16 @@ namespace StardewModdingAPI.Inheritance
if (Game1.currentBillboard != 0)
this.drawBillboard();
- GraphicsEvents.InvokeOnPreRenderHudEventNoCheck(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPreRenderHudEventNoCheck(this.Monitor);
if ((Game1.displayHUD || Game1.eventUp) && Game1.currentBillboard == 0 && Game1.gameMode == 3 && !Game1.freezeControls && !Game1.panMode)
{
- GraphicsEvents.InvokeOnPreRenderHudEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPreRenderHudEvent(this.Monitor);
SGame.DrawHUD.Invoke(Program.gamePtr, null);
- GraphicsEvents.InvokeOnPostRenderHudEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPostRenderHudEvent(this.Monitor);
}
else if (Game1.activeClickableMenu == null && Game1.farmEvent == null)
Game1.spriteBatch.Draw(Game1.mouseCursors, new Vector2(Game1.getOldMouseX(), Game1.getOldMouseY()), Game1.getSourceRectForStandardTileSheet(Game1.mouseCursors, 0, 16, 16), Color.White, 0f, Vector2.Zero, 4f + Game1.dialogueButtonScale / 150f, SpriteEffects.None, 1f);
- GraphicsEvents.InvokeOnPostRenderHudEventNoCheck(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPostRenderHudEventNoCheck(this.Monitor);
if (Game1.hudMessages.Any() && (!Game1.eventUp || Game1.isFestival()))
{
@@ -737,21 +737,21 @@ namespace StardewModdingAPI.Inheritance
if (Game1.showKeyHelp)
Game1.spriteBatch.DrawString(Game1.smallFont, Game1.keyHelpString, new Vector2(Game1.tileSize, Game1.viewport.Height - Game1.tileSize - (Game1.dialogueUp ? (Game1.tileSize * 3 + (Game1.isQuestion ? (Game1.questionChoices.Count * Game1.tileSize) : 0)) : 0) - Game1.smallFont.MeasureString(Game1.keyHelpString).Y), Color.LightGray, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0.9999999f);
- GraphicsEvents.InvokeOnPreRenderGuiEventNoCheck(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPreRenderGuiEventNoCheck(this.Monitor);
if (Game1.activeClickableMenu != null)
{
- GraphicsEvents.InvokeOnPreRenderGuiEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPreRenderGuiEvent(this.Monitor);
Game1.activeClickableMenu.draw(Game1.spriteBatch);
- GraphicsEvents.InvokeOnPostRenderGuiEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPostRenderGuiEvent(this.Monitor);
}
else
Game1.farmEvent?.drawAboveEverything(Game1.spriteBatch);
- GraphicsEvents.InvokeOnPostRenderGuiEventNoCheck(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPostRenderGuiEventNoCheck(this.Monitor);
- GraphicsEvents.InvokeOnPostRenderEvent(null, EventArgs.Empty);
+ GraphicsEvents.InvokeOnPostRenderEvent(this.Monitor);
Game1.spriteBatch.End();
- GraphicsEvents.InvokeDrawInRenderTargetTick();
+ GraphicsEvents.InvokeDrawInRenderTargetTick(this.Monitor);
if (!this.ZoomLevelIsOne)
{
@@ -780,7 +780,7 @@ namespace StardewModdingAPI.Inheritance
Game1.spriteBatch.DrawString(Game1.smoothFont, message, new Vector2(0, i * 14), Color.CornflowerBlue);
i++;
}
- GraphicsEvents.InvokeDrawDebug(null, EventArgs.Empty);
+ GraphicsEvents.InvokeDrawDebug(this.Monitor);
Game1.spriteBatch.End();
}
@@ -834,11 +834,11 @@ namespace StardewModdingAPI.Inheritance
// raise key pressed
foreach (var key in this.FramePressedKeys)
- ControlEvents.InvokeKeyPressed(key);
+ ControlEvents.InvokeKeyPressed(this.Monitor, key);
// raise key released
foreach (var key in this.FrameReleasedKeys)
- ControlEvents.InvokeKeyReleased(key);
+ ControlEvents.InvokeKeyReleased(this.Monitor, key);
// raise controller button pressed
for (var i = PlayerIndex.One; i <= PlayerIndex.Four; i++)
@@ -847,9 +847,9 @@ namespace StardewModdingAPI.Inheritance
foreach (var button in buttons)
{
if (button == Buttons.LeftTrigger || button == Buttons.RightTrigger)
- ControlEvents.InvokeTriggerPressed(i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
+ ControlEvents.InvokeTriggerPressed(this.Monitor, i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
else
- ControlEvents.InvokeButtonPressed(i, button);
+ ControlEvents.InvokeButtonPressed(this.Monitor, i, button);
}
}
@@ -859,20 +859,20 @@ namespace StardewModdingAPI.Inheritance
foreach (var button in this.GetFrameReleasedButtons(i))
{
if (button == Buttons.LeftTrigger || button == Buttons.RightTrigger)
- ControlEvents.InvokeTriggerReleased(i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
+ ControlEvents.InvokeTriggerReleased(this.Monitor, i, button, button == Buttons.LeftTrigger ? GamePad.GetState(i).Triggers.Left : GamePad.GetState(i).Triggers.Right);
else
- ControlEvents.InvokeButtonReleased(i, button);
+ ControlEvents.InvokeButtonReleased(this.Monitor, i, button);
}
}
// raise keyboard state changed
if (this.KStateNow != this.KStatePrior)
- ControlEvents.InvokeKeyboardChanged(this.KStatePrior, this.KStateNow);
+ ControlEvents.InvokeKeyboardChanged(this.Monitor, this.KStatePrior, this.KStateNow);
// raise mouse state changed
if (this.MStateNow != this.MStatePrior)
{
- ControlEvents.InvokeMouseChanged(this.MStatePrior, this.MStateNow, this.MPositionPrior, this.MPositionNow);
+ ControlEvents.InvokeMouseChanged(this.Monitor, this.MStatePrior, this.MStateNow, this.MPositionPrior, this.MPositionNow);
this.MStatePrior = this.MStateNow;
this.MPositionPrior = this.MPositionPrior;
}
@@ -881,23 +881,23 @@ namespace StardewModdingAPI.Inheritance
if (Game1.activeClickableMenu != this.PreviousActiveMenu)
{
if (Game1.activeClickableMenu != null)
- MenuEvents.InvokeMenuChanged(this.PreviousActiveMenu, Game1.activeClickableMenu);
+ MenuEvents.InvokeMenuChanged(this.Monitor, this.PreviousActiveMenu, Game1.activeClickableMenu);
else
- MenuEvents.InvokeMenuClosed(this.PreviousActiveMenu);
+ MenuEvents.InvokeMenuClosed(this.Monitor, this.PreviousActiveMenu);
this.PreviousActiveMenu = Game1.activeClickableMenu;
}
// raise location list changed
if (this.GetHash(Game1.locations) != this.PreviousGameLocations)
{
- LocationEvents.InvokeLocationsChanged(Game1.locations);
+ LocationEvents.InvokeLocationsChanged(this.Monitor, Game1.locations);
this.PreviousGameLocations = this.GetHash(Game1.locations);
}
// raise current location changed
if (Game1.currentLocation != this.PreviousGameLocation)
{
- LocationEvents.InvokeCurrentLocationChanged(this.PreviousGameLocation, Game1.currentLocation);
+ LocationEvents.InvokeCurrentLocationChanged(this.Monitor, this.PreviousGameLocation, Game1.currentLocation);
this.PreviousGameLocation = Game1.currentLocation;
}
@@ -907,39 +907,39 @@ namespace StardewModdingAPI.Inheritance
// raise player changed
if (Game1.player != this.PreviousFarmer)
{
- PlayerEvents.InvokeFarmerChanged(this.PreviousFarmer, Game1.player);
+ PlayerEvents.InvokeFarmerChanged(this.Monitor, this.PreviousFarmer, Game1.player);
this.PreviousFarmer = Game1.player;
}
// raise player leveled up a skill
if (Game1.player.combatLevel != this.PreviousCombatLevel)
{
- PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Combat, Game1.player.combatLevel);
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Combat, Game1.player.combatLevel);
this.PreviousCombatLevel = Game1.player.combatLevel;
}
if (Game1.player.farmingLevel != this.PreviousFarmingLevel)
{
- PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Farming, Game1.player.farmingLevel);
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Farming, Game1.player.farmingLevel);
this.PreviousFarmingLevel = Game1.player.farmingLevel;
}
if (Game1.player.fishingLevel != this.PreviousFishingLevel)
{
- PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Fishing, Game1.player.fishingLevel);
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Fishing, Game1.player.fishingLevel);
this.PreviousFishingLevel = Game1.player.fishingLevel;
}
if (Game1.player.foragingLevel != this.PreviousForagingLevel)
{
- PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Foraging, Game1.player.foragingLevel);
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Foraging, Game1.player.foragingLevel);
this.PreviousForagingLevel = Game1.player.foragingLevel;
}
if (Game1.player.miningLevel != this.PreviousMiningLevel)
{
- PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Mining, Game1.player.miningLevel);
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Mining, Game1.player.miningLevel);
this.PreviousMiningLevel = Game1.player.miningLevel;
}
if (Game1.player.luckLevel != this.PreviousLuckLevel)
{
- PlayerEvents.InvokeLeveledUp(EventArgsLevelUp.LevelType.Luck, Game1.player.luckLevel);
+ PlayerEvents.InvokeLeveledUp(this.Monitor, EventArgsLevelUp.LevelType.Luck, Game1.player.luckLevel);
this.PreviousLuckLevel = Game1.player.luckLevel;
}
@@ -947,7 +947,7 @@ namespace StardewModdingAPI.Inheritance
ItemStackChange[] changedItems = this.GetInventoryChanges(Game1.player.items, this.PreviousItems).ToArray();
if (changedItems.Any())
{
- PlayerEvents.InvokeInventoryChanged(Game1.player.items, changedItems);
+ PlayerEvents.InvokeInventoryChanged(this.Monitor, Game1.player.items, changedItems);
this.PreviousItems = Game1.player.items.Where(n => n != null).ToDictionary(n => n, n => n.Stack);
}
}
@@ -956,36 +956,36 @@ namespace StardewModdingAPI.Inheritance
int? objectHash = Game1.currentLocation?.objects != null ? this.GetHash(Game1.currentLocation.objects) : (int?)null;
if (objectHash != null && this.PreviousLocationObjects != objectHash)
{
- LocationEvents.InvokeOnNewLocationObject(Game1.currentLocation.objects);
+ LocationEvents.InvokeOnNewLocationObject(this.Monitor, Game1.currentLocation.objects);
this.PreviousLocationObjects = objectHash.Value;
}
// raise time changed
if (Game1.timeOfDay != this.PreviousTimeOfDay)
{
- TimeEvents.InvokeTimeOfDayChanged(this.PreviousTimeOfDay, Game1.timeOfDay);
+ TimeEvents.InvokeTimeOfDayChanged(this.Monitor, this.PreviousTimeOfDay, Game1.timeOfDay);
this.PreviousTimeOfDay = Game1.timeOfDay;
}
if (Game1.dayOfMonth != this.PreviousDayOfMonth)
{
- TimeEvents.InvokeDayOfMonthChanged(this.PreviousDayOfMonth, Game1.dayOfMonth);
+ TimeEvents.InvokeDayOfMonthChanged(this.Monitor, this.PreviousDayOfMonth, Game1.dayOfMonth);
this.PreviousDayOfMonth = Game1.dayOfMonth;
}
if (Game1.currentSeason != this.PreviousSeasonOfYear)
{
- TimeEvents.InvokeSeasonOfYearChanged(this.PreviousSeasonOfYear, Game1.currentSeason);
+ TimeEvents.InvokeSeasonOfYearChanged(this.Monitor, this.PreviousSeasonOfYear, Game1.currentSeason);
this.PreviousSeasonOfYear = Game1.currentSeason;
}
if (Game1.year != this.PreviousYearOfGame)
{
- TimeEvents.InvokeYearOfGameChanged(this.PreviousYearOfGame, Game1.year);
+ TimeEvents.InvokeYearOfGameChanged(this.Monitor, this.PreviousYearOfGame, Game1.year);
this.PreviousYearOfGame = Game1.year;
}
// raise player loaded save (in the following tick to let the game finish updating first)
if (this.FireLoadedGameEvent)
{
- PlayerEvents.InvokeLoadedGame(new EventArgsLoadedGameChanged(Game1.hasLoadedGame));
+ PlayerEvents.InvokeLoadedGame(this.Monitor, new EventArgsLoadedGameChanged(Game1.hasLoadedGame));
this.FireLoadedGameEvent = false;
}
if (Game1.hasLoadedGame != this.PreviouslyLoadedGame)
@@ -997,14 +997,14 @@ namespace StardewModdingAPI.Inheritance
// raise mine level changed
if (Game1.mine != null && Game1.mine.mineLevel != this.PreviousMineLevel)
{
- MineEvents.InvokeMineLevelChanged(this.PreviousMineLevel, Game1.mine.mineLevel);
+ MineEvents.InvokeMineLevelChanged(this.Monitor, this.PreviousMineLevel, Game1.mine.mineLevel);
this.PreviousMineLevel = Game1.mine.mineLevel;
}
// raise game transitioning to new day
if (Game1.newDay != this.PreviousIsNewDay)
{
- TimeEvents.InvokeOnNewDay(this.PreviousDayOfMonth, Game1.dayOfMonth, Game1.newDay);
+ TimeEvents.InvokeOnNewDay(this.Monitor, this.PreviousDayOfMonth, Game1.dayOfMonth, Game1.newDay);
this.PreviousIsNewDay = Game1.newDay;
}
}
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index f3751462..5561aeec 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -206,7 +206,7 @@ namespace StardewModdingAPI
// initialise game instance
Program.gamePtr = new SGame(Program.Monitor) { IsMouseVisible = false };
Program.gamePtr.Exiting += (sender, e) => Program.ready = false;
- Program.gamePtr.Window.ClientSizeChanged += GraphicsEvents.InvokeResize;
+ Program.gamePtr.Window.ClientSizeChanged += (sender, e) => GraphicsEvents.InvokeResize(Program.Monitor, sender, e);
Program.gamePtr.Window.Title = $"Stardew Valley - Version {Game1.version}";
Program.StardewGameInfo.SetValue(Program.StardewProgramType, Program.gamePtr);
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index e0608cce..0b6a185e 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -199,6 +199,7 @@
<Compile Include="Extensions.cs" />
<Compile Include="Framework\DeprecationLevel.cs" />
<Compile Include="Framework\DeprecationManager.cs" />
+ <Compile Include="Framework\InternalExtensions.cs" />
<Compile Include="IModHelper.cs" />
<Compile Include="Framework\LogFileManager.cs" />
<Compile Include="LogLevel.cs" />