diff --git a/level/bitstorage.go b/level/bitstorage.go index 842d4da..fcdeac3 100644 --- a/level/bitstorage.go +++ b/level/bitstorage.go @@ -47,13 +47,12 @@ func NewBitStorage(bits, length int, data []uint64) (b *BitStorage) { valuesPerLong: 64 / bits, } dataLen := calcBitStorageSize(bits, length) + b.data = make([]uint64, dataLen) if data != nil { if len(data) != dataLen { panic(newBitStorageErr{ArrlLen: len(data), WantLen: dataLen}) } - b.data = data - } else { - b.data = make([]uint64, dataLen) + copy(b.data, data) } return } diff --git a/level/chunk.go b/level/chunk.go index 4dc249d..3d05514 100644 --- a/level/chunk.go +++ b/level/chunk.go @@ -107,19 +107,16 @@ func ChunkFromSave(c *save.Chunk) (*Chunk, error) { blockEntities[i].Type = block.EntityTypes[tmp.ID] } - motionBlocking := c.Heightmaps.MotionBlocking - motionBlockingNoLeaves := c.Heightmaps.MotionBlockingNoLeaves - oceanFloor := c.Heightmaps.OceanFloor - worldSurface := c.Heightmaps.WorldSurface - bitsForHeight := bits.Len( /* chunk height in blocks */ uint(secs) * 16) return &Chunk{ Sections: sections, HeightMaps: HeightMaps{ - MotionBlocking: NewBitStorage(bitsForHeight, 16*16, motionBlocking), - MotionBlockingNoLeaves: NewBitStorage(bitsForHeight, 16*16, motionBlockingNoLeaves), - OceanFloor: NewBitStorage(bitsForHeight, 16*16, oceanFloor), - WorldSurface: NewBitStorage(bitsForHeight, 16*16, worldSurface), + WorldSurface: NewBitStorage(bitsForHeight, 16*16, c.Heightmaps["WORLD_SURFACE_WG"]), + WorldSurfaceWG: NewBitStorage(bitsForHeight, 16*16, c.Heightmaps["WORLD_SURFACE"]), + OceanFloorWG: NewBitStorage(bitsForHeight, 16*16, c.Heightmaps["OCEAN_FLOOR_WG"]), + OceanFloor: NewBitStorage(bitsForHeight, 16*16, c.Heightmaps["OCEAN_FLOOR"]), + MotionBlocking: NewBitStorage(bitsForHeight, 16*16, c.Heightmaps["MOTION_BLOCKING"]), + MotionBlockingNoLeaves: NewBitStorage(bitsForHeight, 16*16, c.Heightmaps["MOTION_BLOCKING_NO_LEAVES"]), }, BlockEntity: blockEntities, Status: ChunkStatus(c.Status), @@ -188,7 +185,12 @@ func ChunkToSave(c *Chunk, dst *save.Chunk) (err error) { s.BlockLight = v.BlockLight } dst.Sections = sections - dst.Heightmaps.MotionBlocking = c.HeightMaps.MotionBlocking.Raw() + dst.Heightmaps["WORLD_SURFACE_WG"] = c.HeightMaps.WorldSurfaceWG.Raw() + dst.Heightmaps["WORLD_SURFACE"] = c.HeightMaps.WorldSurface.Raw() + dst.Heightmaps["OCEAN_FLOOR_WG"] = c.HeightMaps.OceanFloorWG.Raw() + dst.Heightmaps["OCEAN_FLOOR"] = c.HeightMaps.OceanFloor.Raw() + dst.Heightmaps["MOTION_BLOCKING"] = c.HeightMaps.MotionBlocking.Raw() + dst.Heightmaps["MOTION_BLOCKING_NO_LEAVES"] = c.HeightMaps.MotionBlockingNoLeaves.Raw() dst.Status = string(c.Status) return } @@ -314,10 +316,12 @@ func (c *Chunk) PutData(data []byte) error { } type HeightMaps struct { - MotionBlocking *BitStorage - MotionBlockingNoLeaves *BitStorage - OceanFloor *BitStorage - WorldSurface *BitStorage + WorldSurfaceWG *BitStorage // test = NOT_AIR + WorldSurface *BitStorage // test = NOT_AIR + OceanFloorWG *BitStorage // test = MATERIAL_MOTION_BLOCKING + OceanFloor *BitStorage // test = MATERIAL_MOTION_BLOCKING + MotionBlocking *BitStorage // test = BlocksMotion or isFluid + MotionBlockingNoLeaves *BitStorage // test = BlocksMotion or isFluid } type BlockEntity struct { diff --git a/save/chunk.go b/save/chunk.go index ad34d27..95858bc 100644 --- a/save/chunk.go +++ b/save/chunk.go @@ -12,27 +12,24 @@ import ( // Chunk is 16* chunk type Chunk struct { - DataVersion int32 - XPos int32 `nbt:"xPos"` - YPos int32 `nbt:"yPos"` - ZPos int32 `nbt:"zPos"` - BlockEntities []nbt.RawMessage `nbt:"block_entities"` - Structures nbt.RawMessage `nbt:"structures"` - Heightmaps struct { - MotionBlocking []uint64 `nbt:"MOTION_BLOCKING"` - MotionBlockingNoLeaves []uint64 `nbt:"MOTION_BLOCKING_NO_LEAVES"` - OceanFloor []uint64 `nbt:"OCEAN_FLOOR"` - WorldSurface []uint64 `nbt:"WORLD_SURFACE"` - } - Sections []Section `nbt:"sections"` - - BlockTicks nbt.RawMessage `nbt:"block_ticks"` - FluidTicks nbt.RawMessage `nbt:"fluid_ticks"` - PostProcessing nbt.RawMessage + BlockEntities []nbt.RawMessage `nbt:"block_entities"` + BlockTicks nbt.RawMessage `nbt:"block_ticks"` + CarvingMasks map[string][]uint64 + DataVersion int32 + Entities []nbt.RawMessage `nbt:"entities"` + FluidTicks nbt.RawMessage `nbt:"fluid_ticks"` + Heightmaps map[string][]uint64 // keys: "WORLD_SURFACE_WG", "WORLD_SURFACE", "WORLD_SURFACE_IGNORE_SNOW", "OCEAN_FLOOR_WG", "OCEAN_FLOOR", "MOTION_BLOCKING", "MOTION_BLOCKING_NO_LEAVES" InhabitedTime int64 IsLightOn byte `nbt:"isLightOn"` LastUpdate int64 + Lights []nbt.RawMessage + PostProcessing nbt.RawMessage + Sections []Section `nbt:"sections"` Status string + Structures nbt.RawMessage `nbt:"structures"` + XPos int32 `nbt:"xPos"` + YPos int32 `nbt:"yPos"` + ZPos int32 `nbt:"zPos"` } type Section struct { @@ -68,12 +65,13 @@ func (c *Chunk) Load(data []byte) (err error) { case 3: // none compression } - if err != nil { return err } - _, err = nbt.NewDecoder(r).Decode(c) + d := nbt.NewDecoder(r) + //d.DisallowUnknownFields() + _, err = d.Decode(c) return } diff --git a/save/chunk_test.go b/save/chunk_test.go index e85703f..a3e3837 100644 --- a/save/chunk_test.go +++ b/save/chunk_test.go @@ -1,29 +1,47 @@ package save import ( + "path/filepath" "testing" "github.com/Tnze/go-mc/save/region" ) func TestColumn(t *testing.T) { - r, err := region.Open("testdata/region/r.0.0.mca") + files, err := filepath.Glob("testdata/region/r.*.*.mca") if err != nil { - t.Fatal(err) + return } - defer r.Close() + for _, filename := range files { + r, err := region.Open(filename) + if err != nil { + t.Fatal(err) + } - var c Chunk - data, err := r.ReadSector(0, 0) - if err != nil { - t.Fatal(err) - } - err = c.Load(data) - if err != nil { - t.Fatal(err) - } + for x := 0; x < 32; x++ { + for z := 0; z < 32; z++ { + if !r.ExistSector(x, z) { + continue + } - t.Logf("%+v", c) + data, err := r.ReadSector(x, z) + if err != nil { + t.Fatalf("read %s sec (%d, %d) fail: %v", filepath.Base(filename), x, z, err) + } + + var c Chunk + err = c.Load(data) + if err != nil { + t.Fatalf("read %s sec (%d, %d) fail: %v", filepath.Base(filename), x, z, err) + } + } + } + + err = r.Close() + if err != nil { + t.Fatal(err) + } + } } func BenchmarkColumn_Load(b *testing.B) { diff --git a/save/region/mca.go b/save/region/mca.go index 4f40dd7..0c47d88 100644 --- a/save/region/mca.go +++ b/save/region/mca.go @@ -233,9 +233,9 @@ func (r *Region) ExistSector(x, z int) bool { return r.offsets[z][x] != 0 } -// PadToFullSector writes zeros to the end of the file to make size a multiple of 4096 -// Legacy versions of Minecraft require this -// Need to be called right before Close +// PadToFullSector writes zeros to the end of the file to make size a multiple of 4096. +// Legacy versions of Minecraft require this. +// Need to be called right before Close. func (r *Region) PadToFullSector() error { size, err := r.f.Seek(0, io.SeekEnd) if err != nil {