From eba832b424cafbdc7d438ba314771460499dbf90 Mon Sep 17 00:00:00 2001 From: Tnze Date: Sun, 17 May 2020 13:35:52 +0800 Subject: [PATCH 1/7] rewrite chunk data decoder --- bot/world/chunk.go | 150 +++++++++++++++++++++++----------------- bot/world/motion.go | 78 --------------------- bot/world/world.go | 11 +-- bot/world/world_test.go | 9 --- 4 files changed, 89 insertions(+), 159 deletions(-) delete mode 100644 bot/world/motion.go delete mode 100644 bot/world/world_test.go diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 2d2a97a..cf25df6 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -8,89 +8,111 @@ import ( pk "github.com/Tnze/go-mc/net/packet" ) -//DecodeChunkColumn decode the chunk data structure +// DecodeChunkColumn decode the chunk data structure. +// If decoding went error, successful decoded data will be returned. func DecodeChunkColumn(mask int32, data []byte) (*Chunk, error) { var c Chunk r := bytes.NewReader(data) for sectionY := 0; sectionY < 16; sectionY++ { - if (mask & (1 << uint(sectionY))) == 0 { // Is the given bit set in the mask? - continue - } - var ( - BlockCount pk.Short - BitsPerBlock pk.Byte - ) - if err := BlockCount.Decode(r); err != nil { - return nil, err - } - if err := BitsPerBlock.Decode(r); err != nil { - return nil, err - } - //读调色板 - var palette []uint - if BitsPerBlock < 9 { - var length pk.VarInt - if err := length.Decode(r); err != nil { - return nil, fmt.Errorf("read palette (id len) fail: %v", err) - } - palette = make([]uint, length) - - for id := uint(0); id < uint(length); id++ { - var stateID pk.VarInt - if err := stateID.Decode(r); err != nil { - return nil, fmt.Errorf("read palette (id) fail: %v", err) - } - - palette[id] = uint(stateID) + // If the section's bit set in the mask + if (mask & (1 << uint(sectionY))) != 0 { + // read section + sec, err := readSection(r) + if err != nil { + return &c, fmt.Errorf("read section[%d] error: %w", sectionY, err) } + c.sections[sectionY] = sec } - - //Section数据 - var DataArrayLength pk.VarInt - if err := DataArrayLength.Decode(r); err != nil { - return nil, fmt.Errorf("read DataArrayLength fail: %v", err) - } - - DataArray := make([]int64, DataArrayLength) - for i := 0; i < int(DataArrayLength); i++ { - if err := (*pk.Long)(&DataArray[i]).Decode(r); err != nil { - return nil, fmt.Errorf("read DataArray fail: %v", err) - } - } - //用数据填充区块 - fillSection(&c.sections[sectionY], perBits(byte(BitsPerBlock)), DataArray, palette) } - return &c, nil } -func perBits(BitsPerBlock byte) uint { +func perBits(BitsPerBlock byte) uint32 { switch { case BitsPerBlock <= 4: return 4 case BitsPerBlock < 9: - return uint(BitsPerBlock) + return uint32(BitsPerBlock) default: - return uint(data.BitsPerBlock) // DefaultBitsPerBlock + return uint32(data.BitsPerBlock) // DefaultBitsPerBlock } } -func fillSection(s *Section, bpb uint, DataArray []int64, palette []uint) { - mask := uint(1<>= offset % 64 - if offset%64 > 64-bpb { - l := 64 - offset % 64 - data |= uint(DataArray[offset/64+1] << l) +func readSection(data pk.DecodeReader) (s Section, err error) { + var BlockCount pk.Short + if err := BlockCount.Decode(data); err != nil { + return nil, fmt.Errorf("read block count error: %w", err) + } + var bpb pk.UnsignedByte + if err := bpb.Decode(data); err != nil { + return nil, fmt.Errorf("read bits per block error: %w", err) + } + // If bpb values greater than or equal to 9, use directSection. + // Otherwise use paletteSection. + var palettes []uint32 + if bpb < 9 { + // read palettes + var length pk.VarInt + if err := length.Decode(data); err != nil { + return nil, fmt.Errorf("read palettes length error: %w", err) } - data &= mask - - if bpb < 9 { - s.blocks[n%16][n/(16*16)][n%(16*16)/16].id = palette[data] - } else { - s.blocks[n%16][n/(16*16)][n%(16*16)/16].id = data + palettes = make([]uint32, length) + for i := 0; i < int(length); i++ { + var v pk.VarInt + if err := v.Decode(data); err != nil { + return nil, fmt.Errorf("read palettes[%d] error: %w", i, err) + } + palettes[i] = uint32(v) } } + + // read data array + var dataLen pk.VarInt + if err := dataLen.Decode(data); err != nil { + return nil, fmt.Errorf("read data array length error: %w", err) + } + dataArray := make([]int64, dataLen) + for i := 0; i < int(dataLen); i++ { + var v pk.Long + if err := v.Decode(data); err != nil { + return nil, fmt.Errorf("read dataArray[%d] error: %w", i, err) + } + dataArray[i] = int64(v) + } + + sec := directSection{bpb: perBits(byte(bpb)), data: dataArray} + if bpb < 9 { + return &paletteSection{palette: palettes, directSection: sec}, nil + } else { + return &sec, nil + } +} + +type directSection struct { + bpb uint32 + data []int64 +} + +func (d *directSection) GetBlock(x, y, z int) (blockID uint32) { + // According to wiki.vg: Data Array is given for each block with increasing x coordinates, + // within rows of increasing z coordinates, within layers of increasing y coordinates. + // So offset equals to ( x*16^0 + z*16^1 + y*16^2 )*(bits per block). + offset := uint32(x+z*16+y*16*16) * d.bpb + block := uint32(d.data[offset/64]) + block >>= offset % 64 + if offset%64 > 64-d.bpb { + l := 64 - offset%64 + block |= uint32(d.data[offset/64+1] << l) + } + return block & (1<90 the player's hand will be very strange. -// func (g *Client) LookYawPitch(yaw, pitch float32) { -// g.motion <- func() { -// g.player.Yaw, g.player.Pitch = yaw, pitch -// sendPlayerLookPacket(g) //向服务器更新朝向 -// } -// } - -// // SwingHand sent when the player's arm swings. -// // if hand is true, swing the main hand -// func (g *Client) SwingHand(hand bool) { -// if hand { -// sendAnimationPacket(g, 0) -// } else { -// sendAnimationPacket(g, 1) -// } -// } - -// // Dig a block in the position and wait for it's breaked -// func (g *Client) Dig(x, y, z int) error { -// b := g.GetBlock(x, y, z).id -// sendPlayerDiggingPacket(g, 0, x, y, z, Top) //start -// sendPlayerDiggingPacket(g, 2, x, y, z, Top) //end - -// for { -// time.Sleep(time.Millisecond * 50) -// if g.GetBlock(x, y, z).id != b { -// break -// } -// g.SwingHand(true) -// } - -// return nil -// } - -// // UseItem use the item in hand. -// // if hand is true, swing the main hand -// func (g *Client) UseItem(hand bool) { -// if hand { -// sendUseItemPacket(g, 0) -// } else { -// sendUseItemPacket(g, 1) -// } -// } diff --git a/bot/world/world.go b/bot/world/world.go index 975bec6..9445105 100644 --- a/bot/world/world.go +++ b/bot/world/world.go @@ -10,19 +10,14 @@ type World struct { Chunks map[ChunkLoc]*Chunk } -//Chunk store a 256*16*16 clolumn blocks +//Chunk store a 256*16*16 column blocks type Chunk struct { sections [16]Section } //Section store a 16*16*16 cube blocks -type Section struct { - blocks [16][16][16]Block -} - -//Block is the base of world -type Block struct { - id uint +type Section interface { + GetBlock(x, y, z int) (blockID uint32) } type ChunkLoc struct { diff --git a/bot/world/world_test.go b/bot/world/world_test.go deleted file mode 100644 index 641e28b..0000000 --- a/bot/world/world_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package world - -// import "testing" - -// func TestBlockString(t *testing.T) { -// for i := uint(0); i < 8598+1; i++ { -// t.Log(Block{id: i}) -// } -// } From fa75535f372ef3fd871297c429c9a97a5fd50451 Mon Sep 17 00:00:00 2001 From: Tnze Date: Sun, 17 May 2020 14:45:27 +0800 Subject: [PATCH 2/7] add GetBlock function --- bot/world/chunk.go | 10 +++++----- bot/world/world.go | 43 +++++++++++++++++++------------------------ 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/bot/world/chunk.go b/bot/world/chunk.go index cf25df6..675c69d 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -21,7 +21,7 @@ func DecodeChunkColumn(mask int32, data []byte) (*Chunk, error) { if err != nil { return &c, fmt.Errorf("read section[%d] error: %w", sectionY, err) } - c.sections[sectionY] = sec + c.Sections[sectionY] = sec } } return &c, nil @@ -93,7 +93,7 @@ type directSection struct { data []int64 } -func (d *directSection) GetBlock(x, y, z int) (blockID uint32) { +func (d *directSection) GetBlock(x, y, z int) BlockStatus { // According to wiki.vg: Data Array is given for each block with increasing x coordinates, // within rows of increasing z coordinates, within layers of increasing y coordinates. // So offset equals to ( x*16^0 + z*16^1 + y*16^2 )*(bits per block). @@ -104,7 +104,7 @@ func (d *directSection) GetBlock(x, y, z int) (blockID uint32) { l := 64 - offset%64 block |= uint32(d.data[offset/64+1] << l) } - return block & (1<> 4, z >> 4}] -// if c != nil { -// cx, cy, cz := x&15, y&15, z&15 -// /* -// n = n&(16-1) - -// is equal to - -// n %= 16 -// if n < 0 { n += 16 } -// */ - -// return c.sections[y/16].blocks[cx][cy][cz] -// } - -// return Block{id: 0} -// } +// getBlock return the block in the position (x, y, z) +func (w *World) GetBlockStatus(x, y, z int) BlockStatus { + // Use n>>4 rather then n/16. It acts wrong if n<0. + c := w.Chunks[ChunkLoc{x >> 4, z >> 4}] + if c != nil { + // (n&(16-1)) == (n<0 ? n%16+16 : n%16) + if sec := c.Sections[y>>4]; sec != nil { + return sec.GetBlock(x&15, y&15, z&15) + } + } + return 0 +} // func (b Block) String() string { // return blockNameByID[b.id] From 32527442edde507136897e3adb3a464663e7f780 Mon Sep 17 00:00:00 2001 From: Tnze Date: Tue, 19 May 2020 14:15:44 +0800 Subject: [PATCH 3/7] add SetBlock function --- bot/world/chunk.go | 57 ++++++++++++++++++++++++++++++++-------------- bot/world/world.go | 1 + 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 675c69d..9e71d3e 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -27,14 +27,14 @@ func DecodeChunkColumn(mask int32, data []byte) (*Chunk, error) { return &c, nil } -func perBits(BitsPerBlock byte) uint32 { +func perBits(BitsPerBlock byte) int { switch { case BitsPerBlock <= 4: return 4 case BitsPerBlock < 9: - return uint32(BitsPerBlock) + return int(BitsPerBlock) default: - return uint32(data.BitsPerBlock) // DefaultBitsPerBlock + return data.BitsPerBlock // DefaultBitsPerBlock } } @@ -49,20 +49,20 @@ func readSection(data pk.DecodeReader) (s Section, err error) { } // If bpb values greater than or equal to 9, use directSection. // Otherwise use paletteSection. - var palettes []uint32 + var palettes []BlockStatus if bpb < 9 { // read palettes var length pk.VarInt if err := length.Decode(data); err != nil { return nil, fmt.Errorf("read palettes length error: %w", err) } - palettes = make([]uint32, length) + palettes = make([]BlockStatus, length) for i := 0; i < int(length); i++ { var v pk.VarInt if err := v.Decode(data); err != nil { return nil, fmt.Errorf("read palettes[%d] error: %w", i, err) } - palettes[i] = uint32(v) + palettes[i] = BlockStatus(v) } } @@ -71,13 +71,13 @@ func readSection(data pk.DecodeReader) (s Section, err error) { if err := dataLen.Decode(data); err != nil { return nil, fmt.Errorf("read data array length error: %w", err) } - dataArray := make([]int64, dataLen) + dataArray := make([]uint64, dataLen) for i := 0; i < int(dataLen); i++ { var v pk.Long if err := v.Decode(data); err != nil { return nil, fmt.Errorf("read dataArray[%d] error: %w", i, err) } - dataArray[i] = int64(v) + dataArray[i] = uint64(v) } sec := directSection{bpb: perBits(byte(bpb)), data: dataArray} @@ -89,30 +89,53 @@ func readSection(data pk.DecodeReader) (s Section, err error) { } type directSection struct { - bpb uint32 - data []int64 + bpb int + data []uint64 } func (d *directSection) GetBlock(x, y, z int) BlockStatus { // According to wiki.vg: Data Array is given for each block with increasing x coordinates, // within rows of increasing z coordinates, within layers of increasing y coordinates. // So offset equals to ( x*16^0 + z*16^1 + y*16^2 )*(bits per block). - offset := uint32(x+z*16+y*16*16) * d.bpb - block := uint32(d.data[offset/64]) - block >>= offset % 64 - if offset%64 > 64-d.bpb { - l := 64 - offset%64 + offset := (x + z*16 + y*16*16) * d.bpb + padding := offset % 64 + block := uint32(d.data[offset/64] >> padding) + if padding > 64-d.bpb { + l := 64 - padding block |= uint32(d.data[offset/64+1] << l) } return BlockStatus(block & (1< 64-d.bpb { + l := padding - (64 - d.bpb) + d.data[offset/64+1] = d.data[offset/64+1]&(maxUint64<>(64-padding) + } +} + type paletteSection struct { - palette []uint32 + palette []BlockStatus directSection } func (p *paletteSection) GetBlock(x, y, z int) BlockStatus { v := p.directSection.GetBlock(x, y, z) - return BlockStatus(p.palette[v]) + return p.palette[v] +} + +func (p *paletteSection) SetBlock(x, y, z int, s BlockStatus) { + for i := 0; i < len(p.palette); i++ { + if p.palette[i] == s { + p.directSection.SetBlock(x, y, z, BlockStatus(i)) + return + } + } + p.palette = append(p.palette, s) // TODO: Handle bpb overflow + p.directSection.SetBlock(x, y, z, BlockStatus(len(p.palette)+1)) } diff --git a/bot/world/world.go b/bot/world/world.go index bf12b0c..f3d5a62 100644 --- a/bot/world/world.go +++ b/bot/world/world.go @@ -18,6 +18,7 @@ type Chunk struct { // Section store a 16*16*16 cube blocks type Section interface { GetBlock(x, y, z int) BlockStatus + SetBlock(x, y, z int, s BlockStatus) } type BlockStatus uint32 From 39c9525525eb836d7a09584e219963a7ca26f971 Mon Sep 17 00:00:00 2001 From: Tnze Date: Tue, 19 May 2020 14:41:01 +0800 Subject: [PATCH 4/7] add unit test for directSection --- bot/world/chunk.go | 2 +- bot/world/chunk_test.go | 48 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 bot/world/chunk_test.go diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 9e71d3e..43cfa8b 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -112,7 +112,7 @@ func (d *directSection) SetBlock(x, y, z int, s BlockStatus) { padding := offset % 64 const maxUint64 = 1<<64 - 1 mask := uint64(maxUint64<<(padding+d.bpb) | (1< 64-d.bpb { l := padding - (64 - d.bpb) d.data[offset/64+1] = d.data[offset/64+1]&(maxUint64<>(64-padding) diff --git a/bot/world/chunk_test.go b/bot/world/chunk_test.go new file mode 100644 index 0000000..2878501 --- /dev/null +++ b/bot/world/chunk_test.go @@ -0,0 +1,48 @@ +package world + +import ( + "github.com/Tnze/go-mc/data" + "math/rand" + "testing" +) + +func newDirectSection(bpb int) *directSection { + return &directSection{ + bpb: bpb, + data: make([]uint64, 16*16*16*bpb/64), + } +} + +func TestDirectSection(t *testing.T) { + for bpb := 3; bpb <= data.BitsPerBlock; bpb++ { + s := newDirectSection(bpb) + for _, dataset := range [][16 * 16 * 16]BlockStatus{secData(bpb), randData(bpb)} { + for i := 0; i < 16*16*16; i++ { + s.SetBlock(i%16, i/16%16, i/16/16, dataset[i]) + } + for i := 0; i < 16*16*16; i++ { + if s := s.GetBlock(i%16, i/16%16, i/16/16); dataset[i] != s { + t.Fatalf("direct section error: want: %v, get %v", dataset[i], s) + } + } + } + } +} + +func secData(bpb int) (data [16 * 16 * 16]BlockStatus) { + mask := 1< Date: Tue, 19 May 2020 16:15:39 +0800 Subject: [PATCH 5/7] add unit test for paletteSection --- bot/world/chunk.go | 44 ++++++++++++++++++++++++++++++++--------- bot/world/chunk_test.go | 32 +++++++++++++++++++----------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 43cfa8b..8fd6b90 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -50,6 +50,7 @@ func readSection(data pk.DecodeReader) (s Section, err error) { // If bpb values greater than or equal to 9, use directSection. // Otherwise use paletteSection. var palettes []BlockStatus + var palettesIndex map[BlockStatus]int if bpb < 9 { // read palettes var length pk.VarInt @@ -57,12 +58,14 @@ func readSection(data pk.DecodeReader) (s Section, err error) { return nil, fmt.Errorf("read palettes length error: %w", err) } palettes = make([]BlockStatus, length) + palettesIndex = make(map[BlockStatus]int, length) for i := 0; i < int(length); i++ { var v pk.VarInt if err := v.Decode(data); err != nil { return nil, fmt.Errorf("read palettes[%d] error: %w", i, err) } palettes[i] = BlockStatus(v) + palettesIndex[BlockStatus(v)] = i } } @@ -71,6 +74,9 @@ func readSection(data pk.DecodeReader) (s Section, err error) { if err := dataLen.Decode(data); err != nil { return nil, fmt.Errorf("read data array length error: %w", err) } + if int(dataLen) < 16*16*16*int(bpb)/64 { + return nil, fmt.Errorf("data length (%d) is not enough of given bpb (%d)", dataLen, bpb) + } dataArray := make([]uint64, dataLen) for i := 0; i < int(dataLen); i++ { var v pk.Long @@ -82,7 +88,11 @@ func readSection(data pk.DecodeReader) (s Section, err error) { sec := directSection{bpb: perBits(byte(bpb)), data: dataArray} if bpb < 9 { - return &paletteSection{palette: palettes, directSection: sec}, nil + return &paletteSection{ + palette: palettes, + palettesIndex: palettesIndex, + directSection: sec, + }, nil } else { return &sec, nil } @@ -119,8 +129,24 @@ func (d *directSection) SetBlock(x, y, z int, s BlockStatus) { } } +func (d *directSection) clone(bpb int) *directSection { + newSection := &directSection{ + bpb: bpb, + data: make([]uint64, 16*16*16*bpb/64), + } + for x := 0; x < 16; x++ { + for y := 0; y < 16; y++ { + for z := 0; z < 16; z++ { + newSection.SetBlock(x, y, z, d.GetBlock(x, y, z)) + } + } + } + return newSection +} + type paletteSection struct { - palette []BlockStatus + palette []BlockStatus + palettesIndex map[BlockStatus]int directSection } @@ -130,12 +156,12 @@ func (p *paletteSection) GetBlock(x, y, z int) BlockStatus { } func (p *paletteSection) SetBlock(x, y, z int, s BlockStatus) { - for i := 0; i < len(p.palette); i++ { - if p.palette[i] == s { - p.directSection.SetBlock(x, y, z, BlockStatus(i)) - return - } + if i, ok := p.palettesIndex[s]; ok { + p.directSection.SetBlock(x, y, z, BlockStatus(i)) + return } - p.palette = append(p.palette, s) // TODO: Handle bpb overflow - p.directSection.SetBlock(x, y, z, BlockStatus(len(p.palette)+1)) + i := len(p.palette) + p.palette = append(p.palette, s) + p.palettesIndex[s] = i + p.directSection.SetBlock(x, y, z, BlockStatus(i)) } diff --git a/bot/world/chunk_test.go b/bot/world/chunk_test.go index 2878501..e1e74a4 100644 --- a/bot/world/chunk_test.go +++ b/bot/world/chunk_test.go @@ -6,7 +6,7 @@ import ( "testing" ) -func newDirectSection(bpb int) *directSection { +func newDirectSection(bpb int) Section { return &directSection{ bpb: bpb, data: make([]uint64, 16*16*16*bpb/64), @@ -14,16 +14,26 @@ func newDirectSection(bpb int) *directSection { } func TestDirectSection(t *testing.T) { - for bpb := 3; bpb <= data.BitsPerBlock; bpb++ { - s := newDirectSection(bpb) - for _, dataset := range [][16 * 16 * 16]BlockStatus{secData(bpb), randData(bpb)} { - for i := 0; i < 16*16*16; i++ { - s.SetBlock(i%16, i/16%16, i/16/16, dataset[i]) - } - for i := 0; i < 16*16*16; i++ { - if s := s.GetBlock(i%16, i/16%16, i/16/16); dataset[i] != s { - t.Fatalf("direct section error: want: %v, get %v", dataset[i], s) - } + for bpb := 4; bpb < data.BitsPerBlock; bpb++ { + testSection(t, newDirectSection(bpb), bpb) + } +} + +func TestPaletteSection(t *testing.T) { + testSection(t, &paletteSection{ + palettesIndex: make(map[BlockStatus]int), + directSection: *(newDirectSection(7).(*directSection)), + }, 7) +} + +func testSection(t *testing.T, s Section, bpb int) { + for _, dataset := range [][16 * 16 * 16]BlockStatus{secData(bpb), randData(bpb)} { + for i := 0; i < 16*16*16; i++ { + s.SetBlock(i%16, i/16%16, i/16/16, dataset[i]) + } + for i := 0; i < 16*16*16; i++ { + if s := s.GetBlock(i%16, i/16%16, i/16/16); dataset[i] != s { + t.Fatalf("direct section error: want: %v, get %v", dataset[i], s) } } } From 2db43755f111a28ed7f1e2823e9e7d4c771c8241 Mon Sep 17 00:00:00 2001 From: Tnze Date: Thu, 21 May 2020 17:07:18 +0800 Subject: [PATCH 6/7] The paletteSection can auto increase its underlying directSection. --- bot/world/chunk.go | 17 +++++++++++---- bot/world/chunk_test.go | 47 ++++++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 8fd6b90..5d339df 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -3,9 +3,9 @@ package world import ( "bytes" "fmt" - // "io" "github.com/Tnze/go-mc/data" pk "github.com/Tnze/go-mc/net/packet" + "math" ) // DecodeChunkColumn decode the chunk data structure. @@ -120,15 +120,18 @@ func (d *directSection) GetBlock(x, y, z int) BlockStatus { func (d *directSection) SetBlock(x, y, z int, s BlockStatus) { offset := (x + z*16 + y*16*16) * d.bpb padding := offset % 64 - const maxUint64 = 1<<64 - 1 - mask := uint64(maxUint64<<(padding+d.bpb) | (1< 64-d.bpb { l := padding - (64 - d.bpb) - d.data[offset/64+1] = d.data[offset/64+1]&(maxUint64<>(64-padding) + d.data[offset/64+1] = d.data[offset/64+1]&(math.MaxUint64<>(64-padding) } } +func (d *directSection) CanContain(s BlockStatus) bool { + return s <= (1< Date: Thu, 21 May 2020 17:28:42 +0800 Subject: [PATCH 7/7] change API of Section from (x, y, z int) to (offset int) --- bot/world/chunk.go | 29 +++++++++++------------------ bot/world/chunk_test.go | 11 ++++------- bot/world/world.go | 15 ++++++++++++--- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/bot/world/chunk.go b/bot/world/chunk.go index 5d339df..36fc3a1 100644 --- a/bot/world/chunk.go +++ b/bot/world/chunk.go @@ -103,11 +103,8 @@ type directSection struct { data []uint64 } -func (d *directSection) GetBlock(x, y, z int) BlockStatus { - // According to wiki.vg: Data Array is given for each block with increasing x coordinates, - // within rows of increasing z coordinates, within layers of increasing y coordinates. - // So offset equals to ( x*16^0 + z*16^1 + y*16^2 )*(bits per block). - offset := (x + z*16 + y*16*16) * d.bpb +func (d *directSection) GetBlock(offset int) BlockStatus { + offset *= d.bpb padding := offset % 64 block := uint32(d.data[offset/64] >> padding) if padding > 64-d.bpb { @@ -117,8 +114,8 @@ func (d *directSection) GetBlock(x, y, z int) BlockStatus { return BlockStatus(block & (1<>4]; sec != nil { - return sec.GetBlock(x&15, y&15, z&15) + return sec.GetBlock(SectionOffset(x&15, y&15, z&15)) } } return 0