Permalink
Browse files

Inital hack to support anvil format *.mca files

  • Loading branch information...
quag committed Mar 18, 2012
1 parent fc6b447 commit 80488e01982b8946b7c3f6a91a52638e4ad05c4d
Showing with 104 additions and 22 deletions.
  1. +1 −1 cmd/mcobj/mcobj.go
  2. +1 −1 cmd/mcobj/obj.go
  3. +1 −1 cmd/mcobj/prt.go
  4. +5 −7 mcworld/betaworld.go
  5. +79 −12 nbt/chunk.go
  6. +17 −0 nbt/nbt.go
View
@@ -370,7 +370,7 @@ type Blocks struct {
type BlockColumn []nbt.Block
func (b *Blocks) Get(x, y, z int) nbt.Block {
- return b.data[y+(z*b.height+(x*b.height*16))]
+ return b.data[y+b.height*(z+16*x)]
}
func (b *Blocks) Column(x, z int) BlockColumn {
View
@@ -387,7 +387,7 @@ func (vs *Vertexes) Print(w io.Writer, xPos, zPos int) (count int) {
var (
xa = x + xPos*16
- ya = y - vs.height/2
+ ya = y - 64
za = z + zPos*16
)
View
@@ -84,7 +84,7 @@ func (o *PrtGenerator) chunkProcessor() {
o.particleCount++
var (
xa = x + e.xPos*16
- ya = y - height/2
+ ya = y - 64
za = -(z + e.zPos*16)
)
binary.Write(o.zw, binary.LittleEndian, float32(xa))
View
@@ -31,18 +31,16 @@ func (w *BetaWorld) OpenChunk(x, z int) (io.ReadCloser, error) {
mcrName := fmt.Sprintf("r.%v.%v.mcr", x>>5, z>>5)
mcrPath := filepath.Join(w.worldDir, "region", mcrName)
- var name, path string
+ var path string
if _, err := os.Stat(mcaPath); err == nil {
- name = mcaName
path = mcaPath
} else {
- name = mcrName
path = mcrPath
}
- var file, mcrOpenErr = os.Open(path)
- if mcrOpenErr != nil {
- return nil, mcrOpenErr
+ file, openErr := os.Open(path)
+ if openErr != nil {
+ return nil, openErr
}
defer func() {
if file != nil {
@@ -57,7 +55,7 @@ func (w *BetaWorld) OpenChunk(x, z int) (io.ReadCloser, error) {
}
if loc == 0 {
- return nil, errors.New(fmt.Sprintf("Chunk missing: %v,%v in %v. %v", x, z, name, (x&31)+(z&31)*32))
+ return nil, errors.New(fmt.Sprintf("Chunk missing: %v,%v in %v. %v", x, z, mcaName, (x&31)+(z&31)*32))
}
var (
View
@@ -28,32 +28,79 @@ func ReadChunkDat(reader io.Reader) (*Chunk, error) {
func ReadChunkNbt(reader io.Reader) (*Chunk, error) {
chunkData := new(chunkData)
+ chunkData.sections = make([]*sectionData, 0)
if err := chunkData.parse(NewReader(reader), false); err != nil {
return nil, err
}
chunk := &Chunk{chunkData.xPos, chunkData.zPos, nil}
- if chunkData.blocks != nil && chunkData.data != nil {
- chunk.Blocks = make([]Block, len(chunkData.blocks))
- for i, blockId := range chunkData.blocks {
- var metadata byte
- if i&1 == 1 {
- metadata = chunkData.data[i/2] >> 4
- } else {
- metadata = chunkData.data[i/2] & 0xf
+ if len(chunkData.sections) != 0 {
+ chunk.Blocks = make([]Block, 256*16*16) // Hard coded height for now. TODO: Make variable height chunks.
+ for _, section := range chunkData.sections {
+ for i, blockId := range section.blocks {
+ var metadata byte
+ if i&1 == 1 {
+ metadata = section.data[i/2] >> 4
+ } else {
+ metadata = section.data[i/2] & 0xf
+ }
+ // Note that the old format is XZY and the new format is YZX
+ x, z, y := indexToCoords(i, 16, 16)
+ chunk.Blocks[coordsToIndex(x, z, y+16*section.y, 16, 256)] = Block(blockId) + (Block(metadata) << 8)
+ }
+ }
+ } else {
+ if chunkData.blocks != nil && chunkData.data != nil {
+ chunk.Blocks = make([]Block, len(chunkData.blocks))
+ for i, blockId := range chunkData.blocks {
+ var metadata byte
+ if i&1 == 1 {
+ metadata = chunkData.data[i/2] >> 4
+ } else {
+ metadata = chunkData.data[i/2] & 0xf
+ }
+ chunk.Blocks[i] = Block(blockId) + (Block(metadata) << 8)
}
- chunk.Blocks[i] = Block(blockId) + (Block(metadata) << 8)
}
}
return chunk, nil
}
+func indexToCoords(i, aMax, bMax int) (a, b, c int) {
+ a = i % aMax
+ b = (i / aMax) % bMax
+ c = i / (aMax*bMax)
+ return
+}
+
+func coordsToIndex(a, b, c, bMax, cMax int) int {
+ return c + cMax*(b + bMax*a)
+}
+
+func yzxToXzy(yzx, xMax, zMax, yMax int) int {
+ x := yzx % xMax
+ z := (yzx / xMax) % zMax
+ y := (yzx / (xMax*zMax)) % yMax
+
+ // yzx := x + xMax*(z + zMax*y)
+ xzy := y + yMax*(z + zMax*x)
+ return xzy
+}
+
type chunkData struct {
xPos, zPos int
blocks []byte
data []byte
+ section *sectionData
+ sections []*sectionData
+}
+
+type sectionData struct {
+ y int
+ blocks []byte
+ data []byte
}
func (chunk *chunkData) parse(r *Reader, listStruct bool) error {
@@ -85,15 +132,31 @@ func (chunk *chunkData) parse(r *Reader, listStruct bool) error {
return err
}
if name == "Blocks" {
- chunk.blocks = bytes
+ if chunk.section != nil {
+ chunk.section.blocks = bytes
+ } else {
+ chunk.blocks = bytes
+ }
} else if name == "Data" {
- chunk.data = bytes
+ if chunk.section != nil {
+ chunk.section.data = bytes
+ } else {
+ chunk.data = bytes
+ }
+ }
+ case TagIntArray:
+ _, err := r.ReadInts()
+ if err != nil {
+ return err
}
case TagInt8:
- _, err := r.ReadInt8()
+ number, err := r.ReadInt8()
if err != nil {
return err
}
+ if name == "Y" {
+ chunk.section.y = int(number)
+ }
case TagInt16:
_, err := r.ReadInt16()
if err != nil {
@@ -160,6 +223,10 @@ func (chunk *chunkData) parse(r *Reader, listStruct bool) error {
}
case TagStruct:
for i := 0; i < length; i++ {
+ if name == "Sections" {
+ chunk.section = new(sectionData)
+ chunk.sections = append(chunk.sections, chunk.section)
+ }
err := chunk.parse(r, true)
if err != nil {
return err
View
@@ -22,6 +22,7 @@ const (
TagString TypeId = 8 // { TAG_Short length; An array of bytes defining a string in UTF-8 format. The length of this array is <length> bytes }
TagList TypeId = 9 // { TAG_Byte tagId; TAG_Int length; A sequential list of Tags (not Named Tags), of type <typeId>. The length of this array is <length> Tags. } Notes: All tags share the same type.
TagStruct TypeId = 10 // { A sequential list of Named Tags. This array keeps going until a TAG_End is found.; TAG_End end } Notes: If there's a nested TAG_Compound within this tag, that one will also have a TAG_End, so simply reading until the next TAG_End will not work. The names of the named tags have to be unique within each TAG_Compound The order of the tags is not guaranteed.
+ TagIntArray TypeId = 11 // { TAG_Int length; An array of ints. The length of this array is <length> ints }
)
type Reader struct {
@@ -93,6 +94,22 @@ func (r *Reader) ReadBytes() ([]byte, error) {
return bytes, err
}
+func (r *Reader) ReadInts() ([]int, error) {
+ length, err := r.ReadInt32()
+ if err != nil {
+ return nil, err
+ }
+
+ ints := make([]int, length)
+ for i := 0; i < length; i++ {
+ ints[i], err = r.ReadInt32()
+ if err != nil {
+ return nil, err
+ }
+ }
+ return ints, nil
+}
+
func (r *Reader) ReadInt8() (int, error) {
return r.readIntN(1)
}

0 comments on commit 80488e0

Please sign in to comment.