Files
ngzz-mc/internal/worldgen/gen_test.go

104 lines
2.8 KiB
Go
Raw Normal View History

package worldgen
import (
"bytes"
"path/filepath"
"testing"
"mc/internal/block"
)
// loadReg 加载共享注册表(blocks.json)。
func loadReg(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
}
// TestDeterminism 验证生成确定性:同 seed 两次生成逐字节一致(世界生成.md §2.2)。
func TestDeterminism(t *testing.T) {
g, err := New(loadReg(t), 12345, 0.005, 0.01, 0.1)
if err != nil {
t.Fatalf("创建生成器失败: %v", err)
}
a := g.Generate(-1, 3)
b := g.Generate(-1, 3)
sa, sb := a.Snapshot(), b.Snapshot()
if !bytes.Equal(stateBytes(sa), stateBytes(sb)) {
t.Fatal("同 seed 生成结果不一致")
}
}
// stateBytes 把方块状态切片序列化为字节(比较用)。
func stateBytes(s []block.State) []byte {
out := make([]byte, len(s)*4)
for i, v := range s {
out[i*4] = byte(v >> 24)
out[i*4+1] = byte(v >> 16)
out[i*4+2] = byte(v >> 8)
out[i*4+3] = byte(v)
}
return out
}
// TestTerrainStructure 验证地形结构:基岩层完整、地表为群系方块、海平面下灌水。
func TestTerrainStructure(t *testing.T) {
reg := loadReg(t)
bedrock, _ := reg.ID("bedrock")
water, _ := reg.ID("water")
air := uint16(0)
// caveDensity=1.0 关闭洞穴,便于验证灌水逻辑
g, err := New(reg, 777, 0.005, 0.01, 1.0)
if err != nil {
t.Fatalf("创建生成器失败: %v", err)
}
ch := g.Generate(0, 0)
// 基岩层:y=0 全部为基岩(世界生成.md §6:基岩层保留)
for lx := 0; lx < 16; lx++ {
for lz := 0; lz < 16; lz++ {
if id := ch.Block(lx, 0, lz).ID(); id != bedrock {
t.Fatalf("(%d,0,%d) 非基岩: ID=%d", lx, lz, id)
}
}
}
// 每个地形柱:海平面以下要么是水要么是地形方块,不允许空气
for lx := 0; lx < 16; lx++ {
for lz := 0; lz < 16; lz++ {
h := g.heightAt(int32(lx), int32(lz))
for y := 1; y < seaLevel; y++ {
id := ch.Block(lx, y, lz).ID()
if y > h {
if id != water {
t.Fatalf("(%d,%d,%d) 海平面下应为水,实际 ID=%d", lx, y, lz, id)
}
} else if id == air {
t.Fatalf("(%d,%d,%d) 地形柱内出现空气", lx, y, lz)
}
}
}
}
}
// TestOres 验证矿物只出现在规定深度区间(挖矿与矿物.md §2:y=100 只允许石头/煤矿)。
func TestOres(t *testing.T) {
reg := loadReg(t)
g, err := New(reg, 4242, 0.005, 0.01, 0.1)
if err != nil {
t.Fatalf("创建生成器失败: %v", err)
}
stone, _ := reg.ID("stone")
coal, _ := reg.ID("coal_ore")
for i := 0; i < 2000; i++ {
s := g.oreAt(int32(i), 100, int32(i)) // y=100:只允许石头或煤矿
id := s.ID()
if id != stone && id != coal {
t.Fatalf("y=100 出现异常方块: ID=%d", id)
}
}
}