github.com/df-mc/dragonfly@v0.9.13/server/world/chunk/decode.go (about)

     1  package chunk
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"github.com/df-mc/dragonfly/server/block/cube"
     7  )
     8  
     9  // StateToRuntimeID must hold a function to convert a name and its state properties to a runtime ID.
    10  var StateToRuntimeID func(name string, properties map[string]any) (runtimeID uint32, found bool)
    11  
    12  // NetworkDecode decodes the network serialised data passed into a Chunk if successful. If not, the chunk
    13  // returned is nil and the error non-nil.
    14  // The sub chunk count passed must be that found in the LevelChunk packet.
    15  // noinspection GoUnusedExportedFunction
    16  func NetworkDecode(air uint32, data []byte, count int, r cube.Range) (*Chunk, error) {
    17  	var (
    18  		c   = New(air, r)
    19  		buf = bytes.NewBuffer(data)
    20  		err error
    21  	)
    22  	for i := 0; i < count; i++ {
    23  		index := uint8(i)
    24  		c.sub[index], err = decodeSubChunk(buf, c, &index, NetworkEncoding)
    25  		if err != nil {
    26  			return nil, err
    27  		}
    28  	}
    29  	var last *PalettedStorage
    30  	for i := 0; i < len(c.sub); i++ {
    31  		b, err := decodePalettedStorage(buf, NetworkEncoding, BiomePaletteEncoding)
    32  		if err != nil {
    33  			return nil, err
    34  		}
    35  		if b == nil {
    36  			// b == nil means this paletted storage had the flag pointing to the previous one. It basically means we should
    37  			// inherit whatever palette we decoded last.
    38  			if i == 0 {
    39  				// This should never happen and there is no way to handle this.
    40  				return nil, fmt.Errorf("first biome storage pointed to previous one")
    41  			}
    42  			b = last
    43  		} else {
    44  			last = b
    45  		}
    46  		c.biomes[i] = b
    47  	}
    48  	return c, nil
    49  }
    50  
    51  // DiskDecode decodes the data from a SerialisedData object into a chunk and returns it. If the data was
    52  // invalid, an error is returned.
    53  func DiskDecode(data SerialisedData, r cube.Range) (*Chunk, error) {
    54  	air, ok := StateToRuntimeID("minecraft:air", nil)
    55  	if !ok {
    56  		panic("cannot find air runtime ID")
    57  	}
    58  
    59  	c := New(air, r)
    60  
    61  	err := decodeBiomes(bytes.NewBuffer(data.Biomes), c, DiskEncoding)
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	for i, sub := range data.SubChunks {
    66  		if len(sub) == 0 {
    67  			// No data for this sub chunk.
    68  			continue
    69  		}
    70  		index := uint8(i)
    71  		if c.sub[index], err = decodeSubChunk(bytes.NewBuffer(sub), c, &index, DiskEncoding); err != nil {
    72  			return nil, err
    73  		}
    74  	}
    75  	return c, nil
    76  }
    77  
    78  // decodeSubChunk decodes a SubChunk from a bytes.Buffer. The Encoding passed defines how the block storages of the
    79  // SubChunk are decoded.
    80  func decodeSubChunk(buf *bytes.Buffer, c *Chunk, index *byte, e Encoding) (*SubChunk, error) {
    81  	ver, err := buf.ReadByte()
    82  	if err != nil {
    83  		return nil, fmt.Errorf("error reading version: %w", err)
    84  	}
    85  	sub := NewSubChunk(c.air)
    86  	switch ver {
    87  	default:
    88  		return nil, fmt.Errorf("unknown sub chunk version %v: can't decode", ver)
    89  	case 1:
    90  		// Version 1 only has one layer for each sub chunk, but uses the format with palettes.
    91  		storage, err := decodePalettedStorage(buf, e, BlockPaletteEncoding)
    92  		if err != nil {
    93  			return nil, err
    94  		}
    95  		sub.storages = append(sub.storages, storage)
    96  	case 8, 9:
    97  		// Version 8 allows up to 256 layers for one sub chunk.
    98  		storageCount, err := buf.ReadByte()
    99  		if err != nil {
   100  			return nil, fmt.Errorf("error reading storage count: %w", err)
   101  		}
   102  		if ver == 9 {
   103  			uIndex, err := buf.ReadByte()
   104  			if err != nil {
   105  				return nil, fmt.Errorf("error reading sub-chunk index: %w", err)
   106  			}
   107  			// The index as written here isn't the actual index of the sub-chunk within the chunk. Rather, it is the Y
   108  			// value of the sub-chunk. This means that we need to translate it to an index.
   109  			*index = uint8(int8(uIndex) - int8(c.r[0]>>4))
   110  		}
   111  		sub.storages = make([]*PalettedStorage, storageCount)
   112  
   113  		for i := byte(0); i < storageCount; i++ {
   114  			sub.storages[i], err = decodePalettedStorage(buf, e, BlockPaletteEncoding)
   115  			if err != nil {
   116  				return nil, err
   117  			}
   118  		}
   119  	}
   120  	return sub, nil
   121  }
   122  
   123  // decodeBiomes reads the paletted storages holding biomes from buf and stores it into the Chunk passed.
   124  func decodeBiomes(buf *bytes.Buffer, c *Chunk, e Encoding) error {
   125  	var last *PalettedStorage
   126  	if buf.Len() != 0 {
   127  		for i := 0; i < len(c.sub); i++ {
   128  			b, err := decodePalettedStorage(buf, e, BiomePaletteEncoding)
   129  			if err != nil {
   130  				return err
   131  			}
   132  			// b == nil means this paletted storage had the flag pointing to the previous one. It basically means we should
   133  			// inherit whatever palette we decoded last.
   134  			if i == 0 && b == nil {
   135  				// This should never happen and there is no way to handle this.
   136  				return fmt.Errorf("first biome storage pointed to previous one")
   137  			}
   138  			if b == nil {
   139  				// This means this paletted storage had the flag pointing to the previous one. It basically means we should
   140  				// inherit whatever palette we decoded last.
   141  				b = last
   142  			} else {
   143  				last = b
   144  			}
   145  			c.biomes[i] = b
   146  		}
   147  	}
   148  	return nil
   149  }
   150  
   151  // decodePalettedStorage decodes a PalettedStorage from a bytes.Buffer. The Encoding passed is used to read either a
   152  // network or disk block storage.
   153  func decodePalettedStorage(buf *bytes.Buffer, e Encoding, pe paletteEncoding) (*PalettedStorage, error) {
   154  	blockSize, err := buf.ReadByte()
   155  	if err != nil {
   156  		return nil, fmt.Errorf("error reading block size: %w", err)
   157  	}
   158  	blockSize >>= 1
   159  	if blockSize == 0x7f {
   160  		return nil, nil
   161  	}
   162  
   163  	size := paletteSize(blockSize)
   164  	uint32Count := size.uint32s()
   165  
   166  	uint32s := make([]uint32, uint32Count)
   167  	byteCount := uint32Count * 4
   168  
   169  	data := buf.Next(byteCount)
   170  	if len(data) != byteCount {
   171  		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))
   172  	}
   173  	for i := 0; i < uint32Count; i++ {
   174  		// Explicitly don't use the binary package to greatly improve performance of reading the uint32s.
   175  		uint32s[i] = uint32(data[i*4]) | uint32(data[i*4+1])<<8 | uint32(data[i*4+2])<<16 | uint32(data[i*4+3])<<24
   176  	}
   177  	p, err := e.decodePalette(buf, paletteSize(blockSize), pe)
   178  	return newPalettedStorage(uint32s, p), err
   179  }