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/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs | 6 ++++-- .../Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs | 6 ++++-- src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs | 6 ++++-- src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs | 6 ++++-- src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs | 6 ++++-- src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs | 4 +++- 6 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src/SMAPI/Framework/ModLoading/Rewriters') diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs index 0b679e9d..d40d4111 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/FieldReplaceRewriter.cs @@ -1,7 +1,9 @@ +extern alias MonoCecilPackage; + using System; using System.Reflection; -using Mono.Cecil; -using Mono.Cecil.Cil; +using MonoCecilPackage.Mono.Cecil; +using MonoCecilPackage.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 4b3675bc..147a12f9 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs @@ -1,8 +1,10 @@ #if HARMONY_2 +extern alias MonoCecilPackage; + using System; using HarmonyLib; -using Mono.Cecil; -using Mono.Cecil.Cil; +using MonoCecilPackage.Mono.Cecil; +using MonoCecilPackage.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 f59a6ab1..c381e4e5 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicFieldRewriter.cs @@ -1,7 +1,9 @@ +extern alias MonoCecilPackage; + using System.Collections.Generic; using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; +using MonoCecilPackage.Mono.Cecil; +using MonoCecilPackage.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 e133b6fa..748c1e6f 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/HeuristicMethodRewriter.cs @@ -1,7 +1,9 @@ +extern alias MonoCecilPackage; + using System.Collections.Generic; using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; +using MonoCecilPackage.Mono.Cecil; +using MonoCecilPackage.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 9933e2ca..5e0d9c70 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/MethodParentRewriter.cs @@ -1,7 +1,9 @@ +extern alias MonoCecilPackage; + using System; using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; +using MonoCecilPackage.Mono.Cecil; +using MonoCecilPackage.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 ad5cb96f..a4d09ae9 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/TypeReferenceRewriter.cs @@ -1,5 +1,7 @@ +extern alias MonoCecilPackage; + using System; -using Mono.Cecil; +using MonoCecilPackage.Mono.Cecil; using StardewModdingAPI.Framework.ModLoading.Framework; namespace StardewModdingAPI.Framework.ModLoading.Rewriters -- cgit From 8df578edb6d135796a48b219ecc7a7291c7ef460 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 13 Jul 2021 09:14:07 -0400 Subject: migrate to Harmony 2.1 (#711) --- build/0Harmony.dll | Bin 115200 -> 802816 bytes build/0Harmony.xml | 3130 ++++++++++++++++++++ build/common.targets | 1 + build/prepare-install-package.targets | 1 + docs/release-notes.md | 6 +- docs/technical/smapi.md | 1 - .../Patches/DialogueErrorPatch.cs | 92 +- .../Patches/EventPatches.cs | 8 - .../Patches/GameLocationPatches.cs | 87 +- .../Patches/LoadErrorPatch.cs | 8 - .../Patches/ObjectErrorPatch.cs | 50 +- .../Patches/ScheduleErrorPatch.cs | 50 +- .../Patches/SpriteBatchValidationPatches.cs | 10 +- .../Patches/UtilityErrorPatches.cs | 48 +- .../Framework/Commands/HarmonySummaryCommand.cs | 26 - .../ModLoading/RewriteFacades/AccessToolsFacade.cs | 2 - .../RewriteFacades/HarmonyInstanceFacade.cs | 2 - .../RewriteFacades/HarmonyMethodFacade.cs | 2 - .../Rewriters/Harmony1AssemblyRewriter.cs | 4 +- src/SMAPI/Framework/Patching/GamePatcher.cs | 8 - src/SMAPI/Framework/Patching/IHarmonyPatch.cs | 8 - src/SMAPI/Framework/Patching/PatchHelper.cs | 36 - src/SMAPI/Metadata/InstructionMetadata.cs | 8 +- src/SMAPI/Patches/LoadContextPatch.cs | 8 - 24 files changed, 3149 insertions(+), 447 deletions(-) create mode 100644 build/0Harmony.xml delete mode 100644 src/SMAPI/Framework/Patching/PatchHelper.cs (limited to 'src/SMAPI/Framework/ModLoading/Rewriters') diff --git a/build/0Harmony.dll b/build/0Harmony.dll index 2e893d0e..1c5b9c09 100644 Binary files a/build/0Harmony.dll and b/build/0Harmony.dll differ diff --git a/build/0Harmony.xml b/build/0Harmony.xml new file mode 100644 index 00000000..ba2f340e --- /dev/null +++ b/build/0Harmony.xml @@ -0,0 +1,3130 @@ + + + + 0Harmony + + + + A factory to create delegate types + + + Default constructor + + + Creates a delegate type for a method + The method + The new delegate type + + + + A getter delegate type + Type that getter gets field/property value from + Type of the value that getter gets + The instance get getter uses + An delegate + + + + A setter delegate type + Type that setter sets field/property value for + Type of the value that setter sets + The instance the setter uses + The value the setter uses + An delegate + + + + A constructor delegate type + Type that constructor creates + An delegate + + + + A helper class for fast access to getters and setters + + + Creates an instantiation delegate + Type that constructor creates + The new instantiation delegate + + + + Creates an getter delegate for a property + Type that getter reads property from + Type of the property that gets accessed + The property + The new getter delegate + + + + Creates an getter delegate for a field + Type that getter reads field from + Type of the field that gets accessed + The field + The new getter delegate + + + + Creates an getter delegate for a field (with a list of possible field names) + Type that getter reads field/property from + Type of the field/property that gets accessed + A list of possible field names + The new getter delegate + + + + Creates an setter delegate + Type that setter assigns property value to + Type of the property that gets assigned + The property + The new setter delegate + + + + Creates an setter delegate for a field + Type that setter assigns field value to + Type of the field that gets assigned + The field + The new getter delegate + + + + A delegate to invoke a method + The instance + The method parameters + The method result + + + A helper class to invoke method with delegates + + + Creates a fast invocation handler from a method + The method to invoke + Controls if boxed value object is accessed/updated directly + The + + + The directBoxValueAccess option controls how value types passed by reference (e.g. ref int, out my_struct) are handled in the arguments array + passed to the fast invocation handler. + Since the arguments array is an object array, any value types contained within it are actually references to a boxed value object. + Like any other object, there can be other references to such boxed value objects, other than the reference within the arguments array. + For example, + + var val = 5; + var box = (object)val; + var arr = new object[] { box }; + handler(arr); // for a method with parameter signature: ref/out/in int + + + + + If directBoxValueAccess is true, the boxed value object is accessed (and potentially updated) directly when the handler is called, + such that all references to the boxed object reflect the potentially updated value. + In the above example, if the method associated with the handler updates the passed (boxed) value to 10, both box and arr[0] + now reflect the value 10. Note that the original val is not updated, since boxing always copies the value into the new boxed value object. + + + If directBoxValueAccess is false (default), the boxed value object in the arguments array is replaced with a "reboxed" value object, + such that potential updates to the value are reflected only in the arguments array. + In the above example, if the method associated with the handler updates the passed (boxed) value to 10, only arr[0] now reflects the value 10. + + + + + A low level memory helper + + + + Mark method for no inlining (currently only works on Mono) + The method/constructor to change + + + + Detours a method + The original method/constructor + The replacement method/constructor + An error string + + + + Writes a jump to memory + The memory address + Jump destination + An error string + + + + Gets the start of a method in memory + The method/constructor + [out] Details of the exception + The method start address + + + + special parameter names that can be used in prefix and postfix methods + + + Patch function helpers + + + Sorts patch methods by their priority rules + The original method + Patches to sort + Use debug mode + The sorted patch methods + + + + Creates new replacement method with the latest patches and detours the original method + The original method + Information describing the patches + The newly created replacement method + + + + Creates a patch sorter + Array of patches that will be sorted + Use debugging + + + Sorts internal PatchSortingWrapper collection and caches the results. + After first run the result is provided from the cache. + The original method + The sorted patch methods + + + Checks if the sorter was created with the same patch list and as a result can be reused to + get the sorted order of the patches. + List of patches to check against + true if equal + + + Removes one unresolved dependency from the least important patch. + + + Outputs all unblocked patches from the waiting list to results list + + + Adds patch to both results list and handled patches set + Patch to add + + + Wrapper used over the Patch object to allow faster dependency access and + dependency removal in case of cyclic dependencies + + + Create patch wrapper object used for sorting + Patch to wrap + + + Determines how patches sort + The other patch + integer to define sort order (-1, 0, 1) + + + Determines whether patches are equal + The other patch + true if equal + + + Hash function + A hash code + + + Bidirectionally registers Patches as after dependencies + List of dependencies to register + + + Bidirectionally registers Patches as before dependencies + List of dependencies to register + + + Bidirectionally removes Patch from after dependencies + Patch to remove + + + Bidirectionally removes Patch from before dependencies + Patch to remove + + + Specifies the type of method + + + + This is a normal method + + + This is a getter + + + This is a setter + + + This is a constructor + + + This is a static constructor + + + Specifies the type of argument + + + + This is a normal argument + + + This is a reference argument (ref) + + + This is an out argument (out) + + + This is a pointer argument (&) + + + Specifies the type of patch + + + + Any patch + + + A prefix patch + + + A postfix patch + + + A transpiler + + + A finalizer + + + A reverse patch + + + Specifies the type of reverse patch + + + + Use the unmodified original method (directly from IL) + + + Use the original as it is right now including previous patches but excluding future ones + + + Specifies the type of method call dispatching mechanics + + + + Call the method using dynamic dispatching if method is virtual (including overriden) + + + This is the built-in form of late binding (a.k.a. dynamic binding) and is the default dispatching mechanic in C#. + This directly corresponds with the instruction. + + + For virtual (including overriden) methods, the instance type's most-derived/overriden implementation of the method is called. + For non-virtual (including static) methods, same behavior as : the exact specified method implementation is called. + + + Note: This is not a fully dynamic dispatch, since non-virtual (including static) methods are still called non-virtually. + A fully dynamic dispatch in C# involves using + the dynamic type + (actually a fully dynamic binding, since even the name and overload resolution happens at runtime), which does not support. + + + + + Call the method using static dispatching, regardless of whether method is virtual (including overriden) or non-virtual (including static) + + + a.k.a. non-virtual dispatching, early binding, or static binding. + This directly corresponds with the instruction. + + + For both virtual (including overriden) and non-virtual (including static) methods, the exact specified method implementation is called, without virtual/override mechanics. + + + + + The base class for all Harmony annotations (not meant to be used directly) + + + + The common information for all attributes + + + Annotation to define your Harmony patch methods + + + + An empty annotation can be used together with TargetMethod(s) + + + + An annotation that specifies a class to patch + The declaring class/type + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The argument types of the method or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + Annotation to define the original method for delegate injection + + + + An annotation that specifies a class to patch + The declaring class/type + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The argument types of the method or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The + An array of argument types to target overloads + Array of + + + + An annotation that specifies a method, property or constructor to patch + The declaring class/type + The name of the method, property or constructor to patch + The + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + The name of the method, property or constructor to patch + The + + + + An annotation that specifies call dispatching mechanics for the delegate + The + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + The + An array of argument types to target overloads + An array of + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + + + + An annotation that specifies a method, property or constructor to patch + An array of argument types to target overloads + An array of + + + + Annotation to define your standin methods for reverse patching + + + + An annotation that specifies the type of reverse patching + The of the reverse patch + + + + A Harmony annotation to define that all methods in a class are to be patched + + + + A Harmony annotation + + + + A Harmony annotation to define patch priority + The priority + + + + A Harmony annotation + + + + A Harmony annotation to define that a patch comes before another patch + The array of harmony IDs of the other patches + + + + A Harmony annotation + + + A Harmony annotation to define that a patch comes after another patch + The array of harmony IDs of the other patches + + + + A Harmony annotation + + + A Harmony annotation to debug a patch (output uses to log to your Desktop) + + + + Specifies the Prepare function in a patch class + + + + Specifies the Cleanup function in a patch class + + + + Specifies the TargetMethod function in a patch class + + + + Specifies the TargetMethods function in a patch class + + + + Specifies the Prefix function in a patch class + + + + Specifies the Postfix function in a patch class + + + + Specifies the Transpiler function in a patch class + + + + Specifies the Finalizer function in a patch class + + + + A Harmony annotation + + + + The name of the original argument + + + + The index of the original argument + + + + The new name of the original argument + + + + An annotation to declare injected arguments by name + + + + An annotation to declare injected arguments by index + Zero-based index + + + + An annotation to declare injected arguments by renaming them + Name of the original argument + New name + + + + An annotation to declare injected arguments by index and renaming them + Zero-based index + New name + + + + An abstract wrapper around OpCode and their operands. Used by transpilers + + + + The opcode + + + + The operand + + + + All labels defined on this instruction + + + + All exception block boundaries defined on this instruction + + + + Creates a new CodeInstruction with a given opcode and optional operand + The opcode + The operand + + + + Create a full copy (including labels and exception blocks) of a CodeInstruction + The to copy + + + + Clones a CodeInstruction and resets its labels and exception blocks + A lightweight copy of this code instruction + + + + Clones a CodeInstruction, resets labels and exception blocks and sets its opcode + The opcode + A copy of this CodeInstruction with a new opcode + + + + Clones a CodeInstruction, resets labels and exception blocks and sets its operand + The operand + A copy of this CodeInstruction with a new operand + + + + Creates a CodeInstruction calling a method (CALL) + The class/type where the method is declared + The name of the method (case sensitive) + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A code instruction that calls the method matching the arguments + + + + Creates a CodeInstruction calling a method (CALL) + The target method in the form TypeFullName:MethodName, where the type name matches a form recognized by Type.GetType like Some.Namespace.Type. + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A code instruction that calls the method matching the arguments + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction calling a method (CALL) + The lambda expression using the method + + + + + Creates a CodeInstruction loading a field (LD[S]FLD[A]) + The class/type where the field is defined + The name of the field (case sensitive) + Use address of field + + + + Creates a CodeInstruction storing to a field (ST[S]FLD) + The class/type where the field is defined + The name of the field (case sensitive) + + + + Returns a string representation of the code instruction + A string representation of the code instruction + + + + Exception block types + + + + The beginning of an exception block + + + + The beginning of a catch block + + + + The beginning of an except filter block + + + + The beginning of a fault block + + + + The beginning of a finally block + + + + The end of an exception block + + + + An exception block + + + + Block type + + + + Catch type + + + + Creates an exception block + The + The catch type + + + + The Harmony instance is the main entry to Harmony. After creating one with an unique identifier, it is used to patch and query the current application domain + + + + The unique identifier + + + + Set to true before instantiating Harmony to debug Harmony or use an environment variable to set HARMONY_DEBUG to '1' like this: cmd /C "set HARMONY_DEBUG=1 && game.exe" + This is for full debugging. To debug only specific patches, use the attribute + + + + Creates a new Harmony instance + A unique identifier (you choose your own) + A Harmony instance + + + + Searches the current assembly for Harmony annotations and uses them to create patches + This method can fail to use the correct assembly when being inlined. It calls StackTrace.GetFrame(1) which can point to the wrong method/assembly. If you are unsure or run into problems, use PatchAll(Assembly.GetExecutingAssembly()) instead. + + + + Creates a empty patch processor for an original method + The original method/constructor + A new instance + + + + Creates a patch class processor from an annotated class + The class/type + A new instance + + + + Creates a reverse patcher for one of your stub methods + The original method/constructor + The stand-in stub method as + A new instance + + + + Searches an assembly for Harmony annotations and uses them to create patches + The assembly + + + + Creates patches by manually specifying the methods + The original method/constructor + An optional prefix method wrapped in a object + An optional postfix method wrapped in a object + An optional transpiler method wrapped in a object + An optional finalizer method wrapped in a object + The replacement method that was created to patch the original method + + + + Patches a foreign method onto a stub method of yours and optionally applies transpilers during the process + The original method/constructor you want to duplicate + Your stub method as that will become the original. Needs to have the correct signature (either original or whatever your transpilers generates) + An optional transpiler as method that will be applied during the process + The replacement method that was created to patch the stub method + + + + Unpatches methods by patching them with zero patches. Fully unpatching is not supported. Be careful, unpatching is global + The optional Harmony ID to restrict unpatching to a specific Harmony instance + This method could be static if it wasn't for the fact that unpatching creates a new replacement method that contains your harmony ID + + + + Unpatches a method by patching it with zero patches. Fully unpatching is not supported. Be careful, unpatching is global + The original method/constructor + The + The optional Harmony ID to restrict unpatching to a specific Harmony instance + + + + Unpatches a method by patching it with zero patches. Fully unpatching is not supported. Be careful, unpatching is global + The original method/constructor + The patch method as method to remove + + + + Test for patches from a specific Harmony ID + The Harmony ID + True if patches for this ID exist + + + + Gets patch information for a given original method + The original method/constructor + The patch information as + + + + Gets the methods this instance has patched + An enumeration of original methods/constructors + + + + Gets all patched original methods in the appdomain + An enumeration of patched original methods/constructors + + + + Gets the original method from a given replacement method + A replacement method, for example from a stacktrace + The original method/constructor or null if not found + + + + Tries to get the method from a stackframe including dynamic replacement methods + The + For normal frames, frame.GetMethod() is returned. For frames containing patched methods, the replacement method is returned or null if no method can be found + + + + Gets Harmony version for all active Harmony instances + [out] The current Harmony version + A dictionary containing assembly versions keyed by Harmony IDs + + + + Under Mono, HarmonyException wraps IL compile errors with detailed information about the failure + + + + Default serialization constructor (not implemented) + The info + The context + + + + Get a list of IL instructions in pairs of offset+code + A list of key/value pairs which represent an offset and the code at that offset + + + + Get a list of IL instructions without offsets + A list of + + + + Get the error offset of the errornous IL instruction + The offset + + + + Get the index of the errornous IL instruction + The index into the list of instructions or -1 if not found + + + + A wrapper around a method to use it as a patch (for example a Prefix) + + + + The original method + + + + Class/type declaring this patch + + + + Patch method name + + + + Optional patch + + + + Array of argument types of the patch method + + + + of the patch + + + + Install this patch before patches with these Harmony IDs + + + + Install this patch after patches with these Harmony IDs + + + + Reverse patch type, see + + + + Create debug output for this patch + + + + Whether to use (true) or (false) mechanics + for -attributed delegate + + + + Default constructor + + + + Creates a patch from a given method + The original method + + + + Creates a patch from a given method + The original method + The patch + A list of harmony IDs that should come after this patch + A list of harmony IDs that should come before this patch + Set to true to generate debug output + + + + Creates a patch from a given method + The patch class/type + The patch method name + The optional argument types of the patch method (for overloaded methods) + + + + Gets the names of all internal patch info fields + A list of field names + + + + Merges annotations + The list of to merge + The merged + + + + Returns a string that represents the annotation + A string representation + + + + Annotation extensions + + + + Copies annotation information + The source + The destination + + + + Clones an annotation + The to clone + A copied + + + + Merges annotations + The master + The detail + A new, merged + + + + Gets all annotations on a class/type + The class/type + A list of all + + + + Gets merged annotations on a class/type + The class/type + The merged + + + + Gets all annotations on a method + The method/constructor + A list of + + + + Gets merged annotations on a method + The method/constructor + The merged + + + + + A mutable representation of an inline signature, similar to Mono.Cecil's CallSite. + Used by the calli instruction, can be used by transpilers + + + + + See + + + + See + + + + See + + + + The list of all parameter types or function pointer signatures received by the call site + + + + The return type or function pointer signature returned by the call site + + + + Returns a string representation of the inline signature + A string representation of the inline signature + + + + + A mutable representation of a parameter type with an attached type modifier, + similar to Mono.Cecil's OptionalModifierType / RequiredModifierType and C#'s modopt / modreq + + + + + Whether this is a modopt (optional modifier type) or a modreq (required modifier type) + + + + The modifier type attached to the parameter type + + + + The modified parameter type + + + + Returns a string representation of the modifier type + A string representation of the modifier type + + + + Patch serialization + + + + Control the binding of a serialized object to a type + Specifies the assembly name of the serialized object + Specifies the type name of the serialized object + The type of the object the formatter creates a new instance of + + + + Serializes a patch info + The + The serialized data + + + + Deserialize a patch info + The serialized data + A + + + + Compare function to sort patch priorities + The patch + Zero-based index + The priority + A standard sort integer (-1, 0, 1) + + + + Serializable patch information + + + + Prefixes as an array of + + + + Postfixes as an array of + + + + Transpilers as an array of + + + + Finalizers as an array of + + + + Returns if any of the patches wants debugging turned on + + + + Adds prefixes + An owner (Harmony ID) + The patch methods + + + + Adds a prefix + + + Removes prefixes + The owner of the prefixes, or * for all + + + + Adds postfixes + An owner (Harmony ID) + The patch methods + + + + Adds a postfix + + + Removes postfixes + The owner of the postfixes, or * for all + + + + Adds transpilers + An owner (Harmony ID) + The patch methods + + + + Adds a transpiler + + + Removes transpilers + The owner of the transpilers, or * for all + + + + Adds finalizers + An owner (Harmony ID) + The patch methods + + + + Adds a finalizer + + + Removes finalizers + The owner of the finalizers, or * for all + + + + Removes a patch using its method + The method of the patch to remove + + + + Gets a concatenated list of patches + The Harmony instance ID adding the new patches + The patches to add + The current patches + + + + Gets a list of patches with any from the given owner removed + The owner of the methods, or * for all + The current patches + + + + A serializable patch + + + + Zero-based index + + + + The owner (Harmony ID) + + + + The priority, see + + + + Keep this patch before the patches indicated in the list of Harmony IDs + + + + Keep this patch after the patches indicated in the list of Harmony IDs + + + + A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future + + + + The method of the static patch method + + + + Creates a patch + The method of the patch + Zero-based index + An owner (Harmony ID) + The priority, see + A list of Harmony IDs for patches that should run after this patch + A list of Harmony IDs for patches that should run before this patch + A flag that will log the replacement method via every time this patch is used to build the replacement, even in the future + + + + Creates a patch + The method of the patch + Zero-based index + An owner (Harmony ID) + + + Get the patch method or a DynamicMethod if original patch method is a patch factory + The original method/constructor + The method of the patch + + + + Determines whether patches are equal + The other patch + true if equal + + + + Determines how patches sort + The other patch + integer to define sort order (-1, 0, 1) + + + + Hash function + A hash code + + + + A PatchClassProcessor used to turn on a class/type into patches + + + + Creates a patch class processor by pointing out a class. Similar to PatchAll() but without searching through all classes. + The Harmony instance + The class to process (need to have at least a [HarmonyPatch] attribute) + + + + Applies the patches + A list of all created replacement methods or null if patch class is not annotated + + + + A group of patches + + + + A collection of prefix + + + + A collection of postfix + + + + A collection of transpiler + + + + A collection of finalizer + + + + Gets all owners (Harmony IDs) or all known patches + The patch owners + + + + Creates a group of patches + An array of prefixes as + An array of postfixes as + An array of transpileres as + An array of finalizeres as + + + + A PatchProcessor handles patches on a method/constructor + + + + Creates an empty patch processor + The Harmony instance + The original method/constructor + + + + Adds a prefix + The prefix as a + A for chaining calls + + + + Adds a prefix + The prefix method + A for chaining calls + + + + Adds a postfix + The postfix as a + A for chaining calls + + + + Adds a postfix + The postfix method + A for chaining calls + + + + Adds a transpiler + The transpiler as a + A for chaining calls + + + + Adds a transpiler + The transpiler method + A for chaining calls + + + + Adds a finalizer + The finalizer as a + A for chaining calls + + + + Adds a finalizer + The finalizer method + A for chaining calls + + + + Gets all patched original methods in the appdomain + An enumeration of patched method/constructor + + + + Applies all registered patches + The generated replacement method + + + + Unpatches patches of a given type and/or Harmony ID + The patch type + Harmony ID or * for any + A for chaining calls + + + + Unpatches a specific patch + The method of the patch + A for chaining calls + + + + Gets patch information on an original + The original method/constructor + The patch information as + + + + Sort patch methods by their priority rules + The original method + Patches to sort + The sorted patch methods + + + + Gets Harmony version for all active Harmony instances + [out] The current Harmony version + A dictionary containing assembly version keyed by Harmony ID + + + + Creates a new empty generator to use when reading method bodies + A new + + + + Creates a new generator matching the method/constructor to use when reading method bodies + The original method/constructor to copy method information from + A new + + + + Returns the methods unmodified list of code instructions + The original method/constructor + Optionally an existing generator that will be used to create all local variables and labels contained in the result (if not specified, an internal generator is used) + A list containing all the original + + + + Returns the methods unmodified list of code instructions + The original method/constructor + A new generator that now contains all local variables and labels contained in the result + A list containing all the original + + + + Returns the methods current list of code instructions after all existing transpilers have been applied + The original method/constructor + Apply only the first count of transpilers + Optionally an existing generator that will be used to create all local variables and labels contained in the result (if not specified, an internal generator is used) + A list of + + + + Returns the methods current list of code instructions after all existing transpilers have been applied + The original method/constructor + A new generator that now contains all local variables and labels contained in the result + Apply only the first count of transpilers + A list of + + + + A low level way to read the body of a method. Used for quick searching in methods + The original method + All instructions as opcode/operand pairs + + + + A low level way to read the body of a method. Used for quick searching in methods + The original method + An existing generator that will be used to create all local variables and labels contained in the result + All instructions as opcode/operand pairs + + + + A patch priority + + + + Patch last + + + + Patch with very low priority + + + + Patch with low priority + + + + Patch with lower than normal priority + + + + Patch with normal priority + + + + Patch with higher than normal priority + + + + Patch with high priority + + + + Patch with very high priority + + + + Patch first + + + + A reverse patcher + + + + Creates a reverse patcher + The Harmony instance + The original method/constructor + Your stand-in stub method as + + + + Applies the patch + The type of patch, see + The generated replacement method + + + + A collection of commonly used transpilers + + + + A transpiler that replaces all occurrences of a given method with another one using the same signature + The enumeration of to act on + Method or constructor to search for + Method or constructor to replace with + Modified enumeration of + + + + A transpiler that alters instructions that match a predicate by calling an action + The enumeration of to act on + A predicate selecting the instructions to change + An action to apply to matching instructions + Modified enumeration of + + + + A transpiler that logs a text at the beginning of the method + The instructions to act on + The log text + Modified enumeration of + + + + A helper class for reflection related functions + + + + Shortcut for to simplify the use of reflections and make it work for any access level + + + + Shortcut for to simplify the use of reflections and make it work for any access level but only within the current type + + + + Enumerates all assemblies in the current app domain, excluding visual studio assemblies + An enumeration of + + + Gets a type by name. Prefers a full name with namespace but falls back to the first type matching the name otherwise + The name + A type or null if not found + + + + Gets all successfully loaded types from a given assembly + The assembly + An array of types + + This calls and returns , while catching any thrown . + If such an exception is thrown, returns the successfully loaded types (, + filtered for non-null values). + + + + + Enumerates all successfully loaded types in the current app domain, excluding visual studio assemblies + An enumeration of all in all assemblies, excluding visual studio assemblies + + + Applies a function going up the type hierarchy and stops at the first non-null result + Result type of func() + The class/type to start with + The evaluation function returning T + The first non-null result, or null if no match + + The type hierarchy of a class or value type (including struct) does NOT include implemented interfaces, + and the type hierarchy of an interface is only itself (regardless of whether that interface implements other interfaces). + The top-most type in the type hierarchy of all non-interface types (including value types) is . + + + + + Applies a function going into inner types and stops at the first non-null result + Generic type parameter + The class/type to start with + The evaluation function returning T + The first non-null result, or null if no match + + + + Gets the reflection information for a directly declared field + The class/type where the field is defined + The name of the field + A field or null when type/name is null or when the field cannot be found + + + + Gets the reflection information for a field by searching the type and all its super types + The class/type where the field is defined + The name of the field (case sensitive) + A field or null when type/name is null or when the field cannot be found + + + + Gets the reflection information for a field + The class/type where the field is declared + The zero-based index of the field inside the class definition + A field or null when type is null or when the field cannot be found + + + + Gets the reflection information for a directly declared property + The class/type where the property is declared + The name of the property (case sensitive) + A property or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the getter method of a directly declared property + The class/type where the property is declared + The name of the property (case sensitive) + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the setter method of a directly declared property + The class/type where the property is declared + The name of the property (case sensitive) + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for a property by searching the type and all its super types + The class/type + The name + A property or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the getter method of a property by searching the type and all its super types + The class/type + The name + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for the setter method of a property by searching the type and all its super types + The class/type + The name + A method or null when type/name is null or when the property cannot be found + + + + Gets the reflection information for a directly declared method + The class/type where the method is declared + The name of the method (case sensitive) + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when type/name is null or when the method cannot be found + + + + Gets the reflection information for a method by searching the type and all its super types + The class/type where the method is declared + The name of the method (case sensitive) + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when type/name is null or when the method cannot be found + + + + Gets the reflection information for a method by searching the type and all its super types + The target method in the form TypeFullName:MethodName, where the type name matches a form recognized by Type.GetType like Some.Namespace.Type. + Optional parameters to target a specific overload of the method + Optional list of types that define the generic version of the method + A method or null when type/name is null or when the method cannot be found + + + + Gets the names of all method that are declared in a type + The declaring class/type + A list of method names + + + + Gets the names of all method that are declared in the type of the instance + An instance of the type to search in + A list of method names + + + + Gets the names of all fields that are declared in a type + The declaring class/type + A list of field names + + + + Gets the names of all fields that are declared in the type of the instance + An instance of the type to search in + A list of field names + + + + Gets the names of all properties that are declared in a type + The declaring class/type + A list of property names + + + + Gets the names of all properties that are declared in the type of the instance + An instance of the type to search in + A list of property names + + + + Gets the type of any class member of + A member + The class/type of this member + + + + Test if a class member is actually an concrete implementation + A member + True if the member is a declared + + + + Gets the real implementation of a class member + A member + The member itself if its declared. Otherwise the member that is actually implemented in some base type + + + + Gets the reflection information for a directly declared constructor + The class/type where the constructor is declared + Optional parameters to target a specific overload of the constructor + Optional parameters to only consider static constructors + A constructor info or null when type is null or when the constructor cannot be found + + + + Gets the reflection information for a constructor by searching the type and all its super types + The class/type where the constructor is declared + Optional parameters to target a specific overload of the method + Optional parameters to only consider static constructors + A constructor info or null when type is null or when the method cannot be found + + + + Gets reflection information for all declared constructors + The class/type where the constructors are declared + Optional parameters to only consider static constructors + A list of constructor infos + + + + Gets reflection information for all declared methods + The class/type where the methods are declared + A list of methods + + + + Gets reflection information for all declared properties + The class/type where the properties are declared + A list of properties + + + + Gets reflection information for all declared fields + The class/type where the fields are declared + A list of fields + + + + Gets the return type of a method or constructor + The method/constructor + The return type + + + + Given a type, returns the first inner type matching a recursive search by name + The class/type to start searching at + The name of the inner type (case sensitive) + The inner type or null if type/name is null or if a type with that name cannot be found + + + + Given a type, returns the first inner type matching a recursive search with a predicate + The class/type to start searching at + The predicate to search with + The inner type or null if type/predicate is null or if a type with that name cannot be found + + + + Given a type, returns the first method matching a predicate + The class/type to start searching at + The predicate to search with + The method or null if type/predicate is null or if a type with that name cannot be found + + + + Given a type, returns the first constructor matching a predicate + The class/type to start searching at + The predicate to search with + The constructor info or null if type/predicate is null or if a type with that name cannot be found + + + + Given a type, returns the first property matching a predicate + The class/type to start searching at + The predicate to search with + The property or null if type/predicate is null or if a type with that name cannot be found + + + + Returns an array containing the type of each object in the given array + An array of objects + An array of types or an empty array if parameters is null (if an object is null, the type for it will be object) + + + + Creates an array of input parameters for a given method and a given set of potential inputs + The method/constructor you are planing to call + The possible input parameters in any order + An object array matching the method signature + + + + A readable/assignable reference delegate to an instance field of a class or static field (NOT an instance field of a struct) + + An arbitrary type if the field is static; otherwise the class that defines the field, or a parent class (including ), + implemented interface, or derived class of this type + + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The runtime instance to access the field (ignored and can be omitted for static fields) + A readable/assignable reference to the field + Null instance passed to a non-static field ref delegate + + Instance of invalid type passed to a non-static field ref delegate + (this can happen if is a parent class or interface of the field's declaring type) + + + + This delegate cannot be used for instance fields of structs, since a struct instance passed to the delegate would be passed by + value and thus would be a copy that only exists within the delegate's invocation. This is fine for a readonly reference, + but makes assignment futile. Use instead. + + + Note that is not required to be the field's declaring type. It can be a parent class (including ), + implemented interface, or a derived class of the field's declaring type ("instanceOfT is FieldDeclaringType" must be possible). + Specifically, must be assignable from OR to the field's declaring type. + Technically, this allows Nullable, although Nullable is only relevant for structs, and since only static fields of structs + are allowed for this delegate, and the instance passed to such a delegate is ignored, this hardly matters. + + + Similarly, is not required to be the field's field type, unless that type is a non-enum value type. + It can be a parent class (including object) or implemented interface of the field's field type. It cannot be a derived class. + This variance is not allowed for value types, since that would require boxing/unboxing, which is not allowed for ref values. + Special case for enum types: can also be the underlying integral type of the enum type. + Specifically, for reference types, must be assignable from + the field's field type; for non-enum value types, must be exactly the field's field type; for enum types, + must be either the field's field type or the underyling integral type of that field type. + + + This delegate supports static fields, even those defined in structs, for legacy reasons. + For such static fields, is effectively ignored. + Consider using (and StaticFieldRefAccess methods that return it) instead for static fields. + + + + + + Creates a field reference delegate for an instance field of a class + The class that defines the instance field, or derived class of this type + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The name of the field + A readable/assignable delegate + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + Creates an instance field reference for a specific instance of a class + The class that defines the instance field, or derived class of this type + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The name of the field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance. + If you need to access a field's value for potentially multiple instances, use instead. + FieldRefAccess<T, F>(instance, fieldName) is functionally equivalent to FieldRefAccess<T, F>(fieldName)(instance). + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct) + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + + The type that defines the field, or derived class of this type; must not be a struct type unless the field is static + + The name of the field + + A readable/assignable delegate with T=object + (for static fields, the instance delegate parameter is ignored) + + + + This method is meant for cases where the given type is only known at runtime and thus can't be used as a type parameter T + in e.g. . + + + This method supports static fields, even those defined in structs, for legacy reasons. + Consider using (and other overloads) instead for static fields. + + + + + + Creates a field reference delegate for an instance field of a class or static field (NOT an instance field of a struct) + + An arbitrary type if the field is static; otherwise the class that defines the field, or a parent class (including ), + implemented interface, or derived class of this type ("instanceOfT is FieldDeclaringType" must be possible) + + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable delegate + + + This method is meant for cases where the field has already been obtained, avoiding the field searching cost in + e.g. . + + + This method supports static fields, even those defined in structs, for legacy reasons. + For such static fields, is effectively ignored. + Consider using (and other overloads) instead for static fields. + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + Creates a field reference for an instance field of a class + + The type that defines the field; or a parent class (including ), implemented interface, or derived class of this type + ("instanceOfT is FieldDeclaringType" must be possible) + + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance and where the field has already been obtained. + If you need to access a field's value for potentially multiple instances, use instead. + FieldRefAccess<T, F>(instance, fieldInfo) is functionally equivalent to FieldRefAccess<T, F>(fieldInfo)(instance). + + + For backwards compatibility, there is no class constraint on . + Instead, the non-value-type check is done at runtime within the method. + + + + + + A readable/assignable reference delegate to an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + A reference to the runtime instance to access the field + A readable/assignable reference to the field + + + + Creates a field reference delegate for an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The name of the field + A readable/assignable delegate + + + + Creates an instance field reference for a specific instance of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The name of the field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance. + If you need to access a field's value for potentially multiple instances, use instead. + StructFieldRefAccess<T, F>(ref instance, fieldName) is functionally equivalent to StructFieldRefAccess<T, F>(fieldName)(ref instance). + + + + + + Creates a field reference delegate for an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable delegate + + + This method is meant for cases where the field has already been obtained, avoiding the field searching cost in + e.g. . + + + + + + Creates a field reference for an instance field of a struct + The struct that defines the instance field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The instance + The field + A readable/assignable reference to the field + + + This method is meant for one-off access to a field's value for a single instance and where the field has already been obtained. + If you need to access a field's value for potentially multiple instances, use instead. + StructFieldRefAccess<T, F>(ref instance, fieldInfo) is functionally equivalent to StructFieldRefAccess<T, F>(fieldInfo)(ref instance). + + + + + + A readable/assignable reference delegate to a static field + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + A readable/assignable reference to the field + + + + Creates a static field reference + The type (can be class or struct) the field is defined in + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The name of the field + A readable/assignable reference to the field + + + + Creates a static field reference + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The type (can be class or struct) the field is defined in + The name of the field + A readable/assignable reference to the field + + + + Creates a static field reference + An arbitrary type (by convention, the type the field is defined in) + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable reference to the field + + The type parameter is only used in exception messaging and to distinguish between this method overload + and the overload (which returns a rather than a reference). + + + + + Creates a static field reference delegate + + The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type), + a type that is assignable from that type; or if the field's type is an enum type, + either that type or the underlying integral type of that enum type + + The field + A readable/assignable delegate + + + + Creates a delegate to a given method + The delegate Type + The method to create a delegate from. + + Only applies for instance methods. If null (default), returned delegate is an open (a.k.a. unbound) instance delegate + where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound) + instance delegate where the delegate invocation always applies to the given . + + + Only applies for instance methods. If true (default) and is virtual, invocation of the delegate + calls the instance method virtually (the instance type's most-derived/overriden implementation of the method is called); + else, invocation of the delegate calls the exact specified (this is useful for calling base class methods) + Note: if false and is an interface method, an ArgumentException is thrown. + + A delegate of given to given + + + Delegate invocation is more performant and more convenient to use than + at a one-time setup cost. + + + Works for both type of static and instance methods, both open and closed (a.k.a. unbound and bound) instance methods, + and both class and struct methods. + + + + + + Creates a delegate for a given delegate definition, attributed with [] + The delegate Type, attributed with [] + + Only applies for instance methods. If null (default), returned delegate is an open (a.k.a. unbound) instance delegate + where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound) + instance delegate where the delegate invocation always applies to the given . + + A delegate of given to the method specified via [] + attributes on + + This calls with the method and virtualCall arguments + determined from the [] attributes on , + and the given (for closed instance delegates). + + + + + Returns who called the current method + The calling method/constructor (excluding the caller) + + + + Rethrows an exception while preserving its stack trace (throw statement typically clobbers existing stack traces) + The exception to rethrow + + + + True if the current runtime is based on Mono, false otherwise (.NET) + + + + True if the current runtime is .NET Framework, false otherwise (.NET Core or Mono, although latter isn't guaranteed) + + + + True if the current runtime is .NET Core, false otherwise (Mono or .NET Framework) + + + + Throws a missing member runtime exception + The type that is involved + A list of names + + + + Gets default value for a specific type + The class/type + The default value + + + + Creates an (possibly uninitialized) instance of a given type + The class/type + The new instance + + + + Creates an (possibly uninitialized) instance of a given type + The class/type + The new instance + + + + + A cache for the or similar Add methods for different types. + + + + Makes a deep copy of any object + The type of the instance that should be created; for legacy reasons, this must be a class or interface + The original object + A copy of the original object but of type T + + + + Makes a deep copy of any object + The type of the instance that should be created + The original object + [out] The copy of the original object + Optional value transformation function (taking a field name and src/dst instances) + The optional path root to start with + + + + Makes a deep copy of any object + The original object + The type of the instance that should be created + Optional value transformation function (taking a field name and src/dst instances) + The optional path root to start with + The copy of the original object + + + + Tests if a type is a struct + The type + True if the type is a struct + + + + Tests if a type is a class + The type + True if the type is a class + + + + Tests if a type is a value type + The type + True if the type is a value type + + + + Tests if a type is an integer type + The type + True if the type represents some integer + + + + Tests if a type is a floating point type + The type + True if the type represents some floating point + + + + Tests if a type is a numerical type + The type + True if the type represents some number + + + + Tests if a type is void + The type + True if the type is void + + + + Test whether an instance is of a nullable type + Type of instance + An instance to test + True if instance is of nullable type, false if not + + + + Tests whether a type or member is static, as defined in C# + The type or member + True if the type or member is static + + + + Tests whether a type is static, as defined in C# + The type + True if the type is static + + + + Tests whether a property is static, as defined in C# + The property + True if the property is static + + + + Tests whether an event is static, as defined in C# + The event + True if the event is static + + + + Calculates a combined hash code for an enumeration of objects + The objects + The hash code + + + + General extensions for common cases + + + + Joins an enumeration with a value converter and a delimiter to a string + The inner type of the enumeration + The enumeration + An optional value converter (from T to string) + An optional delimiter + The values joined into a string + + + + Converts an array of types (for example methods arguments) into a human readable form + The array of types + A human readable description including brackets + + + + A full description of a type + The type + A human readable description + + + + A a full description of a method or a constructor without assembly details but with generics + The method/constructor + A human readable description + + + + A helper converting parameter infos to types + The array of parameter infos + An array of types + + + + A helper to access a value via key from a dictionary + The key type + The value type + The dictionary + The key + The value for the key or the default value (of T) if that key does not exist + + + + A helper to access a value via key from a dictionary with extra casting + The value type + The dictionary + The key + The value for the key or the default value (of T) if that key does not exist or cannot be cast to T + + + + Escapes Unicode and ASCII non printable characters + The string to convert + The string to convert + A string literal surrounded by + + + + Extensions for + + + + Shortcut for testing whether the operand is equal to a non-null value + The + The value + True if the operand has the same type and is equal to the value + + + + Shortcut for testing whether the operand is equal to a non-null value + The + The value + True if the operand is equal to the value + This is an optimized version of for + + + + Shortcut for code.opcode == opcode && code.OperandIs(operand) + The + The + The operand value + True if the opcode is equal to the given opcode and the operand has the same type and is equal to the given operand + + + + Shortcut for code.opcode == opcode && code.OperandIs(operand) + The + The + The operand value + True if the opcode is equal to the given opcode and the operand is equal to the given operand + This is an optimized version of for + + + + Tests for any form of Ldarg* + The + The (optional) index + True if it matches one of the variations + + + + Tests for Ldarga/Ldarga_S + The + The (optional) index + True if it matches one of the variations + + + + Tests for Starg/Starg_S + The + The (optional) index + True if it matches one of the variations + + + + Tests for any form of Ldloc* + The + The optional local variable + True if it matches one of the variations + + + + Tests for any form of Stloc* + The + The optional local variable + True if it matches one of the variations + + + + Tests if the code instruction branches + The + The label if the instruction is a branch operation or if not + True if the instruction branches + + + + Tests if the code instruction calls the method/constructor + The + The method + True if the instruction calls the method or constructor + + + + Tests if the code instruction loads a constant + The + True if the instruction loads a constant + + + + Tests if the code instruction loads an integer constant + The + The integer constant + True if the instruction loads the constant + + + + Tests if the code instruction loads a floating point constant + The + The floating point constant + True if the instruction loads the constant + + + + Tests if the code instruction loads an enum constant + The + The enum + True if the instruction loads the constant + + + + Tests if the code instruction loads a field + The + The field + Set to true if the address of the field is loaded + True if the instruction loads the field + + + + Tests if the code instruction stores a field + The + The field + True if the instruction stores this field + + + + Adds labels to the code instruction and return it + The + One or several to add + The same code instruction + + + Adds labels to the code instruction and return it + The + An enumeration of + The same code instruction + + + Extracts all labels from the code instruction and returns them + The + A list of + + + Moves all labels from the code instruction to a different one + The to move the labels from + The to move the labels to + The code instruction labels were moved from (now empty) + + + Moves all labels from a different code instruction to the current one + The to move the labels from + The to move the labels to + The code instruction that received the labels + + + Adds ExceptionBlocks to the code instruction and return it + The + One or several to add + The same code instruction + + + Adds ExceptionBlocks to the code instruction and return it + The + An enumeration of + The same code instruction + + + Extracts all ExceptionBlocks from the code instruction and returns them + The + A list of + + + Moves all ExceptionBlocks from the code instruction to a different one + The to move the ExceptionBlocks from + The to move the ExceptionBlocks to + The code instruction blocks were moved from (now empty) + + + Moves all ExceptionBlocks from a different code instruction to the current one + The to move the ExceptionBlocks from + The to move the ExceptionBlocks to + The code instruction that received the blocks + + + General extensions for collections + + + + A simple way to execute code for every element in a collection + The inner type of the collection + The collection + The action to execute + + + + A simple way to execute code for elements in a collection matching a condition + The inner type of the collection + The collection + The predicate + The action to execute + + + + A helper to add an item to a collection + The inner type of the collection + The collection + The item to add + The collection containing the item + + + + A helper to add an item to an array + The inner type of the collection + The array + The item to add + The array containing the item + + + + A helper to add items to an array + The inner type of the collection + The array + The items to add + The array containing the items + + + + General extensions for collections + + + + Tests a class member if it has an IL method body (external methods for example don't have a body) + The member to test + Returns true if the member has an IL body or false if not + + + A file log for debugging + + + + Full pathname of the log file, defaults to a file called harmony.log.txt on your Desktop + + + + The indent character. The default is tab + + + + The current indent level + + + + Changes the indentation level + The value to add to the indentation level + + + + Log a string in a buffered way. Use this method only if you are sure that FlushBuffer will be called + or else logging information is incomplete in case of a crash + The string to log + + + + Logs a list of string in a buffered way. Use this method only if you are sure that FlushBuffer will be called + or else logging information is incomplete in case of a crash + A list of strings to log (they will not be re-indented) + + + + Returns the log buffer and optionally empties it + True to empty the buffer + The buffer. + + + + Replaces the buffer with new lines + The lines to store + + + + Flushes the log buffer to disk (use in combination with LogBuffered) + + + + Log a string directly to disk. Slower method that prevents missing information in case of a crash + The string to log. + + + + Resets and deletes the log + + + + Logs some bytes as hex values + The pointer to some memory + The length of bytes to log + + + + A helper class to retrieve reflection info for non-private methods + + + + Given a lambda expression that calls a method, returns the method info + The lambda expression using the method + The method in the lambda expression + + + + Given a lambda expression that calls a method, returns the method info + The generic type + The lambda expression using the method + The method in the lambda expression + + + + Given a lambda expression that calls a method, returns the method info + The generic type + The generic result type + The lambda expression using the method + The method in the lambda expression + + + + Given a lambda expression that calls a method, returns the method info + The lambda expression using the method + The method in the lambda expression + + + + A reflection helper to read and write private elements + The result type defined by GetValue() + + + + Creates a traverse instance from an existing instance + The existing instance + + + + Gets/Sets the current value + The value to read or write + + + + A reflection helper to read and write private elements + + + + Creates a new traverse instance from a class/type + The class/type + A instance + + + + Creates a new traverse instance from a class T + The class + A instance + + + + Creates a new traverse instance from an instance + The object + A instance + + + + Creates a new traverse instance from a named type + The type name, for format see + A instance + + + + Creates a new and empty traverse instance + + + + Creates a new traverse instance from a class/type + The class/type + + + + Creates a new traverse instance from an instance + The object + + + + Gets the current value + The value + + + + Gets the current value + The type of the value + The value + + + + Invokes the current method with arguments and returns the result + The method arguments + The value returned by the method + + + + Invokes the current method with arguments and returns the result + The type of the value + The method arguments + The value returned by the method + + + + Sets a value of the current field or property + The value + The same traverse instance + + + + Gets the type of the current field or property + The type + + + + Moves the current traverse instance to a inner type + The type name + A traverse instance + + + + Moves the current traverse instance to a field + The type name + A traverse instance + + + + Moves the current traverse instance to a field + The type of the field + The type name + A traverse instance + + + + Gets all fields of the current type + A list of field names + + + + Moves the current traverse instance to a property + The type name + Optional property index + A traverse instance + + + + Moves the current traverse instance to a field + The type of the property + The type name + Optional property index + A traverse instance + + + + Gets all properties of the current type + A list of property names + + + + Moves the current traverse instance to a method + The name of the method + The arguments defining the argument types of the method overload + A traverse instance + + + + Moves the current traverse instance to a method + The name of the method + The argument types of the method + The arguments for the method + A traverse instance + + + + Gets all methods of the current type + A list of method names + + + + Checks if the current traverse instance is for a field + True if its a field + + + + Checks if the current traverse instance is for a property + True if its a property + + + + Checks if the current traverse instance is for a method + True if its a method + + + + Checks if the current traverse instance is for a type + True if its a type + + + + Iterates over all fields of the current type and executes a traverse action + Original object + The action receiving a instance for each field + + + + Iterates over all fields of the current type and executes a traverse action + Original object + Target object + The action receiving a pair of instances for each field pair + + + + Iterates over all fields of the current type and executes a traverse action + Original object + Target object + The action receiving a dot path representing the field pair and the instances + + + + Iterates over all properties of the current type and executes a traverse action + Original object + The action receiving a instance for each property + + + + Iterates over all properties of the current type and executes a traverse action + Original object + Target object + The action receiving a pair of instances for each property pair + + + + Iterates over all properties of the current type and executes a traverse action + Original object + Target object + The action receiving a dot path representing the property pair and the instances + + + + A default field action that copies fields to fields + + + + Returns a string that represents the current traverse + A string representation + + + + diff --git a/build/common.targets b/build/common.targets index ce805402..f5d01606 100644 --- a/build/common.targets +++ b/build/common.targets @@ -38,6 +38,7 @@ + diff --git a/build/prepare-install-package.targets b/build/prepare-install-package.targets index 408230a9..0c1a6c1a 100644 --- a/build/prepare-install-package.targets +++ b/build/prepare-install-package.targets @@ -45,6 +45,7 @@ + diff --git a/docs/release-notes.md b/docs/release-notes.md index d0aa2fbf..50ed5f29 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -1,11 +1,9 @@ ← [README](README.md) # Release notes - + * Updated Harmony 1.2.0.1 to 2.1.0 (see [_migrate to Harmony 2.0_](https://stardewvalleywiki.com/Modding:Migrate_to_Harmony_2.0) for more info). ## 3.11.0 Released 09 July 2021 for Stardew Valley 1.5.4 or later. See [release highlights](https://www.patreon.com/posts/53514295). diff --git a/docs/technical/smapi.md b/docs/technical/smapi.md index b64239c1..586b17aa 100644 --- a/docs/technical/smapi.md +++ b/docs/technical/smapi.md @@ -59,7 +59,6 @@ flag | purpose `SMAPI_FOR_WINDOWS` | Whether SMAPI is being compiled for Windows; if not set, the code assumes Linux/macOS. Set automatically in `common.targets`. `SMAPI_FOR_WINDOWS_64BIT_HACK` | Whether SMAPI is being [compiled for Windows with a 64-bit Linux version of the game](https://github.com/Pathoschild/SMAPI/issues/767). This is highly specialized and shouldn't be used in most cases. False by default. `SMAPI_FOR_XNA` | Whether SMAPI is being compiled for XNA Framework; if not set, the code assumes MonoGame. Set automatically in `common.targets` with the same value as `SMAPI_FOR_WINDOWS` (unless `SMAPI_FOR_WINDOWS_64BIT_HACK` is set). -`HARMONY_2` | Whether to enable experimental Harmony 2.0 support and rewrite existing Harmony 1._x_ mods for compatibility. Note that you need to replace `build/0Harmony.dll` with a Harmony 2.0 build (or switch to a package reference) to use this flag. ## For SMAPI developers ### Compiling from source diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/DialogueErrorPatch.cs b/src/SMAPI.Mods.ErrorHandler/Patches/DialogueErrorPatch.cs index cce13064..a065e3d7 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/DialogueErrorPatch.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/DialogueErrorPatch.cs @@ -1,15 +1,10 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using StardewModdingAPI.Framework.Patching; -using StardewValley; -#if HARMONY_2 using HarmonyLib; using StardewModdingAPI.Framework; -#else -using System.Reflection; -using Harmony; -#endif +using StardewModdingAPI.Framework.Patching; +using StardewValley; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { @@ -41,9 +36,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches DialogueErrorPatch.Reflection = reflector; } - /// -#if HARMONY_2 public void Apply(Harmony harmony) { harmony.Patch( @@ -55,25 +48,11 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches finalizer: new HarmonyMethod(this.GetType(), nameof(DialogueErrorPatch.Finalize_NPC_CurrentDialogue)) ); } -#else - public void Apply(HarmonyInstance harmony) - { - harmony.Patch( - original: AccessTools.Constructor(typeof(Dialogue), new[] { typeof(string), typeof(NPC) }), - 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)) - ); - } -#endif /********* ** Private methods *********/ -#if HARMONY_2 /// The method to call after the Dialogue constructor. /// The instance being patched. /// The dialogue being parsed. @@ -113,72 +92,5 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches return null; } -#else - - /// The method to call instead of the Dialogue constructor. - /// The instance being patched. - /// The dialogue being parsed. - /// The NPC for which the dialogue is being parsed. - /// Returns whether to execute the original method. - private static bool Before_Dialogue_Constructor(Dialogue __instance, string masterDialogue, NPC speaker) - { - // get private members - bool nameArraysTranslated = DialogueErrorPatch.Reflection.GetField(typeof(Dialogue), "nameArraysTranslated").GetValue(); - IReflectedMethod translateArraysOfStrings = DialogueErrorPatch.Reflection.GetMethod(typeof(Dialogue), "TranslateArraysOfStrings"); - IReflectedMethod parseDialogueString = DialogueErrorPatch.Reflection.GetMethod(__instance, "parseDialogueString"); - IReflectedMethod checkForSpecialDialogueAttributes = DialogueErrorPatch.Reflection.GetMethod(__instance, "checkForSpecialDialogueAttributes"); - - // replicate base constructor - __instance.dialogues ??= new List(); - - // duplicate code with try..catch - try - { - if (!nameArraysTranslated) - translateArraysOfStrings.Invoke(); - __instance.speaker = speaker; - parseDialogueString.Invoke(masterDialogue); - checkForSpecialDialogueAttributes.Invoke(); - } - catch (Exception baseEx) when (baseEx.InnerException is TargetInvocationException invocationEx && invocationEx.InnerException is Exception ex) - { - string name = !string.IsNullOrWhiteSpace(speaker?.Name) ? speaker.Name : null; - DialogueErrorPatch.MonitorForGame.Log($"Failed parsing dialogue string{(name != null ? $" for {name}" : "")}:\n{masterDialogue}\n{ex}", LogLevel.Error); - - parseDialogueString.Invoke("..."); - checkForSpecialDialogueAttributes.Invoke(); - } - - 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. - private static bool Before_NPC_CurrentDialogue(NPC __instance, ref Stack __result, MethodInfo __originalMethod) - { - const string key = nameof(DialogueErrorPatch.Before_NPC_CurrentDialogue); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __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 - { - PatchHelper.StopIntercept(key); - } - } -#endif } } diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs index 72863d17..390aa778 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/EventPatches.cs @@ -1,10 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif using StardewModdingAPI.Framework.Patching; using StardewValley; @@ -34,11 +30,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { harmony.Patch( original: AccessTools.Method(typeof(Event), nameof(Event.LogErrorAndHalt)), diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs index 7a48133e..ec809fba 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/GameLocationPatches.cs @@ -1,11 +1,6 @@ -using System.Diagnostics.CodeAnalysis; -#if HARMONY_2 using System; +using System.Diagnostics.CodeAnalysis; using HarmonyLib; -#else -using System.Reflection; -using Harmony; -#endif using StardewModdingAPI.Framework.Patching; using StardewValley; using xTile; @@ -36,37 +31,22 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// -#if HARMONY_2 public void Apply(Harmony harmony) { harmony.Patch( original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.checkEventPrecondition)), - finalizer: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Finalize_GameLocation_CheckEventPrecondition)) - ); -harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.updateSeasonalTileSheets)), - finalizer: new HarmonyMethod(this.GetType(), nameof(EventErrorPatch.Before_GameLocation_UpdateSeasonalTileSheets)) - ); - } -#else - public void Apply(HarmonyInstance harmony) - { - harmony.Patch( - original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.checkEventPrecondition)), - prefix: new HarmonyMethod(this.GetType(), nameof(GameLocationPatches.Before_GameLocation_CheckEventPrecondition)) + finalizer: new HarmonyMethod(this.GetType(), nameof(GameLocationPatches.Finalize_GameLocation_CheckEventPrecondition)) ); harmony.Patch( original: AccessTools.Method(typeof(GameLocation), nameof(GameLocation.updateSeasonalTileSheets)), - prefix: new HarmonyMethod(this.GetType(), nameof(GameLocationPatches.Before_GameLocation_UpdateSeasonalTileSheets)) + finalizer: new HarmonyMethod(this.GetType(), nameof(GameLocationPatches.Before_GameLocation_UpdateSeasonalTileSheets)) ); } -#endif /********* ** Private methods *********/ -#if HARMONY_2 /// The method to call instead of GameLocation.checkEventPrecondition. /// The return value of the original method. /// The precondition to be parsed. @@ -77,43 +57,12 @@ harmony.Patch( if (__exception != null) { __result = -1; - EventErrorPatch.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{__exception.InnerException}", LogLevel.Error); + GameLocationPatches.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{__exception.InnerException}", LogLevel.Error); } return null; } -#else - /// The method to call instead of . - /// 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. - private static bool Before_GameLocation_CheckEventPrecondition(GameLocation __instance, ref int __result, string precondition, MethodInfo __originalMethod) - { - const string key = nameof(GameLocationPatches.Before_GameLocation_CheckEventPrecondition); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __result = (int)__originalMethod.Invoke(__instance, new object[] { precondition }); - return false; - } - catch (TargetInvocationException ex) - { - __result = -1; - GameLocationPatches.MonitorForGame.Log($"Failed parsing event precondition ({precondition}):\n{ex.InnerException}", LogLevel.Error); - return false; - } - finally - { - PatchHelper.StopIntercept(key); - } - } -#endif -#if HARMONY_2 /// The method to call instead of . /// The instance being patched. /// The map whose tilesheets to update. @@ -126,33 +75,5 @@ harmony.Patch( return null; } -#else - /// The method to call instead of . - /// The instance being patched. - /// The map whose tilesheets to update. - /// The method being wrapped. - /// Returns whether to execute the original method. - private static bool Before_GameLocation_UpdateSeasonalTileSheets(GameLocation __instance, Map map, MethodInfo __originalMethod) - { - const string key = nameof(GameLocationPatches.Before_GameLocation_UpdateSeasonalTileSheets); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __originalMethod.Invoke(__instance, new object[] { map }); - return false; - } - catch (TargetInvocationException ex) - { - GameLocationPatches.MonitorForGame.Log($"Failed updating seasonal tilesheets for location '{__instance.NameOrUniqueName}'. Technical details:\n{ex.InnerException}", LogLevel.Error); - return false; - } - finally - { - PatchHelper.StopIntercept(key); - } - } -#endif } } diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/LoadErrorPatch.cs b/src/SMAPI.Mods.ErrorHandler/Patches/LoadErrorPatch.cs index 52d5f5a1..e14dc662 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/LoadErrorPatch.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/LoadErrorPatch.cs @@ -2,11 +2,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif using StardewModdingAPI.Framework.Exceptions; using StardewModdingAPI.Framework.Patching; using StardewValley; @@ -45,11 +41,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { harmony.Patch( original: AccessTools.Method(typeof(SaveGame), nameof(SaveGame.loadDataToLocations)), diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/ObjectErrorPatch.cs b/src/SMAPI.Mods.ErrorHandler/Patches/ObjectErrorPatch.cs index 9f8a98cd..a68e359c 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/ObjectErrorPatch.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/ObjectErrorPatch.cs @@ -1,16 +1,11 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using HarmonyLib; using StardewModdingAPI.Framework.Patching; using StardewValley; using StardewValley.Menus; using SObject = StardewValley.Object; -#if HARMONY_2 -using System; -using HarmonyLib; -#else -using System.Reflection; -using Harmony; -#endif namespace StardewModdingAPI.Mods.ErrorHandler.Patches { @@ -24,11 +19,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches ** Public methods *********/ /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { // object.getDescription harmony.Patch( @@ -39,11 +30,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches // object.getDisplayName harmony.Patch( original: AccessTools.Method(typeof(SObject), "loadDisplayName"), -#if HARMONY_2 finalizer: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Finalize_Object_loadDisplayName)) -#else - prefix: new HarmonyMethod(this.GetType(), nameof(ObjectErrorPatch.Before_Object_loadDisplayName)) -#endif ); // IClickableMenu.drawToolTip @@ -73,7 +60,6 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches return true; } -#if HARMONY_2 /// The method to call after . /// The patched method's return value. /// The exception thrown by the wrapped method, if any. @@ -88,38 +74,6 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches return __exception; } -#else - /// The method to call instead of . - /// The instance being patched. - /// The patched method's return value. - /// The method being wrapped. - /// Returns whether to execute the original method. - private static bool Before_Object_loadDisplayName(SObject __instance, ref string __result, MethodInfo __originalMethod) - { - const string key = nameof(ObjectErrorPatch.Before_Object_loadDisplayName); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __result = (string)__originalMethod.Invoke(__instance, new object[0]); - return false; - } - catch (TargetInvocationException ex) when (ex.InnerException is KeyNotFoundException) - { - __result = "???"; - return false; - } - catch - { - return true; - } - finally - { - PatchHelper.StopIntercept(key); - } - } -#endif /// The method to call instead of . /// The item for which to draw a tooltip. diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/ScheduleErrorPatch.cs b/src/SMAPI.Mods.ErrorHandler/Patches/ScheduleErrorPatch.cs index d2a5e988..d2e332b4 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/ScheduleErrorPatch.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/ScheduleErrorPatch.cs @@ -1,15 +1,10 @@ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using StardewModdingAPI.Framework.Patching; -using StardewValley; -#if HARMONY_2 -using System; using HarmonyLib; using StardewModdingAPI.Framework; -#else -using System.Reflection; -using Harmony; -#endif +using StardewModdingAPI.Framework.Patching; +using StardewValley; namespace StardewModdingAPI.Mods.ErrorHandler.Patches { @@ -37,19 +32,11 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches } /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { harmony.Patch( original: AccessTools.Method(typeof(NPC), nameof(NPC.parseMasterSchedule)), -#if HARMONY_2 finalizer: new HarmonyMethod(this.GetType(), nameof(ScheduleErrorPatch.Finalize_NPC_parseMasterSchedule)) -#else - prefix: new HarmonyMethod(this.GetType(), nameof(ScheduleErrorPatch.Before_NPC_parseMasterSchedule)) -#endif ); } @@ -57,7 +44,6 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches /********* ** Private methods *********/ -#if HARMONY_2 /// The method to call instead of . /// The raw schedule data to parse. /// The instance being patched. @@ -74,35 +60,5 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches return null; } -#else - /// The method to call instead of . - /// The raw schedule data to parse. - /// The instance being patched. - /// The patched method's return value. - /// The method being wrapped. - /// Returns whether to execute the original method. - private static bool Before_NPC_parseMasterSchedule(string rawData, NPC __instance, ref Dictionary __result, MethodInfo __originalMethod) - { - const string key = nameof(ScheduleErrorPatch.Before_NPC_parseMasterSchedule); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __result = (Dictionary)__originalMethod.Invoke(__instance, new object[] { rawData }); - return false; - } - catch (TargetInvocationException ex) - { - ScheduleErrorPatch.MonitorForGame.Log($"Failed parsing schedule for NPC {__instance.Name}:\n{rawData}\n{ex.InnerException ?? ex}", LogLevel.Error); - __result = new Dictionary(); - return false; - } - finally - { - PatchHelper.StopIntercept(key); - } - } -#endif } } diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs index 8056fd71..7fdf5a48 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/SpriteBatchValidationPatches.cs @@ -1,10 +1,6 @@ -#if HARMONY_2 -using HarmonyLib; -#else -using Harmony; -#endif using System; using System.Diagnostics.CodeAnalysis; +using HarmonyLib; using Microsoft.Xna.Framework.Graphics; using StardewModdingAPI.Framework.Patching; @@ -20,11 +16,7 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches ** Public methods *********/ /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { harmony.Patch( original: Constants.GameFramework == GameFramework.Xna diff --git a/src/SMAPI.Mods.ErrorHandler/Patches/UtilityErrorPatches.cs b/src/SMAPI.Mods.ErrorHandler/Patches/UtilityErrorPatches.cs index 1ddd407c..cd57736f 100644 --- a/src/SMAPI.Mods.ErrorHandler/Patches/UtilityErrorPatches.cs +++ b/src/SMAPI.Mods.ErrorHandler/Patches/UtilityErrorPatches.cs @@ -1,12 +1,6 @@ -#if HARMONY_2 -using System; -using HarmonyLib; -#else -using Harmony; -#endif using System; using System.Diagnostics.CodeAnalysis; -using System.Reflection; +using HarmonyLib; using StardewModdingAPI.Framework.Patching; using StardewValley; @@ -22,7 +16,6 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches ** Public methods *********/ /// -#if HARMONY_2 public void Apply(Harmony harmony) { harmony.Patch( @@ -30,21 +23,11 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches finalizer: new HarmonyMethod(this.GetType(), nameof(UtilityErrorPatches.Finalize_Utility_GetItemFromStandardTextDescription)) ); } -#else - public void Apply(HarmonyInstance harmony) - { - harmony.Patch( - original: AccessTools.Method(typeof(Utility), nameof(Utility.getItemFromStandardTextDescription)), - prefix: new HarmonyMethod(this.GetType(), nameof(UtilityErrorPatches.Before_Utility_GetItemFromStandardTextDescription)) - ); - } -#endif /********* ** Private methods *********/ -#if HARMONY_2 /// The method to call instead of . /// The item text description to parse. /// The delimiter by which to split the text description. @@ -56,34 +39,5 @@ namespace StardewModdingAPI.Mods.ErrorHandler.Patches ? new FormatException($"Failed to parse item text description \"{description}\" with delimiter \"{delimiter}\".", __exception) : null; } -#else - /// The method to call instead of . - /// The return value of the original method. - /// The item text description to parse. - /// The player for which the item is being parsed. - /// The delimiter by which to split the text description. - /// The method being wrapped. - /// Returns whether to execute the original method. - private static bool Before_Utility_GetItemFromStandardTextDescription(ref Item __result, string description, Farmer who, char delimiter, MethodInfo __originalMethod) - { - const string key = nameof(UtilityErrorPatches.Before_Utility_GetItemFromStandardTextDescription); - if (!PatchHelper.StartIntercept(key)) - return true; - - try - { - __result = (Item)__originalMethod.Invoke(null, new object[] { description, who, delimiter }); - return false; - } - catch (TargetInvocationException ex) - { - throw new FormatException($"Failed to parse item text description \"{description}\" with delimiter \"{delimiter}\".", ex.InnerException); - } - finally - { - PatchHelper.StopIntercept(key); - } - } -#endif } } diff --git a/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs b/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs index f3731d16..45b34556 100644 --- a/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs +++ b/src/SMAPI/Framework/Commands/HarmonySummaryCommand.cs @@ -3,25 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif namespace StardewModdingAPI.Framework.Commands { /// The 'harmony_summary' SMAPI console command. internal class HarmonySummaryCommand : IInternalCommand { -#if !HARMONY_2 - /********* - ** Fields - *********/ - /// The Harmony instance through which to fetch patch info. - private readonly HarmonyInstance HarmonyInstance = HarmonyInstance.Create($"SMAPI.{nameof(HarmonySummaryCommand)}"); -#endif - /********* ** Accessors *********/ @@ -60,9 +48,7 @@ namespace StardewModdingAPI.Framework.Commands { PatchType.Prefix => 0, PatchType.Postfix => 1, -#if HARMONY_2 PatchType.Finalizer => 2, -#endif PatchType.Transpiler => 3, _ => 4 }); @@ -111,26 +97,16 @@ namespace StardewModdingAPI.Framework.Commands /// Get all current Harmony patches. private IEnumerable GetAllPatches() { -#if HARMONY_2 foreach (MethodBase method in Harmony.GetAllPatchedMethods().ToArray()) -#else - foreach (MethodBase method in this.HarmonyInstance.GetPatchedMethods().ToArray()) -#endif { // get metadata for method -#if HARMONY_2 HarmonyLib.Patches patchInfo = Harmony.GetPatchInfo(method); -#else - Harmony.Patches patchInfo = this.HarmonyInstance.GetPatchInfo(method); -#endif IDictionary> patchGroups = new Dictionary> { [PatchType.Prefix] = patchInfo.Prefixes, [PatchType.Postfix] = patchInfo.Postfixes, -#if HARMONY_2 [PatchType.Finalizer] = patchInfo.Finalizers, -#endif [PatchType.Transpiler] = patchInfo.Transpilers }; @@ -160,10 +136,8 @@ namespace StardewModdingAPI.Framework.Commands /// A postfix patch. Postfix, -#if HARMONY_2 /// A finalizer patch. Finalizer, -#endif /// A transpiler patch. Transpiler diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs index 102f3364..8e4320b3 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/AccessToolsFacade.cs @@ -1,4 +1,3 @@ -#if HARMONY_2 using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -41,4 +40,3 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades } } } -#endif diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs index ad6d5e4f..54b91679 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyInstanceFacade.cs @@ -1,4 +1,3 @@ -#if HARMONY_2 using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; @@ -81,4 +80,3 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades } } } -#endif diff --git a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs index f3975558..44c97401 100644 --- a/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs +++ b/src/SMAPI/Framework/ModLoading/RewriteFacades/HarmonyMethodFacade.cs @@ -1,4 +1,3 @@ -#if HARMONY_2 using System; using System.Diagnostics.CodeAnalysis; using System.Reflection; @@ -44,4 +43,3 @@ namespace StardewModdingAPI.Framework.ModLoading.RewriteFacades } } } -#endif diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs index 147a12f9..5a84a16a 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs @@ -1,4 +1,3 @@ -#if HARMONY_2 extern alias MonoCecilPackage; using System; @@ -44,7 +43,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters } /// - public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction, Action replaceWith) + public override bool Handle(ModuleDefinition module, ILProcessor cil, Instruction instruction) { // rewrite Harmony 1.x methods to Harmony 2.0 MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); @@ -119,4 +118,3 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters } } } -#endif diff --git a/src/SMAPI/Framework/Patching/GamePatcher.cs b/src/SMAPI/Framework/Patching/GamePatcher.cs index ddecda08..3ce22ee9 100644 --- a/src/SMAPI/Framework/Patching/GamePatcher.cs +++ b/src/SMAPI/Framework/Patching/GamePatcher.cs @@ -1,9 +1,5 @@ using System; -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif namespace StardewModdingAPI.Framework.Patching { @@ -31,11 +27,7 @@ namespace StardewModdingAPI.Framework.Patching /// The patches to apply. public void Apply(params IHarmonyPatch[] patches) { -#if HARMONY_2 Harmony harmony = new Harmony("SMAPI"); -#else - HarmonyInstance harmony = HarmonyInstance.Create("SMAPI"); -#endif foreach (IHarmonyPatch patch in patches) { try diff --git a/src/SMAPI/Framework/Patching/IHarmonyPatch.cs b/src/SMAPI/Framework/Patching/IHarmonyPatch.cs index 38d30ab2..c1ff3040 100644 --- a/src/SMAPI/Framework/Patching/IHarmonyPatch.cs +++ b/src/SMAPI/Framework/Patching/IHarmonyPatch.cs @@ -1,8 +1,4 @@ -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif namespace StardewModdingAPI.Framework.Patching { @@ -14,10 +10,6 @@ namespace StardewModdingAPI.Framework.Patching *********/ /// Apply the Harmony patch. /// The Harmony instance. -#if HARMONY_2 void Apply(Harmony harmony); -#else - void Apply(HarmonyInstance harmony); -#endif } } diff --git a/src/SMAPI/Framework/Patching/PatchHelper.cs b/src/SMAPI/Framework/Patching/PatchHelper.cs deleted file mode 100644 index d1aa0185..00000000 --- a/src/SMAPI/Framework/Patching/PatchHelper.cs +++ /dev/null @@ -1,36 +0,0 @@ -#if !HARMONY_2 -using System; -using System.Collections.Generic; - -namespace StardewModdingAPI.Framework.Patching -{ - /// Provides generic methods for implementing Harmony patches. - internal class PatchHelper - { - /********* - ** Fields - *********/ - /// The interception keys currently being intercepted. - private static readonly HashSet InterceptingKeys = new HashSet(StringComparer.OrdinalIgnoreCase); - - - /********* - ** Public methods - *********/ - /// Track a method that will be intercepted. - /// The intercept key. - /// Returns false if the method was already marked for interception, else true. - public static bool StartIntercept(string key) - { - return PatchHelper.InterceptingKeys.Add(key); - } - - /// Track a method as no longer being intercepted. - /// The intercept key. - public static void StopIntercept(string key) - { - PatchHelper.InterceptingKeys.Remove(key); - } - } -} -#endif diff --git a/src/SMAPI/Metadata/InstructionMetadata.cs b/src/SMAPI/Metadata/InstructionMetadata.cs index d1699636..a787993a 100644 --- a/src/SMAPI/Metadata/InstructionMetadata.cs +++ b/src/SMAPI/Metadata/InstructionMetadata.cs @@ -48,10 +48,8 @@ namespace StardewModdingAPI.Metadata yield return new HeuristicFieldRewriter(this.ValidateReferencesToAssemblies); yield return new HeuristicMethodRewriter(this.ValidateReferencesToAssemblies); -#if HARMONY_2 - // rewrite for SMAPI 3.x (Harmony 1.x => 2.0 update) + // rewrite for SMAPI 3.12 (Harmony 1.x => 2.0 update) yield return new Harmony1AssemblyRewriter(); -#endif } /**** @@ -64,11 +62,7 @@ namespace StardewModdingAPI.Metadata /**** ** detect code which may impact game stability ****/ -#if HARMONY_2 yield return new TypeFinder(typeof(HarmonyLib.Harmony).FullName, InstructionHandleResult.DetectedGamePatch); -#else - yield return new TypeFinder(typeof(Harmony.HarmonyInstance).FullName, InstructionHandleResult.DetectedGamePatch); -#endif yield return new TypeFinder("System.Runtime.CompilerServices.CallSite", InstructionHandleResult.DetectedDynamic); yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.serializer), InstructionHandleResult.DetectedSaveSerializer); yield return new FieldFinder(typeof(SaveGame).FullName, nameof(SaveGame.farmerSerializer), InstructionHandleResult.DetectedSaveSerializer); diff --git a/src/SMAPI/Patches/LoadContextPatch.cs b/src/SMAPI/Patches/LoadContextPatch.cs index c43d7071..721cf53d 100644 --- a/src/SMAPI/Patches/LoadContextPatch.cs +++ b/src/SMAPI/Patches/LoadContextPatch.cs @@ -1,10 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; -#if HARMONY_2 using HarmonyLib; -#else -using Harmony; -#endif using StardewModdingAPI.Enums; using StardewModdingAPI.Framework.Patching; using StardewModdingAPI.Framework.Reflection; @@ -46,11 +42,7 @@ namespace StardewModdingAPI.Patches } /// -#if HARMONY_2 public void Apply(Harmony harmony) -#else - public void Apply(HarmonyInstance harmony) -#endif { // detect CreatedBasicInfo harmony.Patch( -- cgit From 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/Framework/ModLoading/Rewriters') 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 bdae52c9ae76303fd8082b10763b9ab7660fbd35 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Mon, 26 Jul 2021 22:28:32 -0400 Subject: fix rewriting for Harmony ExceptionBlock type (#711) --- .../Rewriters/Harmony1AssemblyRewriter.cs | 46 +++++++++++----------- 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'src/SMAPI/Framework/ModLoading/Rewriters') diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs index 723983be..3197c151 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs @@ -28,7 +28,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters public override bool Handle(ModuleDefinition module, TypeReference type, Action replaceWith) { // rewrite Harmony 1.x type to Harmony 2.0 type - if (type.Scope is AssemblyNameReference scope && scope.Name == "0Harmony" && scope.Version.Major == 1) + if (type.Scope is AssemblyNameReference { Name: "0Harmony" } scope && scope.Version.Major == 1) { Type targetType = this.GetMappedType(type); replaceWith(module.ImportReference(targetType)); @@ -72,24 +72,15 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters return false; // not Harmony (or already using Harmony 2.0) // get facade type - Type toType; - switch (methodRef?.DeclaringType.FullName) + Type toType = methodRef?.DeclaringType.FullName switch { - case "HarmonyLib.Harmony": - toType = typeof(HarmonyInstanceFacade); - break; - - case "HarmonyLib.AccessTools": - toType = typeof(AccessToolsFacade); - break; - - case "HarmonyLib.HarmonyMethod": - toType = typeof(HarmonyMethodFacade); - break; - - default: - return false; - } + "HarmonyLib.Harmony" => typeof(HarmonyInstanceFacade), + "HarmonyLib.AccessTools" => typeof(AccessToolsFacade), + "HarmonyLib.HarmonyMethod" => typeof(HarmonyMethodFacade), + _ => null + }; + if (toType == null) + return false; // map if there's a matching method if (RewriteHelper.HasMatchingSignature(toType, methodRef)) @@ -102,16 +93,23 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters } /// Get an equivalent Harmony 2.x type. - /// The Harmony 1.x method. + /// The Harmony 1.x type. private Type GetMappedType(TypeReference type) { - // main Harmony object - if (type.FullName == "Harmony.HarmonyInstance") - return typeof(Harmony); + return type.FullName switch + { + "Harmony.HarmonyInstance" => typeof(Harmony), + "Harmony.ILCopying.ExceptionBlock" => typeof(ExceptionBlock), + _ => this.GetMappedTypeByConvention(type) + }; + } - // other objects + /// Get an equivalent Harmony 2.x type using the convention expected for most types. + /// The Harmony 1.x type. + private Type GetMappedTypeByConvention(TypeReference type) + { string fullName = type.FullName.Replace("Harmony.", "HarmonyLib."); - string targetName = typeof(Harmony).AssemblyQualifiedName.Replace(typeof(Harmony).FullName, fullName); + string targetName = typeof(Harmony).AssemblyQualifiedName!.Replace(typeof(Harmony).FullName!, fullName); return Type.GetType(targetName, throwOnError: true); } } -- cgit From b4f307e1ba88df072efed3b94975fa45789ae1ef Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Wed, 28 Jul 2021 00:51:45 -0400 Subject: fix rewritten Harmony 1.x code not raising 'detected game patch' flag (#711) --- .../ModLoading/Rewriters/Harmony1AssemblyRewriter.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'src/SMAPI/Framework/ModLoading/Rewriters') diff --git a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs index 3197c151..7a3b428d 100644 --- a/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs +++ b/src/SMAPI/Framework/ModLoading/Rewriters/Harmony1AssemblyRewriter.cs @@ -32,7 +32,7 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters { Type targetType = this.GetMappedType(type); replaceWith(module.ImportReference(targetType)); - this.MarkRewritten(); + this.OnChanged(); this.ReplacedTypes = true; return true; } @@ -46,14 +46,20 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters // rewrite Harmony 1.x methods to Harmony 2.0 MethodReference methodRef = RewriteHelper.AsMethodReference(instruction); if (this.TryRewriteMethodsToFacade(module, methodRef)) + { + this.OnChanged(); return true; + } // rewrite renamed fields FieldReference fieldRef = RewriteHelper.AsFieldReference(instruction); if (fieldRef != null) { if (fieldRef.DeclaringType.FullName == "HarmonyLib.HarmonyMethod" && fieldRef.Name == "prioritiy") + { fieldRef.Name = nameof(HarmonyMethod.priority); + this.OnChanged(); + } } return false; @@ -63,6 +69,13 @@ namespace StardewModdingAPI.Framework.ModLoading.Rewriters /********* ** Private methods *********/ + /// Update the mod metadata when any Harmony 1.x code is migrated. + private void OnChanged() + { + this.MarkRewritten(); + this.MarkFlag(InstructionHandleResult.DetectedGamePatch); + } + /// Rewrite methods to use Harmony facades if needed. /// The assembly module containing the method reference. /// The method reference to map. -- cgit