Prepare, target, and clean up
Annotation patch classes can define helpers to prepare and clean up patching, or choose target methods in code.
Helpers accept these optional arguments, matched by type rather than name:
MethodBase original- the current original being patchedHarmony harmony- the current Harmony instanceException ex- only valid inCleanupand receives a possible exception
Here is a simple example that patches a method inside a private type:
[HarmonyPatch] // at least one Harmony annotation makes Harmony not skip this patch class when calling PatchAll()
class MyPatch
{
// here, inside the patch class, you can place the auxiliary patch methods
// for example TargetMethod:
public static MethodBase TargetMethod()
{
// use normal reflection or helper methods in <AccessTools> to find the method/constructor
// you want to patch and return its MethodInfo/ConstructorInfo
//
var type = AccessTools.FirstInner(typeof(TheClass), t => t.Name.Contains("Stuff"));
return AccessTools.FirstMethod(type, method => method.Name.Contains("SomeMethod"));
}
// your patches
public static void Prefix()
{
// ...
}
}
Prepare
Harmony looks for a preparation method with one of these forms:
static void Prepare(...)
static void Prepare(MethodBase original, ...)
static bool Prepare(MethodBase original, ...)
// or
[HarmonyPrepare]
static void MyInitializer(...)
static void MyInitializer(MethodBase original, ...)
static bool MyInitializer(MethodBase original, ...)
Prepare runs first with original = null for the whole class, then for each target method. Returning false skips the class or that target, respectively.
TargetMethod
To choose the target in code instead of annotations, define:
static MethodBase TargetMethod(...)
// or
[HarmonyTargetMethod]
static MethodBase CalculateMethod(...)
Return the target's MethodBase, never null. Use Prepare() to skip patching conditionally.
TargetMethods
To apply the same patches to several targets, return an enumeration of MethodBase:
static IEnumerable<MethodBase> TargetMethods(...)
// or
[HarmonyTargetMethods]
static IEnumerable<MethodBase> CalculateMethods(...)
A typical implementation would yield the results like this:
static IEnumerable<MethodBase> TargetMethods()
{
// if possible use nameof() or SymbolExtensions.GetMethodInfo() here
yield return AccessTools.Method(typeof(Foo), "Method1");
yield return AccessTools.Method(typeof(Bar), "Method2");
// you could also iterate using reflections over many methods
}
Do not use an empty enumeration to skip patching; use Prepare() instead.
Cleanup
For cleanup after patching, define:
static void Cleanup(...)
static void Cleanup(MethodBase original, ...)
static Exception Cleanup(MethodBase original, ...)
// or
[HarmonyCleanup]
static void MyCleanup(...)
static void MyCleanup(MethodBase original, ...)
static Exception MyCleanup(MethodBase original, ...)
Cleanup runs after each target, then once for the whole class with original = null.
Inject Exception to inspect a patching failure; a HarmonyException may provide more details. Return an exception to replace it, or null to suppress it.