parse the world

This commit is contained in:
adman
2026-04-21 22:24:12 +02:00
parent f6001c8b22
commit 895ec53698
2 changed files with 125 additions and 0 deletions
+22
View File
@@ -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, "", " "))))
}
+103
View File
@@ -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
}