102 lines
2.6 KiB
Go
102 lines
2.6 KiB
Go
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)
|
||
}
|
||
}
|