5 Commits

Author SHA1 Message Date
547f4beb7e M1+M2:1.21.1 构建跑通 + 协议客户端进 play 阶段
M1(构建):
- build.sh 编译 CP 加入 $OUT/fabric/*.jar,解决 net.fabricmc.* 找不到
- gen_1_21 内联 Sodium 通知改为委托共用 RenderCompat,补 reportRenderCompat
- 1.21.1 全量七步构建产物齐备(classes-intermediary.jar / names*.json / srg / inheritance.map)

M2(协议):
- login_start 按协议数据发 UUID(1.21 必填;1.20 可选)
- login_acknowledged / serverbound 包 id 改为查表,不再写死 0x00
- send() 实现压缩帧格式(varint(dataLen)+数据,小包不压)
- configuration 双向协商:发 settings、回 select_known_packs、拒 resource_pack
- protodef 补 bitflags / entityMetadataLoop / count(ctx引用) / compareTo 路径表达式
- NBT 读取器由占位符改为真实现(anonymousNbt 支撑 registry_data)
- 坏包容错:长度前缀是帧层权威,解不开整包丢弃并布告,不断流

实测:login→configuration(11 注册表)→play,位置 (5.5,-60.0,-0.5),map_chunk×9
判据:protodef 6→13 项(含线上真实 entity_metadata 字节回归);全量 77 项通过
2026-09-26 12:15:48 +08:00
e6f8c0e596 build.sh 七步:加 remap 与名字表(加载器路线所需)
## 新增两步(原五步 → 七步)

**[6/7] 反射名次表** —— 调 gen_names.py 生成
    names.json(named 形态)与 names-intermediary.json(intermediary 形态)

**[7/7] remap named → intermediary** —— 三步:
    7a. 复合出 named→intermediary 的 SRG(gen_intermediary_srg.py)
    7b. 造一个 **intermediary 形态的 client jar** ← 继承查找的输入,缺它不行
    7c. 从它生成继承映射(-H),再用 -h 把我们的 classes remap 过去

## 为什么必须 remap

实 mod(Iris/Sodium 等)的 mixin 注解写的是 **intermediary** 名且不带 refmap。
跑 named 时 42 个 mod 的 464 处 mixin 全部找不到目标(实测)。
⇒「mod 要 intermediary」与「我们的产物是 named」在同一 JVM 互斥,
  解法是把**我们的产物** remap 过去(非通用数据由 extern 名次表解决)。

## gen_intermediary_srg.py 的两个实测坑(不处理会出错且症状误导)

① **描述符必须转**。mappings.srg 的 MD 行两侧 desc **都是 official 形式**:
       MD: enn/Z ()Laki; net/.../Minecraft/getResourcePackRepository ()Laki;
   左 desc 必须转成 named、右转成 intermediary。
   只改类名不改 desc 的症状:**类改名成功了、方法却没改** → NoSuchMethodError。

② **必须生成继承映射**。SpecialSource 按 owner+name+desc 精确匹配、
   **不查继承链**;而 MC 里大量方法继承自父类/接口
   (如 ClientPacketCache.registryAccess 实际声明在 RegistryAccess)。
   不带它漏 ~60 处(实测:60 → 12,且剩余 12 全是 JDK 继承方法、
   record component、和我们自己那个不该改名的桥类)。

## 另修三处

- **SS_CP 提到全局**:原来在第 3 步的 if 里定义,而第 7 步也要用它 ——
  若 client-named.jar 已是最新,第 3 步不进入 if ⇒ 变量为空。
- **LoaderBoot 纳入编译**:launcher_fabric 从没被 build.sh 编译过,
  运行期报 ClassNotFoundException: LoaderBoot。
- **common/ 纳入编译**:mcfold/McfoldNames.java 在 common 下,
  漏了它 ⇒ remap 后产物里没有这个类 ⇒ NoSuchFieldException(实测踩过)。
- **natives 平铺**(见上一批提交):jar 内是 linux/x64/org/lwjgl/<mod>/lib*.so,
  而 LWJGL 按**文件名**找库 ⇒ 保留包路径会 UnsatisfiedLinkError。

## 产物清单(落在内容根 .mcfold/)

    classes/                    裸启动 / named
    classes-intermediary.jar    加载器 / intermediary
    client-named.jar · client-intermediary.jar
    names.json · names-intermediary.json
    named2intermediary.srg · inheritance.map
    classpath.txt · natives/(平铺)· fabric/(8 库)
2026-09-26 10:18:08 +08:00
a1ce560c05 修复渲染联测的两个阻断缺陷(之前 5/7 → 现 7/7)
## ① natives 必须平铺,不能保留包路径

natives-linux jar 里的路径是 `linux/x64/org/lwjgl/<module>/lib*.so`,
而 LWJGL 经 java.library.path / LD_LIBRARY_PATH 按**文件名**找库 ——
嵌套一层的目录它找不到。实测:

  UnsatisfiedLinkError: Failed to locate library: liblwjgl.so
    at RenderSystem.<clinit> → Tesselator.<clinit>

build.sh 原来直接 `unzip -d $OUT/natives`(保留包路径)⇒ 产物不可用。
改为解到临时目录再 `find -name '*.so' -exec cp` 平铺。
(已用新逻辑重铺 store/vanilla-1.20.1/.mcfold/natives,7 个 .so 在根下。)

## ② api_notes 应为 staticmethod

35534b1 把世代分派改成类级调用后,`api_notes` 仍是实例方法,
测试里 `Gen_1_20.api_notes()` 直接 TypeError。它不读 self ⇒ 一律 staticmethod。
这也是它能"不启动后端就做世代对照"的前提。

## ③ classpath.txt 的语义写进注释

它**只含第三方 libraries**;client-named.jar 与 classes/ 由使用方拼接
(build.sh:88 自己拼,测试/后端从各自路径取)。
在 build.sh 里注明,避免下一个人以为它是"完整运行 classpath"。

## 验证

  ./run_tests.sh                    → 62 项全绿
  .mcfold classpath + 平铺 natives  → 渲染联测 **7/7 全绿**
    (injected=49 chunks=31 colors=11714 / placed=1003716 chunks=25 colors=4540)
2026-09-26 06:53:30 +08:00
35534b1564 feat: get_block_info —— 方块信息查询(Java 侧回答,Python 只路由)
新增 cmd=blockinfo(两代后端编译通过、实测):
  返回 block 名(含 mod 方块)、stateId、属性、isAir/isSolid、
  光照/硬度、贴图缺失的程序化判据、是否来自 mod。

★ 修掉一个真实缺陷(附录 D 的语义区分落到了实处):
  未加载区块原先返回 void_air(known=true),实测发现两个 API 都不可用:
    - ClientLevel.hasChunk()      反编译实测**恒返回 true**
    - ChunkSource.hasChunk()      走 getChunk(...,false),而 ClientChunkCache
      覆写后在该参数下返回 emptyChunk(占位,非 null)⇒ 也恒 true
  正解:getChunk(..., requireChunk=**false**) 判 null
    (反编译:return requireChunk ? emptyChunk : null;)
  ⇒ 现在未加载明确回 known=false + reason=chunk_not_loaded

实测(1.20.1):
  草地 → minecraft:grass_block props={'snowy':'false'} missing=False
  原木 → minecraft:oak_log       props={'axis':'y'}
  空气 → minecraft:air
  远处 → known=false reason=chunk_not_loaded        ← 与空气区分

实测(1.21.1 + mod):
  mts:mtsofficialpack.fancydirt_block   mod=True tex=mtsofficialpack:block/fancydirt
  createbigcannons:steel_block          mod=True tex=createbigcannons:block/steel_block
  ⇒ mod 方块同样能查到正确贴图名与 fromMod 标记

顺带修 gen_1_21 两处世代差异(ChunkStatus 换包、bridge 编译顺序)。
测试:69 项全绿(新增 test_get_block_info 6 条判据)
2026-09-26 00:24:29 +08:00
e223be2571 P8: scaffold —— 反混淆 + MC 渲染栈离屏初始化 + 真渲染出图
实测链路(全绿):
  1. 官方 ProGuard 映射 → SRG → SpecialSource 重映射 → client-named.jar
  2. 反编译确认 MC 渲染器挂在 Minecraft 单例上,不能独立 new
  3. 权威序列:tryDetectVersion → Bootstrap → RenderSystem → new Minecraft(cfg)
  4. 渲 3 帧 + glReadPixels → PNG,画面是 Mojang 加载屏(真渲染,非清屏)

三个坑(实测证据):
  - 漏 tryDetectVersion → Game version not set
  - FolderData 参数顺序错 → icons/ 404
  - assetIndex 用 id(5) 而非落盘名(1.20.1) → 资源全找不到

下一步:ClientLevel 构造只需 listener.registryAccess(),
ClientChunkCache.replaceWithPacketData 接收 map_chunk 原始字节
(与 chunk.py 同格式)⇒ 这就是数据喂渲染器的落点。
2026-09-25 15:39:41 +08:00