104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
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)
|
||
}
|
||
}
|
||
}
|