-
Notifications
You must be signed in to change notification settings - Fork 43
Patching
Inside the class Harmony searches for methods with the specific names TargetMethod()
, Prepare()
, Prefix()
, Postfix()
or Transpiler()
. Instead of relying on those names, you can also use the method annoations [HarmonyTargetMethod]
, [HarmonyPrepare]
, [HarmonyPrefix]
, [HarmonyPostfix]
or [HarmonyTranspiler]
.
TargetMethod (Optional)
Most of the times, you will use a combination of HarmonyPatch()
annotations on the class to define the method you want to patch. Sometimes it is necessary to calculate the method with code. You can use TargetMethod
for this.
It might be useful when:
- The target method is overloaded and the method has reference parameters (ref, out). You can also use
ParameterByRefAttribute
to mark parameters as being ref/out - Switching between overloaded methods conditionally at runtime
- All other situation which needs target method signature to be built at runtime C# allows only constant expression for annotations, but the required method information will not be a constant expression in such cases.
static MethodBase TargetMethod()
static MethodBase TargetMethod(HarmonyInstance instance)
// or
[HarmonyTargetMethod]
// NOTE: not passing harmony instance with attributes is broken in 1.2.0.1
static MethodBase CalculateMethod(HarmonyInstance instance)
That method, if it exists, is expected to return a MethodInfo
of the method to be patched. You can optionally receive the harmony instance if you want to run other Harmony methods inside your code.
Prepare (Optional)
Before the patching, Harmony gives you a chance to prepare your state. For this, Harmony searches for a method called
static bool Prepare()
static bool Prepare(MethodBase original)
// or
[HarmonyPrepare]
static bool MyInitializer(...)
That method, if it exists, is expected to return a boolean that controls if patching will happen. You can optionally receive the original method.
Prefix (Optional)
static bool Prefix(...)
// or
[HarmonyPrefix]
static bool MyPrefix(...)
This method defines the code that is executed before the original method. Execution will be skipped if an earlier prefix indicates it wants to skip the original method. It follows the guidelines defined in Patching.
Postfix (Optional)
static void Postfix(...)
// or
[HarmonyPostfix]
static void MyPostfix(...)
This method defines the code that is executed after the original method. This is a good place to execute code that always needs execution. It follows the guidelines defined in Patching.
Transpiler (Optional)
static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instr, ...)
// or
[HarmonyTranspiler]
static IEnumerable<CodeInstruction> MyTranspiler(IEnumerable<CodeInstruction> instr, ...)
This method defines the transpiler that modifies the code of the original method. Use this in the advanced case where you want to modify the original methods IL codes. It follows the guidelines defined in Patching.
Cleanup (Optional)
After patching, Harmony can call this cleanup method. It searches for a method called
static bool Cleanup()
static bool Cleanup(MethodBase original)
// or
[HarmonyCleanup]
static bool MyInitializer(...)
Each prefix and postfix can get all the parameters of the original method as well as the instance (if original method is not static) and the return value. In order to patch a method your patches need to follow the following principles when defining them:
- A patch must be a static method
- A prefix patch has a return type of void or bool
- A postfix patch has a return type of void or the return signature must match the type of the first parameter (passthrough mode)
- Patches can use a parameter named __instance to access the instance value if original method is not static
- Patches can use a parameter named __result to access the returned value (prefixes get default value)
- Patches can use a parameter named __state to store information in the prefix method that can be accessed again in the postfix method. Think of it as a local variable. It can be any type and you are responsible to initialize its value in the prefix (Note: either
ref
orout
has to be added to this parameter in prefix in order to make it work) - Parameter names starting with three underscores, for example ___someField, can be used to read and write (with 'ref') private fields on the instance that has the same name (minus the underscores)
- Patches can define only those parameters they want to access (no need to define all)
- Patch parameters must use the exact same name and type as the original method (object is ok too)
- Patches can either get parameters normally or by declaring any parameter ref (for manipulation)
- To allow patch reusing, one can inject the original method by using a parameter named __originalMethod
Transpilers have some other optional parameters:
- A parameter of type
ILGenerator
that will be set to the current IL code generator - A parameter of type
MethodBase
that will be set to the current original method being patched - They must contain one parameter of type
IEnumerable<CodeInstruction>
that will be used to pass the IL codes to it
Example:
// original method in class Customer
private List<string> getNames(int count, out Error error)
// prefix
// - wants instance, result and count
// - wants to change count
// - sets a state that can be accessed by the Postfix
// - returns a boolean that controls if original is executed (true) or not (false)
static bool Prefix(Customer __instance, List<string> __result, ref int count, out int __state)
// postfix
// - wants result and error
// - does not change any of those
// - receives the state value that was set in the Prefix
static void Postfix(List<string> __result, Error error, int __state)
// transpiler
// - wants to use original method
static IEnumerable<CodeInstruction> Transpiler(MethodBase original, IEnumerable<CodeInstruction> instructions)
- 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