From 8595a2a6faffe7af81c6401cd6308f84fbefdd01 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 10 May 2019 23:25:07 -0400 Subject: make Harmony patch names more consistent --- src/SMAPI/Framework/SCore.cs | 4 +- .../Patches/CheckEventPreconditionErrorPatch.cs | 84 ---------------- src/SMAPI/Patches/EventErrorPatch.cs | 84 ++++++++++++++++ src/SMAPI/Patches/LoadContextPatch.cs | 108 +++++++++++++++++++++ src/SMAPI/Patches/LoadForNewGamePatch.cs | 108 --------------------- src/SMAPI/StardewModdingAPI.csproj | 6 +- 6 files changed, 197 insertions(+), 197 deletions(-) delete mode 100644 src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs create mode 100644 src/SMAPI/Patches/EventErrorPatch.cs create mode 100644 src/SMAPI/Patches/LoadContextPatch.cs delete mode 100644 src/SMAPI/Patches/LoadForNewGamePatch.cs (limited to 'src') diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index a0fe1241..5dd52992 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -233,10 +233,10 @@ namespace StardewModdingAPI.Framework // apply game patches new GamePatcher(this.Monitor).Apply( - new CheckEventPreconditionErrorPatch(this.MonitorForGame), + new EventErrorPatch(this.MonitorForGame), new DialogueErrorPatch(this.MonitorForGame, this.Reflection), new ObjectErrorPatch(), - new LoadForNewGamePatch(this.Reflection, this.GameInstance.OnLoadStageChanged) + new LoadContextPatch(this.Reflection, this.GameInstance.OnLoadStageChanged) ); // add exit handler diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs deleted file mode 100644 index c2a16391..00000000 --- a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using Harmony; -using StardewModdingAPI.Framework.Patching; -using StardewValley; - -namespace StardewModdingAPI.Patches -{ - /// A Harmony patch for the constructor which intercepts invalid dialogue lines and logs an error instead of crashing. - internal class CheckEventPreconditionErrorPatch : IHarmonyPatch - { - /********* - ** Fields - *********/ - /// Writes messages to the console and log file on behalf of the game. - private static IMonitor MonitorForGame; - - /// Whether the method is currently being intercepted. - private static bool IsIntercepted; - - - /********* - ** Accessors - *********/ - /// A unique name for this patch. - public string Name => $"{nameof(CheckEventPreconditionErrorPatch)}"; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// Writes messages to the console and log file on behalf of the game. - public CheckEventPreconditionErrorPatch(IMonitor monitorForGame) - { - CheckEventPreconditionErrorPatch.MonitorForGame = monitorForGame; - } - - /// Apply the Harmony patch. - /// The Harmony instance. - public void Apply(HarmonyInstance harmony) - { - harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), - prefix: new HarmonyMethod(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix)) - ); - } - - - /********* - ** Private methods - *********/ - /// The method to call instead of the GameLocation.CheckEventPrecondition. - /// The instance being patched. - /// The return value of the original method. - /// The precondition to be parsed. - /// The method being wrapped. - /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] - private static bool Prefix(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) - { - if (CheckEventPreconditionErrorPatch.IsIntercepted) - return true; - - try - { - CheckEventPreconditionErrorPatch.IsIntercepted = true; - __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition }); - return false; - } - catch (TargetInvocationException ex) - { - __result = -1; - CheckEventPreconditionErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error); - return false; - } - finally - { - CheckEventPreconditionErrorPatch.IsIntercepted = false; - } - } - } -} diff --git a/src/SMAPI/Patches/EventErrorPatch.cs b/src/SMAPI/Patches/EventErrorPatch.cs new file mode 100644 index 00000000..b0074356 --- /dev/null +++ b/src/SMAPI/Patches/EventErrorPatch.cs @@ -0,0 +1,84 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Harmony; +using StardewModdingAPI.Framework.Patching; +using StardewValley; + +namespace StardewModdingAPI.Patches +{ + /// A Harmony patch for the constructor which intercepts invalid dialogue lines and logs an error instead of crashing. + internal class EventErrorPatch : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// Writes messages to the console and log file on behalf of the game. + private static IMonitor MonitorForGame; + + /// Whether the method is currently being intercepted. + private static bool IsIntercepted; + + + /********* + ** Accessors + *********/ + /// A unique name for this patch. + public string Name => $"{nameof(EventErrorPatch)}"; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Writes messages to the console and log file on behalf of the game. + public EventErrorPatch(IMonitor monitorForGame) + { + EventErrorPatch.MonitorForGame = monitorForGame; + } + + /// Apply the Harmony patch. + /// The Harmony instance. + public void Apply(HarmonyInstance harmony) + { + harmony.Patch( + original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), + prefix: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Prefix)) + ); + } + + + /********* + ** Private methods + *********/ + /// The method to call instead of the GameLocation.CheckEventPrecondition. + /// The instance being patched. + /// The return value of the original method. + /// The precondition to be parsed. + /// The method being wrapped. + /// Returns whether to execute the original method. + /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony.")] + private static bool Prefix(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) + { + if (EventErrorPatch.IsIntercepted) + return true; + + try + { + EventErrorPatch.IsIntercepted = true; + __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition }); + return false; + } + catch (TargetInvocationException ex) + { + __result = -1; + EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error); + return false; + } + finally + { + EventErrorPatch.IsIntercepted = false; + } + } + } +} diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs new file mode 100644 index 00000000..43e09573 --- /dev/null +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using Harmony; +using StardewModdingAPI.Enums; +using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Framework.Reflection; +using StardewValley; +using StardewValley.Menus; + +namespace StardewModdingAPI.Patches +{ + /// A Harmony patch for which notifies SMAPI for save creation load stages. + /// This patch hooks into , checks if TitleMenu.transitioningCharacterCreationMenu is true (which means the player is creating a new save file), then raises after the location list is cleared twice (the second clear happens right before locations are created), and when the method ends. + internal class LoadContextPatch : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// Simplifies access to private code. + private static Reflector Reflection; + + /// A callback to invoke when the load stage changes. + private static Action OnStageChanged; + + /// Whether was called as part of save creation. + private static bool IsCreating; + + /// The number of times that has been cleared since started. + private static int TimesLocationsCleared; + + + /********* + ** Accessors + *********/ + /// A unique name for this patch. + public string Name => $"{nameof(LoadContextPatch)}"; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Simplifies access to private code. + /// A callback to invoke when the load stage changes. + public LoadContextPatch(Reflector reflection, Action onStageChanged) + { + LoadContextPatch.Reflection = reflection; + LoadContextPatch.OnStageChanged = onStageChanged; + } + + /// Apply the Harmony patch. + /// The Harmony instance. + public void Apply(HarmonyInstance harmony) + { + harmony.Patch( + original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), + prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Prefix)), + postfix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Postfix)) + ); + } + + + /********* + ** Private methods + *********/ + /// The method to call instead of . + /// Returns whether to execute the original method. + /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. + private static bool Prefix() + { + LoadContextPatch.IsCreating = Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue(); + LoadContextPatch.TimesLocationsCleared = 0; + if (LoadContextPatch.IsCreating) + { + // raise CreatedBasicInfo after locations are cleared twice + ObservableCollection locations = (ObservableCollection)Game1.locations; + locations.CollectionChanged += LoadContextPatch.OnLocationListChanged; + } + + return true; + } + + /// The method to call instead after . + /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. + private static void Postfix() + { + if (LoadContextPatch.IsCreating) + { + // clean up + ObservableCollection locations = (ObservableCollection)Game1.locations; + locations.CollectionChanged -= LoadContextPatch.OnLocationListChanged; + + // raise stage changed + LoadContextPatch.OnStageChanged(LoadStage.CreatedLocations); + } + } + + /// Raised when changes. + /// The event sender. + /// The event arguments. + private static void OnLocationListChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (++LoadContextPatch.TimesLocationsCleared == 2) + LoadContextPatch.OnStageChanged(LoadStage.CreatedBasicInfo); + } + } +} diff --git a/src/SMAPI/Patches/LoadForNewGamePatch.cs b/src/SMAPI/Patches/LoadForNewGamePatch.cs deleted file mode 100644 index def7134d..00000000 --- a/src/SMAPI/Patches/LoadForNewGamePatch.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using Harmony; -using StardewModdingAPI.Enums; -using StardewModdingAPI.Framework.Patching; -using StardewModdingAPI.Framework.Reflection; -using StardewValley; -using StardewValley.Menus; - -namespace StardewModdingAPI.Patches -{ - /// A Harmony patch for which notifies SMAPI for save creation load stages. - /// This patch hooks into , checks if TitleMenu.transitioningCharacterCreationMenu is true (which means the player is creating a new save file), then raises after the location list is cleared twice (the second clear happens right before locations are created), and when the method ends. - internal class LoadForNewGamePatch : IHarmonyPatch - { - /********* - ** Fields - *********/ - /// Simplifies access to private code. - private static Reflector Reflection; - - /// A callback to invoke when the load stage changes. - private static Action OnStageChanged; - - /// Whether was called as part of save creation. - private static bool IsCreating; - - /// The number of times that has been cleared since started. - private static int TimesLocationsCleared; - - - /********* - ** Accessors - *********/ - /// A unique name for this patch. - public string Name => $"{nameof(LoadForNewGamePatch)}"; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// Simplifies access to private code. - /// A callback to invoke when the load stage changes. - public LoadForNewGamePatch(Reflector reflection, Action onStageChanged) - { - LoadForNewGamePatch.Reflection = reflection; - LoadForNewGamePatch.OnStageChanged = onStageChanged; - } - - /// Apply the Harmony patch. - /// The Harmony instance. - public void Apply(HarmonyInstance harmony) - { - harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), - prefix: new HarmonyMethod(this.GetType(), nameof(LoadForNewGamePatch.Prefix)), - postfix: new HarmonyMethod(this.GetType(), nameof(LoadForNewGamePatch.Postfix)) - ); - } - - - /********* - ** Private methods - *********/ - /// The method to call instead of . - /// Returns whether to execute the original method. - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - private static bool Prefix() - { - LoadForNewGamePatch.IsCreating = Game1.activeClickableMenu is TitleMenu menu && LoadForNewGamePatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue(); - LoadForNewGamePatch.TimesLocationsCleared = 0; - if (LoadForNewGamePatch.IsCreating) - { - // raise CreatedBasicInfo after locations are cleared twice - ObservableCollection locations = (ObservableCollection)Game1.locations; - locations.CollectionChanged += LoadForNewGamePatch.OnLocationListChanged; - } - - return true; - } - - /// The method to call instead after . - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - private static void Postfix() - { - if (LoadForNewGamePatch.IsCreating) - { - // clean up - ObservableCollection locations = (ObservableCollection)Game1.locations; - locations.CollectionChanged -= LoadForNewGamePatch.OnLocationListChanged; - - // raise stage changed - LoadForNewGamePatch.OnStageChanged(LoadStage.CreatedLocations); - } - } - - /// Raised when changes. - /// The event sender. - /// The event arguments. - private static void OnLocationListChanged(object sender, NotifyCollectionChangedEventArgs e) - { - if (++LoadForNewGamePatch.TimesLocationsCleared == 2) - LoadForNewGamePatch.OnStageChanged(LoadStage.CreatedBasicInfo); - } - } -} diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj index 5991dd7e..673deab0 100644 --- a/src/SMAPI/StardewModdingAPI.csproj +++ b/src/SMAPI/StardewModdingAPI.csproj @@ -330,10 +330,10 @@ - - - + + + -- cgit