模组:迁移至Harmony 2.0
![]() |
仍需完善
该页面内容由于以下原因仍需进一步完善。
|
← 模组:目录
SMAPI 3.12 将 Harmony 从 1.2.0.1 更新到了 Harmony 2.1。这只影响直接使用 Harmony 的模组;在大多数情况下,这是不推荐的,它并非 SMAPI 公共 API 的正式组成部分,也不受 SMAPI 常规版本管理策略的约束。如果你在模组中使用了 Harmony,本页面将解释此次更新对它们的影响。
概述
有什么变化?
Harmony 2.0 和 2.1 有许多有益于 SMAPI 和模组的变更。一些值得注意的变更包括:
- 添加了终结器(finalizer)和反向补丁(reverse patch)。
- 添加了穿透式后缀(pass-through postfix)。
- 添加了Manipulator 工具、CodeInstruction 扩展以及其他针对代码转换器(transpiler)的改进。
- 添加了更多的 AccessTools.Is* 方法。
- 增加了对 .NET 5 的支持。
- 代码转换器现在可以通过返回 null 来默认使用原始输入。
- 改善了与 Android 模组制作的兼容性。
- 改进了异常信息。
- 改进了对无效补丁的验证。
- 修复了在 Linux/Mac 上方法被内联导致无法修补的问题。
- 修复了返回结构体类型的方法无法修补的问题。
- 其他各种改进和修复;更多信息请参阅 Harmony 2.0 发行说明、Harmony 2.1 发行说明和新的 Harmony 文档。
在等待了一年多以确保该版本稳定后,SMAPI 正在过渡到 Harmony 2.1。
这是模组末日吗?
不。尽管这是一次重大更新,但我们付出了巨大的努力来最小化其影响:
- 不直接使用 Harmony 的模组不受影响;
- 大多数模组的代码会被自动重写以实现兼容,因此它们无需更新即可工作;
- 我们提交了拉取请求以更新受影响的开源模组;
- 为尚未正式更新的模组创建了必要的非官方更新;
- 我们积极地向模组作者沟通和记录了这些变更。
此外,在 SMAPI 迁移之前,我们的目标是为开源模组实现至少 90% 的兼容性。所有这些都意味着,尽管变更范围很大,但此次发布对模组兼容性的影响应该是最小的。
如何更新你的模组
- 确保你遵循了Harmony 指南中概述的最佳实践。特别是,使用
EnableHarmony选项(不要直接引用 Harmony DLL)。 - 将
using Harmony;更改为using HarmonyLib;。 - 将
HarmonyInstance harmony = HarmonyInstance.Create("your mod id");更改为Harmony harmony = new Harmony("your mod id");。 - 检查下方列出的破坏性变更是否适用于你的模组。
- 重新编译模组。
破坏性变更
API 变更
请参阅如何更新你的模组。
更严格的验证
Harmony 2.x 的验证通常更严格,因此,以前可能勉强能用的无效补丁(例如,将 __result 设置为错误的类型)现在会导致错误。请查看异常信息以获取修复帮助。
修补静态构造函数
用于构造函数的 AccessTools 方法(Constructor、DeclaredConstructor 和 GetDeclaredConstructors)默认情况下不再匹配静态构造函数。如果你需要匹配它们,请使用新的 searchForStatic 参数:
// 仅匹配静态构造函数
var method = AccessTools.Constructor(typeof(ExampleType), searchForStatic: true);
// 匹配静态*或*实例构造函数
var method =
AccessTools.Constructor(typeof(ExampleType), searchForStatic: true)
?? AccessTools.Constructor(typeof(ExampleType));
请注意,Harmony 不再匹配静态构造函数是有充分理由的——它们只为该类型调用一次,因此静态构造函数补丁通常无法正常工作。
修补虚方法
在修补虚方法时,你现在必须修补实现它的特定类型。修补错误的类型现在会导致错误:“You can only patch implemented methods/constructors”(你只能修补已实现的方法/构造函数)。
例如,考虑以下代码:
public class GameLocation
{
public virtual void cleanupBeforePlayerExit() {}
}
public class Farm : GameLocation {}
Farm.cleanupBeforePlayerExit 不存在,因此它继承自 GameLocation。Harmony 1.x 会允许你修补 Farm.cleanupBeforePlayerExit,但在 Harmony 2.x 中,你必须以实际的方法为目标(在本例中为 GameLocation.cleanupBeforePlayerExit)。
HarmonyMethod 不再允许 null
Harmony 1.x 允许使用 new HarmonyMethod(null),这样你就可以安全地将它用于可能不存在的方法。Harmony 2.x 现在在这种情况下会抛出异常,所以如果你不确定它是否存在,就应该进行检查:
MethodInfo prefix = AccessTools.Method(this.GetType(), "Prefix");
if (prefix != null)
harmony.Patch(original, new HarmonyMethod(prefix));
代码转换器变更
Harmony 2.x 在底层使用了一个新引擎 (MonoMod),因此代码转换器补丁的工作方式可能会发生意外变化。例如,短格式分支可能会变成长格式。如果你的模组使用代码转换器,你应该逐一测试以确保它们按预期工作。


沪公网安备 31011002002714 号