From bd20c2e1375ed5e32315ef5e292802bccc42f530 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sun, 11 Jul 2021 01:44:02 -0400 Subject: alias Mono.Cecil references (#711) This is needed to migrate to Harmony 2.0 because it uses MonoMod, which has a copy of Mono.Cecil merged into its assembly, which leads to "type X exists in both 0Harmony.dll and Mono.Cecil.dll" errors. We can't use the version bundled with MonoMod since only some of the types are publicly accessible. --- src/SMAPI/SMAPI.csproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/SMAPI/SMAPI.csproj') diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 413d9f33..d36d0d7a 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -20,7 +20,9 @@ - + + MonoCecilPackage + -- cgit From 167d5831d12f0b7c58b3533b716f9041f6ae02e7 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 23 Jul 2021 20:29:44 -0400 Subject: use unmerged Harmony assembly (#711) Harmony merges Mono.Cecil and MonoMod.Common into its DLL, and keeps some (but not all) of the merged types public. That causes type conflicts in SMAPI's code since it uses both Harmony and Mono.Cecil, and extern aliases break on Linux due to IDE/compiler limitations. This commit uses a custom build of Harmony without the assembly merging, so SMAPI can use and manage Mono.Cecil itself. --- build/0Harmony.dll | Bin 802816 -> 166912 bytes build/common.targets | 3 +++ build/prepare-install-package.targets | 3 +++ .../Framework/TemporaryHacks/MiniMonoModHotfix.cs | 2 +- src/SMAPI/SMAPI.csproj | 3 ++- 5 files changed, 9 insertions(+), 2 deletions(-) (limited to 'src/SMAPI/SMAPI.csproj') diff --git a/build/0Harmony.dll b/build/0Harmony.dll index 1c5b9c09..bab3bb4d 100644 Binary files a/build/0Harmony.dll and b/build/0Harmony.dll differ diff --git a/build/common.targets b/build/common.targets index f5d01606..aed619da 100644 --- a/build/common.targets +++ b/build/common.targets @@ -40,6 +40,9 @@ + + + diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index 0c1a6c1a..88e565f9 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -47,6 +47,9 @@ + + + diff --git a/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs b/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs index 6814abea..9f5819d7 100644 --- a/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs +++ b/src/SMAPI/Framework/TemporaryHacks/MiniMonoModHotfix.cs @@ -69,7 +69,7 @@ namespace MonoMod.Utils ); harmony.Patch( - original: typeof(Harmony).Assembly + original: typeof(MonoMod.Utils.ReflectionHelper).Assembly .GetType("MonoMod.Utils.DynamicMethodDefinition+<>c__DisplayClass3_0") .GetMethod("<_CopyMethodToDefinition>g__ResolveTokenAs|1", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), transpiler: new HarmonyMethod(typeof(MiniMonoModHotfix), nameof(ResolveTokenFix)) diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index d36d0d7a..d06e3364 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -20,9 +20,10 @@ - + MonoCecilPackage + -- cgit From 175eaad68373185b010410c5e2de1af9afbba1f5 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Fri, 23 Jul 2021 20:37:26 -0400 Subject: remove now-unneeded Mono.Cecil aliases (#711) --- src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs | 4 +--- src/SMAPI/Framework/ModLoading/AssemblyLoader.cs | 6 ++---- src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs | 4 +--- src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs | 6 ++---- .../Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs | 6 ++---- .../ModLoading/Finders/ReferenceToMissingMemberFinder.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs | 4 +--- src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs | 4 +--- .../Framework/ModLoading/Framework/BaseInstructionHandler.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs | 8 +++----- src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs | 6 ++---- src/SMAPI/Framework/ModLoading/IInstructionHandler.cs | 6 ++---- src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs | 4 +--- src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs | 6 ++---- .../Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs | 6 ++---- .../Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs | 6 ++---- .../Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs | 6 ++---- src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs | 4 +--- src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs | 4 +--- src/SMAPI/SMAPI.csproj | 4 +--- 24 files changed, 41 insertions(+), 89 deletions(-) (limited to 'src/SMAPI/SMAPI.csproj') diff --git a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs index 9867ed8b..aefb0126 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyDefinitionResolver.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - using System.Collections.Generic; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; namespace StardewModdingAPI.Framework.ModLoading { diff --git a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs index 8311a4b9..3606eb66 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyLoader.cs @@ -1,12 +1,10 @@ -extern alias MonoCecilPackage; - using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.ModLoading.Framework; using StardewModdingAPI.Metadata; diff --git a/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs b/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs index 6493ccf8..b56a776c 100644 --- a/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs +++ b/src/SMAPI/Framework/ModLoading/AssemblyParseResult.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - using System.IO; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; namespace StardewModdingAPI.Framework.ModLoading { diff --git a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs index 2e349616..01ed153b 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/EventFinder.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs index 434ff5ab..2c062243 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/FieldFinder.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs index 80229155..d2340f01 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/MethodFinder.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs index 5ef66df4..99344848 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/PropertyFinder.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs index 80296e38..b01a3240 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMemberWithUnexpectedTypeFinder.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System.Collections.Generic; using System.Linq; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs index fae8ee95..b64a255e 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/ReferenceToMissingMemberFinder.cs @@ -1,8 +1,6 @@ -extern alias MonoCecilPackage; - using System.Collections.Generic; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs index 3e107b90..24ab2eca 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/TypeAssemblyFinder.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - using System; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs index 9453c39f..bbd081e8 100644 --- a/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs +++ b/src/SMAPI/Framework/ModLoading/Finders/TypeFinder.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - using System; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Finders diff --git a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs index 3979d431..624113b3 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/BaseInstructionHandler.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System; using System.Collections.Generic; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; namespace StardewModdingAPI.Framework.ModLoading.Framework { diff --git a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs index e79bb488..10f68f0d 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RecursiveRewriter.cs @@ -1,11 +1,9 @@ -extern alias MonoCecilPackage; - using System; using System.Collections.Generic; using System.Linq; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; -using MonoCecilPackage.Mono.Collections.Generic; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Collections.Generic; namespace StardewModdingAPI.Framework.ModLoading.Framework { diff --git a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs index e88b75ed..60bbd2c7 100644 --- a/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs +++ b/src/SMAPI/Framework/ModLoading/Framework/RewriteHelper.cs @@ -1,10 +1,8 @@ -extern alias MonoCecilPackage; - using System; using System.Linq; using System.Reflection; -using MonoCecilPackage::Mono.Cecil; -using MonoCecilPackage::Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; namespace StardewModdingAPI.Framework.ModLoading.Framework { diff --git a/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs b/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs index 342721cd..17c9ba68 100644 --- a/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs +++ b/src/SMAPI/Framework/ModLoading/IInstructionHandler.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System; using System.Collections.Generic; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; namespace StardewModdingAPI.Framework.ModLoading { diff --git a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs index ee123e75..d4366294 100644 --- a/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs +++ b/src/SMAPI/Framework/ModLoading/PlatformAssemblyMap.cs @@ -1,10 +1,8 @@ -extern alias MonoCecilPackage; - using System; using System.Collections.Generic; using System.Linq; using System.Reflection; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; using StardewModdingAPI.Toolkit.Utilities; namespace StardewModdingAPI.Framework.ModLoading diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs index d40d4111..0b679e9d 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System; using System.Reflection; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs index 5a84a16a..723983be 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System; using HarmonyLib; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; using StardewModdingAPI.Framework.ModLoading.RewriteFacades; diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs index c381e4e5..f59a6ab1 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System.Collections.Generic; using System.Linq; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs index 748c1e6f..e133b6fa 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System.Collections.Generic; using System.Linq; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs index 5e0d9c70..9933e2ca 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System; using System.Linq; -using MonoCecilPackage.Mono.Cecil; -using MonoCecilPackage.Mono.Cecil.Cil; +using Mono.Cecil; +using Mono.Cecil.Cil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs index a4d09ae9..ad5cb96f 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs @@ -1,7 +1,5 @@ -extern alias MonoCecilPackage; - using System; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters diff --git a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs index fab424f3..a4ac54e2 100644 --- a/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs +++ b/src/SMAPI/Framework/ModLoading/TypeReferenceComparer.cs @@ -1,9 +1,7 @@ -extern alias MonoCecilPackage; - using System; using System.Collections.Generic; using System.Linq; -using MonoCecilPackage.Mono.Cecil; +using Mono.Cecil; namespace StardewModdingAPI.Framework.ModLoading { diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index d06e3364..0c6cfdd3 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -20,9 +20,7 @@ - - MonoCecilPackage - + -- 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.Internal.Patching/BasePatcher.cs | 54 +++++++++++++++ src/SMAPI.Internal.Patching/HarmonyPatcher.cs | 36 ++++++++++ src/SMAPI.Internal.Patching/IPatcher.cs | 16 +++++ src/SMAPI.Internal.Patching/PatchHelper.cs | 77 ++++++++++++++++++++++ .../SMAPI.Internal.Patching.projitems | 17 +++++ .../SMAPI.Internal.Patching.shproj | 13 ++++ src/SMAPI.Internal/ExceptionExtensions.cs | 41 ++++++++++++ src/SMAPI.Internal/SMAPI.Internal.projitems | 1 + src/SMAPI.Mods.ErrorHandler/ModEntry.cs | 4 +- .../Patches/DialoguePatcher.cs | 18 ++--- .../Patches/DictionaryPatcher.cs | 28 ++++---- .../Patches/EventPatcher.cs | 12 ++-- .../Patches/GameLocationPatcher.cs | 24 +++---- .../Patches/IClickableMenuPatcher.cs | 14 ++-- src/SMAPI.Mods.ErrorHandler/Patches/NpcPatcher.cs | 24 +++---- .../Patches/ObjectPatcher.cs | 16 ++--- .../Patches/SaveGamePatcher.cs | 15 ++--- .../Patches/SpriteBatchPatcher.cs | 20 +++--- .../Patches/UtilityPatcher.cs | 14 ++-- .../SMAPI.Mods.ErrorHandler.csproj | 1 + src/SMAPI.sln | 6 ++ .../Framework/Content/AssetInterceptorChange.cs | 1 + .../ContentManagers/GameContentManager.cs | 1 + .../Framework/ContentManagers/ModContentManager.cs | 1 + src/SMAPI/Framework/Events/ManagedEvent.cs | 1 + src/SMAPI/Framework/InternalExtensions.cs | 35 +--------- src/SMAPI/Framework/Logging/LogManager.cs | 1 + src/SMAPI/Framework/Patching/GamePatcher.cs | 45 ------------- src/SMAPI/Framework/Patching/IHarmonyPatch.cs | 15 ----- src/SMAPI/Framework/SCore.cs | 5 +- src/SMAPI/Framework/SGame.cs | 1 + src/SMAPI/Metadata/CoreAssetPropagator.cs | 1 + src/SMAPI/Patches/Game1Patcher.cs | 38 +++++------ src/SMAPI/Patches/TitleMenuPatcher.cs | 17 +++-- src/SMAPI/Properties/AssemblyInfo.cs | 1 - src/SMAPI/SMAPI.csproj | 1 + 36 files changed, 394 insertions(+), 221 deletions(-) create mode 100644 src/SMAPI.Internal.Patching/BasePatcher.cs create mode 100644 src/SMAPI.Internal.Patching/HarmonyPatcher.cs create mode 100644 src/SMAPI.Internal.Patching/IPatcher.cs create mode 100644 src/SMAPI.Internal.Patching/PatchHelper.cs create mode 100644 src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.projitems create mode 100644 src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.shproj create mode 100644 src/SMAPI.Internal/ExceptionExtensions.cs delete mode 100644 src/SMAPI/Framework/Patching/GamePatcher.cs delete mode 100644 src/SMAPI/Framework/Patching/IHarmonyPatch.cs (limited to 'src/SMAPI/SMAPI.csproj') diff --git a/src/SMAPI.Internal.Patching/BasePatcher.cs b/src/SMAPI.Internal.Patching/BasePatcher.cs new file mode 100644 index 00000000..87155d7f --- /dev/null +++ b/src/SMAPI.Internal.Patching/BasePatcher.cs @@ -0,0 +1,54 @@ +using System; +using System.Reflection; +using HarmonyLib; + +namespace StardewModdingAPI.Internal.Patching +{ + /// Provides base implementation logic for instances. + internal abstract class BasePatcher : IPatcher + { + /********* + ** Public methods + *********/ + /// + public abstract void Apply(Harmony harmony, IMonitor monitor); + + + /********* + ** Protected methods + *********/ + /// Get a method and assert that it was found. + /// The type containing the method. + /// The method parameter types, or null if it's not overloaded. + protected ConstructorInfo RequireConstructor(params Type[] parameters) + { + return PatchHelper.RequireConstructor(parameters); + } + + /// Get a method and assert that it was found. + /// The type containing the method. + /// The method name. + /// The method parameter types, or null if it's not overloaded. + /// The method generic types, or null if it's not generic. + protected MethodInfo RequireMethod(string name, Type[] parameters = null, Type[] generics = null) + { + return PatchHelper.RequireMethod(name, parameters, generics); + } + + /// Get a Harmony patch method on the current patcher instance. + /// The method name. + /// The patch priority to apply, usually specified using Harmony's enum, or null to keep the default value. + protected HarmonyMethod GetHarmonyMethod(string name, int? priority = null) + { + var method = new HarmonyMethod( + AccessTools.Method(this.GetType(), name) + ?? throw new InvalidOperationException($"Can't find patcher method {PatchHelper.GetMethodString(this.GetType(), name)}.") + ); + + if (priority.HasValue) + method.priority = priority.Value; + + return method; + } + } +} diff --git a/src/SMAPI.Internal.Patching/HarmonyPatcher.cs b/src/SMAPI.Internal.Patching/HarmonyPatcher.cs new file mode 100644 index 00000000..c07e3b41 --- /dev/null +++ b/src/SMAPI.Internal.Patching/HarmonyPatcher.cs @@ -0,0 +1,36 @@ +using System; +using HarmonyLib; + +namespace StardewModdingAPI.Internal.Patching +{ + /// Simplifies applying instances to the game. + internal static class HarmonyPatcher + { + /********* + ** Public methods + *********/ + /// Apply the given Harmony patchers. + /// The mod ID applying the patchers. + /// The monitor with which to log any errors. + /// The patchers to apply. + public static Harmony Apply(string id, IMonitor monitor, params IPatcher[] patchers) + { + Harmony harmony = new Harmony(id); + + foreach (IPatcher patcher in patchers) + { + try + { + patcher.Apply(harmony, monitor); + } + catch (Exception ex) + { + monitor.Log($"Couldn't apply runtime patch '{patcher.GetType().Name}' to the game. Some SMAPI features may not work correctly. See log file for details.", LogLevel.Error); + monitor.Log($"Technical details:\n{ex.GetLogSummary()}"); + } + } + + return harmony; + } + } +} diff --git a/src/SMAPI.Internal.Patching/IPatcher.cs b/src/SMAPI.Internal.Patching/IPatcher.cs new file mode 100644 index 00000000..a732d64f --- /dev/null +++ b/src/SMAPI.Internal.Patching/IPatcher.cs @@ -0,0 +1,16 @@ +using HarmonyLib; + +namespace StardewModdingAPI.Internal.Patching +{ + /// A set of Harmony patches to apply. + internal interface IPatcher + { + /********* + ** Public methods + *********/ + /// Apply the Harmony patches for this instance. + /// The Harmony instance. + /// The monitor with which to log any errors. + public void Apply(Harmony harmony, IMonitor monitor); + } +} diff --git a/src/SMAPI.Internal.Patching/PatchHelper.cs b/src/SMAPI.Internal.Patching/PatchHelper.cs new file mode 100644 index 00000000..c9758616 --- /dev/null +++ b/src/SMAPI.Internal.Patching/PatchHelper.cs @@ -0,0 +1,77 @@ +using System; +using System.Linq; +using System.Reflection; +using System.Text; +using HarmonyLib; + +namespace StardewModdingAPI.Internal.Patching +{ + /// Provides utility methods for patching game code with Harmony. + internal static class PatchHelper + { + /********* + ** Public methods + *********/ + /// Get a constructor and assert that it was found. + /// The type containing the method. + /// The method parameter types, or null if it's not overloaded. + /// The type has no matching constructor. + public static ConstructorInfo RequireConstructor(Type[] parameters = null) + { + return + AccessTools.Constructor(typeof(TTarget), parameters) + ?? throw new InvalidOperationException($"Can't find constructor {PatchHelper.GetMethodString(typeof(TTarget), null, parameters)} to patch."); + } + + /// Get a method and assert that it was found. + /// The type containing the method. + /// The method name. + /// The method parameter types, or null if it's not overloaded. + /// The method generic types, or null if it's not generic. + /// The type has no matching method. + public static MethodInfo RequireMethod(string name, Type[] parameters = null, Type[] generics = null) + { + return + AccessTools.Method(typeof(TTarget), name, parameters, generics) + ?? throw new InvalidOperationException($"Can't find method {PatchHelper.GetMethodString(typeof(TTarget), name, parameters, generics)} to patch."); + } + + /// Get a human-readable representation of a method target. + /// The type containing the method. + /// The method name, or null for a constructor. + /// The method parameter types, or null if it's not overloaded. + /// The method generic types, or null if it's not generic. + public static string GetMethodString(Type type, string name, Type[] parameters = null, Type[] generics = null) + { + StringBuilder str = new(); + + // type + str.Append(type.FullName); + + // method name (if not constructor) + if (name != null) + { + str.Append('.'); + str.Append(name); + } + + // generics + if (generics?.Any() == true) + { + str.Append('<'); + str.Append(string.Join(", ", generics.Select(p => p.FullName))); + str.Append('>'); + } + + // parameters + if (parameters?.Any() == true) + { + str.Append('('); + str.Append(string.Join(", ", parameters.Select(p => p.FullName))); + str.Append(')'); + } + + return str.ToString(); + } + } +} diff --git a/src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.projitems b/src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.projitems new file mode 100644 index 00000000..4fa2a062 --- /dev/null +++ b/src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.projitems @@ -0,0 +1,17 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + 6c16e948-3e5c-47a7-bf4b-07a7469a87a5 + + + SMAPI.Internal.Patching + + + + + + + + \ No newline at end of file diff --git a/src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.shproj b/src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.shproj new file mode 100644 index 00000000..1a102c82 --- /dev/null +++ b/src/SMAPI.Internal.Patching/SMAPI.Internal.Patching.shproj @@ -0,0 +1,13 @@ + + + + 6c16e948-3e5c-47a7-bf4b-07a7469a87a5 + 14.0 + + + + + + + + diff --git a/src/SMAPI.Internal/ExceptionExtensions.cs b/src/SMAPI.Internal/ExceptionExtensions.cs new file mode 100644 index 00000000..d7a2252b --- /dev/null +++ b/src/SMAPI.Internal/ExceptionExtensions.cs @@ -0,0 +1,41 @@ +using System; +using System.Reflection; + +namespace StardewModdingAPI.Internal +{ + /// Provides extension methods for handling exceptions. + internal static class ExceptionExtensions + { + /********* + ** Public methods + *********/ + /// Get a string representation of an exception suitable for writing to the error log. + /// The error to summarize. + public static string GetLogSummary(this Exception exception) + { + switch (exception) + { + case TypeLoadException ex: + return $"Failed loading type '{ex.TypeName}': {exception}"; + + case ReflectionTypeLoadException ex: + string summary = exception.ToString(); + foreach (Exception childEx in ex.LoaderExceptions) + summary += $"\n\n{childEx.GetLogSummary()}"; + return summary; + + default: + return exception.ToString(); + } + } + + /// Get the lowest exception in an exception stack. + /// The exception from which to search. + public static Exception GetInnermostException(this Exception exception) + { + while (exception.InnerException != null) + exception = exception.InnerException; + return exception; + } + } +} diff --git a/src/SMAPI.Internal/SMAPI.Internal.projitems b/src/SMAPI.Internal/SMAPI.Internal.projitems index 0d583a6d..0ee94a5b 100644 --- a/src/SMAPI.Internal/SMAPI.Internal.projitems +++ b/src/SMAPI.Internal/SMAPI.Internal.projitems @@ -14,5 +14,6 @@ + \ No newline at end of file diff --git a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs index ac9d1b94..067f6a8d 100644 --- a/src/SMAPI.Mods.ErrorHandler/ModEntry.cs +++ b/src/SMAPI.Mods.ErrorHandler/ModEntry.cs @@ -1,7 +1,7 @@ using System; using System.Reflection; using StardewModdingAPI.Events; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewModdingAPI.Mods.ErrorHandler.Patches; using StardewValley; @@ -28,7 +28,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler IMonitor monitorForGame = this.GetMonitorForGame(); // apply patches - new GamePatcher(this.Monitor).Apply( + HarmonyPatcher.Apply(this.ModManifest.UniqueID, this.Monitor, new DialoguePatcher(monitorForGame, this.Helper.Reflection), new DictionaryPatcher(this.Helper.Reflection), new EventPatcher(monitorForGame), diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/DialoguePatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/DialoguePatcher.cs index 7b730ee5..7a3af39c 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/DialoguePatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/DialoguePatcher.cs @@ -1,17 +1,17 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal; +using StardewModdingAPI.Internal.Patching; using StardewValley; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// A Harmony patch for the constructor which intercepts invalid dialogue lines and logs an error instead of crashing. + /// Harmony patches for which intercept invalid dialogue lines and logs an error instead of crashing. /// 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 DialoguePatcher : IHarmonyPatch + internal class DialoguePatcher : BasePatcher { /********* ** Fields @@ -36,11 +36,11 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }), - finalizer: new HarmonyMethod(this.GetType(), nameof(DialoguePatcher.Finalize_Dialogue_Constructor)) + original: this.RequireConstructor(typeof(string), typeof(NPC)), + finalizer: this.GetHarmonyMethod(nameof(DialoguePatcher.Finalize_Constructor)) ); } @@ -48,13 +48,13 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /********* ** Private methods *********/ - /// The method to call after the Dialogue constructor. + /// The method to call when the Dialogue constructor throws an exception. /// The instance being patched. /// The dialogue being parsed. /// The NPC for which the dialogue is being parsed. /// The exception thrown by the wrapped method, if any. /// Returns the exception to throw, if any. - private static Exception Finalize_Dialogue_Constructor(Dialogue __instance, string masterDialogue, NPC speaker, Exception __exception) + private static Exception Finalize_Constructor(Dialogue __instance, string masterDialogue, NPC speaker, Exception __exception) { if (__exception != null) { diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatcher.cs index 3c5240b6..6ad64e16 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/DictionaryPatcher.cs @@ -2,18 +2,18 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley.GameData; using StardewValley.GameData.HomeRenovations; using StardewValley.GameData.Movies; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// A Harmony patch for which adds the accessed key to exceptions. + /// Harmony patches for which add the accessed key to exceptions. /// 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 DictionaryPatcher : IHarmonyPatch + internal class DictionaryPatcher : BasePatcher { /********* ** Fields @@ -33,7 +33,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { Type[] keyTypes = { typeof(int), typeof(string) }; Type[] valueTypes = { typeof(int), typeof(string), typeof(HomeRenovation), typeof(MovieData), typeof(SpecialOrderData) }; @@ -45,8 +45,8 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(keyType, valueType); harmony.Patch( - original: AccessTools.Method(dictionaryType, "get_Item"), - finalizer: new HarmonyMethod(this.GetType(), nameof(DictionaryPatcher.Finalize_GetItem)) + original: AccessTools.Method(dictionaryType, "get_Item") ?? throw new InvalidOperationException($"Can't find method {PatchHelper.GetMethodString(dictionaryType, "get_Item")} to patch."), + finalizer: this.GetHarmonyMethod(nameof(DictionaryPatcher.Finalize_GetItem)) ); } } @@ -63,19 +63,13 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches private static Exception Finalize_GetItem(object key, Exception __exception) { if (__exception is KeyNotFoundException) - AddKeyTo(__exception, key?.ToString()); + { + DictionaryPatcher.Reflection + .GetField(__exception, "_message") + .SetValue($"{__exception.Message}\nkey: '{key}'"); + } return __exception; } - - /// Add the accessed key to an exception message. - /// The exception to modify. - /// The dictionary key. - private static void AddKeyTo(Exception exception, string key) - { - DictionaryPatcher.Reflection - .GetField(exception, "_message") - .SetValue($"{exception.Message}\nkey: '{key}'"); - } } } diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/EventPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/EventPatcher.cs index 9a7b34d8..1b706147 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/EventPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/EventPatcher.cs @@ -1,7 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley; namespace StardewModdingAPI.Mods.ErrorHandler.Patches @@ -10,7 +10,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// 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 EventPatcher : IHarmonyPatch + internal class EventPatcher : BasePatcher { /********* ** Fields @@ -30,11 +30,11 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Method(typeof(Event), nameof(Event.LogErrorAndHalt)), - postfix: new HarmonyMethod(this.GetType(), nameof(EventPatcher.After_Event_LogErrorAndHalt)) + original: this.RequireMethod(nameof(Event.LogErrorAndHalt)), + postfix: this.GetHarmonyMethod(nameof(EventPatcher.After_LogErrorAndHalt)) ); } @@ -44,7 +44,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches *********/ /// The method to call after . /// The exception being logged. - private static void After_Event_LogErrorAndHalt(Exception e) + private static void After_LogErrorAndHalt(Exception e) { EventPatcher.MonitorForGame.Log(e.ToString(), LogLevel.Error); } diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatcher.cs index 7427fe48..7df6b0a2 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatcher.cs @@ -1,17 +1,17 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley; using xTile; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// Harmony patches for and which intercept errors instead of crashing. + /// Harmony patches for which intercept errors instead of crashing. /// 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 GameLocationPatcher : IHarmonyPatch + internal class GameLocationPatcher : BasePatcher { /********* ** Fields @@ -31,15 +31,15 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.checkEventPrecondition)), - finalizer: new HarmonyMethod(this.GetType(), nameof(GameLocationPatcher.Finalize_GameLocation_CheckEventPrecondition)) + original: this.RequireMethod(nameof(GameLocation.checkEventPrecondition)), + finalizer: this.GetHarmonyMethod(nameof(GameLocationPatcher.Finalize_CheckEventPrecondition)) ); harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.updateSeasonalTileSheets)), - finalizer: new HarmonyMethod(this.GetType(), nameof(GameLocationPatcher.Before_GameLocation_UpdateSeasonalTileSheets)) + original: this.RequireMethod(nameof(GameLocation.updateSeasonalTileSheets)), + finalizer: this.GetHarmonyMethod(nameof(GameLocationPatcher.Finalize_UpdateSeasonalTileSheets)) ); } @@ -47,12 +47,12 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /********* ** Private methods *********/ - /// The method to call instead of GameLocation.checkEventPrecondition. + /// The method to call when throws an exception. /// The return value of the original method. /// The precondition to be parsed. /// The exception thrown by the wrapped method, if any. /// Returns the exception to throw, if any. - private static Exception Finalize_GameLocation_CheckEventPrecondition(ref int __result, string precondition, Exception __exception) + private static Exception Finalize_CheckEventPrecondition(ref int __result, string precondition, Exception __exception) { if (__exception != null) { @@ -63,12 +63,12 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches return null; } - /// The method to call instead of . + /// The method to call when throws an exception. /// The instance being patched. /// The map whose tilesheets to update. /// The exception thrown by the wrapped method, if any. /// Returns the exception to throw, if any. - private static Exception Before_GameLocation_UpdateSeasonalTileSheets(GameLocation __instance, Map map, Exception __exception) + private static Exception Finalize_UpdateSeasonalTileSheets(GameLocation __instance, Map map, Exception __exception) { if (__exception != null) GameLocationPatcher.MonitorForGame.Log($"Failed updating seasonal tilesheets for location '{__instance.NameOrUniqueName}': \n{__exception}", LogLevel.Error); diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/IClickableMenuPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/IClickableMenuPatcher.cs index d6f9fbf4..b65a695a 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/IClickableMenuPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/IClickableMenuPatcher.cs @@ -1,27 +1,27 @@ using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley; using StardewValley.Menus; using SObject = StardewValley.Object; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// A Harmony patch for which intercepts crashes due to invalid items. + /// Harmony patches for which intercept crashes due to invalid items. /// 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 IClickableMenuPatcher : IHarmonyPatch + internal class IClickableMenuPatcher : BasePatcher { /********* ** Public methods *********/ /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Method(typeof(IClickableMenu), nameof(IClickableMenu.drawToolTip)), - prefix: new HarmonyMethod(this.GetType(), nameof(IClickableMenuPatcher.Before_IClickableMenu_DrawTooltip)) + original: this.RequireMethod(nameof(IClickableMenu.drawToolTip)), + prefix: this.GetHarmonyMethod(nameof(IClickableMenuPatcher.Before_DrawTooltip)) ); } @@ -32,7 +32,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// The method to call instead of . /// The item for which to draw a tooltip. /// Returns whether to execute the original method. - private static bool Before_IClickableMenu_DrawTooltip(Item hoveredItem) + private static bool Before_DrawTooltip(Item hoveredItem) { // invalid edible item cause crash when drawing tooltips if (hoveredItem is SObject obj && obj.Edibility != -300 && !Game1.objectInformation.ContainsKey(obj.ParentSheetIndex)) diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/NpcPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/NpcPatcher.cs index 4a07ea1d..275bb5bf 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/NpcPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/NpcPatcher.cs @@ -2,17 +2,17 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal; +using StardewModdingAPI.Internal.Patching; using StardewValley; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// A Harmony patch for which intercepts crashes due to invalid schedule data. + /// Harmony patches for which intercept crashes due to invalid schedule data. /// 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 NpcPatcher : IHarmonyPatch + internal class NpcPatcher : BasePatcher { /********* ** Fields @@ -32,16 +32,16 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Property(typeof(NPC), nameof(NPC.CurrentDialogue)).GetMethod, - finalizer: new HarmonyMethod(this.GetType(), nameof(NpcPatcher.Finalize_NPC_CurrentDialogue)) + original: this.RequireMethod($"get_{nameof(NPC.CurrentDialogue)}"), + finalizer: this.GetHarmonyMethod(nameof(NpcPatcher.Finalize_CurrentDialogue)) ); harmony.Patch( - original: AccessTools.Method(typeof(NPC), nameof(NPC.parseMasterSchedule)), - finalizer: new HarmonyMethod(this.GetType(), nameof(NpcPatcher.Finalize_NPC_parseMasterSchedule)) + original: this.RequireMethod(nameof(NPC.parseMasterSchedule)), + finalizer: this.GetHarmonyMethod(nameof(NpcPatcher.Finalize_ParseMasterSchedule)) ); } @@ -49,12 +49,12 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /********* ** Private methods *********/ - /// The method to call after . + /// The method to call when throws an exception. /// The instance being patched. /// The return value of the original method. /// The exception thrown by the wrapped method, if any. /// Returns the exception to throw, if any. - private static Exception Finalize_NPC_CurrentDialogue(NPC __instance, ref Stack __result, Exception __exception) + private static Exception Finalize_CurrentDialogue(NPC __instance, ref Stack __result, Exception __exception) { if (__exception == null) return null; @@ -71,7 +71,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// The patched method's return value. /// The exception thrown by the wrapped method, if any. /// Returns the exception to throw, if any. - private static Exception Finalize_NPC_parseMasterSchedule(string rawData, NPC __instance, ref Dictionary __result, Exception __exception) + private static Exception Finalize_ParseMasterSchedule(string rawData, NPC __instance, ref Dictionary __result, Exception __exception) { if (__exception != null) { diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/ObjectPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/ObjectPatcher.cs index c4b25b96..fd4ea35c 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/ObjectPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/ObjectPatcher.cs @@ -2,34 +2,34 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley; using SObject = StardewValley.Object; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// A Harmony patch for which intercepts crashes due to the item no longer existing. + /// Harmony patches for which intercept crashes due to invalid items. /// 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 ObjectPatcher : IHarmonyPatch + internal class ObjectPatcher : BasePatcher { /********* ** Public methods *********/ /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { // object.getDescription harmony.Patch( - original: AccessTools.Method(typeof(SObject), nameof(SObject.getDescription)), - prefix: new HarmonyMethod(this.GetType(), nameof(ObjectPatcher.Before_Object_GetDescription)) + original: this.RequireMethod(nameof(SObject.getDescription)), + prefix: this.GetHarmonyMethod(nameof(ObjectPatcher.Before_Object_GetDescription)) ); // object.getDisplayName harmony.Patch( - original: AccessTools.Method(typeof(SObject), "loadDisplayName"), - finalizer: new HarmonyMethod(this.GetType(), nameof(ObjectPatcher.Finalize_Object_loadDisplayName)) + original: this.RequireMethod("loadDisplayName"), + finalizer: this.GetHarmonyMethod(nameof(ObjectPatcher.Finalize_Object_loadDisplayName)) ); } diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs index ef165831..8945e4f3 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/SaveGamePatcher.cs @@ -4,18 +4,18 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using HarmonyLib; using Microsoft.Xna.Framework.Content; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley; using StardewValley.Buildings; using StardewValley.Locations; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// A Harmony patch for which prevents some errors due to broken save data. + /// Harmony patches for which prevent some errors due to broken save data. /// 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 SaveGamePatcher : IHarmonyPatch + internal class SaveGamePatcher : BasePatcher { /********* ** Fields @@ -39,13 +39,12 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches SaveGamePatcher.OnContentRemoved = onContentRemoved; } - /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Method(typeof(SaveGame), nameof(SaveGame.loadDataToLocations)), - prefix: new HarmonyMethod(this.GetType(), nameof(SaveGamePatcher.Before_SaveGame_LoadDataToLocations)) + original: this.RequireMethod(nameof(SaveGame.loadDataToLocations)), + prefix: this.GetHarmonyMethod(nameof(SaveGamePatcher.Before_LoadDataToLocations)) ); } @@ -56,7 +55,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// The method to call instead of . /// The game locations being loaded. /// Returns whether to execute the original method. - private static bool Before_SaveGame_LoadDataToLocations(List gamelocations) + private static bool Before_LoadDataToLocations(List gamelocations) { bool removedAny = SaveGamePatcher.RemoveBrokenBuildings(gamelocations) diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchPatcher.cs index 1099afee..6860a4ec 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchPatcher.cs @@ -2,27 +2,27 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; using Microsoft.Xna.Framework.Graphics; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { - /// Harmony patch for to validate textures earlier. + /// Harmony patches for which validate textures earlier. /// 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 SpriteBatchPatcher : IHarmonyPatch + internal class SpriteBatchPatcher : BasePatcher { /********* ** Public methods *********/ /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( original: Constants.GameFramework == GameFramework.Xna - ? AccessTools.Method(typeof(SpriteBatch), "InternalDraw") - : AccessTools.Method(typeof(SpriteBatch), "CheckValid", new[] { typeof(Texture2D) }), - postfix: new HarmonyMethod(this.GetType(), nameof(SpriteBatchPatcher.After_SpriteBatch_CheckValid)) + ? this.RequireMethod("InternalDraw") + : this.RequireMethod("CheckValid", new[] { typeof(Texture2D) }), + postfix: this.GetHarmonyMethod(nameof(SpriteBatchPatcher.After_CheckValid)) ); } @@ -31,13 +31,13 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches ** Private methods *********/ #if SMAPI_FOR_XNA - /// The method to call instead of . + /// The method to call after . /// The texture to validate. #else - /// The method to call instead of . + /// The method to call after . /// The texture to validate. #endif - private static void After_SpriteBatch_CheckValid(Texture2D texture) + private static void After_CheckValid(Texture2D texture) { if (texture?.IsDisposed == true) throw new ObjectDisposedException("Cannot draw this texture because it's disposed."); diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/UtilityPatcher.cs b/src/SMAPI.Mods.ErrorHandler/Patches/UtilityPatcher.cs index e29e3030..ce85d0c2 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/UtilityPatcher.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/UtilityPatcher.cs @@ -1,7 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; using HarmonyLib; -using StardewModdingAPI.Framework.Patching; +using StardewModdingAPI.Internal.Patching; using StardewValley; namespace StardewModdingAPI.Mods.ErrorHandler.Patches @@ -10,17 +10,17 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// 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 UtilityPatcher : IHarmonyPatch + internal class UtilityPatcher : BasePatcher { /********* ** Public methods *********/ /// - public void Apply(Harmony harmony) + public override void Apply(Harmony harmony, IMonitor monitor) { harmony.Patch( - original: AccessTools.Method(typeof(Utility), nameof(Utility.getItemFromStandardTextDescription)), - finalizer: new HarmonyMethod(this.GetType(), nameof(UtilityPatcher.Finalize_Utility_GetItemFromStandardTextDescription)) + original: this.RequireMethod(nameof(Utility.getItemFromStandardTextDescription)), + finalizer: this.GetHarmonyMethod(nameof(UtilityPatcher.Finalize_GetItemFromStandardTextDescription)) ); } @@ -28,12 +28,12 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /********* ** Private methods *********/ - /// The method to call instead of . + /// The method to call when throws an exception. /// The item text description to parse. /// The delimiter by which to split the text description. /// The exception thrown by the wrapped method, if any. /// Returns the exception to throw, if any. - private static Exception Finalize_Utility_GetItemFromStandardTextDescription(string description, char delimiter, ref Exception __exception) + private static Exception Finalize_GetItemFromStandardTextDescription(string description, char delimiter, ref Exception __exception) { return __exception != null ? new FormatException($"Failed to parse item text description \"{description}\" with delimiter \"{delimiter}\".", __exception) diff --git a/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj b/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj index 531d3699..ffda5f89 100644 --- a/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj +++ b/src/SMAPI.Mods.ErrorHandler/SMAPI.Mods.ErrorHandler.csproj @@ -47,4 +47,5 @@ + diff --git a/src/SMAPI.sln b/src/SMAPI.sln index 58228ce9..92c6cb24 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -52,6 +52,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Mods", "Mods", "{AE9A4D46-E EndProject Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SMAPI.Internal", "SMAPI.Internal\SMAPI.Internal.shproj", "{85208F8D-6FD1-4531-BE05-7142490F59FE}" EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "SMAPI.Internal.Patching", "SMAPI.Internal.Patching\SMAPI.Internal.Patching.shproj", "{6C16E948-3E5C-47A7-BF4B-07A7469A87A5}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.ModBuildConfig.Analyzer.Tests", "SMAPI.ModBuildConfig.Analyzer.Tests\SMAPI.ModBuildConfig.Analyzer.Tests.csproj", "{680B2641-81EA-467C-86A5-0E81CDC57ED0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Tests", "SMAPI.Tests\SMAPI.Tests.csproj", "{AA95884B-7097-476E-92C8-D0500DE9D6D1}" @@ -86,10 +88,13 @@ Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{0a9bb24f-15ff-4c26-b1a2-81f7ae316518}*SharedItemsImports = 5 + SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{491e775b-ead0-44d4-b6ca-f1fc3e316d33}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{491e775b-ead0-44d4-b6ca-f1fc3e316d33}*SharedItemsImports = 5 + SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{6c16e948-3e5c-47a7-bf4b-07a7469a87a5}*SharedItemsImports = 13 SMAPI.Internal\SMAPI.Internal.projitems*{80efd92f-728f-41e0-8a5b-9f6f49a91899}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{85208f8d-6fd1-4531-be05-7142490f59fe}*SharedItemsImports = 13 SMAPI.Internal\SMAPI.Internal.projitems*{cd53ad6f-97f4-4872-a212-50c2a0fd3601}*SharedItemsImports = 5 + SMAPI.Internal.Patching\SMAPI.Internal.Patching.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 SMAPI.Internal\SMAPI.Internal.projitems*{e6da2198-7686-4f1d-b312-4a4dc70884c0}*SharedItemsImports = 5 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -156,6 +161,7 @@ Global {EB35A917-67B9-4EFA-8DFC-4FB49B3949BB} = {86C452BE-D2D8-45B4-B63F-E329EB06CEDA} {5947303D-3512-413A-9009-7AC43F5D3513} = {EB35A917-67B9-4EFA-8DFC-4FB49B3949BB} {85208F8D-6FD1-4531-BE05-7142490F59FE} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} + {6C16E948-3E5C-47A7-BF4B-07A7469A87A5} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {680B2641-81EA-467C-86A5-0E81CDC57ED0} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {AA95884B-7097-476E-92C8-D0500DE9D6D1} = {82D22ED7-A0A7-4D64-8E92-4B6A5E74ED11} {0634EA4C-3B8F-42DB-AEA6-CA9E4EF6E92F} = {AE9A4D46-E910-4293-8BC4-673F85FFF6A5} diff --git a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs index 037d9f89..10488b84 100644 --- a/src/SMAPI/Framework/Content/AssetInterceptorChange.cs +++ b/src/SMAPI/Framework/Content/AssetInterceptorChange.cs @@ -1,5 +1,6 @@ using System; using System.Reflection; +using StardewModdingAPI.Internal; namespace StardewModdingAPI.Framework.Content { diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 80a9937a..63cd1759 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -9,6 +9,7 @@ using StardewModdingAPI.Framework.Content; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Utilities; +using StardewModdingAPI.Internal; using StardewValley; using xTile; diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs index bc5a8b74..d24ffb81 100644 --- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs @@ -7,6 +7,7 @@ using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Internal; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; diff --git a/src/SMAPI/Framework/Events/ManagedEvent.cs b/src/SMAPI/Framework/Events/ManagedEvent.cs index 2204966c..fa20a079 100644 --- a/src/SMAPI/Framework/Events/ManagedEvent.cs +++ b/src/SMAPI/Framework/Events/ManagedEvent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using StardewModdingAPI.Events; +using StardewModdingAPI.Internal; namespace StardewModdingAPI.Framework.Events { diff --git a/src/SMAPI/Framework/InternalExtensions.cs b/src/SMAPI/Framework/InternalExtensions.cs index ab7f1e6c..6c9a5f3b 100644 --- a/src/SMAPI/Framework/InternalExtensions.cs +++ b/src/SMAPI/Framework/InternalExtensions.cs @@ -14,6 +14,9 @@ namespace StardewModdingAPI.Framework /// Provides extension methods for SMAPI's internal use. internal static class InternalExtensions { + /********* + ** Public methods + *********/ /**** ** IMonitor ****/ @@ -54,38 +57,6 @@ namespace StardewModdingAPI.Framework @event.Raise(Singleton.Instance); } - /**** - ** Exceptions - ****/ - /// Get a string representation of an exception suitable for writing to the error log. - /// The error to summarize. - public static string GetLogSummary(this Exception exception) - { - switch (exception) - { - case TypeLoadException ex: - return $"Failed loading type '{ex.TypeName}': {exception}"; - - case ReflectionTypeLoadException ex: - string summary = exception.ToString(); - foreach (Exception childEx in ex.LoaderExceptions) - summary += $"\n\n{childEx.GetLogSummary()}"; - return summary; - - default: - return exception.ToString(); - } - } - - /// Get the lowest exception in an exception stack. - /// The exception from which to search. - public static Exception GetInnermostException(this Exception exception) - { - while (exception.InnerException != null) - exception = exception.InnerException; - return exception; - } - /**** ** ReaderWriterLockSlim ****/ diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index e16b5c0d..a3d4f23d 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -9,6 +9,7 @@ using System.Threading; using StardewModdingAPI.Framework.Commands; using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Framework.ModLoading; +using StardewModdingAPI.Internal; using StardewModdingAPI.Internal.ConsoleWriting; using StardewModdingAPI.Toolkit.Framework.ModData; using StardewModdingAPI.Toolkit.Utilities; diff --git a/src/SMAPI/Framework/Patching/GamePatcher.cs b/src/SMAPI/Framework/Patching/GamePatcher.cs deleted file mode 100644 index 3ce22ee9..00000000 --- a/src/SMAPI/Framework/Patching/GamePatcher.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using HarmonyLib; - -namespace StardewModdingAPI.Framework.Patching -{ - /// Encapsulates applying Harmony patches to the game. - internal class GamePatcher - { - /********* - ** Fields - *********/ - /// Encapsulates monitoring and logging. - private readonly IMonitor Monitor; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// Encapsulates monitoring and logging. - public GamePatcher(IMonitor monitor) - { - this.Monitor = monitor; - } - - /// Apply all loaded patches to the game. - /// The patches to apply. - public void Apply(params IHarmonyPatch[] patches) - { - Harmony harmony = new Harmony("SMAPI"); - foreach (IHarmonyPatch patch in patches) - { - try - { - patch.Apply(harmony); - } - catch (Exception ex) - { - this.Monitor.Log($"Couldn't apply runtime patch '{patch.GetType().Name}' to the game. Some SMAPI features may not work correctly. See log file for details.", LogLevel.Error); - this.Monitor.Log(ex.GetLogSummary(), LogLevel.Trace); - } - } - } - } -} diff --git a/src/SMAPI/Framework/Patching/IHarmonyPatch.cs b/src/SMAPI/Framework/Patching/IHarmonyPatch.cs deleted file mode 100644 index c1ff3040..00000000 --- a/src/SMAPI/Framework/Patching/IHarmonyPatch.cs +++ /dev/null @@ -1,15 +0,0 @@ -using HarmonyLib; - -namespace StardewModdingAPI.Framework.Patching -{ - /// A Harmony patch to apply. - internal interface IHarmonyPatch - { - /********* - ** Methods - *********/ - /// Apply the Harmony patch. - /// The Harmony instance. - void Apply(Harmony harmony); - } -} diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 35db2da2..a34b3eff 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -31,13 +31,14 @@ using StardewModdingAPI.Framework.Models; using StardewModdingAPI.Framework.ModHelpers; using StardewModdingAPI.Framework.ModLoading; using StardewModdingAPI.Framework.Networking; -using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.Rendering; using StardewModdingAPI.Framework.Serialization; using StardewModdingAPI.Framework.StateTracking.Comparers; using StardewModdingAPI.Framework.StateTracking.Snapshots; using StardewModdingAPI.Framework.Utilities; +using StardewModdingAPI.Internal; +using StardewModdingAPI.Internal.Patching; using StardewModdingAPI.Patches; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; @@ -254,7 +255,7 @@ namespace StardewModdingAPI.Framework // apply game patches MiniMonoModHotfix.Apply(); - new GamePatcher(this.Monitor).Apply( + HarmonyPatcher.Apply("SMAPI", this.Monitor, new Game1Patcher(this.Reflection, this.OnLoadStageChanged), new TitleMenuPatcher(this.OnLoadStageChanged) ); diff --git a/src/SMAPI/Framework/SGame.cs b/src/SMAPI/Framework/SGame.cs index af7fa387..55ab8377 100644 --- a/src/SMAPI/Framework/SGame.cs +++ b/src/SMAPI/Framework/SGame.cs @@ -11,6 +11,7 @@ using StardewModdingAPI.Framework.Input; using StardewModdingAPI.Framework.Reflection; using StardewModdingAPI.Framework.StateTracking.Snapshots; using StardewModdingAPI.Framework.Utilities; +using StardewModdingAPI.Internal; using StardewModdingAPI.Utilities; using StardewValley; using StardewValley.BellsAndWhistles; diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 5641f90f..9273864e 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -8,6 +8,7 @@ using Netcode; using StardewModdingAPI.Framework; using StardewModdingAPI.Framework.ContentManagers; using StardewModdingAPI.Framework.Reflection; +using StardewModdingAPI.Internal; using StardewModdingAPI.Toolkit.Utilities; using StardewValley; using StardewValley.BellsAndWhistles; 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; diff --git a/src/SMAPI/Properties/AssemblyInfo.cs b/src/SMAPI/Properties/AssemblyInfo.cs index ae758e9b..ee8a1674 100644 --- a/src/SMAPI/Properties/AssemblyInfo.cs +++ b/src/SMAPI/Properties/AssemblyInfo.cs @@ -1,5 +1,4 @@ using System.Runtime.CompilerServices; [assembly: InternalsVisibleTo("SMAPI.Tests")] -[assembly: InternalsVisibleTo("ErrorHandler")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] // Moq for unit testing diff --git a/src/SMAPI/SMAPI.csproj b/src/SMAPI/SMAPI.csproj index 0c6cfdd3..7d5e7ef9 100644 --- a/src/SMAPI/SMAPI.csproj +++ b/src/SMAPI/SMAPI.csproj @@ -76,4 +76,5 @@ + -- cgit