Jar-in-Jar 嵌套 jar

基本信息

属性 值
触发字段 manifest 的 Jar-In-Jar 属性,CSV 形式相对路径
抽取类 JarUtil.getNestedJar
抽取目录 <mc>/nestedmods/ (由 CoreModManagerV2.setupNestedModDir 创建)
去重机制 SHA-256 → 文件名 <basename>-<sha256>.jar
重新抽取条件 同 hash 文件不存在

Jar-in-Jar 是 Forge 1.7.10 时代引入但并未实际实现的"嵌套 mod"机制——JarJar 接管了这一流程,让 mod 开发者能把多个 jar 嵌入到自己的分发 jar 内,按嵌套依赖加载。

读取位置

  1. Coremod 阶段:CoreModManagerV2.loadCommandLineCoremods 对命令行通过 -Dfml.coreMods.load= 注入的每个 coremod 检查其 Jar-in-Jar
  2. Mod 发现阶段:ParallellModDiscoverer.ModScanTask.computeJarFile 检测外层 jar 的 manifest;存在 Jar-In-Jar 时通过 JarUtil.checkNestedJars 抽取并并行扫描每个嵌套 jar
  3. 校验阶段:JarUtil.examineJarCandidate 内 if(coremodPass) 分支设置 nestedModcandidates

抽取算法

JarUtil.getNestedJar(jarFile, nestedJarPath, targetDir):

  1. 用 jar.getJarEntry(nestedJarPath) 取 entry;找不到则打 ERROR 跳过
  2. 套 RewindableModInputStream 包裹 jar.getInputStream(entry),支持读完 SHA-256 后倒回再写盘
  3. DigestUtils.sha256Hex 计算 64 字符 hex
  4. 同步块内构造 outputJarFile = new File(targetDir, baseName + "-" + hash + ".jar")
  5. 若不存在:
    • is.rewind()
    • 1 KB 缓冲循环写出
  6. 返回 record NestedJar(File file, String sourceFilename, String hash)

JarUtil.checkNestedJars(jar):

  1. manifest.getMainAttributes().getValue("Jar-In-Jar") 为空 → 返回空列表
  2. 用 HashSet 去重 CSV 路径(防止 manifest 写重)
  3. 调 getNestedJar 把每条记录抽取到 CoreModManagerV2.getNestedDir()(即 <mc>/nestedmods/)

并行机制

ParallellModDiscoverer.ModScanTask.computeJarFile:

  • 遍历 modCandidate.getNestedJars()(即 NestedJar 列表)
  • 用 ConcurrentHashMap<String, ModScanTask> jijDedupMap(key = nestedJar.hash())避免同一 hash 重复 fork
  • 第一个 task 不 fork,留给当前线程;其余 task.fork() 异步执行
  • tasks 收集完成后,最末尾 localTask.invoke() 阻塞等首任务,递归把结果装入 modCandidate.setNestedModcandidates(nestedMods)
  • nestedModInitDatas.add(new NestedModInitData(tasks, nestedMods)) 统一收集 future,外层 discoverMods() 二次 future.get(timeout, ...) 收割

输出命名

输入 entry 名 输出文件名
libs/optional-1.2.3.jar optional-<sha256>.jar
mymod.jar mymod-<sha256>.jar

抽取目录 <mc>/nestedmods/:

  • 在 CoreModManagerV2.handleLaunch 中 setupNestedModDir 创建
  • 路径规范化用 getCanonicalFile()
  • 已存在但不是目录则抛 RuntimeException

相关条目