package level import ( "fmt" "io" "math" pk "github.com/Tnze/go-mc/net/packet" ) const indexOutOfBounds = "index out of bounds" const valueOutOfBounds = "value out of bounds" // BitStorage implement the compacted data array used in chunk storage and heightmaps. // You can think of this as a []intN whose N is called "bits" in NewBitStorage. // For more info, see: https://wiki.vg/Chunk_Format // This is implementation of the format since Minecraft 1.16 type BitStorage struct { data []uint64 mask uint64 bits, length int valuesPerLong int } // NewBitStorage create a new BitStorage. Return nil if bits == 0. // // The "bits" is the number of bits per value, which can be calculated by math/bits.Len() // The "length" is the number of values. // The "data" is optional for initializing. Panic if data != nil && len(data) != calcBitStorageSize(bits, length). func NewBitStorage(bits, length int, data []uint64) (b *BitStorage) { if bits == 0 { return &BitStorage{ data: nil, mask: 0, bits: 0, length: length, valuesPerLong: 0, } } b = &BitStorage{ mask: 1< b.mask { panic(valueOutOfBounds) } if i < 0 || i > b.length-1 { panic(indexOutOfBounds) } c, offset := b.calcIndex(i) l := b.data[c] old = int(l >> offset & b.mask) b.data[c] = l&(b.mask< b.mask { panic(valueOutOfBounds) } if i < 0 || i > b.length-1 { panic(indexOutOfBounds) } c, offset := b.calcIndex(i) l := b.data[c] b.data[c] = l&(b.mask< b.length-1 { panic(indexOutOfBounds) } c, offset := b.calcIndex(i) l := b.data[c] return int(l >> offset & b.mask) } // Len is the number of stored values. func (b *BitStorage) Len() int { return b.length } // Raw return the underling array of uint64 for encoding/decoding. func (b *BitStorage) Raw() []uint64 { if b == nil { return []uint64{} } return b.data } func (b *BitStorage) ReadFrom(r io.Reader) (int64, error) { var Len pk.VarInt n, err := Len.ReadFrom(r) if err != nil { return n, err } if cap(b.data) >= int(Len) { b.data = b.data[:Len] } else { b.data = make([]uint64, Len) } var v pk.Long for i := range b.data { nn, err := v.ReadFrom(r) n += nn if err != nil { return n, err } b.data[i] = uint64(v) } return n, nil } func (b *BitStorage) WriteTo(w io.Writer) (int64, error) { if b == nil { return pk.VarInt(0).WriteTo(w) } n, err := pk.VarInt(len(b.data)).WriteTo(w) if err != nil { return n, err } for _, v := range b.data { nn, err := pk.Long(v).WriteTo(w) n += nn if err != nil { return n, err } } return n, nil } func (b *BitStorage) Fix(bits int) error { b.mask = 1<