add SetBlock function
This commit is contained in:
@ -27,14 +27,14 @@ func DecodeChunkColumn(mask int32, data []byte) (*Chunk, error) {
|
|||||||
return &c, nil
|
return &c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func perBits(BitsPerBlock byte) uint32 {
|
func perBits(BitsPerBlock byte) int {
|
||||||
switch {
|
switch {
|
||||||
case BitsPerBlock <= 4:
|
case BitsPerBlock <= 4:
|
||||||
return 4
|
return 4
|
||||||
case BitsPerBlock < 9:
|
case BitsPerBlock < 9:
|
||||||
return uint32(BitsPerBlock)
|
return int(BitsPerBlock)
|
||||||
default:
|
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.
|
// If bpb values greater than or equal to 9, use directSection.
|
||||||
// Otherwise use paletteSection.
|
// Otherwise use paletteSection.
|
||||||
var palettes []uint32
|
var palettes []BlockStatus
|
||||||
if bpb < 9 {
|
if bpb < 9 {
|
||||||
// read palettes
|
// read palettes
|
||||||
var length pk.VarInt
|
var length pk.VarInt
|
||||||
if err := length.Decode(data); err != nil {
|
if err := length.Decode(data); err != nil {
|
||||||
return nil, fmt.Errorf("read palettes length error: %w", err)
|
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++ {
|
for i := 0; i < int(length); i++ {
|
||||||
var v pk.VarInt
|
var v pk.VarInt
|
||||||
if err := v.Decode(data); err != nil {
|
if err := v.Decode(data); err != nil {
|
||||||
return nil, fmt.Errorf("read palettes[%d] error: %w", i, err)
|
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 {
|
if err := dataLen.Decode(data); err != nil {
|
||||||
return nil, fmt.Errorf("read data array length error: %w", err)
|
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++ {
|
for i := 0; i < int(dataLen); i++ {
|
||||||
var v pk.Long
|
var v pk.Long
|
||||||
if err := v.Decode(data); err != nil {
|
if err := v.Decode(data); err != nil {
|
||||||
return nil, fmt.Errorf("read dataArray[%d] error: %w", i, err)
|
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}
|
sec := directSection{bpb: perBits(byte(bpb)), data: dataArray}
|
||||||
@ -89,30 +89,53 @@ func readSection(data pk.DecodeReader) (s Section, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type directSection struct {
|
type directSection struct {
|
||||||
bpb uint32
|
bpb int
|
||||||
data []int64
|
data []uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *directSection) GetBlock(x, y, z int) BlockStatus {
|
func (d *directSection) GetBlock(x, y, z int) BlockStatus {
|
||||||
// According to wiki.vg: Data Array is given for each block with increasing x coordinates,
|
// 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.
|
// 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).
|
// 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
|
offset := (x + z*16 + y*16*16) * d.bpb
|
||||||
block := uint32(d.data[offset/64])
|
padding := offset % 64
|
||||||
block >>= offset % 64
|
block := uint32(d.data[offset/64] >> padding)
|
||||||
if offset%64 > 64-d.bpb {
|
if padding > 64-d.bpb {
|
||||||
l := 64 - offset%64
|
l := 64 - padding
|
||||||
block |= uint32(d.data[offset/64+1] << l)
|
block |= uint32(d.data[offset/64+1] << l)
|
||||||
}
|
}
|
||||||
return BlockStatus(block & (1<<d.bpb - 1)) // mask
|
return BlockStatus(block & (1<<d.bpb - 1)) // mask
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<<padding - 1))
|
||||||
|
d.data[offset/64] = uint64(d.data[offset/64])&mask | uint64(s)<<padding
|
||||||
|
if padding > 64-d.bpb {
|
||||||
|
l := padding - (64 - d.bpb)
|
||||||
|
d.data[offset/64+1] = d.data[offset/64+1]&(maxUint64<<l) | uint64(s)>>(64-padding)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type paletteSection struct {
|
type paletteSection struct {
|
||||||
palette []uint32
|
palette []BlockStatus
|
||||||
directSection
|
directSection
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *paletteSection) GetBlock(x, y, z int) BlockStatus {
|
func (p *paletteSection) GetBlock(x, y, z int) BlockStatus {
|
||||||
v := p.directSection.GetBlock(x, y, z)
|
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))
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ type Chunk struct {
|
|||||||
// Section store a 16*16*16 cube blocks
|
// Section store a 16*16*16 cube blocks
|
||||||
type Section interface {
|
type Section interface {
|
||||||
GetBlock(x, y, z int) BlockStatus
|
GetBlock(x, y, z int) BlockStatus
|
||||||
|
SetBlock(x, y, z int, s BlockStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockStatus uint32
|
type BlockStatus uint32
|
||||||
|
Reference in New Issue
Block a user