parse the world
This commit is contained in:
@@ -1,10 +1,13 @@
|
|||||||
package anvil_test
|
package anvil_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/admin-else/strom/level/anvil"
|
"github.com/admin-else/strom/level/anvil"
|
||||||
|
"github.com/admin-else/strom/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLevel(t *testing.T) {
|
func TestLevel(t *testing.T) {
|
||||||
@@ -20,3 +23,22 @@ func TestLevel(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Log(l)
|
t.Log(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRegionFile(t *testing.T) {
|
||||||
|
f, err := os.Open("./testdata/testworld/region/r.0.0.mca")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
ch, err := anvil.ReadChunkHeader(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := ch.ChunkAt(f, 0, 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(string(util.MustT(json.MarshalIndent(n, "", " "))))
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package anvil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"compress/gzip"
|
||||||
|
"compress/zlib"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/admin-else/strom/nbt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CompressionStrategy uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
ChunksWidthRegionFile = 32
|
||||||
|
ChunksRegionFile = ChunksWidthRegionFile * ChunksWidthRegionFile
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ CompressionStrategy = iota
|
||||||
|
CompressionStrategyGZIP
|
||||||
|
CompressionStrategyZLIB
|
||||||
|
CompressionStrategyNONE
|
||||||
|
CompressionStrategyLZ4
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c CompressionStrategy) Wrap(r io.ReadCloser) (rNew io.ReadCloser, shouldClose bool, err error) {
|
||||||
|
switch c {
|
||||||
|
case CompressionStrategyGZIP:
|
||||||
|
shouldClose = true
|
||||||
|
rNew, err = gzip.NewReader(r)
|
||||||
|
return
|
||||||
|
case CompressionStrategyZLIB:
|
||||||
|
shouldClose = true
|
||||||
|
rNew, err = zlib.NewReader(r)
|
||||||
|
return
|
||||||
|
case CompressionStrategyNONE:
|
||||||
|
rNew = r
|
||||||
|
return
|
||||||
|
case CompressionStrategyLZ4:
|
||||||
|
err = fmt.Errorf("lz4 compression not supported")
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("unknown compression strategy %d", c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChunkHeader struct {
|
||||||
|
Chunk, Time [ChunksRegionFile]int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadChunkHeader(r *os.File) (ch *ChunkHeader, err error) {
|
||||||
|
var h ChunkHeader
|
||||||
|
err = binary.Read(r, binary.BigEndian, &h)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ch = &h
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ChunkHeader) ChunkAt(f *os.File, x, z int32) (n *nbt.Tag, err error) {
|
||||||
|
off, size := chunkLocation(c.Chunk[chunkXZtoIndex(x, z)])
|
||||||
|
_, err = f.Seek(int64(off), 0)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_ = size // i dont really know why mc has this maybe to point out how much space is wasted?
|
||||||
|
var realSize int32
|
||||||
|
err = binary.Read(f, binary.BigEndian, &realSize)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var compressionStrategy CompressionStrategy
|
||||||
|
err = binary.Read(f, binary.BigEndian, &compressionStrategy)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
r, shouldClose, err := compressionStrategy.Wrap(f)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if shouldClose {
|
||||||
|
defer r.Close()
|
||||||
|
}
|
||||||
|
n = &nbt.Tag{}
|
||||||
|
err = n.Decode(r)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func chunkXZtoIndex(x, z int32) int32 {
|
||||||
|
return (x % ChunksWidthRegionFile) + (z%ChunksWidthRegionFile)*ChunksWidthRegionFile
|
||||||
|
}
|
||||||
|
|
||||||
|
func chunkLocation(v int32) (offset, l int32) {
|
||||||
|
return ((v >> 8) & 0xFFFFFF) * 4096, (v & 0xFF) * 4096
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user