package save import ( "fmt" "math" ) 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) != BitStorageSize(bits, length). func NewBitStorage(bits, length int, data []uint64) (b *BitStorage) { if bits == 0 { return nil } b = &BitStorage{ mask: 1< b.length-1 { panic(indexOutOfBounds) } if v < 0 || uint64(v) > b.mask { panic(valueOutOfBounds) } c, offset := b.calcIndex(i) l := b.data[c] old = int(l >> offset & b.mask) b.data[c] = l&(b.mask< b.length-1 { panic(indexOutOfBounds) } if v < 0 || uint64(v) > b.mask { panic(valueOutOfBounds) } 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 { if b == nil { return 0 } return b.length } // Longs return the underling array of uint64 for encoding/decoding. func (b *BitStorage) Longs() []uint64 { if b == nil { return []uint64{} } return b.data }