Patching

This is used to override functions within a mod.

The patching functionality leverages version 2 of HarmonyLib

You should utilise the AzzaMods APIs where possible as they will automatically handle patching and unpatching of methods when mods are loaded and unloaded. If you use Harmony Lib directly then you need to manage unhooking yourself.

In rare cases where you do want direct access to Harmony Lib, the Harmony Lib functionality can be added to your project directly by adding using HarmonyLib;

Patching.AnyMethod

Patching.AnyMethod:BindingFlags

This is a getting that is often used to pickup any method when searching for methods.

This is the same constant as the AccessTools.all constant in HarmonyLib

Patching.Prefix

What is a Prefix?

A prefix allows you to run a peace of code before a target method is executed. A prefix can modify the return value of the target function and even prevent the target function from being executed.

Methods

The following methods are available:

Patching.Prefix(MethodBase originalMethod, MethodInfo prefix = null)
Patching.Prefix(Type originalType, string methodName, Type prefixType, string prefixMethod)

Example Usage

Infinite Jumps Mod

Let's create an infinite jumps mod in Muck:

// Infinite Jumps Mod
public class MuckJumpMod : MonoBehaviour
{
    private static string optionInfiniteJumps = "Infinite Jumps";

    // When the mod is loaded
    void OnModLoaded()
    {
        // Tell the launcher about our infinite jumps mod
        Options.RegisterBool(optionInfiniteJumps, false);
        Options.SetDescription(optionInfiniteJumps, "Give you an endless number of jumps.");
        Options.AddPersistence(optionInfiniteJumps);

        // Apply our patch of infinite jumps
        Patching.Prefix(
            typeof(PowerupInventory).GetMethod("GetExtraJumps", Patching.AnyMethod),
            this.GetType().GetMethod("PrefixGetExtraJumps", Patching.AnyMethod)
        );
    }

    // Define our prefix
    private static bool PrefixGetExtraJumps(ref int __result)
    {
        // Is the option enabled?
        if(Options.GetBool(optionInfiniteJumps))
        {
            // Option is enabled

            // Set max jumps to the highest value we can store in an int
            __result = int.MaxValue;

            // Don't run original method
            return false;
        }

        // Option is NOT enabled

        // Run original method
        return true;
    }
}

We register our option as a bool and give it a nice description.

This applies a Prefix to the GetExtraJumps method of the PowerupInventory class, that basically means that our PrefixGetExtraJumps method will be invoked prior to the real GetExtraJumps method being invoked.

We simply edit the return result to be the highest int possible, effectively giving ourselves infinite jumps. It's not ACTUALLY infinite, but someone isn't going to jump that many times to find out.

Patching.Postfix

What is a Postfix?

A postfix allows you to run a peace of code directly after a function has finished executing. You can use this to reset a value after a function has changed it.

Methods

The following methods are available:

Patching.Postfix(MethodBase originalMethod, MethodInfo postfix = null)
Patching.Postfix(Type originalType, string methodName, Type postfixType, string postfixMethod)

Example Usage

Infinite Stamina Mod

Let's create an infinite stamina mod in Muck:

// Infinite Jumps Mod
public class MuckStaminaMod : MonoBehaviour
{
    private static string optionUnlimitedStamina = "Full Stamina";

    // When the mod is loaded
    void OnModLoaded()
    {
        // Tell the launcher about our infinite stamina mod
        Options.RegisterBool(optionUnlimitedStamina, false);
        Options.SetDescription(optionUnlimitedStamina, "Gives you unlimited stamina.");
        Options.AddPersistence(optionUnlimitedStamina);

        // Apply our patch of infinite stamina
        Patching.Postfix(
            typeof(PlayerStatus).GetMethod("Stamina", Patching.AnyMethod),
            typeof(MuckEssentials).GetMethod("PostfixStamina", Patching.AnyMethod)
        );
    }

    // Define our prefix
    private static void PostfixStamina(PlayerStatus __instance)
    {
        // Is our option enabled?
        if(Options.GetBool(optionUnlimitedStamina))
        {
            // Option is enabled

            // Set the current stamina to the max stamina
            __instance.stamina = __instance.maxStamina;
        }
    }
}

We define our options, then we register a postfix for the Stamina method on the PlayerStatus class. The Stamina method is responsible for taking away stamina from the player. We let the method run and remove what ever stamina, then, we set our stamina back up to max, leaving us with an end result of unlimied stamina.

Note that the return type is void as the original method always runs when using a postfix.

Patching.Transpiler

Methods

The following methods are available:

Patching.Transpiler(MethodBase originalMethod, MethodInfo transpiler = null)
Patching.Transpiler(Type originalType, string methodName, Type transpilerType, string transpilerMethod)

Patching.Finalizer

Methods

The following methods are available:

Patching.Finalizer(MethodBase originalMethod, MethodInfo finalizer = null)
Patching.Finalizer(Type originalType, string methodName, Type finalizerType, string finalizerMethod)