package world import ( "bytes" "fmt" "math" "github.com/Tnze/go-mc/data/block" pk "github.com/Tnze/go-mc/net/packet" ) const maxPaletteBits = 8 // 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 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 } } return &c, nil } func perBits(bpb byte) uint { switch { case bpb <= 4: return 4 case bpb <= maxPaletteBits: return uint(bpb) default: return uint(block.BitsPerBlock) } } func readSection(data pk.DecodeReader) (s Section, err error) { var nonAirBlockCount pk.Short if err := nonAirBlockCount.Decode(data); err != nil { return nil, fmt.Errorf("block count: %w", err) } var bpb pk.UnsignedByte if err := bpb.Decode(data); err != nil { return nil, fmt.Errorf("bits per block: %w", err) } // If bpb values greater than or equal to 9, use directSection. // Otherwise use paletteSection. var palettes []BlockStatus var palettesIndex map[BlockStatus]int if bpb <= maxPaletteBits { // read palettes var length pk.VarInt if err := length.Decode(data); err != nil { return nil, fmt.Errorf("palette length: %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 } } // 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) } 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 if err := v.Decode(data); err != nil { return nil, fmt.Errorf("read dataArray[%d] error: %w", i, err) } dataArray[i] = uint64(v) } width := perBits(byte(bpb)) sec := directSection{ bitArray{ width: width, valuesPerElement: valuesPerBitArrayElement(width), data: dataArray, }, } if bpb <= maxPaletteBits { return &paletteSection{ palette: palettes, palettesIndex: palettesIndex, directSection: sec, }, nil } else { return &sec, nil } } type directSection struct { bitArray } func (d *directSection) GetBlock(offset uint) BlockStatus { return BlockStatus(d.Get(offset)) } func (d *directSection) SetBlock(offset uint, s BlockStatus) { d.Set(offset, uint(s)) } func (d *directSection) CanContain(s BlockStatus) bool { return s <= (1<