|
|
6a9a955472
|
M10:启动生命周期(多实例/重复启动/残留清理)+ 10 项判据
用户定位:框架本身是给 agent 用的 MC 启动器 ⇒ 多实例、多版本隔离、
单个实例多次启动是天然要求。盘点发现缺的是**运行时管理**那一层。
新增 mcfold/launch.py:
- claim():启动前的**闸门**(重复启动必须拦在启动之前 ——
不拦的话两个 JVM 抢同一个 run/ 与 X display,报错指向渲染异常,
完全指不到「重复启动」)
- register():JVM 起来后登记 pid/启动时间/世代/版本/加载器
- status():四态分清 free / stale(有记录但进程已死=崩溃残留)/
running / foreign(pid 存活但不属于本实例=pid 被复用)
- stop():先 SIGTERM 超时再 SIGKILL,**两次都复核身份**
- cleanup():只清记录不杀进程(状态 foreign 时杀就是误杀)
防误杀:pid 会被系统回收复用 ⇒ 终止前必须校验 cmdline 含本实例路径。
判据 10 项,用**真 java 进程**(mock 测不出 pid 复用/残留这类缺陷)。
★ 「模拟进程的形状」必须与真实启动一致:sleep 3600 带路径会拒绝参数退出;
bash -c 会 exec 掉自己、cmdline 变成裸 sleep ⇒ 两种都测不到真实情形。
改用 java -cp … Hold <实例路径>(形状同真实 --gameDir)。
4 项变异全被抓。
★ 又一次**空变异**:把身份校验的 return 改成恒真,看似改了,其实上面还有
「是不是 java」早退 ⇒ 判据假绿。结论重申:**必须先验证变异真的落地**
(打印改动后的行为),再信它的结果。
210 项全通过。
|
2026-09-26 14:08:06 +08:00 |
|
|
|
4980d6e81f
|
M8/M9:细渲染接服务端真状态 + capture_photo 拍照用例
新增 mcfold/fine.py:把 M3 状态层的区块灌进细渲染器
- chunks_to_sections:铺平顺序 = (y<<8)|(z<<4)|x(与 Java PalettedContainer 一致)
★ 错一位不报错、只是地形静默错位 ⇒ 判据用构造数据打这个点
- 缺失的 section **省略**而非填 0(0=空气,把「没数据」渲染成空洞)
- render_from_state:单次调用,失败全部返回 ok:false + why + how_to
新增 mcfold/photo.py:capture_photo
- propose_shots 用**粗渲染观察**生成机位候选(正面/斜侧/俯视/远景/当前位置),
每个都带「为什么选它」的依据;候选阶段不出图(省时省钱)
- 构图好坏是审美判断=决策,工具不替 agent 选
★ 关键发现:桥接比预想的干净
原以为要把 state id 反算成 name[props],但 Java 侧 set_blocks 收的
**本来就是 state id**(走官方 LevelChunk API),而 state id 本身含属性
⇒ 无损、无需转换。
修的真 bug:
1. ★★ HUD 没隐藏:桥层 RenderBackend.set_view 早有 hide_gui
(→ 官方 options.hideGui),但 WorldRenderer **没有这个入口**
⇒ AttributeError 被 except: pass 吞掉 ⇒ 出图带生命条/饥饿/物品栏,
而返回值仍写 hide_gui: True(自相矛盾)
教训:桥层有能力 ≠ 上层有入口;except: pass 让「以为设了」与
「实际没设」无法区分。现在 hide_gui 设不上就显式失败。
2. 俯视机位朝向不自洽(水平 yaw 退化却配写死的 pitch)→ 3D dot=0.82。
改为由位置向量反算 yaw/pitch;正面/斜侧/远景同样修正。
3. inject_world 的 ok 自相矛盾(无区块时 ok=True 却说「没有可渲染的区块」)
4. 缺失 section 被填 0 冒充空气
实测出图:854×480、1902 种颜色,地形/天空/月亮/草地纹理正确。
判据 17 项;2 项变异全被抓。
★ 「机位朝向」判据我第一版只比水平分量 ⇒ 俯视机位恒为 0 会判红,
改为完整 3D 点积(dot > 0.99)。
200 项全通过。
|
2026-09-26 13:52:33 +08:00 |
|
|
|
93243165bf
|
寻路:reachable 与 find_path 两个独立工具(完整版 + 可达性判断)
用户裁定:完整版寻路 + 可达性判断,且这两个是**两个独立工具**;
未加载走到边界为止并如实报告;执行方式两者都给。
新增 mcfold/pathfind.py:
- 移动词表对齐 mineflayer movements.js:forward/step_up/step_down/drop/jump/dig/place
- A*(八向 + 高度),可按「节点数/半径」有界
- reachable:只答「能不能到 + 大概多远」,**不给路线**,默认不挖不放
- find_path:给具体路线 + world_changes(要挖/放哪些方块,逐格列出)
修的真 bug(6 个):
1. is_ground(这格是实心底)与 is_standable(脚能停这格)语义混淆,差一格
→ 混用导致平地找不到落脚点,只肯搭桥
2. can_already_pass 判据用错对象(拿「更上方 standable」当「已能通过」,
而那是挖完才成立)→ dig 永不生成,2 格墙走不通
3. dig 只支持挖 1 格 → 4 格墙永远不通。改「挖穿一列」,代价按格数线性
4. 代价权重失衡 → 1 格台阶被挖而不是 step_up(挖穿一排墙)
调高 dig/place 代价 + 加「背离目标的额外代价」后修正
5. ★ 未加载被报成 exhausted(听起来像「地形不通」):根因是 neighbors()
在未加载格不生成移动 ⇒ A* 的未加载检测永远执行不到
→ 改为主动探测边界,现在报 hit_unloaded + 停在边界 + 已走步数
6. Terrain.known 调用签名错;挖清单会含空气
诚实性(用户最在意的一条):
- 未加载格所有判定回 None,**不当成空旷**
- 岩浆/水不当地面;solid=True 但致命的(仙人掌/岩浆块/篝火)也被排除
- 认不出的方块 → 不知道(None),不猜
- 碰撞粒度只有 block/empty 两档这个限制**写在返回值里**
判据 19 项;5 项变异全被抓。
★ 「岩浆当地面」变异第一次**没被抓** —— 查下去发现我的判据测的是冗余代码
(lava/water 本来 solid=False,去掉 hazard 检查也不会红);
真正承载语义的是 solid=True 但致命的那批方块 → 改用仙人掌才抓到。
|
2026-09-26 13:42:32 +08:00 |
|
|
|
69f54dc5a6
|
修复状态层撒谎:自身位置是客户端权威,move 必须更新本地状态
★★ 真 bug(用户问「寻路呢」时暴露出来):move() 之后本地坐标不变,
而服务端认为玩家真的移动了。
实测证据:
连发 5 次 move 后
本地以为: (0.5, -60.0, -3.5) ← 没动
服务端认为: (5.5, -60.0, -3.5) ← 真的动了
修后:本地 (10.5,-60,-3.5) == 服务端 [10.5d,-60.0d,-3.5d] ✓
根因:MC 的自身位置是**客户端权威** —— 客户端跑自己那侧物理并上报,
服务端只做校验(穿墙/超速会发 position 拉回),普通移动**不回包**。
我把这条规则错用成「等服务端权威」⇒ 本地状态永久陈旧。
与另一条的对比(别搞成一套):
自身移动(move/look) 客户端权威 ⇒ 本地必须立刻更新,标 pending 待确认
改世界(dig/place) 服务端权威 ⇒ 本地不动,等 block_changed 事件
★ 同时纠正一条**我自己写错的判据**:
test_move_does_not_falsely_update_local_state(断言「不该改本地」)是错的,
已替换为 test_move_updates_local_state_because_client_is_authoritative,
并补 test_dig_place_do_not_touch_local_world_state 守住相反的那条。
这个 bug 影响很大:寻路/碰撞/可达性判断全都建立在玩家位置上,
状态陈旧会让整个工具箱在错误前提下工作。
|
2026-09-26 13:21:44 +08:00 |
|
|
|
27b5c448b0
|
M6:粗渲染/常驻感知层(纯 Python,无 JVM)+ 20 项判据
新增 mcfold/rough.py:agent 日常游玩的感知层
- raycast(Amanatides & Woo 逐格体素遍历,不采样不插值)
- can_see / can_stand / walkable / slice_view / surroundings
- BlockRegistry 扩展 solid/transparent(从 blocks.json 读,不编)
修的真 bug:
- can_see 射到 max_distance ⇒ 越过目标撞身后的墙,把「看得见」误报「被挡」
→ 改为射程只到目标距离
- 切面从脚下往上取 ⇒ 全是空气看不出地形 → 基准下移让地面入画
- walkable 的 ? 漏统计「已加载但认不出名字」的方块
纪律:
- 有界(超范围拒绝并说明,不静默缩小)
- 不撒谎(unloaded / unknown-state / None 三态分明;把「没见过」当「空旷」
是这层最危险的错)
- 不决策(只给观察,不告诉 agent 该走哪)
判据用构造场景(plan §4.5:粗渲染不需要细渲染参与):
单格薄墙、空走廊、未加载区、缺残注册表。
146 项全通过;6 项变异全被抓(其中一项初次未抓到 ⇒ 补判据覆盖面后才抓住)
|
2026-09-26 13:13:15 +08:00 |
|
|
|
1a6f197572
|
M5:操作层(真能改世界)+ 16 项判据
新增 mcfold/actions.py(16 个操作:look/move/move_and_look/look_at/
jump/sneak/sprint/select_slot/use_item/swing/dig/place/interact_block/
attack/use_entity/interact_entity_at + chat/command)
新增 mcfold/textcomp.py(1.20.3+ 的 NBT 文本组件渲染,查 language.json)
★★ 最关键发现:teleport_confirm 是必需前置包
1.19+ 的 position 带 teleportId,必须回 confirm,否则服务端**默默忽略所有方块操作**。
症状是「操作没反应、零报错」,与权限/物品/位置问题无法区分。
定位过程:先猜了 5 轮(包名/字段顺序/face 类型/sequence/位置与面)都不对;
最后拿 minecraft-protocol 对照,发现它也失败 ⇒ 排除我的包有问题;
再用 data get entity 排除权限与物品 ⇒ 补 confirm 后立刻成功。
其他真 bug:
- packet_interact/swing/animation 在 1.21.1 都不存在(应是 use_entity/arm_animation)
- dig 原写成 block_place + 多余 varint(应为独立 packet_block_dig)→ 断连
- use_entity(mouse=0) 也带 hand 字段,我漏了 → 少 1 字节
- 背包字段是 itemId(驼峰),我写 item_id → 永远判「空手」
- window0 的 slot 36..44 才是热键栏
- 聊天 NBT 组件三重漏(空串/键名/空键参数)→ 现在正确渲染人话
判据:126 项全通过;5 项变异全被抓。核心判据「16 个包能被官方 protodef
精确解回(0 余字节)」—— 唯一能离线证明「包写对了」的办法
|
2026-09-26 12:44:08 +08:00 |
|
|
|
d2b4c5029d
|
M4:事件层(可按需排空的日志 + 游标)+ 16 项判据
新增 mcfold/events.py:EventLog(环形缓冲 + seq + 游标)
- 不做回调式推送:LLM 是回合制的,回调会让事件在两次观察之间静默丢失
- drain(limit) 只取本轮、剩余留待下次(不丢)
- 细分层(block_changed❌y:z)独立可查,不污染粗粒度流
- render_events() 输出紧凑文本行,省 token
session 接线:block_change / multi_block_change / chat / damage /
entity spawn·move·destroy / held_item_slot,并加 chat()/command() 发送
修的真 bug:
- dropped 恒 0:deque(maxlen=) 丢元素无声 ⇒ 改手动计数(事件丢了必须说)
- 事件键 to_state_id 与渲染器的 to 不一致 ⇒ 显示 None,改为解出方块名;
from 区分「未加载/界外」而非裸 None
- run_tests.sh 只数 ✓ 不数 ★ ⇒ 判据少报(98 修正为 110)
实测:/setblock 后事件正确报 grass_block→stone→air,与状态层一致
判据:110 项全通过;4 项变异全部被抓
|
2026-09-26 12:27:28 +08:00 |
|
|
|
40b2e1d60f
|
M3:状态层(服务端真状态)+ 包流灌入 + 14 项判据
新增:
- mcfold/state.py WorldState / WorldGeometry / PlayerView / Entity
- mcfold/session.py StateSession:connect() 走完 login→configuration→play,
pump() 把包落进状态,on() 留 M4 事件口
修的真 bug:
- unload_chunk 协议顺序是 chunkZ 在前、chunkX 在后;按 x 先读会坐标互换,
卸载永不命中 ⇒ 区块只增不减(状态撒谎)
设计立场(防越界):
- 只陈述观察、不做决策(nearby_blocks 给统计不给「该挖哪个」)
- 未知 ≠ 没看见:认不出的 state id 显式记账,绝不静默映射成别的方块
- 超范围拒绝并说明,不静默缩小
- 几何从服务端 dimension_type 吸收,不写死 24/384
实测:11 注册表 / 9 区块 / 生命 20 饥饿 20 / 列剖面 bedrock→dirt→grass_block
判据:91 项全通过;4 项变异全部被抓(含「变异空操作 ⇒ 假绿」的核对)
|
2026-09-26 12:21:18 +08:00 |
|
|
|
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 |
|
|
|
b21b869e09
|
plan.md:M0 完成(空白测试服已起并可协议级探活)
|
2026-09-26 11:12:52 +08:00 |
|
|
|
c80b06552f
|
plan.md:立起最顶层目的 —— 给 agent 一副能在 MC 里感知与行动的工具包
用户定调:插件目的是「让 agent 可以借助我们提供的工具包去玩我的世界」。
推论三条(改变工程重心):
① API 形状要照 LLM 用法设计,不是照程序员用法
(mineflayer 是给写 bot 的人用的库;我们面向 LLM 直接调用)
② 感知 + 行动缺一不可 ⇒ 状态/事件/操作三层是正式骨架
③ 渲染是工具之一,不是全部 —— 之前把它当主线是重心错了
新增:
§1c 空白测试服(不用现役服;现役 world 15G + mods 64,测不出边界)
§1d 面向 LLM 的 API 形状(自省 / 可读返回 / 限量 / 失败要说清为什么)
§6 里程碑重排:M0 测试服 → M1 修构建 → M2 协议客户端(真正的门槛)
细渲染降到 M8(已能跑,只是接不上服务端真数据)
拍照降为 M9(验证工具包的用例,不是工具包本身)
已核实的关键事实(写入 plan):
· mineflayer 自述 'create minecraft bots with a stable, high level API'
41 个 plugins 全是动作与感知,grep 行为树/目标选择 = 0 命中
⇒ 它是给 bot 开发者的库;决策在它之外,那是我们该留给 agent 的部分
|
2026-09-26 10:50:21 +08:00 |
|
|
|
7c7297ebad
|
plan.md:按用户口径重写 —— 粗/细渲染分工、抽象模型(参考 mineflayer)、机位降为用例
|
2026-09-26 10:32:22 +08:00 |
|
|
|
c5560765a3
|
加 plan.md:工程计划(含 ass 粗渲染与聊天拍照的新方向)
|
2026-09-26 10:25:11 +08:00 |
|