parse the world
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
package anvil_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/admin-else/strom/level/anvil"
|
||||
"github.com/admin-else/strom/util"
|
||||
)
|
||||
|
||||
func TestLevel(t *testing.T) {
|
||||
@@ -20,3 +23,22 @@ func TestLevel(t *testing.T) {
|
||||
}
|
||||
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