Files
agentmc/scaffold/ARCHITECTURE.md
JianFeeeee 16f2e04fff 架构重构:差异全部下移到 Java,Python 只做路由
用户口径:差异放在 Java 层,Python 相当于路由。

下移到 Java(新增 cmd=setblocks):
  Python 只发 RLE([[stateId,count],...]),Java 用官方 API 完成
  调色板组装 / 位打包 / 官方序列化 / 入 cache / 渲染。

★ 意外收益:走 ClientboundLevelChunkPacketData(chunk).getReadBuffer()
  + replaceWithPacketData(...) 这条官方路径,两代签名完全一致
  ⇒ 原先的 Storage.chunks 反射注入**整段删掉**。

新增 cmd=capacity:世界尺寸(sectionsCount/minSection/defaultBiome)
  由运行时回答,Python 不再硬编码 24/-4(1.16 时代是 16/0)。

Python 侧删除(防回归,见 test_import_surface):
  render_bridge.py(旧桥,无世代概念)
  render._pack/_long_array/_encode_paletted/_encode_chunk/_varint
  anvil.encode_block_section/encode_chunk_payload/save_chunk_to_payload
  合计 454→374 行(render.py)、300→177 行(anvil.py)

保留在 Python(都是「不随版本变」的知识):
  RLE 压缩(rle_encode/rle_decode,具名可测)
  存档读取(region/NBT)
  方块名→id 的路由(查询在 Java)
  NDJSON 协议

测试:62 项单元 + 6 项渲染联测全绿
  新测试反映新架构:RLE 边界、运行时容量、世代分派、新路径渲染
  test_anvil 里原有 8 项协议位打包测试已删(那已下移到 Java,
  由两代后端各自的编译验证覆盖)

新增 scaffold/ARCHITECTURE.md(分层原则 + 加新世代步骤 + 防回归清单)
2026-09-25 19:21:45 +08:00

82 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 架构分层:谁负责什么
用户口径(2026-09-25):**差异放在 Java 层,Python 相当于路由。**
## 三层
```
Python(mcfold/)
├── backends/__init__.py 路由:按 client jar 判世代 → 选后端 ← 唯一的 switch
├── backends/base.py 路由:NDJSON 协议、命令集、RLE 压缩
├── anvil.py 读取:存档 region/NBT → 方块(名字规格)
└── render.py 读取 + 编排:WorldRenderer
│
│ NDJSON(chunk 数据 / RLE 方块 / 相机 / 渲染指令)
▼
Java(scaffold/java/gen_1_20/ , gen_1_21/)
├── McfoldRenderServer.java 协议格式、调色板组装、位打包、入 cache、渲染
└── McfoldBridge.java 包私有 API 桥(reloadShaders / loadEffect)
│
▼
官方客户端 jar(各自版本,重映射为可读名)
```
## 分界原则
| 层 | 负责 | 为什么 |
|---|---|---|
| **Python** | 路由、存档读取、方块名→id 查询、RLE 压缩、编排 | 这些**不随 MC 版本变** |
| **Java** | 协议格式、调色板、位打包、官方序列化、渲染调用 | 这些**历代改过**,必须贴着版本走 |
### 判据:这个知识「随版本变吗」
| 知识 | 随版本变? | 归属 |
|---|---|---|
| 方块名 → state id | 变(mod/版本) | Java(问运行时注册表) |
| 世界尺寸(sectionsCount / minSection) | 变(1.16 是 16/0,1.20 是 24/-4) | Java(`cmd="capacity"`) |
| PalettedContainer 位打包 | 变过 | Java(官方 API) |
| LongArray 编码 | 变过 | Java(官方 API) |
| 区块入 cache 的路径 | 签名变过 | Java(官方 `replaceWithPacketData`) |
| **RLE 压缩** | **不变** | Python(只是压重复值) |
| **存档 NBT 结构** | 基本不变 | Python(读取) |
| **NDJSON 协议** | 不变(我们自己定的) | Python(路由层) |
## 数据流:渲染一个存档
```
1. Python: 读 level.dat + region/*.mca
2. Python: NBT → Sections[].block_states(palette + data)
3. Python: palette 名字(+属性) → "minecraft:oak_log[axis=y]" 规格
4. Python: 向后端批量查询规格 → state id [Java: BuiltInRegistries.BLOCK.asLookup()]
5. Python: state id 列表 → RLE [[id,count],...] ← 唯一被压缩的东西
6. Python: setblocks(cx, cz, sections) ← NDJSON
7. Java: LevelChunk + LevelChunkSection.setBlockState(...)
8. Java: 光照(queueSectionData 全亮)
9. Java: ClientboundLevelChunkPacketData(chunk) ← 官方序列化
10. Java: replaceWithPacketData(官方入口入 cache)
11. Java: gameRenderer.render(...)(世代差异在此)
12. Java: 读 FBO → PNG → base64 回传
```
**第 4/7/8/9/10/11 步都在 Java 侧** —— 版本相关知识全部集中在那里。
## 加新世代(用户 2026-09-25 定向的收益)
1. `scaffold/java/gen_<ver>/` 建目录,拷上一代源码
2. 对着 **javap 输出**改差异点(实测共 11 处,见 VERSION-DIFFS.md)
3. `mcfold/backends/gen_<ver>.py` 声明 `markers`(判据类)
4. `mcfold/backends/__init__.py` 的 `GENERATIONS` 加一条
5. 各自对**对应版本**的 named jar 编译
**Python 侧只动第 3、4 步**(各一处),协议与渲染逻辑无需碰。
## 已删除(防回归)
| 已删 | 原因 |
|---|---|
| `mcfold/render_bridge.py` | 被 `backends/` 取代(旧版无世代概念) |
| `render._pack/_long_array/_encode_paletted/_encode_chunk/_varint` | 协议编码下移到 Java |
| `anvil.encode_* / save_chunk_to_payload` | 同上 |
回归判据见 `tests/test_anvil.py::test_import_surface` —— 这些名字**不应再出现**在 Python 里。