Files
ngzz-mc/internal/save/save_test.go

146 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package save
import (
"path/filepath"
"testing"
"time"
"mc/internal/block"
"mc/internal/world"
"mc/internal/worldgen"
)
// loadSaveReg 加载注册表。
func loadSaveReg(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
}
// newGen 创建生成器。
func newGen(t *testing.T, reg *block.Registry, seed int64) *worldgen.Generator {
t.Helper()
g, err := worldgen.New(reg, seed, 0.005, 0.01, 0.1)
if err != nil {
t.Fatalf("创建生成器失败: %v", err)
}
return g
}
// TestChunkRoundtrip 区块序列化往返(存档格式.md §4
func TestChunkRoundtrip(t *testing.T) {
reg := loadSaveReg(t)
g := newGen(t, reg, 777)
c := g.Generate(3, -5)
c.SetBlockLight(8, 70, 8, 13)
dec, err := DecodeChunk(EncodeChunk(c))
if err != nil {
t.Fatalf("反序列化失败: %v", err)
}
if dec.CX != 3 || dec.CZ != -5 {
t.Fatalf("坐标不一致: %d,%d", dec.CX, dec.CZ)
}
if dec.Block(8, 70, 8) != c.Block(8, 70, 8) {
t.Fatal("方块数据不一致")
}
if dec.BlockLight(8, 70, 8) != 13 {
t.Fatalf("方块光不一致: %d", dec.BlockLight(8, 70, 8))
}
if dec.SkyLight(8, 100, 8) != c.SkyLight(8, 100, 8) {
t.Fatal("天空光不一致")
}
}
// TestRegionWriteRead 区域文件写入/读取(含 CRC 与跨重启重开)。
func TestRegionWriteRead(t *testing.T) {
reg := loadSaveReg(t)
g := newGen(t, reg, 99)
dir := t.TempDir()
data := EncodeChunk(g.Generate(1, 1))
region, err := OpenRegion(dir, 0, 0)
if err != nil {
t.Fatalf("打开区域失败: %v", err)
}
if err := region.WriteChunk(1, 1, data); err != nil {
t.Fatalf("写区块失败: %v", err)
}
// 模拟重启:重新打开区域
region2, err := OpenRegion(dir, 0, 0)
if err != nil {
t.Fatalf("重开区域失败: %v", err)
}
got, ok, err := region2.ReadChunk(1, 1)
if err != nil || !ok {
t.Fatalf("读区块失败: ok=%v err=%v", ok, err)
}
if string(got) != string(data) {
t.Fatal("读取数据不一致")
}
// 未保存区块应返回 ok=false
if _, ok, _ := region2.ReadChunk(2, 2); ok {
t.Fatal("未保存区块应返回 false")
}
}
// TestSaveLoadWorld 世界级存取:放火把 → 保存 → 载入 → 火把与光仍在。
func TestSaveLoadWorld(t *testing.T) {
reg := loadSaveReg(t)
seed := int64(2024)
g := newGen(t, reg, seed)
w, err := world.New(reg, g, 3)
if err != nil {
t.Fatalf("创建世界失败: %v", err)
}
defer w.Close()
// 生成并等待区块
deadline := time.Now().Add(15 * time.Second)
for time.Now().Before(deadline) {
w.Update(8, 64, 8, 8*time.Millisecond)
if w.Block(8, 0, 8) != block.Air {
break
}
time.Sleep(2 * time.Millisecond)
}
// 放一个火把
torch, _ := reg.ID("torch")
var surf int32
for y := int32(255); y >= 0; y-- {
if w.Block(8, y, 8) != block.Air {
surf = y
break
}
}
w.SetBlock(8, surf+1, 8, block.NewState(torch, 0))
dir := t.TempDir()
if err := SaveWorld(w, dir, "TestWorld", seed, 1000); err != nil {
t.Fatalf("保存失败: %v", err)
}
// 载入到新世界
g2 := newGen(t, reg, seed)
w2, err := world.New(reg, g2, 3)
if err != nil {
t.Fatalf("创建世界失败: %v", err)
}
defer w2.Close()
if gotSeed, err := LoadWorld(w2, dir, "TestWorld"); err != nil {
t.Fatalf("载入失败: %v", err)
} else if gotSeed != seed {
t.Fatalf("种子不一致: %d", gotSeed)
}
// 火把及其光
if s := w2.Block(8, surf+1, 8); s.ID() != torch {
t.Fatalf("火把丢失: %v", s)
}
if l := w2.BlockLight(7, surf+1, 8); l != 13 {
t.Fatalf("火把光丢失: %d", l)
}
}