用户定向:在 python 层写 switch,调用不同 java 后端(而非一个文件里 switch)。
新增:
mcfold/backends/{__init__,base,gen_1_20,gen_1_21}.py 后端体系与分派
scaffold/java/gen_1_20/ 对 1.20.x client jar 编译
scaffold/java/gen_1_21/ 对 1.21.1 client jar 编译(✅ 实测编译通过)
scaffold/java/VERSION-DIFFS.md 实测差异全表
判据:DeltaTracker 类是否存在(1.21 引入,正是 render 签名变化的根源)
⇒ 比硬编码版本号稳
实测差异共 11 处(21 个检查点里 13 个跨世代完全一致):
setLevel / GameRenderer.render / countRendered* / createPackRepository /
ResourceLocation 构造 / enableDataFixerOptimizations(移除) / User 构造 /
ChunkStatus 包路径 / ClientPacketListener 构造(参数个数语义都变) /
loadEffect(变 private)
为什么必须分后端:DeltaTracker 在 1.20.x jar 中不存在,
两代调用无法共存于一份源码(实测编译报 cannot find symbol)。
1.21.1 反混淆已验证(29MB named jar,DeltaTracker 3 处)
57 lines
3.0 KiB
Markdown
57 lines
3.0 KiB
Markdown
# 世代差异清单(实测,非推断)
|
||
|
||
来源:官方 `client_mappings.txt` 逐版本对比(1.20.1 / 1.20.2 / 1.21.1),
|
||
以及两侧源码对各自 client jar 的实际编译结果。
|
||
|
||
## 判据
|
||
|
||
**`net.minecraft.client.DeltaTracker` 类是否存在** ⇒ 1.21+。
|
||
这是 1.21 引入的时间抽象,也正是 `GameRenderer.render` 签名变化的根源。
|
||
比硬编码版本号稳(官方改版本号不影响判据)。
|
||
|
||
实现:`mcfold/backends/__init__.py:detect_generation()`
|
||
|
||
## 差异全表(8 处,覆盖 21 个检查点中的 13 个「完全一致」之外的部分)
|
||
|
||
| # | API | 1.20.x | 1.21+ | 处理 |
|
||
|---|---|---|---|---|
|
||
| 1 | `Minecraft.setLevel` | `(ClientLevel)` | `(ClientLevel, ReceivingLevelScreen$Reason)` | gen_1_21 传 `Reason.OTHER` |
|
||
| 2 | `GameRenderer.render` | `(float,long,boolean)` | `(DeltaTracker, boolean)` | gen_1_21 用 `mc.getTimer()` |
|
||
| 3 | 区块计数 | `countRenderedChunks()` | `countRenderedSections()` | 各世代用各自名字 |
|
||
| 4 | 同理 | `hasRenderedAllChunks()` | `hasRenderedAllSections()` | 同上 |
|
||
| 5 | `ServerPacksSource.createPackRepository` | `(Path)` | `(Path, DirectoryValidator)` | gen_1_21 构造 validator |
|
||
| 6 | `ResourceLocation` 构造 | `new ResourceLocation(s)` | `ResourceLocation.parse(s)` | 静态工厂 |
|
||
| 7 | `SharedConstants.enableDataFixerOptimizations` | 有 | **已移除** | gen_1_21 不调 |
|
||
| 8 | `User` 构造 | `(String,String sessionId,...)` | `(String,UUID,...)` | 传 UUID |
|
||
| 9 | `ChunkStatus` | `world.level.chunk.ChunkStatus` | `world.level.chunk.status.ChunkStatus` | 包路径变了 |
|
||
| 10 | `ClientPacketListener` 构造 | `(Minecraft,Screen,Connection,ServerData,GameProfile,Telemetry)` | `(Minecraft,Connection,CommonListenerCookie)` | ★ 参数个数与语义都变 |
|
||
| 11 | `GameRenderer.loadEffect` | package-private(同包可调) | **private**(同包也调不到) | gen_1_21 用反射 |
|
||
|
||
★ 关键结论:**差异集中在 11 处,而不是「每个版本一套」**。
|
||
21 个检查点里 13 个(如 `tick`/`allChanged`/`replaceWithPacketData`/
|
||
`updateViewCenter`/`getChunkSource`/`PackRepository.*`)跨世代**完全一致**。
|
||
|
||
## 为什么必须分后端(而不是一个文件里 switch)
|
||
|
||
Java 编译期绑定签名。实测:
|
||
|
||
```
|
||
世代 B 的调用对 1.20.1 jar 编译:
|
||
error: cannot find symbol class DeltaTracker
|
||
```
|
||
|
||
`DeltaTracker` 在 1.20.x 的 jar 里不存在 ⇒ 两代的调用**无法共存于一份源码**。
|
||
所以每个世代独立编译,Python 层做分派。
|
||
|
||
## 加新世代的做法(用户 2026-09-25 定向)
|
||
|
||
1. `scaffold/java/gen_<ver>/` 建目录,拷上一代源码
|
||
2. 按上表改差异点(对着 **javap 输出**改,不要凭印象写 API 名)
|
||
3. `mcfold/backends/gen_<ver>.py` 声明 `markers`(判据类)
|
||
4. `mcfold/backends/__init__.py` 的 `GENERATIONS` 加一条
|
||
5. 各自对**对应版本**的 named jar 编译
|
||
|
||
⚠️ 教训(本轮踩过):`Reason.LEVEL_LOAD`、`DirectoryValidator.NONE`
|
||
都是凭印象写出来的、实际不存在的 API;`loadEffect` 的可见性也没验证。
|
||
**改之前先 `javap`。**
|