package world import ( "path/filepath" "testing" "time" "mc/internal/block" "mc/internal/worldgen" ) // loadWorldReg 加载注册表。 func loadWorldReg(t *testing.T) *block.Registry { t.Helper() r, err := block.Load(filepath.Join("..", "..", "assets", "config", "blocks.json")) if err != nil { t.Fatalf("加载注册表失败: %v", err) } return r } // newTestWorld 创建小视距世界。 func newTestWorld(t *testing.T, view int) *World { t.Helper() reg := loadWorldReg(t) gen, err := worldgen.New(reg, 42, 0.005, 0.01, 0.1) if err != nil { t.Fatalf("创建生成器失败: %v", err) } w, err := New(reg, gen, view) if err != nil { t.Fatalf("创建世界失败: %v", err) } t.Cleanup(w.Close) return w } // waitChunk 轮询 Update 直到指定区块激活(异步生成流水线)。 func waitChunk(t *testing.T, w *World, cx, cz int32) { t.Helper() deadline := time.Now().Add(15 * time.Second) for time.Now().Before(deadline) { w.Update(float64(cx*16+8), 64, float64(cz*16+8), 8*time.Millisecond) if w.chunkOf(int32(cx*16+8), int32(cz*16+8)) != nil { return } time.Sleep(2 * time.Millisecond) } t.Fatalf("区块 (%d,%d) 未在时限内生成", cx, cz) } // TestLoadChunk 验证异步生成:基岩层存在、地表可站。 func TestLoadChunk(t *testing.T) { w := newTestWorld(t, 3) waitChunk(t, w, 0, 0) bedrock, _ := w.reg.ID("bedrock") if w.Block(8, 0, 8).ID() != bedrock { t.Fatal("y=0 应为基岩") } // 地表:从顶向下找第一个非空气方块,其下应有实体方块 var surf int32 = -1 for y := int32(255); y >= 0; y-- { if w.Block(8, y, 8) != block.Air { surf = y break } } if surf < 8 { t.Fatalf("地表高度异常: %d", surf) } } // TestTorchLightCycle 验证火把放置→照亮→移除→重算的完整闭环(方块交互与动画.md §9)。 func TestTorchLightCycle(t *testing.T) { w := newTestWorld(t, 2) waitChunk(t, w, 0, 0) // 找地表 var surf int32 for y := int32(255); y >= 0; y-- { if w.Block(8, y, 8) != block.Air { surf = y break } } // 放置火把:地表上一格(地表方块不透明不受光,其周围空气受光) torch, _ := w.reg.ID("torch") w.SetBlock(8, surf+1, 8, block.NewState(torch, 0)) if got := w.BlockLight(8, surf+1, 8); got != 14 { t.Fatalf("火把自身光期望 14,实际 %d", got) } if got := w.BlockLight(7, surf+1, 8); got != 13 { t.Fatalf("火把侧邻光期望 13,实际 %d", got) } // 移除火把:光应清零(relight) w.SetBlock(8, surf+1, 8, block.Air) if got := w.BlockLight(7, surf+1, 8); got != 0 { t.Fatalf("移除火把后侧邻光期望 0,实际 %d", got) } }