Skip to content
Geoffrey Horsington edited this page Jan 11, 2022 · 39 revisions

NOTE: This documentation refers to HarmonyX 2.1 and newer.
You can still use the information for Harmony 2 as core API is the same, but note that some of the API might be missing.

HarmonyX

A library for patching, replacing and decorating .NET methods during runtime powered by MonoMod.


Where should I start?

This wiki contains information related to HarmonyX -- that is, the extensions we added to Harmony 2. We attempt to keep our API consistent with the latest Harmony code when it comes to base Harmony features. Because of that, you can use official Harmony docs.

As such:

  • If you're looking for the base Harmony guide, use official Harmony 2 documentation
  • Use this wiki to check the additions and extensions introduced by HarmonyX. Check the links in the sidebar for all topics.

About HarmonyX

If you develop in C# and your code is loaded as a module/plugin into a host application, you can use HarmonyX (later referred to as Harmony) to alter the functionality of all the available assemblies of that application. Where other patch libraries allow you to replace the original method, Harmony goes one step further and gives you:

  • A way to keep the original method intact
  • Execute your code before or after the original method
  • Modify the original with IL code processors
  • Have multiple Harmony patches co-exist and don't conflict with each other

HarmonyX builds on top of the original Harmony library, extending and streamlining its features. Most importantly, you get

  • Better logging via streamlined API
  • Helper methods for creating patches
  • Easy extendibility to support patching special methods (like IL2CPP methods)
  • Reduced overall complexity and code duplication by using helpers from MonoMod instead of reimplementing them

HarmonyX is based on MonoMod, a robust tool for patching .NET assemblies. With it, you get additional features such as

  • Ability to target methods marked with extern
  • Ability to use HarmonyX in environments where dynamic code generation is not supported (e.g. Unity's .NET Standard 2.0 API)
  • Interop with MonoMod patches

Prerequisites

HarmonyX works on any games that support running code in .NET. Currently, HarmonyX is built against the following targets:

  • .NET Framework 3.5
  • .NET Framework 4.0
  • .NET Standard 2.0

HarmonyX has been tested mainly on Unity games and has been confirmed to work on all Unity versions (even ones with dynamic code generation disabled).
HarmonyX supports patching on all architectures that MonoMod supports. At the time of the writing, that is x86, x64, ARM, ARM64.

Why another fork of Harmony? What did you change?

NOTE: HarmonyX design is strongly motivated by our needs that arose over time working with BepInEx. While Harmony aims at general runtime patching, our target is to make Harmony "modding-framework-friendly". You might not agree with all our changes, but they proved useful enough to warrant a custom fork.

Without an extended essay on the history of BepInEx Harmony forks and our needs to integrate them with MonoMod, here are some of our goals with HarmonyX:

  • Logging: current Harmony 2 logging system is primitive and not enough for modding frameworks. We added a custom extendable logging system to facilitate custom log levels, lazy logging and multiple log targets.
  • Remove "global patch state": in modding frameworks, there is only one source of Harmony. Instead of the slowdown of serializing patch state and handling version incompatibilities, we prefer assembly shimming (as it is also very viable in modding context).
  • Interop with MonoMod.RuntimeDetours so that Harmony patches won't overwrite Detours and ILHooks.
  • Remove duplicated code between MonoMod and Harmony where possible: IL parsing, delegate generation should be done by only one library. We use MonoMod.RuntimeDetour to its full capabilities to remove duplicated code from Harmony.
  • Don't hide useful code, allow extendability: most internal patching code is made public as helpers. HarmonyX users can implement custom patching backends to support patching new methods (e.g. native methods and Il2Cpp methods)
  • Helper methods to make life easier: unpatching current instance, patching specific type, emitting calls to a delegate, code matching.

For a specific explanation of more technical changes, refer to implementation difference outline.