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 jar
  • candidate.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。

相关条目