-
Notifications
You must be signed in to change notification settings - Fork 44
ILManipulators
In addition to the normal Harmony transpiler, HarmonyX provides the additional ILManipulator
patch type, which enables the use of common MonoMod helpers such as ILCursor
. These patches will allow you to receive an (optional) ILContext
for the method you're patching as well as the (optional) MethodBase
of the original method.
ILManipulators are meant as an alternative to Transpilers, and are fully integrated and compatible with everything else that Harmony provides.
ILManipulators run after all other patch types have been applied (this is due to a technical limitation and making sure existing patches work as expected). This can lead to some easy errors when you start with ILManipualtors, and you should keep in mind these conditions when designing your patches.
Because of how prefixes, postfixes, and finalizers are applied to methods, they will be inside the method body by the time your patch runs. This has several repercussions when it comes to what you write:
- All
ret
opcodes in the method will have becomebr
opcodes that branch to the beginning of where the postfixes and finalizers run.- This means that you should be careful about adding
ret
opcodes yourself, as that will skip all postfixes and finalizers applied to the method.
- This means that you should be careful about adding
- Since Harmony may have changed the method before your patch recieves it, the IL may not be exactly the same as what ILSpy/dnSpy/dotPeek tell you.
- If you need to see the exact IL Harmony generates, enable the
IL
log channel in your configs.
- If you need to see the exact IL Harmony generates, enable the
ILManipulators can be used in all of the same contexts as Transpilers, with an attribute, with the correct name, or as part of a Reverse Patch.
ILManipulators should always return void
.
Examples for each usage:
public class ExampleClassToBePatched
{
public string ExampleMethod()
{
return "example string";
}
}
[HarmonyPatch(typeof(ExampleClassToBePatched), "ExampleMethod")]
public class PatchClass
{
// With the correct naming scheme
public static void ILManipulator(ILContext il, MethodBase original) { }
// With the correct attribute applied to the method
[HarmonyILManipulator]
public static void SomeOtherILManipulator(ILContext ctx, MethodBase orig) { } // parameter names can be anything
// As part of a reverse patch
[HarmonyReversePatch]
[MethodImpl(MethodImplOptions.NoInlining)] // make sure the method is never inlined so the patch as actually called in our code
public static string ExampleMethodReverse()
{
void Manipulator(ILContext il) { } // can be named anything, and all parameters are optional
Manipulator(null); // get rid of compiler warning about unused method
return default(string); // get rid of compiler error about no value being returned
}
}
TODO: Write comprehensive examples unique to HarmonyX
To see more details about implementation of MonoMod's ILContext and its helpers to manipulate it, please reference:
TODO: Find more resources for MonoMod's helpers
- 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