-
Notifications
You must be signed in to change notification settings - Fork 44
Prefix changes
In HarmonyX, prefixes have a slightly different behaviour from Harmony in how they are run.
In Harmony, prefixes can be skipped:
Note: The first prefix that returns false will skip all remaining prefixes unless they have no side effects (no return value, no ref arguments) and will skip the original too. Postfixes and Finalizers are not affected.
This is not the case in HarmonyX: by default, all prefixes are run to allow symmetrical patches (e.g. for profiling) without the chicken-egg problem that can come with patch ordering.
Consider the following example:
class SomeTargetClass
{
void SomeImportantMethod() { /* Does some important stuff */ }
}
class Patch1
{
[HarmonyPatch(typeof(SomeTargetClass), "SomeImportantMethod")]
[HarmonyPrefix]
static bool Prefix()
{
// Skip original
return false;
}
}
class Patch2
{
private static Stopwatch sw;
[HarmonyPatch(typeof(SomeTargetClass), "SomeImportantMethod")]
[HarmonyPrefix]
static void SomeImportantPrefix()
{
sw = new Stopwatch();
sw.Start();
}
[HarmonyPatch(typeof(SomeTargetClass), "SomeImportantMethod")]
[HarmonyPostfix]
static void SomeImportantPostfix()
{
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
// In your main code
var instance = new Harmony("tester");
instance.PatchAll(typeof(Patch1)); // First Patch1 which will skip original
instance.PatchAll(typeof(Patch2)); // Patch1 comes before Patch2
Calling SomeImportantMethod
will HarmonyX print the execution time of the method (even though it was skipped).
In Harmony 2 this would've caused a NullReferenceException
as Patch2
's prefix would be never run (skipped by Patch1
) but postix would be.
If you need to mimick Harmony 2 behaviour and skip a prefix when another prefix wants to skip the original method, you can add ref bool __runOriginal
parameter to your prefix and check that:
static void Prefix(ref bool __runOriginal)
{
// Skip this prefix if some other prefix wants to skip the original method
if (!__runOriginal)
return;
}
You can also use __runOriginal
as an alternative to bool
return value:
static void Prefix(ref bool __runOriginal)
{
// Skip running the original method
__runOriginal = false;
}
- 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