ModCandidateV2 数据模型
基本信息
| 属性 | 值 |
|---|---|
| 类 | com.mitchej123.jarjar.fml.common.discovery.ModCandidateV2 |
| 父类 | cpw.mods.fml.common.discovery.ModCandidate |
| 实现接口 | com.mitchej123.jarjar.discovery.SortableCandidate |
| API 注解 descriptor | Lcpw/mods/fml/common/API; |
ModCandidateV2 是 FML 原版 ModCandidate 的扩展载体,保存 JarJar 引入的全部元数据:access transformer 列表、cascaded tweaker、coreMod、嵌套 jar 候选、API 包声明、earlyPackages、nestLevel、SHA-256 hash、sourceFilename 等。
字段
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
accessTransformers |
Map<String, String> |
null |
FMLAT 解析后的 jar→AT 内容映射 |
cascadedTweaker |
String |
null |
manifest TweakClass |
fmlCorePlugin |
String |
null |
manifest FMLCorePlugin |
containsMod |
boolean |
false |
manifest FMLCorePluginContainsFMLMod 或 ForceLoadAsMod=true |
containsAPI |
boolean |
false |
在 class scanning 阶段发现 @API |
earlyPackages |
Set<String> |
null |
class scanning 阶段收集的包前缀 |
declaredApiPackages |
Map<String, DefaultArtifactVersion> |
null |
package-info.class 中 @API(apiVersion=...) |
nestedModcandidates |
Collection<ModCandidateV2> |
null |
Jar-in-Jar 嵌套候选列表 |
parentModcandidates |
Collection<ModCandidateV2> |
null |
父 jar 引用(用于 nestLevel 累计) |
nestLevel |
int |
0 |
嵌套深度 |
wrappedMods |
List<ModContainerWrapper> |
null |
类扫描阶段构建的 ModContainer 列表 |
asmDataCollection |
List<ASMModParserV2> |
new ArrayList<>() |
该 jar 内每个 .class 解析结果 |
nestedJars |
List<JarUtil.NestedJar> |
null |
抽取出来的嵌套 jar(scan 后释放) |
hash |
String |
null |
整个 jar 的 SHA-256(嵌套 jar 才填) |
sourceFilename |
String |
null |
在外层 jar 中的 entry 名(嵌套 jar 才填) |
sortOrder |
int |
0 |
manifest TweakOrder 或覆写 |
metadataCollection |
MetadataCollection |
null |
mcmod.info 解析结果 |
version |
DefaultArtifactVersion |
"0.0.0" |
从 mcmod.info 或文件名提取 |
getId 重写
@Override
public String getId() {
if (fmlCorePlugin != null) return fmlCorePlugin;
if (sourceFilename != null) return sourceFilename;
return modContainer.getName();
}
fmlCorePlugin 优先(coremod 用类名去重);嵌套 jar 用其在父 jar 里的 entry 名;普通 jar 用文件 basename。
getFilename
public String getFilename() {
if (sourceFilename != null) return sourceFilename;
return modContainer.getName();
}
nestLevel 累计
private void updateNestLevel(ModCandidateV2 parent) {
if (parent != null && parent.nestLevel + 1 > this.nestLevel) {
this.nestLevel = parent.nestLevel + 1;
}
}
ParallellModDiscoverer.discoverMods 在递归发现 parent → child 时调用 addParent:
public boolean addParent(ModCandidateV2 parent) {
if (this.parentModcandidates == null) this.parentModcandidates = new ArrayList<>();
if (this.parentModcandidates.contains(parent)) return false;
this.parentModcandidates.add(parent);
updateNestLevel(parent);
return true;
}
释放流程
| 方法 | 释放内容 |
|---|---|
releaseEarlyScanData() |
earlyPackages、declaredApiPackages |
releaseAccessTransformers() |
accessTransformers |
releaseNestedJars() |
nestedJars |
releaseParsedData() |
asmDataCollection → 空列表;metadataCollection → null |
LoaderV2.identifyMods 在所有 candidates 加入后调 releaseParsedData 释放 ASM 字节与 metadata 引用,降低内存峰值。
sendToTable
public void sendToTable(ASMDataTable table) {
setTable(table);
for (ASMModParserV2 asmData : asmDataCollection) {
addClassEntry(asmData.getClassEntry());
asmData.sendToTable(table, this);
}
}
addClassEntry 来自父类 ModCandidate,把 jar 内的 class 完整路径加到 classEntries。asmData.sendToTable 触发 ASMModParserV2.sendToTable 把 @Mod 与 interface ASMData 注入 table。
构造
public ModCandidateV2(File classPathRoot, File modContainer, ContainerType sourceType, boolean isMinecraft, boolean classpath) {
super(classPathRoot, modContainer, sourceType, isMinecraft, classpath);
}
isMinecraft 标记 Minecraft jar(classpath 阶段唯一拥有此标志);classpath 标记为 classpath mod。
相关条目
- 并行 mod 发现 - 主填充流程
- JarUtil 嵌套抽取与版本识别 -
examineJarCandidate设置 fmlCorePlugin/tweaker/version 等 - ModCandidateV2Sorter - 排序与去重消费者
- API 所有权排序 - 消费
declaredApiPackages