Show / Hide Table of Contents

Introduction

Harmony is used to monkey patch "unchangable" methods.

Examples

Prefix

The prefix allows patching of existing methods before they execute. Prefixes are mainly used to replace existing methods.

Full Class

using HarmonyLib;
using System;
using System.Reflection;

namespace ConsoleApp
{
    // Example of Bannerlord code. Uneditable code.
    class Foo
    {
        private int myVar;

        public void PrintMyVar()
        {
            Console.WriteLine(myVar);
        }

        // Method we want to change.
        public void SetMyVar(int newInt)
        {
            myVar = newInt;
        }
    }

    [HarmonyPatch(typeof(Foo), "SetMyVar")]
    class FooPatch
    {
        // __instance works similar to the 'this' keyword
        static bool Prefix(ref Foo __instance, ref int newInt)
        {
            // Access private field
            FieldInfo myVarField = typeof(Foo).GetField("myVar", BindingFlags.Instance | BindingFlags.NonPublic);
            // Set newInto of __instance
            myVarField.SetValue(__instance, newInt + 1);

            // Returning false skips original method
            return false;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Harmony harmony = new Harmony("com.company.project.product");

            Foo foo = new Foo();

            foo.SetMyVar(2);
            foo.PrintMyVar(); // -> 2

            harmony.PatchAll();

            foo.SetMyVar(2);
            foo.PrintMyVar(); // -> 3

            Console.ReadKey();
        }
    }
}


Postfix

The postfix allows patching of existing methods after they execute. Postfixes are normally used to replace return values.

Full Class

using HarmonyLib;
using System;

namespace ConsoleApp
{
    // Example of Bannerlord code. Uneditable code.
    class Foo
    {
        private int myVar = 2;

        public void PrintMyVar()
        {
            Console.WriteLine(myVar);
        }

        // Method we want to change.
        public int GetMyVar()
        {
            return myVar;
        }
    }

    [HarmonyPatch(typeof(Foo), "GetMyVar")]
    class FooPatch
    {
        // __result is the return value of the original method
        static int Postfix(int __result)
        {
            // This will overwrite the return value
            return __result + 1;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Harmony harmony = new Harmony("com.company.project.product");

            Foo foo = new Foo();

            Console.WriteLine(foo.GetMyVar()); // -> 2

            // Apply patch
            harmony.PatchAll();

            Console.WriteLine(foo.GetMyVar()); // -> 3

            Console.ReadKey();
        }
    }
}


Transpiler

Transpilers work directly with the compiled C# code, aka MSIL.

This is an advanced topic and we should use this sparingly, for more information see here.

Transpiler Tools

There is a library that can help with transpilers by searching and replacing specific IL code.

  • Improve this Doc
☀
☾
Back to top Generated by DocFX