开发指南
依赖声明
模组间依赖分两层:硬依赖决定「能不能加载」,软约束只决定「同阶段内的遍历次序」。
9.1 硬依赖:ModInfo.dependsOn(List<String>)
ModInfo 是 record,dependsOn 是第 6 个分量,声明本模组依赖的模组 id 列表;不声明依赖的模组用工厂方法 ModInfo.of(id, name, version, authors, description) 构造,此时 dependsOn 为空列表。
语义:
- 宿主按拓扑顺序激活模组;
- 依赖缺失(
dependsOn里有未注册或未启用的模组 id)时,宿主在加载阶段抛MissingDependencyException,该模组状态标记为ModLoadStatus.LOAD_FAILED,消息形如Missing dependencies: <缺失的 id 列表>,可经ModManagerAccess.getLoadError(id)读到;getMissing()返回缺失 id 列表; - 循环依赖同样失败:
MissingDependencyException.circular(...)构造的消息形如Circular dependency: A -> B -> A,getCircularChain()返回环上的模组 id 列表(首尾相同,如["A","B","A"]),此时getMissing()为空列表。
java
@Override
public ModInfo info() {
return new ModInfo(
"my_hud",
"My HUD",
"0.1.0",
List.of("You"),
"依赖 core_lib 提供的状态",
List.of("core_lib") // 硬依赖:core_lib 未注册 / 未启用则本模组 LOAD_FAILED
);
}9.2 软依赖:Mod.loadOrder() 与 LoadStage
Mod.loadOrder() 默认返回 null,等价于落在 LoadStage.INIT 阶段、无软依赖。返回 ModLoadOrder 可声明加载阶段与软依赖:
java
public record ModLoadOrder(
LoadStage stage,
List<String> loadAfter,
List<String> loadBefore
) {
public static ModLoadOrder of(LoadStage stage);
public static ModLoadOrder init();
}LoadStage 取值:CORE → PRE_INIT → INIT → POST_INIT,宿主按阶段升序激活,未声明阶段的模组默认落在 INIT。
关键语义:
loadAfter/loadBefore是软约束:只决定同阶段内、每个阶段内部的遍历次序;目标模组不存在(未注册 / 未启用)时约束自动失效,不影响本模组加载;stage只决定激活顺序,不改变生命周期方法 —— 所有模组都在各自排序位置调用同一个onInit(ModContext);「何时做」由onPreInit/onInit/onPostInit三段回调表达;- 渲染顺序联动:激活顺序决定叠加顺序(
CORE模组最先叠加,位于最底层); - 反滥用规则:声明
CORE但注册表中没有任何模组依赖它的模组,会被宿主自动降级为INIT并记录告警; stage为null视为INIT;构造时null列表归一为空列表。
java
@Override
public ModLoadOrder loadOrder() {
// 落在 INIT 阶段,并在 other_mod 参与本次加载时排在它之后(目标不在则自动失效)
return new ModLoadOrder(LoadStage.INIT, List.of("other_mod"), List.of());
}9.3 依赖声明写错时的现象
| 写法 | 现象 |
|---|---|
dependsOn 写了一个未安装 / 未启用的 id | 本模组 LOAD_FAILED,getLoadError(id) 给出 Missing dependencies: [...];其余模组不受影响 |
两个模组互相 dependsOn | 两者(或环上成员)LOAD_FAILED,原因为 Circular dependency: A -> B -> A |
把软依赖当硬依赖用(只写 loadAfter 却没写 dependsOn) | 目标模组未启用时不报错,只是次序约束失效;若代码假定目标一定存在,会在运行期取到 null(如 modServices().find(...) 返回 null) |
无消费者却声明 LoadStage.CORE | 宿主自动降级为 INIT 并记录告警,不加载失败 |
| 依赖了一个「加载失败」的模组 | 视为依赖不满足,本模组同样 LOAD_FAILED |
需要「目标模组的服务一定已注册」这类保证时,正确做法是硬依赖 + 软依赖一起声明(dependsOn 保证它在,loadAfter 保证它先跑完);不要依赖加载顺序碰运气。