From accaa6c0e03e99411d7b10f938dd17b142b8eedc Mon Sep 17 00:00:00 2001 From: berkay2578 Date: Sun, 14 Apr 2019 12:29:23 +0300 Subject: checkEventPrecondition crash fix --- .../Patches/CheckEventPreconditionErrorPatch.cs | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs new file mode 100644 index 00000000..63eca5d7 --- /dev/null +++ b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs @@ -0,0 +1,77 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +using Harmony; + +using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Framework.Reflection; + +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 { + /********* + ** Private methods + *********/ + /// Writes messages to the console and log file on behalf of the game. + private static IMonitor MonitorForGame; + + /// Local variable to store the patched method. + private static MethodInfo method; + /// Local variable to check if the method was already arbitrated. + private static bool isArbitrated; + + + /********* + ** 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. + /// Simplifies access to private code. + public CheckEventPreconditionErrorPatch(IMonitor monitorForGame, Reflector reflector) { + CheckEventPreconditionErrorPatch.MonitorForGame = monitorForGame; + } + + + /// Apply the Harmony patch. + /// The Harmony instance. + public void Apply(HarmonyInstance harmony) { + method = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); + MethodInfo transpiler = AccessTools.Method(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix)); + harmony.Patch(method, new HarmonyMethod(transpiler)); + } + + /********* + ** Private methods + *********/ + /// The method to call instead of the GameLocation.CheckEventPrecondition. + /// The instance being patched. + /// The precondition to be parsed. + /// 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, string precondition) { + if (isArbitrated) { + isArbitrated = false; + return true; + } else { + isArbitrated = true; + try { + method.Invoke(__instance, new object[] { precondition }); + } catch (System.Exception ex) { + CheckEventPreconditionErrorPatch.MonitorForGame.Log($"Failed parsing event info. Event precondition: {precondition}\n{ex}", LogLevel.Error); + } + + return false; + } + } + } +} -- cgit From a13af946e21b12953454540ef4e3ef54dbe50f2d Mon Sep 17 00:00:00 2001 From: berkay2578 Date: Sun, 14 Apr 2019 19:29:47 +0300 Subject: Implement the return value of the original method --- src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs index 63eca5d7..54168969 100644 --- a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs +++ b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs @@ -17,8 +17,8 @@ namespace StardewModdingAPI.Patches { /// Writes messages to the console and log file on behalf of the game. private static IMonitor MonitorForGame; - /// Local variable to store the patched method. - private static MethodInfo method; + /// Local variable to store the original method. + private static MethodInfo originalMethod; /// Local variable to check if the method was already arbitrated. private static bool isArbitrated; @@ -44,9 +44,8 @@ namespace StardewModdingAPI.Patches { /// Apply the Harmony patch. /// The Harmony instance. public void Apply(HarmonyInstance harmony) { - method = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); - MethodInfo transpiler = AccessTools.Method(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix)); - harmony.Patch(method, new HarmonyMethod(transpiler)); + originalMethod = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); + harmony.Patch(originalMethod, new HarmonyMethod(AccessTools.Method(this.GetType(), "Prefix"))); } /********* @@ -54,19 +53,22 @@ namespace StardewModdingAPI.Patches { *********/ /// 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. /// 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, string precondition) { + private static bool Prefix(GameLocation __instance, ref int __result, string precondition) { if (isArbitrated) { isArbitrated = false; return true; } else { isArbitrated = true; try { - method.Invoke(__instance, new object[] { precondition }); + object _ = originalMethod.Invoke(__instance, new object[] { precondition }); + __result = _ is null ? -1 : (int)_; } catch (System.Exception ex) { + __result = -1; CheckEventPreconditionErrorPatch.MonitorForGame.Log($"Failed parsing event info. Event precondition: {precondition}\n{ex}", LogLevel.Error); } -- cgit From 05bfd33ac4d4d089ed88fddcc8f8304ffb99f1f4 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Apr 2019 21:17:51 -0400 Subject: fix formatting and code style (#636) --- .../Patches/CheckEventPreconditionErrorPatch.cs | 59 ++++++++++++---------- src/SMAPI/Patches/DialogueErrorPatch.cs | 2 +- src/SMAPI/Patches/LoadForNewGamePatch.cs | 2 +- 3 files changed, 35 insertions(+), 28 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs index 54168969..b62cf41c 100644 --- a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs +++ b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs @@ -1,26 +1,25 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; - using Harmony; - using StardewModdingAPI.Framework.Patching; -using StardewModdingAPI.Framework.Reflection; - using StardewValley; -namespace StardewModdingAPI.Patches { +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 { + internal class CheckEventPreconditionErrorPatch : IHarmonyPatch + { /********* - ** Private methods + ** Fields *********/ /// Writes messages to the console and log file on behalf of the game. private static IMonitor MonitorForGame; - /// Local variable to store the original method. - private static MethodInfo originalMethod; - /// Local variable to check if the method was already arbitrated. - private static bool isArbitrated; + /// The method being wrapped. + private static MethodInfo OriginalMethod; + + /// Whether the method is currently being intercepted. + private static bool IsArbitrated; /********* @@ -35,19 +34,20 @@ namespace StardewModdingAPI.Patches { *********/ /// Construct an instance. /// Writes messages to the console and log file on behalf of the game. - /// Simplifies access to private code. - public CheckEventPreconditionErrorPatch(IMonitor monitorForGame, Reflector reflector) { + public CheckEventPreconditionErrorPatch(IMonitor monitorForGame) + { CheckEventPreconditionErrorPatch.MonitorForGame = monitorForGame; } - /// Apply the Harmony patch. /// The Harmony instance. - public void Apply(HarmonyInstance harmony) { - originalMethod = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); - harmony.Patch(originalMethod, new HarmonyMethod(AccessTools.Method(this.GetType(), "Prefix"))); + public void Apply(HarmonyInstance harmony) + { + CheckEventPreconditionErrorPatch.OriginalMethod = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); + harmony.Patch(CheckEventPreconditionErrorPatch.OriginalMethod, new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix)))); } + /********* ** Private methods *********/ @@ -58,16 +58,23 @@ namespace StardewModdingAPI.Patches { /// 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) { - if (isArbitrated) { - isArbitrated = false; + private static bool Prefix(GameLocation __instance, ref int __result, string precondition) + { + if (CheckEventPreconditionErrorPatch.IsArbitrated) + { + CheckEventPreconditionErrorPatch.IsArbitrated = false; return true; - } else { - isArbitrated = true; - try { - object _ = originalMethod.Invoke(__instance, new object[] { precondition }); - __result = _ is null ? -1 : (int)_; - } catch (System.Exception ex) { + } + else + { + CheckEventPreconditionErrorPatch.IsArbitrated = true; + try + { + object isValid = CheckEventPreconditionErrorPatch.OriginalMethod.Invoke(__instance, new object[] { precondition }); + __result = isValid is null ? -1 : (int)isValid; + } + catch (System.Exception ex) + { __result = -1; CheckEventPreconditionErrorPatch.MonitorForGame.Log($"Failed parsing event info. Event precondition: {precondition}\n{ex}", LogLevel.Error); } diff --git a/src/SMAPI/Patches/DialogueErrorPatch.cs b/src/SMAPI/Patches/DialogueErrorPatch.cs index d8905fd1..5af6ceef 100644 --- a/src/SMAPI/Patches/DialogueErrorPatch.cs +++ b/src/SMAPI/Patches/DialogueErrorPatch.cs @@ -13,7 +13,7 @@ namespace StardewModdingAPI.Patches internal class DialogueErrorPatch : IHarmonyPatch { /********* - ** Private methods + ** Fields *********/ /// Writes messages to the console and log file on behalf of the game. private static IMonitor MonitorForGame; diff --git a/src/SMAPI/Patches/LoadForNewGamePatch.cs b/src/SMAPI/Patches/LoadForNewGamePatch.cs index 9e788e84..f4ce2023 100644 --- a/src/SMAPI/Patches/LoadForNewGamePatch.cs +++ b/src/SMAPI/Patches/LoadForNewGamePatch.cs @@ -16,7 +16,7 @@ namespace StardewModdingAPI.Patches internal class LoadForNewGamePatch : IHarmonyPatch { /********* - ** Accessors + ** Fields *********/ /// Simplifies access to private code. private static Reflector Reflection; -- cgit From bac92d6f26af84f3492db1fc8d1724155d6245ee Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Apr 2019 21:32:49 -0400 Subject: log underlying error (#636) --- src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs index b62cf41c..673fae1c 100644 --- a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs +++ b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs @@ -70,16 +70,15 @@ namespace StardewModdingAPI.Patches CheckEventPreconditionErrorPatch.IsArbitrated = true; try { - object isValid = CheckEventPreconditionErrorPatch.OriginalMethod.Invoke(__instance, new object[] { precondition }); - __result = isValid is null ? -1 : (int)isValid; + __result = (int)CheckEventPreconditionErrorPatch.OriginalMethod.Invoke(__instance, new object[] { precondition }); + return false; } - catch (System.Exception ex) + catch (TargetInvocationException ex) { __result = -1; - CheckEventPreconditionErrorPatch.MonitorForGame.Log($"Failed parsing event info. Event precondition: {precondition}\n{ex}", LogLevel.Error); + CheckEventPreconditionErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error); + return false; } - - return false; } } } -- cgit From 9732ddb2759774e6b22c9414e3f5341865257270 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Apr 2019 21:55:11 -0400 Subject: avoid possible invalid state if checkEventPrecondition is called asynchronously (#636) --- .../Patches/CheckEventPreconditionErrorPatch.cs | 45 +++++++++++----------- 1 file changed, 22 insertions(+), 23 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs index 673fae1c..74cfbfb0 100644 --- a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs +++ b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs @@ -15,11 +15,8 @@ namespace StardewModdingAPI.Patches /// Writes messages to the console and log file on behalf of the game. private static IMonitor MonitorForGame; - /// The method being wrapped. - private static MethodInfo OriginalMethod; - /// Whether the method is currently being intercepted. - private static bool IsArbitrated; + private static bool IsIntercepted; /********* @@ -43,8 +40,10 @@ namespace StardewModdingAPI.Patches /// The Harmony instance. public void Apply(HarmonyInstance harmony) { - CheckEventPreconditionErrorPatch.OriginalMethod = AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"); - harmony.Patch(CheckEventPreconditionErrorPatch.OriginalMethod, new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix)))); + harmony.Patch( + original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), + prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix))) + ); } @@ -55,30 +54,30 @@ namespace StardewModdingAPI.Patches /// 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) + private static bool Prefix(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) { - if (CheckEventPreconditionErrorPatch.IsArbitrated) - { - CheckEventPreconditionErrorPatch.IsArbitrated = false; + 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; } - else + finally { - CheckEventPreconditionErrorPatch.IsArbitrated = true; - try - { - __result = (int)CheckEventPreconditionErrorPatch.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; - } + CheckEventPreconditionErrorPatch.IsIntercepted = false; } } } -- cgit From 26cac2c12a2b9ae7d486c000406deb2958f5fe30 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 8 Mar 2019 21:49:35 -0500 Subject: prevent invalid items from breaking menus on hover --- src/SMAPI/Patches/ObjectErrorPatch.cs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs index 0481259d..d72201c3 100644 --- a/src/SMAPI/Patches/ObjectErrorPatch.cs +++ b/src/SMAPI/Patches/ObjectErrorPatch.cs @@ -1,8 +1,8 @@ using System.Diagnostics.CodeAnalysis; -using System.Reflection; using Harmony; using StardewModdingAPI.Framework.Patching; using StardewValley; +using StardewValley.Menus; using SObject = StardewValley.Object; namespace StardewModdingAPI.Patches @@ -24,10 +24,17 @@ namespace StardewModdingAPI.Patches /// The Harmony instance. public void Apply(HarmonyInstance harmony) { - MethodInfo method = AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)); - MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.Prefix)); + // object.getDescription + harmony.Patch( + original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)), + prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.Object_GetDescription_Prefix))) + ); - harmony.Patch(method, new HarmonyMethod(prefix), null); + // IClickableMenu.drawToolTip + harmony.Patch( + original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)), + prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.IClickableMenu_DrawTooltip_Prefix))) + ); } @@ -40,7 +47,7 @@ namespace StardewModdingAPI.Patches /// 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(SObject __instance, ref string __result) + private static bool Object_GetDescription_Prefix(SObject __instance, ref string __result) { // invalid bigcraftables crash instead of showing '???' like invalid non-bigcraftables if (!__instance.IsRecipe && __instance.bigCraftable.Value && !Game1.bigCraftablesInformation.ContainsKey(__instance.ParentSheetIndex)) @@ -51,5 +58,20 @@ namespace StardewModdingAPI.Patches return true; } + + /// The method to call instead of . + /// The instance being patched. + /// The item for which to draw a tooltip. + /// 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 IClickableMenu_DrawTooltip_Prefix(IClickableMenu __instance, Item hoveredItem) + { + // invalid edible item cause crash when drawing tooltips + if (hoveredItem is SObject obj && obj.Edibility != -300 && !Game1.objectInformation.ContainsKey(obj.ParentSheetIndex)) + return false; + + return true; + } } } -- cgit From e43f01ffce7238d40d275c47615c24b9134b4954 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 14 Apr 2019 22:14:43 -0400 Subject: tweak patch code style --- src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs | 2 +- src/SMAPI/Patches/DialogueErrorPatch.cs | 8 ++++---- src/SMAPI/Patches/LoadForNewGamePatch.cs | 15 +++++++-------- src/SMAPI/Patches/ObjectErrorPatch.cs | 4 ++-- 4 files changed, 14 insertions(+), 15 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs index 74cfbfb0..c2a16391 100644 --- a/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs +++ b/src/SMAPI/Patches/CheckEventPreconditionErrorPatch.cs @@ -42,7 +42,7 @@ namespace StardewModdingAPI.Patches { harmony.Patch( original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), - prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix))) + prefix: new HarmonyMethod(this.GetType(), nameof(CheckEventPreconditionErrorPatch.Prefix)) ); } diff --git a/src/SMAPI/Patches/DialogueErrorPatch.cs b/src/SMAPI/Patches/DialogueErrorPatch.cs index 5af6ceef..7d57464c 100644 --- a/src/SMAPI/Patches/DialogueErrorPatch.cs +++ b/src/SMAPI/Patches/DialogueErrorPatch.cs @@ -46,10 +46,10 @@ namespace StardewModdingAPI.Patches /// The Harmony instance. public void Apply(HarmonyInstance harmony) { - ConstructorInfo constructor = AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }); - MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(DialogueErrorPatch.Prefix)); - - harmony.Patch(constructor, new HarmonyMethod(prefix), null); + harmony.Patch( + original: AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }), + prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Prefix)) + ); } diff --git a/src/SMAPI/Patches/LoadForNewGamePatch.cs b/src/SMAPI/Patches/LoadForNewGamePatch.cs index f4ce2023..def7134d 100644 --- a/src/SMAPI/Patches/LoadForNewGamePatch.cs +++ b/src/SMAPI/Patches/LoadForNewGamePatch.cs @@ -1,7 +1,6 @@ using System; using System.Collections.ObjectModel; using System.Collections.Specialized; -using System.Reflection; using Harmony; using StardewModdingAPI.Enums; using StardewModdingAPI.Framework.Patching; @@ -28,7 +27,7 @@ namespace StardewModdingAPI.Patches private static bool IsCreating; /// The number of times that has been cleared since started. - private static int TimesLocationsCleared = 0; + private static int TimesLocationsCleared; /********* @@ -54,11 +53,11 @@ namespace StardewModdingAPI.Patches /// The Harmony instance. public void Apply(HarmonyInstance harmony) { - MethodInfo method = AccessTools.Method(typeof(Game1), nameof(Game1.loadForNewGame)); - MethodInfo prefix = AccessTools.Method(this.GetType(), nameof(LoadForNewGamePatch.Prefix)); - MethodInfo postfix = AccessTools.Method(this.GetType(), nameof(LoadForNewGamePatch.Postfix)); - - harmony.Patch(method, new HarmonyMethod(prefix), new HarmonyMethod(postfix)); + 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)) + ); } @@ -89,7 +88,7 @@ namespace StardewModdingAPI.Patches if (LoadForNewGamePatch.IsCreating) { // clean up - ObservableCollection locations = (ObservableCollection) Game1.locations; + ObservableCollection locations = (ObservableCollection)Game1.locations; locations.CollectionChanged -= LoadForNewGamePatch.OnLocationListChanged; // raise stage changed diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs index d72201c3..0b17b101 100644 --- a/src/SMAPI/Patches/ObjectErrorPatch.cs +++ b/src/SMAPI/Patches/ObjectErrorPatch.cs @@ -27,13 +27,13 @@ namespace StardewModdingAPI.Patches // object.getDescription harmony.Patch( original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)), - prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.Object_GetDescription_Prefix))) + prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Object_GetDescription_Prefix)) ); // IClickableMenu.drawToolTip harmony.Patch( original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)), - prefix: new HarmonyMethod(AccessTools.Method(this.GetType(), nameof(ObjectErrorPatch.IClickableMenu_DrawTooltip_Prefix))) + prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.IClickableMenu_DrawTooltip_Prefix)) ); } -- cgit 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 --- .../Patches/CheckEventPreconditionErrorPatch.cs | 84 ---------------- src/SMAPI/Patches/EventErrorPatch.cs | 84 ++++++++++++++++ src/SMAPI/Patches/LoadContextPatch.cs | 108 +++++++++++++++++++++ src/SMAPI/Patches/LoadForNewGamePatch.cs | 108 --------------------- 4 files changed, 192 insertions(+), 192 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/SMAPI/Patches') 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); - } - } -} -- cgit From 6285c7954843557eec06cbae406c8ae436512803 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 12 Jul 2019 20:01:38 -0400 Subject: prevent mods from crashing the game with invalid dialogue in more cases --- src/SMAPI/Patches/DialogueErrorPatch.cs | 41 +++++++++++++++++++++++++++++++-- src/SMAPI/Patches/EventErrorPatch.cs | 4 ++-- src/SMAPI/Patches/LoadContextPatch.cs | 8 +++---- src/SMAPI/Patches/ObjectErrorPatch.cs | 8 +++---- 4 files changed, 49 insertions(+), 12 deletions(-) (limited to 'src/SMAPI/Patches') diff --git a/src/SMAPI/Patches/DialogueErrorPatch.cs b/src/SMAPI/Patches/DialogueErrorPatch.cs index 7d57464c..f1c25c05 100644 --- a/src/SMAPI/Patches/DialogueErrorPatch.cs +++ b/src/SMAPI/Patches/DialogueErrorPatch.cs @@ -21,6 +21,9 @@ namespace StardewModdingAPI.Patches /// Simplifies access to private code. private static Reflector Reflection; + /// Whether the getter is currently being intercepted. + private static bool IsInterceptingCurrentDialogue; + /********* ** Accessors @@ -48,7 +51,11 @@ namespace StardewModdingAPI.Patches { harmony.Patch( original: AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }), - prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Prefix)) + prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Before_Dialogue_Constructor)) + ); + harmony.Patch( + original: AccessTools.Property(typeof(NPC), nameof(NPC.CurrentDialogue)).GetMethod, + prefix: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Before_NPC_CurrentDialogue)) ); } @@ -63,7 +70,7 @@ namespace StardewModdingAPI.Patches /// 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(Dialogue __instance, string masterDialogue, NPC speaker) + private static bool Before_Dialogue_Constructor(Dialogue __instance, string masterDialogue, NPC speaker) { // get private members bool nameArraysTranslated = DialogueErrorPatch.Reflection.GetField(typeof(Dialogue), "nameArraysTranslated").GetValue(); @@ -96,5 +103,35 @@ namespace StardewModdingAPI.Patches return false; } + + /// The method to call instead of . + /// The instance being patched. + /// The return value of the original method. + /// 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 Before_NPC_CurrentDialogue(NPC __instance, ref Stack __result, MethodInfo __originalMethod) + { + if (DialogueErrorPatch.IsInterceptingCurrentDialogue) + return true; + + try + { + DialogueErrorPatch.IsInterceptingCurrentDialogue = true; + __result = (Stack)__originalMethod.Invoke(__instance, new object[0]); + return false; + } + catch (TargetInvocationException ex) + { + DialogueErrorPatch.MonitorForGame.Log($"Failed loading current dialogue for NPC {__instance.Name}:\n{ex.InnerException ?? ex}", LogLevel.Error); + __result = new Stack(); + return false; + } + finally + { + DialogueErrorPatch.IsInterceptingCurrentDialogue = false; + } + } } } diff --git a/src/SMAPI/Patches/EventErrorPatch.cs b/src/SMAPI/Patches/EventErrorPatch.cs index b0074356..cd530616 100644 --- a/src/SMAPI/Patches/EventErrorPatch.cs +++ b/src/SMAPI/Patches/EventErrorPatch.cs @@ -42,7 +42,7 @@ namespace StardewModdingAPI.Patches { harmony.Patch( original: AccessTools.Method(typeof(GameLocation), "checkEventPrecondition"), - prefix: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Prefix)) + prefix: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Before_GameLocation_CheckEventPrecondition)) ); } @@ -58,7 +58,7 @@ namespace StardewModdingAPI.Patches /// 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) + private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) { if (EventErrorPatch.IsIntercepted) return true; diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index 43e09573..3f86c9a9 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -55,8 +55,8 @@ namespace StardewModdingAPI.Patches { 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)) + prefix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.Before_Game1_LoadForNewGame)), + postfix: new HarmonyMethod(this.GetType(), nameof(LoadContextPatch.After_Game1_LoadForNewGame)) ); } @@ -67,7 +67,7 @@ namespace StardewModdingAPI.Patches /// 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() + private static bool Before_Game1_LoadForNewGame() { LoadContextPatch.IsCreating = Game1.activeClickableMenu is TitleMenu menu && LoadContextPatch.Reflection.GetField(menu, "transitioningCharacterCreationMenu").GetValue(); LoadContextPatch.TimesLocationsCleared = 0; @@ -83,7 +83,7 @@ namespace StardewModdingAPI.Patches /// 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() + private static void After_Game1_LoadForNewGame() { if (LoadContextPatch.IsCreating) { diff --git a/src/SMAPI/Patches/ObjectErrorPatch.cs b/src/SMAPI/Patches/ObjectErrorPatch.cs index 0b17b101..5b918d39 100644 --- a/src/SMAPI/Patches/ObjectErrorPatch.cs +++ b/src/SMAPI/Patches/ObjectErrorPatch.cs @@ -27,13 +27,13 @@ namespace StardewModdingAPI.Patches // object.getDescription harmony.Patch( original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)), - prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Object_GetDescription_Prefix)) + prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_Object_GetDescription)) ); // IClickableMenu.drawToolTip harmony.Patch( original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)), - prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.IClickableMenu_DrawTooltip_Prefix)) + prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_IClickableMenu_DrawTooltip)) ); } @@ -47,7 +47,7 @@ namespace StardewModdingAPI.Patches /// 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 Object_GetDescription_Prefix(SObject __instance, ref string __result) + private static bool Before_Object_GetDescription(SObject __instance, ref string __result) { // invalid bigcraftables crash instead of showing '???' like invalid non-bigcraftables if (!__instance.IsRecipe && __instance.bigCraftable.Value && !Game1.bigCraftablesInformation.ContainsKey(__instance.ParentSheetIndex)) @@ -65,7 +65,7 @@ namespace StardewModdingAPI.Patches /// 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 IClickableMenu_DrawTooltip_Prefix(IClickableMenu __instance, Item hoveredItem) + private static bool Before_IClickableMenu_DrawTooltip(IClickableMenu __instance, Item hoveredItem) { // invalid edible item cause crash when drawing tooltips if (hoveredItem is SObject obj && obj.Edibility != -300 && !Game1.objectInformation.ContainsKey(obj.ParentSheetIndex)) -- cgit