故障排查 · Minecraft 整合包

HMCL 整合包卡在「处理游戏依赖 0/241」
——RLCraft Dregora 实测排查与通用解法

手动把 242 个 mods 补齐后依然报 Unable to download?这不是单纯的网络问题,而是网络、打包清单、运行目录三层坑同时踩到。

实测:RLCraft Dregora v1.2.0 另测:v1.2.0-beta-2.0 Forge 1.12.2-14.23.5.2860 Windows + HMCL 无代理 / 无梯子

结论先行

这个包的失败是三层叠加的,缺一层都推不出正确解法:

  1. 网络层:国内直连 CurseForge API 与 CDN 失败,manifest.json 里的 projectID / fileID 无法在线解析。
  2. 清单层:整合包自带的 modpack.cfg 里,文件名和下载地址缺 .jar 扩展名,请求本身就是 404,网络再好也无解。
  3. 逻辑层:HMCL 的依赖补全以清单为准、不看磁盘,且文件落在「运行目录」而不是 versions\<实例>\mods,所以你手动补齐后它照样从 0 开始重来。

正确解法:绕开整合包补全流程——手动解析清单、走国内镜像下载、最后把它当普通 Forge 版本启动。

01三步自检:先判断卡在哪一层

不要一上来就怀疑网络。按顺序做完这三步,基本能确定病灶。

第一步 · 检查报错里的完整 URL

把 Unable to download 后面的地址复制到浏览器打开:

  • 返回 404 → 清单 URL 本身错了(本案就是这种),换源、挂代理都无效。
  • 超时 / 连接被重置 → 纯网络层问题,换 BMCLAPI 源或代理即可。
  • 能正常下载 → 个别文件偶发失败,重试即可。

第二步 · 查 modpack.cfg 的 fileName 有没有扩展名

路径:.minecraft\versions\<实例名>\modpack.cfg

对照
反例:Aquaculture-1.12.2-1.6.8        ← 缺 .jar,必然 404
正例:Aquaculture-1.12.2-1.6.8.jar

第三步 · 确认文件到底该放哪

HMCL 按「运行目录(runningDirectory)」找 mods。实例被导入或改名后,运行目录可能还停在 .minecraft 根目录,于是 versions\<实例>\mods 里的文件它完全不认。

检查文件:.hmcl\config\instance-game-settings.json

02根因拆解

2.1 网络层:CurseForge 在线解析不可用

CurseForge 整合包的 manifest.json 里只存 projectID / fileID,没有真实文件名。HMCL 必须先调 api.curseforge.com 把 ID 解析成文件名和下载地址,再去 mediafilez.forgecdn.net 取文件。国内这两个域名基本不可达,于是「处理游戏依赖」在第一步就 0% 失败。

2.2 清单层:包作者的打包失误

就算解析成功,modpack.cfg 里的名字和 URL 少了扩展名。HMCL 照着这份配置请求,地址长这样:

HTTP 地址对照
https://mediafilez.forgecdn.net/files/2659/258/Aquaculture-1.12.2-1.6.8      → 404
https://mediafilez.forgecdn.net/files/2659/258/Aquaculture-1.12.2-1.6.8.jar  → 200

结果 241 个文件全部 404,进度仍然是 0%。这种情况下「手动把文件补齐」没有任何意义,因为 HMCL 不会检查你已经放好的文件。

2.3 逻辑层:判定依据是清单,不是磁盘

整合包流程的语义是「按 manifest 重建一套依赖」:重新解析 → 重新下载 → 重新校验。你往 versions\<实例>\mods 里塞满文件,它仍然报 0/241。再加上运行目录错位,即使清单是对的,文件也会被下到别的地方去。

一句话记忆:报错地址能打开就不是网络问题;打不开且是 404 就是清单问题;文件都在却还从 0 开始,就是「它以清单为准」的问题。

03修复流程:手动导入法(最稳)

目标:让 HMCL 把它当普通 Forge 版本启动,彻底没有「补全依赖」这一步。

1解压 overrides,不要只搬 mods

把整合包 zip 里的 overrides/ 全部解到 versions\<实例名>\。这里有 config、scripts、resources、structures、shaderpacks、fancymenu_data 等共 4499 个文件。

只放 mods 是进不去世界的——配方、脚本、结构全在 overrides 里。

2解析清单,拿到 projectID / fileID

读 manifest.json 的 files 数组即可,这一步不需要网络。本案共 242 条。

3确定真实文件名

三种来源,任选其一:

  • 镜像 / CF 兼容接口返回的 fileName(有代理时最省事);
  • 已经导入过一遍的 modpack.cfg——里面的 fileName 只缺扩展名:.zip 的补 .zip,其余补 .jar(本案 242 条全部命中);
  • 用文件大小做交叉验证,不符就换扩展名重试。
4改走国内镜像下载

把 CF 的下载地址换成镜像的等价路径(实测可用,且支持 Range 断点续传):

URL 映射
官方:https://mediafilez.forgecdn.net/files/{pid高位}/{pid低位}/{fileName}
镜像:https://mod.mcimirror.top/files/{projectID}/{fileID}/{fileName}

实例:https://mod.mcimirror.top/files/9345/656/DregoraRL-1.12.2-3.9.3.jar
5必须按字节数校验

镜像偶发返回截断内容。每个文件下载后与 HEAD 返回的 Content-Length 比对,不一致就删掉重下;0 字节的 jar 一定要清掉。

6能复用旧实例就复用

旧版本实例里同名且大小完全一致的 jar 直接复制,别重下(本案省了 188 MB / 151 个文件)。

注意:只认同名同大小。名字像但版本不同的一律不要混用,否则轻则花屏、重则崩溃。

7切断整合包流程 + 固定运行目录

删除或改名 manifest.json、modpack.cfg(本案改成 *.disabled-<时间戳>,可回滚);versions\<实例>\<实例>.json 的 id 必须与目录名一致;再显式写死运行目录:

JSON · instance-game-settings.json
{
  "$schema": "https://schemas.glavo.site/hmcl/instance-game-settings/1.0.0",
  "overrideProperties": ["runningDirectory"],
  "runningDirectory": "D:\\我的世界\\.minecraft\\versions\\RLCraft Dregora v1.2.0-beta-2.0"
}
8完全退出 HMCL 再重开

配置只在启动时读取,不重启等于没改。列表里它会显示成普通版本(没有整合包图标),点启动即可,不会再有任何下载。

04附:可直接改用的脚本

思路:解析清单 → 拼镜像地址 → 并发下载 → 逐字节校验 → 落盘 mods。大文件(本案 DregoraRL 188 MB)建议再拆 Range 分段,否则镜像单连接被限速到 20–25 KB/s,一个文件要一小时。

4.1 下载器(PowerShell)

用法:先按第 1 步解压 overrides,并准备 files.txt(每行 fileName<TAB>projectID<TAB>fileID)。

PowerShell
# 用法:先按 Step 1 解压 overrides,并准备 files.txt(每行 fileName TAB projectID TAB fileID)
$mirror  = 'https://mod.mcimirror.top/files'
$mods    = 'D:\我的世界\.minecraft\versions\<实例名>\mods'
$lines   = Get-Content -LiteralPath '.\files.txt' -Encoding UTF8 | Where-Object { $_.Trim() }

Add-Type -AssemblyName System.Net.Http
$http = New-Object System.Net.Http.HttpClient
$http.Timeout = [TimeSpan]::FromSeconds(600)
$http.DefaultRequestHeaders.UserAgent.ParseAdd('Mozilla/5.0')

$ok = 0; $fail = @()
foreach ($line in $lines) {
    $name, $pid, $fid = $line.Split("`t")
    $url  = "$mirror/$pid/$fid/$name"
    $dest = Join-Path $mods $name
    if ((Test-Path -LiteralPath $dest) -and (Get-Item -LiteralPath $dest).Length -gt 0) { continue }
    try {
        # HEAD 拿真实大小,避免截断文件
        $head = New-Object System.Net.Http.HttpRequestMessage([System.Net.Http.HttpMethod]::Head, $url)
        $exp  = $http.SendAsync($head).Result.Content.Headers.ContentLength
        $bytes = $http.GetByteArrayAsync($url).Result
        if ([int64]$bytes.Length -ne [int64]$exp) { throw "size mismatch $($bytes.Length)/$exp" }
        [IO.File]::WriteAllBytes($dest, $bytes)
        $ok++
    } catch { $fail += $name }
}
$http.Dispose()
"downloaded=$ok failed=$($fail.Count)"; $fail

4.2 校验器

直接跑在实例目录上,能输出 verified=242/242 这类结果,顺手扫掉 0 字节文件。

PowerShell
$mods = 'D:\我的世界\.minecraft\versions\<实例名>\mods'
$zero = Get-ChildItem -LiteralPath $mods -File | Where-Object Length -eq 0
"0字节文件: $($zero.Count)"; $zero | Select-Object -ExpandProperty Name
$all = @(Get-ChildItem -LiteralPath $mods -File)
"files=$($all.Count) jars=$(@($all | Where-Object Extension -eq '.jar').Count) sizeMB=$([math]::Round((($all | Measure-Object Length -Sum).Sum)/1MB,1))"

05常见误区

误区实际情况
「挂个梯子就好了」本案 241 个 URL 缺 .jar,代理再快也是 404
「文件都下好了,HMCL 应该认」HMCL 按清单重算,不看磁盘;只有删掉清单才能绕过
「换 BMCLAPI 源就行」BMCLAPI 只管原版游戏库 / assets,不管 CurseForge 模组文件
「只搬 mods 就够」overrides 里还有 config / scripts / structures / shaderpacks,缺了会崩或进不去世界
「jar 名字差不多就能用」必须同名同大小才可复用,版本不同会崩溃
「改完直接启动」HMCL 只在启动时读配置,必须完全退出再重开

06本次实测数据(可作基准)

242 / 242
清单依赖,逐字节校验全部通过
4499
overrides 解压文件数
606 MB
mods 目录(234 jar + 16 zip)
151
旧实例复用模组数
188 MB
复用节省的下载流量
~300 KB/s
镜像分段并发后的吞吐
项目数值
清单依赖242(全部按字节数校验通过,缺失 0)
mods 目录234 jar + 16 zip = 250 个文件,606 MB(含 8 个包自带 overrides jar)
overrides4499 个文件
旧实例复用151 个模组,省 188 MB
镜像下载量91 个文件 / 约 259 MB(含 188 MB 的 DregoraRL)
镜像限速特征单连接约 20–25 KB/s,拆 32 段并发后约 300 KB/s
启动方式普通 Forge 版本(无 manifest / modpack.cfg),零下载

建议内存:6–8 GB。首次进入 Dregora 地形生成较慢,属正常现象。

07回滚:想恢复成「整合包」识别

  1. modpack.cfg.disabled-<时间戳> → modpack.cfg;manifest.json.disabled-<时间戳> → manifest.json;
  2. 还原 instance-game-settings.json.bak-<时间戳>;
  3. 若还希望依赖补全能正常工作,必须同时满足两个前提:文件名带扩展名 + 能访问 CurseForge 接口。

否则保持「普通版本」模式,稳定得多。