编辑
2025-09-29
C#
00

目录

摘要
正文
应用场景
Harmony 的基本概念
例子 1: 在游戏中添加Mod功能
例子 2: 修改第三方库的行为
例子 3: 动态日志记录
结论

摘要

Harmony 是一个用于 .NET 的库,它允许开发者在运行时创建、应用或修改程序集的补丁,即所谓的 "热补丁" (hot patching)。这使得开发者能够动态地改变已编译代码的行为,而无需修改原始的源代码。Harmony 在游戏Mod开发、软件插件系统和复杂的应用程序中非常流行,因为它可以在不改变原始程序集的情况下,注入或改变代码的功能。

正文

应用场景

Harmony 的常见应用场景包括:

  1. 游戏Mod开发:在不修改游戏原始代码的情况下添加新功能或修改现有功能。
  2. 软件扩展:在现有应用程序中注入代码以增加新功能或修改现有逻辑。
  3. 行为修正:修复第三方库中的错误或不希望的行为,而不需要等待官方更新。
  4. 测试和Mocking:动态替换方法以进行单元测试或集成测试。

Harmony 的基本概念

在深入例子之前,让我们快速了解一下 Harmony 的一些基本概念:

  • 原始方法 (Original Method):需要被修改或补丁的方法。
  • 前置补丁 (Prefix):在原始方法执行之前运行的代码。
  • 后置补丁 (Postfix):在原始方法执行之后运行的代码。
  • 替换方法 (Transpiler):修改原始方法的IL代码的方法。
  • 反射补丁 (Reverse Patch):允许调用私有方法作为公共的静态方法。

例子 1: 在游戏中添加Mod功能

假设我们正在为一个游戏添加Mod,我们想要修改玩家的移动速度。原始的游戏代码可能是这样的:

C#
public class Player { public float MoveSpeed { get; set; } = 10f; public void Move(Vector3 direction) { // 移动玩家的逻辑 Console.WriteLine("MOVE:" + direction.X * MoveSpeed); Console.WriteLine("MOVE:" + direction.Y * MoveSpeed); Console.WriteLine("MOVE:" + direction.Z * MoveSpeed); } }

我们想要在不修改原始游戏代码的情况下增加玩家的移动速度。我们可以使用 Harmony 创建一个前置补丁:

C#
using C20240114C; using HarmonyLib; [HarmonyPatch(typeof(Player))] [HarmonyPatch("Move")] public static class PlayerMoveSpeedPatch { static void Prefix(Player __instance) { __instance.MoveSpeed *= 2; // 将移动速度翻倍 } } class Program { static void Main() { var harmony = new Harmony("com.mod.yourmod"); harmony.PatchAll(); Player player= new Player(); player.Move(new System.Numerics.Vector3(1, 2, 3)); } }

image.png

在这个例子中,我们创建了一个名为 PlayerMoveSpeedPatch 的类,并使用 HarmonyPatch 属性指定要补丁的类和方法。我们定义了一个 Prefix 方法,它会在玩家移动之前执行,并将移动速度翻倍。

例子 2: 修改第三方库的行为

假设我们使用了一个第三方库,该库有一个方法 Calculate,但它的行为不是我们想要的。我们想要修改它的返回值。

C#
public class ThirdPartyCalculator { public int Calculate(int a, int b) { return a + b; // 原始行为是相加 } }
C#
using C20240114C; using HarmonyLib; [HarmonyPatch(typeof(ThirdPartyCalculator))] [HarmonyPatch("Calculate")] public static class CalculatorPatch { static void Postfix(ref int __result, int a, int b) { __result = a * b; // 修改返回值为乘积 } } class Program { static void Main() { var harmony = new Harmony("com.mod.yourmod"); harmony.PatchAll(); ThirdPartyCalculator calculator=new ThirdPartyCalculator(); var ret= calculator.Calculate(10,20); Console.WriteLine(ret); } }

image.png

在这个例子中,我们使用了 Postfix 方法来修改 Calculate 方法的返回值。我们引用了 __result 参数来改变原始方法的输出。

例子 3: 动态日志记录

假设你有一个生产环境中的应用程序,你想要为特定的方法添加额外的日志记录,但你不能重新编译和部署整个应用程序。使用Harmony,你可以创建一个前置补丁来动态添加日志记录。

C#
// 假设这是你想要添加日志的方法 public class PaymentProcessor { public bool ProcessPayment(decimal amount, string accountNumber) { // 支付处理逻辑 return true; } }
C#
using C20240114C; using HarmonyLib; // Harmony补丁类 [HarmonyPatch(typeof(PaymentProcessor))] [HarmonyPatch("ProcessPayment")] public static class LogPaymentPatch { static void Prefix(decimal amount, string accountNumber) { Console.WriteLine($"Processing payment of {amount:C} for account {accountNumber}."); } } class Program { static void Main() { var harmony = new Harmony("com.mod.yourmod"); harmony.PatchAll(); PaymentProcessor payment=new PaymentProcessor(); payment.ProcessPayment(200, "10001"); } }

image.png

在这个例子中,LogPaymentPatch 类在 PaymentProcessorProcessPayment 方法之前添加了日志记录,记录了每次支付处理的详细信息。

结论

Harmony 是一个功能强大的库,它为C#开发者提供了前所未有的灵活性,使他们能够动态地修改和扩展代码的行为。无论是在游戏开发、软件插件还是单元测试中,Harmony 都能提供强大的支持。通过合理使用 Harmony,开发者可以跨越原有代码的限制,实现更加丰富和定制化的功能。

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!