"""世界模型回归:区块聚合 + 世界坐标查询 + 显式降级。""" import sys, os, json, subprocess sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from mcfold.world import World, in_world from mcfold.chunk import BlockRegistry, MIN_Y, WORLD_HEIGHT from mcfold.protodef import Writer RUNTIME = "/home/newqqagent/plugin_data/mc/runtime" BLOCKS = f"{RUNTIME}/node_modules/minecraft-data/minecraft-data/data/pc/1.20/blocks.json" def reg(): return BlockRegistry.from_json_file(BLOCKS) def test_negative_coords(): """★ 负坐标定位:MC 世界坐标可为负,这是最容易错的地方。""" w = World(reg()) # 在 (-1,-1) 区块放一个方块:(x=-1,z=-1) ⇒ chunk (-1,-1), 内部 (15,15) assert (-1) >> 4 == -1 and (-1) & 15 == 15 # 先确认未加载时报 unloaded(而不是假装空气) hit = w.block_at(-1, 64, -1) assert not hit.loaded and hit.source == "unloaded", hit print(" ✓ 负坐标:未加载区块显式返回 unloaded(非假装空气)") def test_unloaded_vs_air_distinction(): """★ 关键语义:「未加载」与「空气」必须可区分。 mineflayer 的 bot.blockAt 在未加载时返回 null,但很多调用方当空气处理; 我们要求显式区分,避免 agent 误判。 """ w = World(reg()) unloaded = w.block_at(0, 64, 0) assert unloaded.source == "unloaded", unloaded # 加载一个全空气区块后,同一坐标应变成 air(registry) wr = Writer() for _ in range(24): wr.write((0).to_bytes(2,"big")); wr.write(bytes([0])) wr.varint(0); wr.varint(0) wr.write(bytes([0])); wr.varint(0); wr.varint(0) w.load_chunk_data(0, 0, wr.getvalue()) air = w.block_at(0, 64, 0) assert air.loaded and air.name == "air", (air.loaded, air.name) print(" ✓ 未加载(unloaded) 与 空气(air) 语义分明") def test_real_chunk_via_world(): """用 prismarine 产出的真实区块走完 World 全路径。""" r = subprocess.run(["node", f"{RUNTIME}/chunkgen.js"], capture_output=True, text=True, cwd=RUNTIME, timeout=120) if r.returncode != 0: print(f" - 跳过({r.stderr[:80]})"); return d = json.loads(r.stdout) w = World(reg()) w.load_chunk_data(0, 0, bytes.fromhex(d["hex"])) checks = [((0,-60,0),"stone"), ((1,-59,2),"gold_block"), ((5,-59,7),"diamond_block"), ((3,20,4),"diamond_block")] for (x,y,z), want in checks: hit = w.block_at(x,y,z) assert hit.loaded and hit.name == want, (x,y,z,hit) print(f" ✓ World 全路径: 4/4 方块命中(解真实区块数据)") def test_world_height_bounds(): w = World(reg()) assert w.block_at(0, MIN_Y-1, 0).source == "out-of-world" assert w.block_at(0, MIN_Y+WORLD_HEIGHT, 0).source == "out-of-world" assert w.block_at(0, MIN_Y, 0).source == "unloaded" # 合法高度但未加载 assert in_world(MIN_Y) and not in_world(MIN_Y-1) print(f" ✓ 世界高度边界: [{MIN_Y}, {MIN_Y+WORLD_HEIGHT}) 之外显式 out-of-world") def test_unknown_state_reported(): """★ mod 方块的可见降级:unknown(id) 且计入统计。""" r = reg() w = World(r) wr = Writer() # section0: palette=[99999] wr.write((1).to_bytes(2,"big")); wr.write(bytes([4])) wr.varint(1); wr.varint(99999); wr.varint(256) wr.write(b"\x00"*(256*8)) wr.write(bytes([0])); wr.varint(0); wr.varint(0) for _ in range(23): wr.write((0).to_bytes(2,"big")); wr.write(bytes([0])) wr.varint(0); wr.varint(0) wr.write(bytes([0])); wr.varint(0); wr.varint(0) w.load_chunk_data(0, 0, wr.getvalue()) hit = w.block_at(0, MIN_Y, 0) # section 0 的首个方块 assert hit.source == "unknown-state", hit assert "mod" in hit.describe(), hit.describe() s = w.summary() assert s.get("unknown_state_count") == 1, s assert "mod" in s.get("warning",""), s print(f" ✓ ★ mod 方块可见降级: {hit.describe()[:40]}… + 世界摘要含告警") def test_multiple_chunks(): """多区块聚合:跨区块查询各自命中自己的列。""" w = World(reg()) wr = Writer() for _ in range(24): wr.write((0).to_bytes(2,"big")); wr.write(bytes([0])) wr.varint(0); wr.varint(0) wr.write(bytes([0])); wr.varint(0); wr.varint(0) data = wr.getvalue() for cx, cz in [(0,0), (1,0), (-1,-1), (2,-3)]: w.load_chunk_data(cx, cz, data) assert w.loaded_count == 4, w.loaded_count # (16,64,0) 属于区块 (1,0) assert w.block_at(16,64,0).loaded # (-1,64,-1) 属于区块 (-1,-1) assert w.block_at(-1,64,-1).loaded # (32,64,-48) 属于区块 (2,-3) assert w.block_at(32,64,-48).loaded # (16,64,-1) 属于区块 (1,-1) —— 未加载 assert w.block_at(16,64,-1).source == "unloaded" print(" ✓ 多区块聚合: 4 列,跨区块/负坐标定位均正确,未加载区可辨") # 卸载 w.unload_chunk(1, 0) assert w.block_at(16,64,0).source == "unloaded" print(" ✓ 区块卸载后查询回到 unloaded") if __name__ == "__main__": for fn in [test_negative_coords, test_unloaded_vs_air_distinction, test_real_chunk_via_world, test_world_height_bounds, test_unknown_state_reported, test_multiple_chunks]: fn() print("\n世界模型:全部通过")