APIOnlyWrapper
基本信息
| 属性 | 值 |
|---|---|
| 类型 | @Desugar record |
| 实现 | SortableCandidate |
| 字段 | ModCandidateV2 candidate |
某些 jar 只声明 @API 但没有 @Mod 类(如 Ender IO API、AE2 API)。原版 FML 1.7.10 会把它们当作 non-mod lib 跳过,导致 classpath 上找不到这些 API 类型。APIOnlyWrapper 把它们包成 SortableCandidate 参与排序与 classpath 加载,但不产出 ModContainer。
实现
@Desugar
public record APIOnlyWrapper(ModCandidateV2 candidate) implements SortableCandidate {
@Override
public @NotNull String getId() { return candidate.getId(); }
@Override
public DefaultArtifactVersion getVersion() { return candidate.getVersion(); }
@Override
public File getFile() { return candidate.getFile(); }
public int getNestLevel() { return candidate.getNestLevel(); }
}
创建点
LoaderV2.identifyMods:
if (mods.isEmpty() && !candidate.isClasspath() && !candidate.containsAPIAnnotations()) {
nonModLibs.add(candidate.getModContainer());
} else {
if (mods.isEmpty() && candidate.containsAPIAnnotations()) {
sortableCandidates.add(new APIOnlyWrapper(candidate));
} else {
sortableCandidates.addAll(mods);
}
}
判定条件:
mods.isEmpty():jar 内没有任何@Mod类!candidate.isClasspath():不是 Minecraft jarcandidate.containsAPIAnnotations():class scanning 阶段发现@API注解
满足 → 用 APIOnlyWrapper 包装。
排序与 classpath
ModCandidateV2Sorter.computeClasspathOrder 把 APIOnlyWrapper 当作 ModCandidateV2 处理(instanceof ModCandidateV2 检查在 computeClasspathOrder 跳过此 wrapper —— 它不是 ModCandidateV2 实例,但 candidate 字段是)。
排序输出后 LoaderV2:
} else if (sortable instanceof APIOnlyWrapper apiWrapper) {
final ModCandidateV2 candidate = apiWrapper.candidate();
uniqueCandidates.add(candidate);
try {
modClassLoader.addFile(candidate.getModContainer());
} catch (MalformedURLException e) {
FMLRelaunchLog.log(Level.ERROR, e, "Failed to add API-only jar %s to classpath", candidate.getFilename());
}
}
把 API-only jar 加进 classpath,但不构造 ModContainer、不加入 mods。
相关条目
- SortableCandidate 接口 - 实现
- ModContainerWrapper - 兄弟实现
- LoaderV2 - 创建与消费 APIOnlyWrapper
- ModCandidateV2 数据模型 -
containsAPIAnnotations来源