up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package chunk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
)
|
||||
|
||||
// NetworkDecode decodes the network serialised data passed into a Chunk if successful. If not, the chunk
|
||||
// returned is nil and the error non-nil.
|
||||
// The sub chunk count passed must be that found in the LevelChunk packet.
|
||||
// NetworkDecode creates a new buffer and calls NetworkDecodeBuffer.
|
||||
//
|
||||
// The BlockRegistry passed must be finalized and must correspond to the runtime IDs used in the chunk data.
|
||||
// noinspection GoUnusedExportedFunction
|
||||
func NetworkDecode(br BlockRegistry, data []byte, count int, r cube.Range) (*Chunk, error) {
|
||||
return NetworkDecodeBuffer(br, bytes.NewBuffer(data), count, r)
|
||||
}
|
||||
|
||||
// NetworkDecodeBuffer decodes the network serialised data from buf passed into a Chunk if successful. If not, the chunk
|
||||
// returned is nil and the error non-nil.
|
||||
// The sub chunk count passed must be that found in the LevelChunk packet.
|
||||
// noinspection GoUnusedExportedFunction
|
||||
func NetworkDecodeBuffer(br BlockRegistry, buf *bytes.Buffer, count int, r cube.Range) (*Chunk, error) {
|
||||
var (
|
||||
c = New(br, r)
|
||||
err error
|
||||
)
|
||||
for i := 0; i < count; i++ {
|
||||
index := uint8(i)
|
||||
c.sub[index], err = decodeSubChunk(buf, c, &index, NetworkEncoding)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var last *PalettedStorage
|
||||
for i := 0; i < len(c.sub); i++ {
|
||||
b, err := decodePalettedStorage(buf, NetworkEncoding, BiomePaletteEncoding)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b == nil {
|
||||
// b == nil means this paletted storage had the flag pointing to the previous one. It basically means we should
|
||||
// inherit whatever palette we decoded last.
|
||||
if i == 0 {
|
||||
// This should never happen and there is no way to handle this.
|
||||
return nil, fmt.Errorf("first biome storage pointed to previous one")
|
||||
}
|
||||
b = last
|
||||
} else {
|
||||
last = b
|
||||
}
|
||||
c.biomes[i] = b
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// DiskDecode decodes the data from a SerialisedData object into a chunk and returns it. If the data was invalid,
|
||||
// an error is returned.
|
||||
//
|
||||
// The BlockRegistry passed must be finalized and must correspond to the runtime IDs used in the chunk data.
|
||||
func DiskDecode(br BlockRegistry, data SerialisedData, r cube.Range) (*Chunk, error) {
|
||||
c := New(br, r)
|
||||
|
||||
err := decodeBiomes(bytes.NewBuffer(data.Biomes), c, DiskEncoding)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i, sub := range data.SubChunks {
|
||||
if len(sub) == 0 {
|
||||
// No data for this sub chunk.
|
||||
continue
|
||||
}
|
||||
index := uint8(i)
|
||||
if c.sub[index], err = decodeSubChunk(bytes.NewBuffer(sub), c, &index, DiskEncoding); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// decodeSubChunk decodes a SubChunk from a bytes.Buffer. The Encoding passed defines how the block storages of the
|
||||
// SubChunk are decoded.
|
||||
func decodeSubChunk(buf *bytes.Buffer, c *Chunk, index *byte, e Encoding) (*SubChunk, error) {
|
||||
ver, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading version: %w", err)
|
||||
}
|
||||
sub := NewSubChunk(c.air)
|
||||
switch ver {
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown sub chunk version %v: can't decode", ver)
|
||||
case 1:
|
||||
// Version 1 only has one layer for each sub chunk, but uses the format with palettes.
|
||||
storage, err := decodePalettedStorage(buf, e, BlockPaletteEncoding{Blocks: c.br})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sub.storages = append(sub.storages, storage)
|
||||
case 8, 9:
|
||||
// Version 8 allows up to 256 layers for one sub chunk.
|
||||
storageCount, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading storage count: %w", err)
|
||||
}
|
||||
if ver == 9 {
|
||||
uIndex, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading sub-chunk index: %w", err)
|
||||
}
|
||||
// The index as written here isn't the actual index of the sub-chunk within the chunk. Rather, it is the Y
|
||||
// value of the sub-chunk. This means that we need to translate it to an index.
|
||||
*index = uint8(int8(uIndex) - int8(c.r[0]>>4))
|
||||
}
|
||||
sub.storages = make([]*PalettedStorage, storageCount)
|
||||
|
||||
for i := byte(0); i < storageCount; i++ {
|
||||
sub.storages[i], err = decodePalettedStorage(buf, e, BlockPaletteEncoding{Blocks: c.br})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
// decodeBiomes reads the paletted storages holding biomes from buf and stores it into the Chunk passed.
|
||||
func decodeBiomes(buf *bytes.Buffer, c *Chunk, e Encoding) error {
|
||||
var last *PalettedStorage
|
||||
if buf.Len() != 0 {
|
||||
for i := 0; i < len(c.sub); i++ {
|
||||
b, err := decodePalettedStorage(buf, e, BiomePaletteEncoding)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// b == nil means this paletted storage had the flag pointing to the previous one. It basically means we should
|
||||
// inherit whatever palette we decoded last.
|
||||
if i == 0 && b == nil {
|
||||
// This should never happen and there is no way to handle this.
|
||||
return fmt.Errorf("first biome storage pointed to previous one")
|
||||
}
|
||||
if b == nil {
|
||||
// This means this paletted storage had the flag pointing to the previous one. It basically means we should
|
||||
// inherit whatever palette we decoded last.
|
||||
b = last
|
||||
} else {
|
||||
last = b
|
||||
}
|
||||
c.biomes[i] = b
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodePalettedStorage decodes a PalettedStorage from a bytes.Buffer. The Encoding passed is used to read either a
|
||||
// network or disk block storage.
|
||||
func decodePalettedStorage(buf *bytes.Buffer, e Encoding, pe paletteEncoding) (*PalettedStorage, error) {
|
||||
blockSize, err := buf.ReadByte()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading block size: %w", err)
|
||||
}
|
||||
blockSize >>= 1
|
||||
if blockSize == 0x7f {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
size := paletteSize(blockSize)
|
||||
if size > 32 {
|
||||
return nil, fmt.Errorf("cannot read paletted storage (size=%v) %T: size too large", blockSize, pe)
|
||||
}
|
||||
uint32Count := size.uint32s()
|
||||
|
||||
uint32s := make([]uint32, uint32Count)
|
||||
byteCount := uint32Count * 4
|
||||
|
||||
data := buf.Next(byteCount)
|
||||
if len(data) != byteCount {
|
||||
return nil, fmt.Errorf("cannot read paletted storage (size=%v) %T: not enough block data present: expected %v bytes, got %v", blockSize, pe, byteCount, len(data))
|
||||
}
|
||||
for i := 0; i < uint32Count; i++ {
|
||||
// Explicitly don't use the binary package to greatly improve performance of reading the uint32s.
|
||||
uint32s[i] = uint32(data[i*4]) | uint32(data[i*4+1])<<8 | uint32(data[i*4+2])<<16 | uint32(data[i*4+3])<<24
|
||||
}
|
||||
p, err := e.decodePalette(buf, paletteSize(blockSize), pe)
|
||||
return newPalettedStorage(uint32s, p), err
|
||||
}
|
||||
Reference in New Issue
Block a user