-
Notifications
You must be signed in to change notification settings - Fork 0
Midfix Patch
Midfix Patches are designed to work like Harmony's Prefix patches that includes injections.
The main difference, is that they need a MidFixInstructionMatcher
to know where to insert themselves.
To understand how to use Midfix Patches, here's a somewhat realistic example. This is the class we want to patch:
public class Pokemon {
public int MaxHealth { get; private set; }
public int Health { get; private set; }
public int Defense { get; private set; }
public int CombatExperience { get; private set; }
public Pokemon(int health, int defense, int combatExperience) {
MaxHealth = health;
Health = health;
Defense = defense;
CombatExperience = combatExperience;
}
public void TakeDamage(int damage) {
GainCombatExperience((int) (damage * 0.25));
Health -= (damage - Defense);
}
public void GainCombatExperience(int experience) {
CombatExperience += experience;
}
}
Suppose we want to add a mechanic that negates the damage a Pokemon takes, if the resulting damage would be less than 20% of its max health.
But we still want the Pokemon to gain combat experience, even if it does negate the damage.
To do that, we'll insert our Midfix patch in the 'TakeDamage' Method, after 'GainCombatExperience' is called.
Here's the Patcher class:
[HarmonyPatch(declaringType: typeof(Pokemon))]
public class Pokemon_Patch {
[HarmonyPatch(methodName: nameof(Pokemon.TakeDamage))]
[BTHarmonyMidFix(nameof(TakeDamage_Matcher))]
private static bool TakeDamage_Midfix(Pokemon __instance, int damage) {
int maxDamageNegate = (int) (__instance.MaxHealth * 0.2);
int trueDamage = damage - __instance.Defense;
return trueDamage > maxDamageNegate; // if damage <= maxDamageNegate, then exit early.
}
private static MidFixInstructionMatcher TakeDamage_Matcher() {
MethodInfo gainCombatExperience = AccessTools.DeclaredMethod(typeof(Pokemon), nameof(Pokemon.GainCombatExperience));
return new MidFixInstructionMatcher(
expectedMatches: 1,
prefixInstructionSequence: new[] {
InstructionMask.MatchInstruction(OpCodes.Call, gainCombatExperience),
}
);
}
}
Then, in the same location you placed harmony.PatchAll()
, you must add PatcherUtils.PatchAll(harmony)
Or, if you want to apply patch classes individually, you can use PatcherUtils.PatchAll(harmony, typeof(Pokemon_Patch))
Some clarifications:
-
[HarmonyPatch(declaringType: typeof(Pokemon))]
- tells Harmony which Class you want to alter. -
[HarmonyPatch(methodName: nameof(Pokemon.TakeDamage))]
- tells Harmony which Method you want to alter. -
[BTHarmonyMidFix(nameof(TakeDamage_Matcher))]
- tells BTHU where to find the MidFixInstructionMatcher. - the return value of Midfix Patchers should be read as 'patched method should continue executing'.
So if you return 'false' the patched Method should stop, if you return 'true' the patched method should continue.
You can also use 'void' as your return type, which will be treated as returning 'true'.
Once the patch is applied, the 'TakeDamage' method will look like this instead:
public void TakeDamage(int damage) {
GainCombatExperience((int) (damage * 0.25));
if (!Pokemon_Patch.TakeDamage_Midfix(this, damage)) {
return;
}
Health -= (damage - Defense);
}
Just like with Harmony's Attribute based Patches, you must tell BTHU to apply your MidFix Patches.
Harmony harmony = /* ... */
BTHarmonyUtils.PatcherUtils.PatchAll(harmony);
- Just like with Harmony, you can specify a
priority
to control the order in which Midfix patches are applied (higher priorities are applied first)
for example:[BTHarmonyMidFix(nameof(TakeDamage_Matcher), priority: 42)]
- If your MidFixInstructionMatcher Method is in a different class from the Midfix Patch, you can use the
instructionMatcherDeclaringType
parameter.
for example, if it was in a class named 'MyMatchers' instead, you can do this:[BTHarmonyMidFix(typeof(MyMatcher), "TakeDamage_Matcher")]
- Instruction Simplifier - simplification rules apply to MidFixInstructionMatchers.
- Instruction Mask - recommended for matching CodeInstructions
- IEnumerator Patching - if you want to apply Midfix Patches to Methods that return 'IEnumerator's
- HarmonyTargetMethod and HarmonyTargetMethods - both are supported by MidFix patches.
Made with ❤️ by BlazingTwist
If you like my work and wish to support me, a
goes a long way