全站通知:

模组:迁移至Harmony 2.0

来自星露谷物语维基
跳到导航 跳到搜索

模组:目录

当前页面编写的内容面向模组的开发者。模组玩家请阅读模组:模组兼容性


SMAPI 3.12 将 Harmony 从 1.2.0.1 更新到了 Harmony 2.1。这只影响直接使用 Harmony 的模组;在大多数情况下,这是不推荐的,它并非 SMAPI 公共 API 的正式组成部分,也不受 SMAPI 常规版本管理策略的约束。如果你在模组中使用了 Harmony,本页面将解释此次更新对它们的影响。

概述

有什么变化?

Harmony 2.02.1 有许多有益于 SMAPI 和模组的变更。一些值得注意的变更包括:

在等待了一年多以确保该版本稳定后,SMAPI 正在过渡到 Harmony 2.1。

这是模组末日吗?

不。尽管这是一次重大更新,但我们付出了巨大的努力来最小化其影响:

  • 不直接使用 Harmony 的模组不受影响;
  • 大多数模组的代码会被自动重写以实现兼容,因此它们无需更新即可工作;
  • 我们提交了拉取请求以更新受影响的开源模组;
  • 为尚未正式更新的模组创建了必要的非官方更新;
  • 我们积极地向模组作者沟通和记录了这些变更。

此外,在 SMAPI 迁移之前,我们的目标是为开源模组实现至少 90% 的兼容性。所有这些都意味着,尽管变更范围很大,但此次发布对模组兼容性的影响应该是最小的。

如何更新你的模组

  1. 确保你遵循了Harmony 指南中概述的最佳实践。特别是,使用 EnableHarmony 选项(不要直接引用 Harmony DLL)。
  2. using Harmony; 更改为 using HarmonyLib;
  3. HarmonyInstance harmony = HarmonyInstance.Create("your mod id"); 更改为 Harmony harmony = new Harmony("your mod id");
  4. 检查下方列出的破坏性变更是否适用于你的模组。
  5. 重新编译模组。

破坏性变更

API 变更

请参阅如何更新你的模组

更严格的验证

Harmony 2.x 的验证通常更严格,因此,以前可能勉强能用的无效补丁(例如,将 __result 设置为错误的类型)现在会导致错误。请查看异常信息以获取修复帮助。

修补静态构造函数

用于构造函数的 AccessTools 方法(ConstructorDeclaredConstructorGetDeclaredConstructors)默认情况下不再匹配静态构造函数。如果你需要匹配它们,请使用新的 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),因此代码转换器补丁的工作方式可能会发生意外变化。例如,短格式分支可能会变成长格式。如果你的模组使用代码转换器,你应该逐一测试以确保它们按预期工作。