-
Notifications
You must be signed in to change notification settings - Fork 44
Patching with Harmony
By default, Harmony provides two ways to apply a patch: attribute-based targeting an assembly via PatchAll(Assembly)
overloads and manual via Patch
overloads. In some cases these options are not enough because
- the assembly is too big to be iterated at an acceptable speed with
PatchAll
; -
PatchAll
triggers type resolving for all types inside an assembly, which can in turn trigger unnecessary assembly resolving. This is especially unwanted in cases where you want to control when assemblies get loaded (for example in case of BepInEx preloader patchers); -
Patch
is too verbose.
In these cases you can make use of attribute-based patching targeting a type.
This is a new HarmonyX addition which allows you to instead selectively apply all patches defined in a single type. Call Harmony.PatchAll
and pass a type that contains methods annotated with HarmonyPatch:
harmony.PatchAll(typeof(Patches));
This will search a type for all methods annotated with HarmonyPatch
and other Harmony annotations and will apply patches to the targeted methods accordingly.
This method is recommended for small patches or in cases where you need to selectively apply a large number of patches.
Most of the cases you'll want to simply create an instance, call PatchAll
and be done with patching. For that, HarmonyX provides helper methods to both create an instance and apply a patch:
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly());
// or
Harmony.CreateAndPatchAll(typeof(Patch));
Note that you don't have to specify an ID: if you specify none, HarmonyX generates a unique one for you.
Note: Having HarmonyX generate an ID means that other patches can't easily unpatch or reorder your patches.
On the other hand, our experience with BepInEx showed that relying on patch ordering is unreliable at best and at worst inducing almost undebuggable errors.
Helper methods all return the created harmony instance so you can further apply additional patches.
In many cases you may want to unpatch all methods you patch with your Harmony instance. However, using Unpatch
to unpatch methods one-by-one is slow and UnpatchAll
has an often-forgotten default behaviour of unpatching EVERYTHING. We found over time that many developers forget to specify the ID of the instance to UnpatchAll
and instead end up unpatching all instances.
To unpatch just the current instance, you can use UnpatchSelf
:
// equivalent to instance.UnpatchAll(instance.Id);
instance.UnpatchSelf();
This method eliminates all possible mistakes of accidentally (and understandably) forgetting the parameter.
- Basic usage
-
HarmonyX extensions
1.1. Patching and unpatching
1.2. Prefixes are flowthrough
1.3. Targeting multiple methods with one patch
1.4. Patching enumerators
1.5. Transpiler helpers
1.6. ILManipulators
1.7. Extended patch targets
1.8. New patch attributes -
Extending HarmonyX
2.1. Custom patcher backends -
Misc
4.1. Patch parameters - Implementation differences from Harmony