BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。
模组:制作指南/APIs/Integrations
← 模组:目录
模组整合(mod integration)是指两个模组以某种方式通信或合作。SMAPI 提供了一些支持模组整合的功能。
依赖
您可以在 manifest.json 文件中定义依赖,也就是您的模组需要哪些前置模组。如果需要的依赖缺失,SMAPI 会向玩家显示一个友好的错误。参见[[../Manifest|清单文件]]以获取更多信息。
模组注册项
您的模组可以获取已加载模组的信息,或检查某个模组是否已加载(当调用您模组的 Entry(…) 方法时,所有模组都已加载完毕)。
// check if a mod is loaded
bool isLoaded = this.Helper.ModRegistry.IsLoaded("UniqueModID");
// get info for a mod
IModInfo mod = this.Helper.ModRegistry.Get("UniqueModID");
bool isContentPack = mod.IsContentPack;
IManifest manifest = mod.Manifest; // name, description, version, etc
// get info for all loaded mods
foreach(IModInfo mod in this.Helper.ModRegistry.GetAll()) { … }
模组API
模组可以将自身的 API 提供给其他模组,甚至不需要依赖或程序集引用。这可以用于整合模组、提供自定义信息或提供新的框架接口,以作为 SMAPI 接口的补充。
提供接口
按如下步骤来提供可供其他模组使用的 API:
- 向您的模组添加一个正常的类,其中包含您希望公开的方法和属性。
(如需要,您可以使用构造函数以初始化此 API)
public class YourModApi { public string ExampleProperty { get; set; } = "Example value"; public bool GetThing(string example) { return true; } }
- 重写您模组入口类的 GetApi 并返回您的 API 的一个实例。您可以选择该方法的两种版本之一:
- 重写 GetApi() 以向所有模组提供 API 的同一个实例。此方法只会被调用一次,随后 SMAPI 会缓存其创建的实例。
public override object GetApi() { return new YourModApi(); }
- 或重写 GetApi(IModInfo mod) 以为每个模组提供单独的实例。每个请求此 API 的模组都会导致此方法被调用一次。
注意此 IModInfo mod 参数仅用于获取信息(例如用于记录错误)。请不要使用此参数来阻止特定模组调用 API,否则可能被视作滥用行为。
public override object GetApi(IModInfo mod) { return new YourModApi(mod.Manifest); }
- 重写 GetApi() 以向所有模组提供 API 的同一个实例。此方法只会被调用一次,随后 SMAPI 会缓存其创建的实例。
大功告成!SMAPI 会获取您的 API 的一个实例并缓存它。
说明:
- GetApi 总是在 Entry 之后被调用,因此可以放心将其传入您的模组的初始化字段。
- 谨慎修改您的接口!如果您做了较大修改,其他模组可能需要随之更新。
- 您可以酌情向您的 API 添加一个接口类。如果其他模组直接引用您的模组 DLL,这样他们就能够使用您的接口类而无需再自行创建。
使用API
您如果需要使用某个模组提供的 API,您可以将其映射到一个接口类:
- 创建一个接口类,其中仅有您希望访问的属性和方法。此接口类必须为公共类,且不能为内部接口。(如果您直接引用模组 DLL,且后者提供了公共的 API 接口类,则您可以直接使用它。)
public interface ISomeModApi { bool GetThing(string example); }
- 在您的模组代码中(Entry 之后),您可以通过指定您在第一步创建的接口类以及[[../Manifest#基本字段|模组唯一ID]]来获取 API:
ISomeModApi api = helper.ModRegistry.GetApi<ISomeModApi>("other-mod-ID"); if (api != null) bool result = api.GetThing("boop");
您也可以使用反射而非接口类来实现快速整合:
object api = helper.ModRegistry.GetApi("other-mod-id");
if (api != null)
bool result = helper.Reflection.GetMethod(api, "GetThing").Invoke<bool>("boop");
注意:
- 在所有模组都初始化完毕且其 Entry 方法被调用之前,您不能调用 GetApi。如果您需要在较早时调用模组 API,则 GameLoop.GameLaunched [[../Events|事件]];该事件一定会在所有模组初始化完毕后触发。
- 您总是应当检查您调用的 API 是否为空。如果无法调用,则 GetApi 会返回空(无法调用的情形例如模组未安装或不提供对应 API)。若 GetAPi</smap> 不能映射某个 API,则会抛出异常。
- 请留心模组可能会在未来改变其 API 接口;因此,在试图映射接口之前,可以先检查模组版本。
已知的限制
- 当您提供 API 时,接口类和实现类必须都是公共的。
发送消息
您可以使用多人接口来发送消息。消息的接收方可以很精确(例如,某台联机计算机上的某一个具体的模组),也可以很宽泛(所有计算机上的所有模组)。消息也可以发送到本地计算机上,例如用于两个模组之间的通讯。该特性可以用于各种模组整合。
例如:
- 从主模组处请求某些东西。(拖拉机模组 Tactor Mod 在多人游戏中使用此特性来给当前玩家生成一个拖拉机,即使拖拉机所在地点并未同步到该玩家。)
- 告知其他模组某些信息。(随时随地查看箱子 Chest Anywhere 模组使用此特性来告知自动化 Automate 模组,当箱子的自动化选项被编辑)。
共享程序集引用
注意:这并不是 SMAPI 的功能,但是我们仍将其列入文档,因为这是模组整合的常用手段。
您可以在您的 csproj 中添加对某个模组程序集的引用,然后直接向您的模组代码中导入其命名空间及函数。注意,这仅用于如下情形:您希望的功能无法藉由模组的公共 API 实现,或这是目标模组希望被公开使用的方法。这会使您的模组必须依赖于目标模组。
例如,下面的片段向您的模组引用了一个 Content Patcher 程序集,就在 ContentPatcher 命名空间下,从而无需在构建模组时嵌入 ContentPatcher.dll。
<ItemGroup>
<Reference Include="ContentPatcher" HintPath="$(GamePath)\Mods\ContentPatcher\ContentPatcher.dll" Private="false" />
</ItemGroup>
请确保 ContentPatcher.dll 的路径符合您的实际安装情况。