Files
agentmc/scaffold/java/VERSION-DIFFS.md
JianFeeeee 8c7d5b9d38 世代分派体系:Python 层 switch + 各世代独立编译的 Java 后端
用户定向:在 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 处)
2026-09-25 18:21:08 +08:00

3.0 KiB
Raw Blame History

世代差异清单(实测,非推断)

来源:官方 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。