From 8df578edb6d135796a48b219ecc7a7291c7ef460 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 13 Jul 2021 09:14:07 -0400 Subject: migrate to Harmony 2.1 (#711) --- src/SMAPI/Patches/LoadContextPatch.cs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index c43d7071..721cf53d 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -1,10 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif using StardewModdingAPI.Enums; using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; @@ -46,11 +42,7 @@ namespace StardewModdingAPI.Patches } /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { // detect CreatedBasicInfo harmony.Patch( -- cgit From aa65b2e2f6ae2578f9d1f81d6fc1f4c5a261d90f Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 30 Jul 2021 00:34:53 -0400 Subject: split patch classes which target multiple types --- src/SMAPI/Patches/LoadContextPatch.cs | 15 ---------- src/SMAPI/Patches/TitleMenuPatcher.cs | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 15 deletions(-) create mode 100644 src/SMAPI/Patches/TitleMenuPatcher.cs (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index 721cf53d..c7f7d986 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -44,12 +44,6 @@ namespace StardewModdingAPI.Patches /// public void Apply(Harmony harmony) { - // detect CreatedBasicInfo - harmony.Patch( - original: AccessTools.Method(typeof(TitleMenu), nameof(TitleMenu.createdNewCharacter)), - prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_TitleMenu_CreatedNewCharacter)) - ); - // detect CreatedInitialLocations and SaveAddedLocations harmony.Patch( original: AccessTools.Method(typeof(Game1), nameof(Game1.AddModNPCs)), @@ -74,15 +68,6 @@ namespace StardewModdingAPI.Patches /********* ** Private methods *********/ - /// Called before . - /// 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 Before_TitleMenu_CreatedNewCharacter() - { - LoadContextPatch.OnStageChanged(LoadStage.CreatedBasicInfo); - return true; - } - /// Called before . /// Returns whether to execute the original method. /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. diff --git a/src/SMAPI/Patches/TitleMenuPatcher.cs b/src/SMAPI/Patches/TitleMenuPatcher.cs new file mode 100644 index 00000000..a889adfc --- /dev/null +++ b/src/SMAPI/Patches/TitleMenuPatcher.cs @@ -0,0 +1,56 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using HarmonyLib; +using StardewModdingAPI.Enums; +using StardewModdingAPI.Framework.Patching; +using StardewValley.Menus; + +namespace StardewModdingAPI.Patches +{ + /// Harmony patches which notify SMAPI for save creation load stages. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + internal class TitleMenuPatcher : IHarmonyPatch + { + /********* + ** Fields + *********/ + /// A callback to invoke when the load stage changes. + private static Action OnStageChanged; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// A callback to invoke when the load stage changes. + public TitleMenuPatcher(Action onStageChanged) + { + TitleMenuPatcher.OnStageChanged = onStageChanged; + } + + /// + public void Apply(Harmony harmony) + { + // detect CreatedBasicInfo + harmony.Patch( + original: AccessTools.Method(typeof(TitleMenu), nameof(TitleMenu.createdNewCharacter)), + prefix: new HarmonyMethod(this.GetType(), nameof(TitleMenuPatcher.Before_TitleMenu_CreatedNewCharacter)) + ); + } + + + /********* + ** Private methods + *********/ + /// Called before . + /// 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 Before_TitleMenu_CreatedNewCharacter() + { + TitleMenuPatcher.OnStageChanged(LoadStage.CreatedBasicInfo); + return true; + } + } +} -- cgit From 4074f697d73f5cac6699836550b144fd0c4e2803 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 30 Jul 2021 00:40:12 -0400 Subject: rename patch classes for consistency --- src/SMAPI/Patches/Game1Patcher.cs | 125 ++++++++++++++++++++++++++++++++++ src/SMAPI/Patches/LoadContextPatch.cs | 125 ---------------------------------- 2 files changed, 125 insertions(+), 125 deletions(-) create mode 100644 src/SMAPI/Patches/Game1Patcher.cs delete mode 100644 src/SMAPI/Patches/LoadContextPatch.cs (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/Game1Patcher.cs b/src/SMAPI/Patches/Game1Patcher.cs new file mode 100644 index 00000000..82b13869 --- /dev/null +++ b/src/SMAPI/Patches/Game1Patcher.cs @@ -0,0 +1,125 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using HarmonyLib; +using StardewModdingAPI.Enums; +using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Framework.Reflection; +using StardewValley; +using StardewValley.Menus; +using StardewValley.Minigames; + +namespace StardewModdingAPI.Patches +{ + /// Harmony patches which notify SMAPI for save creation load stages. + /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. + [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] + internal class Game1Patcher : 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 the game is running running the code in . + private static bool IsInLoadForNewGame; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Simplifies access to private code. + /// A callback to invoke when the load stage changes. + public Game1Patcher(Reflector reflection, Action onStageChanged) + { + Game1Patcher.Reflection = reflection; + Game1Patcher.OnStageChanged = onStageChanged; + } + + /// + public void Apply(Harmony harmony) + { + // detect CreatedInitialLocations and SaveAddedLocations + harmony.Patch( + original: AccessTools.Method(typeof(Game1), nameof(Game1.AddModNPCs)), + prefix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.Before_Game1_AddModNPCs)) + ); + + // detect CreatedLocations, and track IsInLoadForNewGame + harmony.Patch( + original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), + prefix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.Before_Game1_LoadForNewGame)), + postfix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.After_Game1_LoadForNewGame)) + ); + + // detect ReturningToTitle + harmony.Patch( + original: AccessTools.Method(typeof(Game1), nameof(Game1.CleanupReturningToTitle)), + prefix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.Before_Game1_CleanupReturningToTitle)) + ); + } + + + /********* + ** Private methods + *********/ + /// Called before . + /// 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 Before_Game1_AddModNPCs() + { + // When this method is called from Game1.loadForNewGame, it happens right after adding the vanilla + // locations but before initializing them. + if (Game1Patcher.IsInLoadForNewGame) + { + Game1Patcher.OnStageChanged(Game1Patcher.IsCreating() + ? LoadStage.CreatedInitialLocations + : LoadStage.SaveAddedLocations + ); + } + + return true; + } + + /// Called before . + /// 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 Before_Game1_CleanupReturningToTitle() + { + Game1Patcher.OnStageChanged(LoadStage.ReturningToTitle); + return true; + } + + /// Called before . + /// 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 Before_Game1_LoadForNewGame() + { + Game1Patcher.IsInLoadForNewGame = true; + return true; + } + + /// Called after . + /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. + private static void After_Game1_LoadForNewGame() + { + Game1Patcher.IsInLoadForNewGame = false; + + if (Game1Patcher.IsCreating()) + Game1Patcher.OnStageChanged(LoadStage.CreatedLocations); + } + + /// Get whether the save file is currently being created. + private static bool IsCreating() + { + return + (Game1.currentMinigame is Intro) // creating save with intro + || (Game1.activeClickableMenu is TitleMenu menu && Game1Patcher.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue()); // creating save, skipped intro + } + } +} diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs deleted file mode 100644 index c7f7d986..00000000 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using HarmonyLib; -using StardewModdingAPI.Enums; -using StardewModdingAPI.Framework.Patching; -using StardewModdingAPI.Framework.Reflection; -using StardewValley; -using StardewValley.Menus; -using StardewValley.Minigames; - -namespace StardewModdingAPI.Patches -{ - /// Harmony patches which notify SMAPI for save creation load stages. - /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. - [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] - [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] - 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 the game is running running the code in . - private static bool IsInLoadForNewGame; - - - /********* - ** 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; - } - - /// - public void Apply(Harmony harmony) - { - // detect CreatedInitialLocations and SaveAddedLocations - harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.AddModNPCs)), - prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_AddModNPCs)) - ); - - // detect CreatedLocations, and track IsInLoadForNewGame - harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), - prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_LoadForNewGame)), - postfix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.After_Game1_LoadForNewGame)) - ); - - // detect ReturningToTitle - harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.CleanupReturningToTitle)), - prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_CleanupReturningToTitle)) - ); - } - - - /********* - ** Private methods - *********/ - /// Called before . - /// 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 Before_Game1_AddModNPCs() - { - // When this method is called from Game1.loadForNewGame, it happens right after adding the vanilla - // locations but before initializing them. - if (LoadContextPatch.IsInLoadForNewGame) - { - LoadContextPatch.OnStageChanged(LoadContextPatch.IsCreating() - ? LoadStage.CreatedInitialLocations - : LoadStage.SaveAddedLocations - ); - } - - return true; - } - - /// Called before . - /// 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 Before_Game1_CleanupReturningToTitle() - { - LoadContextPatch.OnStageChanged(LoadStage.ReturningToTitle); - return true; - } - - /// Called before . - /// 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 Before_Game1_LoadForNewGame() - { - LoadContextPatch.IsInLoadForNewGame = true; - return true; - } - - /// Called after . - /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - private static void After_Game1_LoadForNewGame() - { - LoadContextPatch.IsInLoadForNewGame = false; - - if (LoadContextPatch.IsCreating()) - LoadContextPatch.OnStageChanged(LoadStage.CreatedLocations); - } - - /// Get whether the save file is currently being created. - private static bool IsCreating() - { - return - (Game1.currentMinigame is Intro) // creating save with intro - || (Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue()); // creating save, skipped intro - } - } -} -- cgit From 948c800a98f00b1bdcfd05ee6228e3423f9eb465 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 30 Jul 2021 00:54:15 -0400 Subject: migrate to the new Harmony patch pattern used in my mods That improves validation and error-handling. --- src/SMAPI/Patches/Game1Patcher.cs | 38 +++++++++++++++++------------------ src/SMAPI/Patches/TitleMenuPatcher.cs | 17 ++++++++-------- 2 files changed, 27 insertions(+), 28 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/Game1Patcher.cs b/src/SMAPI/Patches/Game1Patcher.cs index 82b13869..173a2055 100644 --- a/src/SMAPI/Patches/Game1Patcher.cs +++ b/src/SMAPI/Patches/Game1Patcher.cs @@ -2,19 +2,19 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; using StardewModdingAPI.Enums; -using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Internal.Patching; using StardewValley; using StardewValley.Menus; using StardewValley.Minigames; namespace StardewModdingAPI.Patches { - /// Harmony patches which notify SMAPI for save creation load stages. + /// Harmony patches for which notify SMAPI for save load stages. /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] - internal class Game1Patcher : IHarmonyPatch + internal class Game1Patcher : BasePatcher { /********* ** Fields @@ -42,25 +42,25 @@ namespace StardewModdingAPI.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { // detect CreatedInitialLocations and SaveAddedLocations harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.AddModNPCs)), - prefix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.Before_Game1_AddModNPCs)) + original: this.RequireMethod(nameof(Game1.AddModNPCs)), + prefix: this.GetHarmonyMethod(nameof(Game1Patcher.Before_AddModNpcs)) ); // detect CreatedLocations, and track IsInLoadForNewGame harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)), - prefix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.Before_Game1_LoadForNewGame)), - postfix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.After_Game1_LoadForNewGame)) + original: this.RequireMethod(nameof(Game1.loadForNewGame)), + prefix: this.GetHarmonyMethod(nameof(Game1Patcher.Before_LoadForNewGame)), + postfix: this.GetHarmonyMethod(nameof(Game1Patcher.After_LoadForNewGame)) ); // detect ReturningToTitle harmony.Patch( - original: AccessTools.Method(typeof(Game1), nameof(Game1.CleanupReturningToTitle)), - prefix: new HarmonyMethod(this.GetType(), nameof(Game1Patcher.Before_Game1_CleanupReturningToTitle)) + original: this.RequireMethod(nameof(Game1.CleanupReturningToTitle)), + prefix: this.GetHarmonyMethod(nameof(Game1Patcher.Before_CleanupReturningToTitle)) ); } @@ -68,10 +68,10 @@ namespace StardewModdingAPI.Patches /********* ** Private methods *********/ - /// Called before . + /// The method to call before . /// 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 Before_Game1_AddModNPCs() + private static bool Before_AddModNpcs() { // When this method is called from Game1.loadForNewGame, it happens right after adding the vanilla // locations but before initializing them. @@ -86,27 +86,27 @@ namespace StardewModdingAPI.Patches return true; } - /// Called before . + /// The method to call before . /// 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 Before_Game1_CleanupReturningToTitle() + private static bool Before_CleanupReturningToTitle() { Game1Patcher.OnStageChanged(LoadStage.ReturningToTitle); return true; } - /// Called before . + /// The method to call before . /// 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 Before_Game1_LoadForNewGame() + private static bool Before_LoadForNewGame() { Game1Patcher.IsInLoadForNewGame = true; return true; } - /// Called after . + /// The method to call after . /// This method must be static for Harmony to work correctly. See the Harmony documentation before renaming arguments. - private static void After_Game1_LoadForNewGame() + private static void After_LoadForNewGame() { Game1Patcher.IsInLoadForNewGame = false; diff --git a/src/SMAPI/Patches/TitleMenuPatcher.cs b/src/SMAPI/Patches/TitleMenuPatcher.cs index a889adfc..b4320ce0 100644 --- a/src/SMAPI/Patches/TitleMenuPatcher.cs +++ b/src/SMAPI/Patches/TitleMenuPatcher.cs @@ -2,16 +2,16 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; using StardewModdingAPI.Enums; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley.Menus; namespace StardewModdingAPI.Patches { - /// Harmony patches which notify SMAPI for save creation load stages. + /// Harmony patches for which notify SMAPI when a new character was created. /// Patch methods must be static for Harmony to work correctly. See the Harmony documentation before renaming patch arguments. [SuppressMessage("ReSharper", "InconsistentNaming", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] [SuppressMessage("ReSharper", "IdentifierTypo", Justification = "Argument names are defined by Harmony and methods are named for clarity.")] - internal class TitleMenuPatcher : IHarmonyPatch + internal class TitleMenuPatcher : BasePatcher { /********* ** Fields @@ -31,12 +31,11 @@ namespace StardewModdingAPI.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { - // detect CreatedBasicInfo harmony.Patch( - original: AccessTools.Method(typeof(TitleMenu), nameof(TitleMenu.createdNewCharacter)), - prefix: new HarmonyMethod(this.GetType(), nameof(TitleMenuPatcher.Before_TitleMenu_CreatedNewCharacter)) + original: this.RequireMethod(nameof(TitleMenu.createdNewCharacter)), + prefix: this.GetHarmonyMethod(nameof(TitleMenuPatcher.Before_CreatedNewCharacter)) ); } @@ -44,10 +43,10 @@ namespace StardewModdingAPI.Patches /********* ** Private methods *********/ - /// Called before . + /// The method to call before . /// 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 Before_TitleMenu_CreatedNewCharacter() + private static bool Before_CreatedNewCharacter() { TitleMenuPatcher.OnStageChanged(LoadStage.CreatedBasicInfo); return true; -- cgit