gen_1_21 实测启动成功 + provision 工具

决定性验证:gen_1_21 后端在 1.21.1 上收到 {"event":"ready"}
  ⇒ 世代分派架构成立:同一套 Python 层,两个独立编译的 Java 后端

运行时发现第 12 处世代差异(编译期看不出):
  1.20.x  registryAccess 是可变 LayeredRegistryAccess → 事后反射替换
  1.21.x  registryAccess 是 final RegistryAccess$Frozen → 反射抛
          "Can not set final field"
  处理:gen_1_21 改为先载注册表 → 经 CommonListenerCookie.receivedRegistries
        传入 → 再构造 listener。比 1.20 的反射做法更干净。

新增 mcfold/provision.py(从官方 manifest 装任意版本,版本无关):
  - 跳过音频资源:1.21.1 实测 3911 条里跳过 3744 条
  - natives 两种形态都认(1.21 起是独立库条目,非 classifiers)
  - 实测 1.21.1:274 文件 / 200MB / 32s / 0 失败
This commit is contained in:
JianFeeeee
2026-09-25 18:35:28 +08:00
parent 8c7d5b9d38
commit 253146cffe
8 changed files with 316 additions and 40 deletions

View File

@ -54,3 +54,28 @@ Java 编译期绑定签名。实测:
⚠️ 教训(本轮踩过):`Reason.LEVEL_LOAD`、`DirectoryValidator.NONE`
都是凭印象写出来的、实际不存在的 API;`loadEffect` 的可见性也没验证。
**改之前先 `javap`。**
## 补充:1.21.1 实际运行验证(比编译更强的证据)
`gen_1_21` 已实测启动成功(stdout 收到 `{"event":"ready"}`)。
运行期又暴露 1 处「编译期看不出」的差异:
| # | API | 1.20.x | 1.21+ | 处理 |
|---|---|---|---|---|
| 12 | `ClientPacketListener.registryAccess` | 可变 `LayeredRegistryAccess`,可事后反射替换 | **`final RegistryAccess$Frozen`**,反射抛 `Can not set final field` | gen_1_21 改为**先载注册表 → 经 `CommonListenerCookie.receivedRegistries` 传入 → 再构造 listener** |
★ 这条是本轮最有价值的发现:1.21 的 cookie 机制让注册表注入**比 1.20 的反射更干净**。
两代的启动顺序因此不同:
```
1.20.x: 构造 listener → 反射替换 registryAccess 字段
1.21.x: 先加载注册表 → 构造 cookie(含注册表) → 构造 listener(final 字段一次到位)
```
## provision 的实测发现
- natives 在 1.21.1 是**独立库条目**(`name` 含 `:natives-linux`),
不走老版 `downloads.classifiers` 结构 ⇒ 两种形态都要认。
- 跳过音频资源可省 **3744/3911 条**(仅 167 条实际下载),
实测 1.21.1 全量 274 文件 / 200MB / 32s,0 失败。