### HarmonyX Patching Example Source: https://github.com/bepinex/harmonyx/wiki/Prefix-changes Demonstrates how multiple patches interact in HarmonyX, where a prefix that skips the original method does not prevent subsequent prefixes from executing. ```cs 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 ``` -------------------------------- ### Example of JIT inlining Source: https://github.com/bepinex/harmonyx/wiki/Valid-patch-targets Demonstrates how small methods like getters can be inlined by the JIT compiler, potentially bypassing patches. ```csharp int _myInt = 0; int MyInt { get // Small method, compiled to `int get_MyInt()` { return _myInt; } } void MyMethod() { Console.WriteLine(MyInt); // Compiled to Console.WriteLine(get_MyInt()); } ``` ```csharp // NOTE: This is pseudocode of how inlining works; the actual process is a bit more tricky than that void MyMethod() { Console.WriteLine(_myInt); // get_MyInt() got inlined and replaced with `_myInt` field directly. } ``` -------------------------------- ### Multitargeting Patch Example in C# Source: https://github.com/bepinex/harmonyx/wiki/Multitargeted-patches This example demonstrates how to apply a single prefix patch to two different methods in separate classes using multiple `HarmonyPatch` attributes on the patch method itself. Ensure that patch parameters are compatible with all target methods. ```csharp class TargetType1 { void SomeMethod1(); } class TargetType2 { void SomeMethod2(); } // Apply prefix onto both methods at the same time [HarmonyPrefix] [HarmonyPatch(typeof(TargetType1), "SomeMethod1")] [HarmonyPatch(typeof(TargetType2), "SomeMethod2")] static void SomeMethodPrefix(); ``` -------------------------------- ### Custom Patcher Initialization Logic Source: https://github.com/bepinex/harmonyx/wiki/Custom-MethodPatcher Example logic within a resolver method to check if a method should be patched by a custom patcher and to instantiate it. ```csharp if (/* some logic to check if args.Original should be patched with the custom patcher */) args.MethodPatcher = new MyCustomMethodPatcher(args.Original); ``` -------------------------------- ### Harmony Patch Parameter Examples Source: https://github.com/bepinex/harmonyx/wiki/Patching Illustrates how to define prefix, postfix, and transpiler methods to access various parameters and state. Prefixes can control execution flow and set state, while postfixes can access results and state. Transpilers receive the original method and IL instructions. ```csharp // original method in class Customer private List getNames(int count, out Error error) // prefix // - wants instance, result and count // - wants to change count // - sets a state that can be accessed by the Postfix // - returns a boolean that controls if original is executed (true) or not (false) static bool Prefix(Customer __instance, List __result, ref int count, out int __state) // postfix // - wants result and error // - does not change any of those // - receives the state value that was set in the Prefix static void Postfix(List __result, Error error, int __state) // transpiler // - wants to use original method static IEnumerable Transpiler(MethodBase original, IEnumerable instructions) ``` -------------------------------- ### Harmony ReversePatch Example Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Use Reverse patches to copy a target method into the annotated one, enabling calls to private or unpatched methods without reflection overhead. ```csharp [HarmonyReversePatch] T OriginalMethod(...) ``` -------------------------------- ### Defining native extern methods Source: https://github.com/bepinex/harmonyx/wiki/Valid-patch-targets Examples of native methods marked with DllImport or InternalCall. ```csharp // Native method from kernel32.dll [DllImport("kernel32.dll")] static extern void Sleep(int seconds); // Internall call (e.g. in Unity) [MethodImpl(MethodImplOptions.InternalCall)] extern AsyncResult AsyncLoad(); ``` -------------------------------- ### Example of a C# IEnumerator Source: https://github.com/bepinex/harmonyx/wiki/Enumerator-patches This code demonstrates a simple C# enumerator using `yield return` statements. It shows how `yield return` pauses the method execution and returns a value. ```csharp IEnumerator SomeEnumerator() { yield return 0; // Return 0 and "pause" the method Console.WriteLine("Some thing"); yield return 1; yield return 2; } ``` -------------------------------- ### Wrapping Enumerator with Postfix Source: https://github.com/bepinex/harmonyx/wiki/Enumerator-patches This example demonstrates how to add a postfix to an enumerator by wrapping the original enumerator with a custom wrapper method. This approach is simpler than directly patching `MoveNext` for postfix operations. ```csharp [HarmonyPostfix] [HarmonyPatch(typeof(TargetClass), "SomeEnumerator")] static IEnumerator MyWrapper(IEnumerator __result) { // Run original enumerator code while (__result.MoveNext()) yield return __result.Current; // Run your postfix } ``` -------------------------------- ### Harmony Transpiler Example Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Define a transpiler to modify the IL code of the original method. The transpiler must accept an IEnumerable and return a new IEnumerable representing the modified code. ```csharp static IEnumerable Transpiler(IEnumerable instr[, ...]) ``` ```csharp [HarmonyTranspiler] static IEnumerable MyTranspiler(IEnumerable instr[, ...]) ``` -------------------------------- ### Patching MoveNext with Harmony Transpiler Attribute Source: https://github.com/bepinex/harmonyx/wiki/Enumerator-patches This example shows how to use the `HarmonyTranspiler` attribute to patch the `MoveNext` method of an enumerator. It specifies `MethodType.Enumerator` to target the correct method. ```csharp // This will transpile MoveNext of `TargetClass.SomeEnumerator` [HarmonyTranspiler] [HarmonyPatch(typeof(TargetClass), "SomeEnumerator", MethodType.Enumerator)] static IEnumerable TranspileMoveNext(IEnumerable); ``` -------------------------------- ### HarmonyEmitIL Attribute Example Source: https://github.com/bepinex/harmonyx/wiki/Patch-attributes Specify HarmonyEmitIL to generate a DLL containing the patched version of the target method in the specified folder. This DLL includes all Harmony patches and ILHooks applied before Harmony. ```csharp [HarmonyEmitIL("./dumps")] [HarmonyPrefix] [HarmonyPatch(typeof(TargetClass), "TargetMethod")] static void ExamplePrefix(); ``` -------------------------------- ### Harmony Finalizer Examples Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Use Finalizers to catch, throw, or suppress exceptions in a method. They run before postfixes and immediately if an exception occurs in the original method. Finalizers can accept various patch parameters. ```csharp static void Finalizer([...]) ``` ```csharp [HarmonyFinalizer] static void MyFinalizer([...]) ``` ```csharp static Exception Finalizer([...]) ``` ```csharp [HarmonyFinalizer] static Exception MyFinalizer([...]) ``` -------------------------------- ### HarmonyWrapSafe Attribute Example Source: https://github.com/bepinex/harmonyx/wiki/Patch-attributes Use HarmonyWrapSafe to automatically wrap a patch method in a try-catch block. Exceptions thrown by the patch are logged by Harmony but do not affect other patches or the original code. ```csharp [HarmonyPrefix] [HarmonyWrapSafe] [HarmonyPatch(typeof(TargetClass), "TargetMethod")] static void ExamplePrefix(); ``` -------------------------------- ### Patching Enumerator Method Directly Source: https://github.com/bepinex/harmonyx/wiki/Enumerator-patches This example demonstrates patching the enumerator method itself, rather than its generated `MoveNext` implementation. This is useful when the enumerator method primarily consists of returning a new enumerator instance. ```csharp // NOTE THE DIFFERENCE: This will transpile `TargetClass.SomeEnumerator` which only has `new SomeEnumerator_Impl()`! [HarmonyTranspiler] [HarmonyPatch(typeof(TargetClass), "SomeEnumerator")] static IEnumerable TranspileMoveNext(IEnumerable); ``` -------------------------------- ### Implement Prepare Method Source: https://github.com/bepinex/harmonyx/wiki/Class-patches The Prepare method controls whether the patch should be applied; return true to proceed or false to skip. ```csharp static bool Prepare([MethodBase original, Harmony instance]) // or [HarmonyPrepare] static bool MyPrepare([MethodBase original, Harmony instance]) ``` -------------------------------- ### Prepare Method Signatures Source: https://github.com/bepinex/harmonyx/wiki/Patching Allows pre-patching state preparation. Returns a boolean to control if patching proceeds. Can optionally receive the original method. ```csharp static bool Prepare() static bool Prepare(MethodBase original) ``` ```csharp [HarmonyPrepare] static bool MyInitializer(...) ``` -------------------------------- ### Implement Prefix Method Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Prefixes execute before the original method. Returning false skips the original method execution. ```csharp static (void|bool) Prefix([...]) // or [HarmonyPrefix] static (void|bool) MyPrefix([...]) ``` -------------------------------- ### Implement HarmonyX Patch Parameters Source: https://context7.com/bepinex/harmonyx/llms.txt Demonstrates accessing instance state, modifying arguments, and passing state between prefix and postfix methods. ```csharp using HarmonyLib; using System; using System.Reflection; public class Customer { private int loyaltyPoints = 100; public decimal CalculateDiscount(decimal price, bool isPremium) { return isPremium ? price * 0.2m : price * 0.1m; } } [HarmonyPatch(typeof(Customer), "CalculateDiscount")] public class DiscountPatch { // Prefix with state that passes to postfix [HarmonyPrefix] static void Prefix( Customer __instance, // The instance (null for static methods) decimal price, // Original argument by name ref bool isPremium, // Modify argument with ref int ___loyaltyPoints, // Access private field (3 underscores + field name) out decimal __state, // Store state for postfix MethodBase __originalMethod) // The original method being patched { __state = price; // Save original price // Make customer premium if they have enough loyalty points if (___loyaltyPoints > 50) isPremium = true; Console.WriteLine($"Patching {__originalMethod.Name}"); } [HarmonyPostfix] static void Postfix( decimal __result, // Return value decimal __state, // State from prefix bool __runOriginal) // HarmonyX: was original method executed? { if (__runOriginal) { Console.WriteLine($"Original price: {__state}, Discount: {__result}"); } } } ``` -------------------------------- ### Initialize a Harmony instance Source: https://github.com/bepinex/harmonyx/wiki/Instantiating-Harmony-instance Create a new Harmony instance using a unique ID, preferably in reverse domain name notation. ```csharp var harmony = new Harmony("com.company.project.product"); ``` -------------------------------- ### Prepare Source: https://github.com/bepinex/harmonyx/wiki/Patching Allows for state preparation before patching and controls whether patching should proceed. ```APIDOC ## Prepare ### Description Provides a chance to prepare state before patching and returns a boolean to control if patching should occur. ### Method Static method returning `bool`. ### Endpoint N/A (Code construct) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp static bool Prepare() static bool Prepare(MethodBase original) // or using attribute: [HarmonyPrepare] static bool MyInitializer(...) ``` ### Response #### Success Response (200) `true` if patching should proceed, `false` otherwise. #### Response Example ```json { "example": true } ``` ``` -------------------------------- ### Create Harmony Instance and Patch All Methods Source: https://github.com/bepinex/harmonyx/wiki/Patching-with-Harmony Convenient helper methods to create a Harmony instance and apply patches simultaneously. You can patch all methods in the executing assembly or a specific type. HarmonyX generates a unique ID if none is specified, which can affect patch ordering and unpatching. ```csharp Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly()); ``` ```csharp Harmony.CreateAndPatchAll(typeof(Patch)); ``` -------------------------------- ### Advanced IL Manipulation with ILManipulator and ILCursor Source: https://context7.com/bepinex/harmonyx/llms.txt Leverage ILManipulator and MonoMod's `ILContext` with `ILCursor` for fine-grained, cursor-based IL editing. This example doubles the points added to a score. ```csharp using HarmonyLib; using Mono.Cecil.Cil; using MonoMod.Cil; using System.Reflection; public class GameLogic { public int Score { get; private set; } public void AddScore(int points) { Score += points; } } [HarmonyPatch(typeof(GameLogic), "AddScore")] public class GameLogicPatch { [HarmonyILManipulator] static void Manipulator(ILContext il, MethodBase original, ILLabel retLabel) { var cursor = new ILCursor(il); // Move to the add instruction if (cursor.TryGotoNext(MoveType.After, x => x.MatchLdarg(1))) { // Emit code to double the points cursor.Emit(OpCodes.Ldc_I4_2); cursor.Emit(OpCodes.Mul); } } } // Usage var harmony = Harmony.CreateAndPatchAll(typeof(GameLogicPatch)); var game = new GameLogic(); game.AddScore(10); // Score becomes 20 (doubled) ``` -------------------------------- ### Configuring HarmonyX Logging and Debugging Source: https://context7.com/bepinex/harmonyx/llms.txt Sets up file logging, channel filtering, and patch-specific IL inspection tools. ```csharp using HarmonyLib; using HarmonyLib.Tools; using System; // Enable file logging HarmonyFileLog.Enabled = true; HarmonyFileLog.FileWriterPath = "./harmony.log"; // Configure log channels Logger.ChannelFilter = Logger.LogChannel.Info | Logger.LogChannel.Warn | Logger.LogChannel.Error; // Custom log handler Logger.MessageReceived += (sender, args) => { Console.WriteLine($"[{args.LogChannel}] {args.Message}"); }; // Debug specific patches with attribute [HarmonyPatch(typeof(TargetClass), "TargetMethod")] [HarmonyDebug] // Outputs IL to harmony.log.txt on Desktop public class DebugPatch { [HarmonyPrefix] static void Prefix() { } } // Emit IL to a DLL file for inspection [HarmonyPatch(typeof(TargetClass), "TargetMethod")] [HarmonyEmitIL("./debug")] // Emits to ./debug/ public class EmitPatch { [HarmonyPrefix] static void Prefix() { } ``` -------------------------------- ### Basic CodeMatcher implementation Source: https://github.com/bepinex/harmonyx/wiki/Transpiler-helpers Initializes a CodeMatcher with an instruction collection and returns the modified instructions via InstructionEnumeration. ```cs IEnumerable Transpiler(IEnumerable instructions) { return new CodeMatcher(instructions) .InstructionEnumeration(); } ``` -------------------------------- ### Implement ILManipulator Patches Source: https://github.com/bepinex/harmonyx/wiki/ILManipulators Demonstrates defining ILManipulators using naming conventions, attributes, and within reverse patches. ```cs 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, ILLabel retLabel) { } // With the correct attribute applied to the method [HarmonyILManipulator] public static void SomeOtherILManipulator(ILContext ctx, MethodBase orig) { } // parameter names can be anything, all parameters are optional // 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) { } // manipulator method 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 } } ``` -------------------------------- ### Implement a Postfix Patch Source: https://context7.com/bepinex/harmonyx/llms.txt Postfix patches execute after the target method. They can access the instance, parameters, and the return value to modify behavior. ```csharp using HarmonyLib; using System; public class GamePlayer { public int Health { get; private set; } = 100; public int TakeDamage(int damage) { Health -= damage; return Health; } } [HarmonyPatch(typeof(GamePlayer), "TakeDamage")] public class DamagePatch { [HarmonyPostfix] static void Postfix(GamePlayer __instance, int damage, ref int __result) { Console.WriteLine($"Player took {damage} damage, health now: {__result}"); // Modify result: ensure health never goes below 1 if (__result < 1) { __result = 1; } } } // Usage var harmony = Harmony.CreateAndPatchAll(typeof(DamagePatch)); var player = new GamePlayer(); player.TakeDamage(50); // Output: "Player took 50 damage, health now: 50" player.TakeDamage(100); // Output: "Player took 100 damage, health now: 1" (clamped) ``` -------------------------------- ### Implement Postfix Method Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Postfixes execute after the original method. Passthrough variants can modify the return value of the original method. ```csharp // Normal prefix (behaves like prefix) static void Postfix([...]) // or [HarmonyPostfix] static void MyPostfix([...]) // Passthrough prefix (receives return value as first parameter, returns new return value) static T Postfix([T result, ...]) // or [HarmonyPostfix] static T MyPostfix([T result, ...]) ``` -------------------------------- ### Implement a Prefix Patch Source: https://context7.com/bepinex/harmonyx/llms.txt Prefix patches execute before the target method. Returning false from the prefix skips the original method execution. ```csharp using HarmonyLib; using System; public class TargetClass { public int Calculate(int value) { return value * 2; } } [HarmonyPatch(typeof(TargetClass), "Calculate")] public class CalculatePatch { [HarmonyPrefix] static bool Prefix(int value, ref int __result) { // Skip original if value is negative if (value < 0) { __result = 0; // Set return value return false; // Skip original method } Console.WriteLine($"Calculate called with: {value}"); return true; // Execute original method } } // Usage var harmony = Harmony.CreateAndPatchAll(typeof(CalculatePatch)); var target = new TargetClass(); Console.WriteLine(target.Calculate(5)); // Output: "Calculate called with: 5" then "10" Console.WriteLine(target.Calculate(-1)); // Output: "0" (original skipped) ``` -------------------------------- ### Define a Prefix patch method Source: https://github.com/bepinex/harmonyx/wiki/Method-patches Prefixes execute before the original method. Returning false skips the original method execution. ```csharp [HarmonyPrefix] static (void|bool) MyPrefix([...]) ``` -------------------------------- ### Initialize and Manage Harmony Instances Source: https://context7.com/bepinex/harmonyx/llms.txt Use the Harmony class to manage patches. PatchAll can be used to apply patches from an assembly or specific type, while UnpatchSelf removes all patches associated with the instance. ```csharp using HarmonyLib; using System.Reflection; // Create a Harmony instance with a unique ID var harmony = new Harmony("com.example.myplugin"); // Apply all patches in the current assembly harmony.PatchAll(Assembly.GetExecutingAssembly()); // Or apply patches from a specific type harmony.PatchAll(typeof(MyPatches)); // Shorthand: create and patch in one call var harmony2 = Harmony.CreateAndPatchAll(typeof(MyPatches), "com.example.myplugin"); // Unpatch all methods patched by this instance harmony.UnpatchSelf(); ``` -------------------------------- ### Match IL Instructions by Opcode and Operand Source: https://github.com/bepinex/harmonyx/wiki/Transpiler-helpers Use CodeMatch to define patterns for IL instructions, matching by opcode, operand, or both. Combine multiple CodeMatch instances to match sequences of instructions. ```csharp new CodeMatcher(instructions) .MatchForward(false, // false = move at the start of the match, true = move at the end of the match new CodeMatch(OpCodes.Ldstr), new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(Foo), "Foo")), new CodeMatch(OpCodes.Ret)) ``` ```csharp new CodeMatcher(instructions) .MatchForward(false, // false = move at the start of the match, true = move at the end of the match new CodeMatch(OpCodes.Stfld), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "test")) ``` -------------------------------- ### Prefix Method Signatures Source: https://github.com/bepinex/harmonyx/wiki/Patching Code executed before the original method. Execution can be skipped by an earlier prefix. ```csharp static bool Prefix(...) ``` ```csharp [HarmonyPrefix] static bool MyPrefix(...) ``` -------------------------------- ### Query All Patched Methods and Patch Details Source: https://context7.com/bepinex/harmonyx/llms.txt Iterate through all methods patched by any Harmony instance and retrieve detailed information about each patch, including counts of prefixes, postfixes, transpilers, finalizers, and the owners of the patches. This is useful for global analysis of patching activity. ```csharp using HarmonyLib; using System; using System.Reflection; var harmony = new Harmony("com.example.query"); // Get all patched methods globally foreach (MethodBase method in Harmony.GetAllPatchedMethods()) { Console.WriteLine($"Patched: {method.DeclaringType?.Name}.{method.Name}"); // Get detailed patch info Patches patches = Harmony.GetPatchInfo(method); Console.WriteLine($" Prefixes: {patches.Prefixes.Count}"); Console.WriteLine($" Postfixes: {patches.Postfixes.Count}"); Console.WriteLine($" Transpilers: {patches.Transpilers.Count}"); Console.WriteLine($" Finalizers: {patches.Finalizers.Count}"); Console.WriteLine($" Owners: {string.Join(", ", patches.Owners)}"); } // Get methods patched by specific instance foreach (MethodBase method in harmony.GetPatchedMethods()) { Console.WriteLine($"This instance patched: {method.Name}"); } // Check if specific Harmony ID has any patches bool hasPatches = Harmony.HasAnyPatches("com.other.plugin"); // Get version info Dictionary versions = Harmony.VersionInfo(out Version currentVersion); Console.WriteLine($"Current HarmonyX version: {currentVersion}"); ``` -------------------------------- ### Prefix, Postfix, and Finalizer Parameters Source: https://github.com/bepinex/harmonyx/wiki/Patch-parameters Parameters available for standard HarmonyX patches. Parameter names are significant, and they can be passed by reference using 'ref' to modify values. ```APIDOC ## HarmonyX Patch Parameters ### Description Parameters used in prefixes, postfixes, and finalizers to access or modify the state of the original method execution. ### Parameters - **__state** (Any) - Local state shared between patch types. - **__instance** (object) - The instance of the class for non-static methods. - **__result** (Type) - The return value of the original method. - **__originalMethod** (MethodBase) - The MethodBase of the patched method. - **__runOriginal** (bool) - Controls whether the original method code executes. - **__exception** (Exception) - Caught exception in finalizers. - **__** (Type) - Argument at index . - **** (Type) - Argument with specific name. - **___** (Type) - Field value with name in declaring class. - **__args** (object[]) - All arguments as an array. ``` -------------------------------- ### Implement a Reverse Patch Source: https://context7.com/bepinex/harmonyx/llms.txt Use a stub method marked with [HarmonyReversePatch] to copy and execute the original method's code. ```csharp using HarmonyLib; using System.Runtime.CompilerServices; public class SecretClass { private int secretValue = 42; private int GetSecret() { return secretValue; } } [HarmonyPatch] public class SecretPatch { // Stub method that will receive the original code [HarmonyReversePatch] [HarmonyPatch(typeof(SecretClass), "GetSecret")] [MethodImpl(MethodImplOptions.NoInlining)] public static int CallOriginalGetSecret(SecretClass instance) { // This body is replaced with the original method's code throw new NotImplementedException("Stub"); } } // Usage var harmony = new Harmony("com.example.reverse"); harmony.PatchAll(typeof(SecretPatch)); var secret = new SecretClass(); int value = SecretPatch.CallOriginalGetSecret(secret); // Returns 42 ``` -------------------------------- ### Prefix Source: https://github.com/bepinex/harmonyx/wiki/Patching Code executed before the original method. Can optionally skip the original method's execution. ```APIDOC ## Prefix ### Description Defines code that executes before the original method. If an earlier prefix indicates skipping, the original method's execution will be skipped. ### Method Static method. ### Endpoint N/A (Code construct) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp static bool Prefix(...) // or using attribute: [HarmonyPrefix] static bool MyPrefix(...) ``` ### Response #### Success Response (200) Typically a boolean indicating whether to skip the original method. Refer to [[Patching|Patching]] for detailed guidelines. #### Response Example ```json { "example": "boolean indicating skip or continue" } ``` ``` -------------------------------- ### Postfix Method Signatures Source: https://github.com/bepinex/harmonyx/wiki/Patching Code executed after the original method, ensuring execution. Follows patching guidelines. ```csharp static void Postfix(...) ``` ```csharp [HarmonyPostfix] static void MyPostfix(...) ``` -------------------------------- ### Repeat instruction matching with CodeMatcher Source: https://github.com/bepinex/harmonyx/wiki/Transpiler-helpers Use Repeat to execute a sequence of operations for every occurrence of a specific instruction pattern. The matcher cursor advances automatically through the matches. ```cs new CodeMatcher(instructions) .MatchForward(false, // false = move at the start of the match, true = move at the end of the match new CodeMatch(OpCodes.Stfld), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "test")) .Repeat( matcher => // Do the following for each match matcher .Advance(2) // Move cursor to before ldfld .InsertAndAdvance( new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Foo), "Foo")) ) ) .InstructionEnumerable(); // Finally, return the manipulated method instructions ``` -------------------------------- ### Access Members with AccessTools Source: https://context7.com/bepinex/harmonyx/llms.txt AccessTools provides shorthand methods for reflection, including colon-based syntax for types and members. ```csharp using HarmonyLib; using System; using System.Reflection; public class MyClass { private int _privateField = 10; private string PrivateProperty { get; set; } = "secret"; private void PrivateMethod(int x) { } public int PublicMethod(string s, int i) => i; } // Get types Type type = AccessTools.TypeByName("MyNamespace.MyClass"); Type[] allTypes = AccessTools.GetTypesFromAssembly(Assembly.GetExecutingAssembly()); // Get fields FieldInfo field = AccessTools.Field(typeof(MyClass), "_privateField"); FieldInfo declaredField = AccessTools.DeclaredField(typeof(MyClass), "_privateField"); // Get properties and their accessors PropertyInfo prop = AccessTools.Property(typeof(MyClass), "PrivateProperty"); MethodInfo getter = AccessTools.PropertyGetter(typeof(MyClass), "PrivateProperty"); MethodInfo setter = AccessTools.PropertySetter(typeof(MyClass), "PrivateProperty"); // Get methods with various overloads MethodInfo method1 = AccessTools.Method(typeof(MyClass), "PrivateMethod"); MethodInfo method2 = AccessTools.Method(typeof(MyClass), "PublicMethod", new Type[] { typeof(string), typeof(int) }); // Shorthand with colon syntax FieldInfo fieldAlt = AccessTools.Field("MyNamespace.MyClass:_privateField"); MethodInfo methodAlt = AccessTools.Method("MyNamespace.MyClass:PublicMethod"); // Get constructor ConstructorInfo ctor = AccessTools.Constructor(typeof(MyClass)); ConstructorInfo ctorWithParams = AccessTools.Constructor(typeof(MyClass), new Type[] { typeof(int) }); // Get all declared members var allFields = AccessTools.GetDeclaredFields(typeof(MyClass)); var allMethods = AccessTools.GetDeclaredMethods(typeof(MyClass)); var allProperties = AccessTools.GetDeclaredProperties(typeof(MyClass)); ``` -------------------------------- ### Manual Patching API Usage Source: https://context7.com/bepinex/harmonyx/llms.txt Applies patches programmatically using MethodInfo and the Harmony instance, providing more control than attribute-based patching. ```csharp using HarmonyLib; using System.Reflection; public class Target { public void DoSomething(string message) { Console.WriteLine(message); } } public class ManualPatches { public static void MyPrefix(string message) { Console.WriteLine($"[PREFIX] {message}"); } public static void MyPostfix() { Console.WriteLine("[POSTFIX] Done"); } } // Manual patching var harmony = new Harmony("com.example.manual"); // Get the original method MethodInfo original = AccessTools.Method(typeof(Target), "DoSomething"); // Get patch methods MethodInfo prefix = AccessTools.Method(typeof(ManualPatches), "MyPrefix"); MethodInfo postfix = AccessTools.Method(typeof(ManualPatches), "MyPostfix"); // Apply patches harmony.Patch(original, prefix: new HarmonyMethod(prefix), postfix: new HarmonyMethod(postfix)); // Usage var target = new Target(); target.DoSomething("Hello"); // Output: // [PREFIX] Hello // Hello // [POSTFIX] Done // Unpatch specific method harmony.Unpatch(original, prefix); // Or unpatch all from this instance harmony.UnpatchSelf(); ``` -------------------------------- ### HarmonyPrefix Source: https://github.com/bepinex/harmonyx/wiki/Method-patches Defines code executed before the original method. Can optionally skip the original method by returning false. ```APIDOC ## [HarmonyPrefix] ### Description Defines code that is executed before the original method. If the prefix returns false, the original method code is skipped. ### Signature `static (void|bool) MyPrefix([...])` ``` -------------------------------- ### Implement a basic Harmony prefix patch Source: https://github.com/bepinex/harmonyx/wiki/Basic-usage Uses the HarmonyPatch attribute to target a method and a prefix patch to override the return value. Returning false in the prefix method prevents the original method from executing. ```csharp using System; using HarmonyLib; using System.Reflection; namespace HarmonyTest { class Original { public static int RollDice() { var random = new Random(); return random.Next(1, 7); // Roll dice from 1 to 6 } } class Main { static void Main(string[] args) { Console.WriteLine($"Random roll: {Original.RollDice()}"); // Prints: "Random roll: " // Actual patching is just a one-liner! Harmony.CreateAndPatchAll(typeof(Main)); Console.WriteLine($"Random roll: {Original.RollDice()}"); // Will always print "Random roll: 4" } [HarmonyPatch(typeof(Original), "RollDice")] // Specify target method with HarmonyPatch attribute [HarmonyPrefix] // There are different patch types. Prefix code runs before original code static bool RollRealDice(ref int __result) { // https://xkcd.com/221/ __result = 4; // The special __result variable allows you to read or change the return value return false; // Returning false in prefix patches skips running the original code } } } ``` -------------------------------- ### Define a Postfix patch method Source: https://github.com/bepinex/harmonyx/wiki/Method-patches Postfixes execute after the original method. Passthrough variants can modify the return value. ```csharp [HarmonyPostfix] static void MyPostfix([...]) // Passthrough prefix (receives return value as first parameter, returns new return value) [HarmonyPostfix] static T MyPostfix([T result, ...]) ``` -------------------------------- ### Postfix Source: https://github.com/bepinex/harmonyx/wiki/Patching Code executed after the original method, guaranteed to run. ```APIDOC ## Postfix ### Description Defines code that executes after the original method. This is suitable for code that must always run. ### Method Static method. ### Endpoint N/A (Code construct) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```csharp static void Postfix(...) // or using attribute: [HarmonyPostfix] static void MyPostfix(...) ``` ### Response #### Success Response (200) Typically `void` or a value to be returned if the original method was skipped. Refer to [[Patching|Patching]] for detailed guidelines. #### Response Example ```json { "example": "void or return value" } ``` ``` -------------------------------- ### Conditional Prefix Execution Source: https://github.com/bepinex/harmonyx/wiki/Prefix-changes Techniques for mimicking Harmony 2 behavior by checking or setting the __runOriginal parameter. ```cs static void Prefix(ref bool __runOriginal) { // Skip this prefix if some other prefix wants to skip the original method if (!__runOriginal) return; } ``` ```cs static void Prefix(ref bool __runOriginal) { // Skip running the original method __runOriginal = false; } ``` -------------------------------- ### Define TargetMethod and TargetMethods Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Use these methods to dynamically determine which methods to patch, useful for generic or dynamic methods. ```csharp // Patch single method static MethodBase TargetMethod([Harmony instance]) // or [HarmonyTargetMethod] static MethodBase CalculateMethod([Harmony instance]) // Patch multiple methods static IEnumerable TargetMethods([Harmony instance]) // or [HarmonyTargetMethods] static IEnumerable CalculateMethods([Harmony instance]) ``` -------------------------------- ### Implement HarmonyX Transpiler Source: https://context7.com/bepinex/harmonyx/llms.txt Modifies IL instructions of a method. Use this for low-level logic changes. ```csharp using HarmonyLib; using System.Collections.Generic; using System.Reflection; using System.Reflection.Emit; public class MathOperations { public int Multiply(int a, int b) { return a * b; // We'll change this to addition } } [HarmonyPatch(typeof(MathOperations), "Multiply")] public class MathPatch { [HarmonyTranspiler] static IEnumerable Transpiler( IEnumerable instructions, ILGenerator generator, MethodBase original) { foreach (var instruction in instructions) { // Replace multiplication with addition if (instruction.opcode == OpCodes.Mul) { yield return new CodeInstruction(OpCodes.Add); } else { yield return instruction; } } } } // Usage var harmony = Harmony.CreateAndPatchAll(typeof(MathPatch)); var math = new MathOperations(); Console.WriteLine(math.Multiply(3, 4)); // Output: "7" (3 + 4 instead of 3 * 4) ``` -------------------------------- ### Patching native extern methods Source: https://github.com/bepinex/harmonyx/wiki/Valid-patch-targets HarmonyX allows applying prefixes and transpilers to extern methods similarly to managed methods. ```csharp class MyNativeClass { // A simple internal call // Can also be DllImport for a proper extern call [MethodImpl(MethodImplOptions.InternalCall)] extern SomeSpecialType MyICall(); } // Prefixes work [HarmonyPatch(typeof(MyNativeClass), "MyICall")] [HarmonyPrefix] static void Prefix(); // Transpilers also work // Note: because externs have no body, `instrs` will get body of a // special wrapper code that calls the original native method [HarmonyPatch(typeof(MyNativeClass), "MyICall")] [HarmonyTranspiler] static IEnumerable Transpiler(IEnumerable instrs); ``` -------------------------------- ### Find and Replace IL Instructions with CodeMatcher Source: https://context7.com/bepinex/harmonyx/llms.txt Use CodeMatcher to find specific IL instructions and replace their operands. This is useful for modifying string literals or method calls within existing code. ```csharp using HarmonyLib; using System; using System.Collections.Generic; using System.Reflection.Emit; public class Logger { public void Log(string message) { Console.WriteLine($"[LOG] {message}"); } } [HarmonyPatch(typeof(Logger), "Log")] public class LoggerPatch { [HarmonyTranspiler] static IEnumerable Transpiler(IEnumerable instructions) { return new CodeMatcher(instructions) // Find the ldstr instruction that loads "[LOG] " .MatchForward(false, new CodeMatch(OpCodes.Ldstr, "[LOG] ")) // Replace its operand with a new prefix .SetOperandAndAdvance("[DEBUG] ") // Return modified instructions .InstructionEnumeration(); } } ``` -------------------------------- ### TargetMethod Signatures Source: https://github.com/bepinex/harmonyx/wiki/Patching Defines the method to be patched, useful for overloaded methods or runtime selection. Can optionally receive the Harmony instance. ```csharp static MethodBase TargetMethod() static MethodBase TargetMethod(HarmonyInstance instance) ``` ```csharp [HarmonyTargetMethod] // NOTE: not passing harmony instance with attributes is broken in 1.2.0.1 static MethodBase CalculateMethod(HarmonyInstance instance) ``` -------------------------------- ### Cleanup Method Signatures Source: https://github.com/bepinex/harmonyx/wiki/Patching Method called after patching is complete. Can optionally receive the original method. ```csharp static bool Cleanup() static bool Cleanup(MethodBase original) ``` ```csharp [HarmonyCleanup] static bool MyInitializer(...) ``` -------------------------------- ### Transpiler Parameters Source: https://github.com/bepinex/harmonyx/wiki/Patch-parameters Parameters available specifically for Transpiler patches. Parameter names do not matter; only types are used for injection. ```APIDOC ## Transpiler Parameters ### Description Parameters used in Transpiler methods to manipulate IL instructions. ### Parameters - **IEnumerable** (Required) - The list of IL instructions. - **ILGenerator** (Optional) - Used to define labels. - **MethodInfo** (Optional) - Info pointing to the original method. ``` -------------------------------- ### HarmonyFinalizer Source: https://github.com/bepinex/harmonyx/wiki/Method-patches Allows catching, throwing, and suppressing exceptions in a method. ```APIDOC ## [HarmonyFinalizer] ### Description Finalizers run before postfixes if the original method was not skipped, or immediately if an exception occurs. ### Signature `static void MyFinalizer([...])` `static Exception MyFinalizer([...])` ``` -------------------------------- ### Manipulate IL Instructions with CodeMatcher Source: https://github.com/bepinex/harmonyx/wiki/Transpiler-helpers After matching instructions, use CodeMatcher methods to modify them. Use SetOperandAndAdvance to replace an operand, or InsertAndAdvance to insert new instructions. ```csharp new CodeMatcher(instructions) .MatchForward(false, // false = move at the start of the match, true = move at the end of the match new CodeMatch(OpCodes.Ldstr), new CodeMatch(OpCodes.Call, AccessTools.Method(typeof(Foo), "Foo")), new CodeMatch(OpCodes.Ret)) .SetOperandAndAdvance("Woo!") ``` ```csharp new CodeMatcher(instructions) .MatchForward(false, // false = move at the start of the match, true = move at the end of the match new CodeMatch(OpCodes.Stfld), new CodeMatch(OpCodes.Ldarg_0), new CodeMatch(i => i.opcode == OpCodes.Ldfld && ((FieldInfo)i.operand).Name == "test")) .Advance(2) // Move cursor to before ldfld .InsertAndAdvance( new CodeInstruction(OpCodes.Dup), new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Foo), "Foo")) ) ``` -------------------------------- ### Define a Finalizer patch method Source: https://github.com/bepinex/harmonyx/wiki/Method-patches Finalizers handle exceptions within methods. They run before postfixes if no skip occurs. ```csharp // Rethrowing finalizer [HarmonyFinalizer] static void MyFinalizer([...]) // Throwing finalizer [HarmonyFinalizer] static Exception MyFinalizer([...]) ``` -------------------------------- ### Patching Native Methods with HarmonyX Source: https://context7.com/bepinex/harmonyx/llms.txt Intercepts P/Invoke or internal calls by defining a prefix that returns false to skip the original native execution. ```csharp using HarmonyLib; using System; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; public class NativeWrapper { [DllImport("kernel32.dll")] public static extern uint GetTickCount(); [MethodImpl(MethodImplOptions.InternalCall)] public extern void InternalMethod(); } [HarmonyPatch(typeof(NativeWrapper), "GetTickCount")] public class NativePatch { [HarmonyPrefix] static bool Prefix(ref uint __result) { Console.WriteLine("GetTickCount intercepted!"); __result = 12345; // Return fake value return false; // Skip original native call } } // Usage var harmony = Harmony.CreateAndPatchAll(typeof(NativePatch)); uint ticks = NativeWrapper.GetTickCount(); // Output: "GetTickCount intercepted!" returns 12345 ``` -------------------------------- ### Controlling Patch Priority and Ordering Source: https://context7.com/bepinex/harmonyx/llms.txt Defines execution order for multiple patches using HarmonyPriority or explicit dependency attributes. ```csharp using HarmonyLib; using System; public class SharedTarget { public void Process() { } } // Higher priority runs first for prefixes, last for postfixes [HarmonyPatch(typeof(SharedTarget), "Process")] [HarmonyPriority(Priority.High)] // 400 public class HighPriorityPatch { [HarmonyPrefix] static void Prefix() => Console.WriteLine("High priority prefix (runs first)"); [HarmonyPostfix] static void Postfix() => Console.WriteLine("High priority postfix (runs last)"); } [HarmonyPatch(typeof(SharedTarget), "Process")] [HarmonyPriority(Priority.Low)] // 200 public class LowPriorityPatch { [HarmonyPrefix] static void Prefix() => Console.WriteLine("Low priority prefix (runs last)"); [HarmonyPostfix] static void Postfix() => Console.WriteLine("Low priority postfix (runs first)"); } // Explicit ordering by Harmony ID [HarmonyPatch(typeof(SharedTarget), "Process")] [HarmonyBefore("com.other.plugin")] [HarmonyAfter("com.base.plugin")] public class OrderedPatch { [HarmonyPrefix] static void Prefix() => Console.WriteLine("Ordered prefix"); } // Priority constants: // Priority.First = 0 // Priority.VeryHigh = 500 (was HigherThanNormal) // Priority.High = 400 (was Higher) // Priority.Normal = 300 (was Default) // Priority.Low = 200 (was Lower) // Priority.VeryLow = 100 (was LowerThanNormal) // Priority.Last = 600 ``` -------------------------------- ### Class Patching Lifecycle Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Overview of the methods used to control the patching process and execution flow. ```APIDOC ## Class Patching Methods ### Prepare - **Signature**: static bool Prepare([MethodBase original, Harmony instance]) - **Description**: Executed before patching. If it returns true, the patch is applied; if false, the patch is skipped. ### TargetMethod / TargetMethods - **Signature**: static MethodBase TargetMethod([Harmony instance]) or static IEnumerable TargetMethods([Harmony instance]) - **Description**: Used to dynamically identify the method(s) to be patched when static attributes are insufficient. ### Prefix - **Signature**: static (void|bool) Prefix([...]) - **Description**: Executed before the original method. Returning false skips the original method execution. ### Postfix - **Signature**: static (void|T) Postfix([T result, ...]) - **Description**: Executed after the original method. Passthrough postfixes can modify the return value of the original method. ### Cleanup - **Signature**: static void Cleanup([MethodBase original, Harmony instance]) - **Description**: Executed after the patching process is complete. ``` -------------------------------- ### Define a class patch with Prefix and Postfix Source: https://github.com/bepinex/harmonyx/wiki/Method-patches Use HarmonyPatch attributes to target specific methods and define Prefix or Postfix logic. ```csharp public class OriginalType { public static void TargetMethod() { Console.WriteLine("Target method!"); } } public class MyPatch { // Specifies the method to be a patch that targets OriginalType.TargetMethod [HarmonyPatch(typeof(OriginalType), "TargetMethod")] [HarmonyPrefix] public static void Prefix() { // Code to run at the start of the original method Console.WriteLine("Hello"); } // Specifies the method to be a patch that targets OriginalType.TargetMethod [HarmonyPatch(typeof(OriginalType), "TargetMethod")] [HarmonyPostfix] public static void Postfix() { // Code to run after the original method Console.WriteLine("Bye"); } } ``` -------------------------------- ### Manually Obtaining MoveNext Method Reference Source: https://github.com/bepinex/harmonyx/wiki/Enumerator-patches This code snippet illustrates how to manually obtain a reference to the `MoveNext` method of an enumerator using `AccessTools.Method` and `AccessTools.EnumeratorMoveNext`. ```csharp // Get reference to SomeEnumerator var enumeratorMethod = AccessTools.Method(typeof(TargetClass), "SomeEnumerator"); // Resolve MoveNext from the enumerator var moveNext = AccessTools.EnumeratorMoveNext(enumeratorMethod); ``` -------------------------------- ### Patch All Methods in a Type with HarmonyPatch Annotations Source: https://github.com/bepinex/harmonyx/wiki/Patching-with-Harmony Use this method to selectively apply all patches defined within a single type. It searches the specified type for methods annotated with HarmonyPatch and applies the patches accordingly. Recommended for small patches or selective application of many patches. ```csharp harmony.PatchAll(typeof(Patches)); ``` -------------------------------- ### ILManipulator Parameters Source: https://github.com/bepinex/harmonyx/wiki/Patch-parameters Parameters available for ILManipulator patches. Parameter names do not matter; only types are used for injection. ```APIDOC ## ILManipulator Parameters ### Description Parameters used in ILManipulator methods to interact with MonoMod IL contexts. ### Parameters - **ILContext** (Type) - Context for interacting with MonoMod. - **MethodBase** (Type) - MethodBase for the manipulated method. - **ILLabel** (Type) - Label to the end of the original method. ``` -------------------------------- ### Define a Basic HarmonyX Class Patch Source: https://github.com/bepinex/harmonyx/wiki/Class-patches Use the HarmonyPatch attribute to target a specific method and define Prefix/Postfix logic to execute around the original method. ```csharp public class OriginalType { public static void TargetMethod() { Console.WriteLine("Target method!"); } } // Specifies the class to be a patch that targets OriginalType.TargetMethod [HarmonyPatch(typeof(OriginalType), "TargetMethod")] public class MyPatch { public static void Prepare() { // Executed before patching } public static void Prefix() { // Code to run at the start of the original method Console.WriteLine("Hello"); } public static void Postfix() { // Code to run after the original method Console.WriteLine("Bye"); } public static void Cleanup() { // Executed after patching } } ```