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

     1  package chunk
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"github.com/df-mc/worldupgrader/blockupgrader"
     8  	"github.com/sandertv/gophertunnel/minecraft/nbt"
     9  	"github.com/sandertv/gophertunnel/minecraft/protocol"
    10  )
    11  
    12  type (
    13  	// Encoding is an encoding type used for Chunk encoding. Implementations of this interface are DiskEncoding and
    14  	// NetworkEncoding, which can be used to encode a Chunk to an intermediate disk or network representation respectively.
    15  	Encoding interface {
    16  		encodePalette(buf *bytes.Buffer, p *Palette, e paletteEncoding)
    17  		decodePalette(buf *bytes.Buffer, blockSize paletteSize, e paletteEncoding) (*Palette, error)
    18  		network() byte
    19  	}
    20  	// paletteEncoding is an encoding type used for Chunk encoding. It is used to encode different types of palettes
    21  	// (for example, blocks or biomes) differently.
    22  	paletteEncoding interface {
    23  		encode(buf *bytes.Buffer, v uint32)
    24  		decode(buf *bytes.Buffer) (uint32, error)
    25  	}
    26  )
    27  
    28  var (
    29  	// DiskEncoding is the Encoding for writing a Chunk to disk. It writes block palettes using NBT and does not use
    30  	// varints.
    31  	DiskEncoding diskEncoding
    32  	// NetworkEncoding is the Encoding used for sending a Chunk over network. It does not use NBT and writes varints.
    33  	NetworkEncoding networkEncoding
    34  	// BiomePaletteEncoding is the paletteEncoding used for encoding a palette of biomes.
    35  	BiomePaletteEncoding biomePaletteEncoding
    36  	// BlockPaletteEncoding is the paletteEncoding used for encoding a palette of block states encoded as NBT.
    37  	BlockPaletteEncoding blockPaletteEncoding
    38  )
    39  
    40  // biomePaletteEncoding implements the encoding of biome palettes to disk.
    41  type biomePaletteEncoding struct{}
    42  
    43  func (biomePaletteEncoding) encode(buf *bytes.Buffer, v uint32) {
    44  	_ = binary.Write(buf, binary.LittleEndian, v)
    45  }
    46  func (biomePaletteEncoding) decode(buf *bytes.Buffer) (uint32, error) {
    47  	var v uint32
    48  	return v, binary.Read(buf, binary.LittleEndian, &v)
    49  }
    50  
    51  // blockPaletteEncoding implements the encoding of block palettes to disk.
    52  type blockPaletteEncoding struct{}
    53  
    54  func (blockPaletteEncoding) encode(buf *bytes.Buffer, v uint32) {
    55  	// Get the block state registered with the runtime IDs we have in the palette of the block storage
    56  	// as we need the name and data value to store.
    57  	name, props, _ := RuntimeIDToState(v)
    58  	_ = nbt.NewEncoderWithEncoding(buf, nbt.LittleEndian).Encode(blockEntry{Name: name, State: props, Version: CurrentBlockVersion})
    59  }
    60  func (blockPaletteEncoding) decode(buf *bytes.Buffer) (uint32, error) {
    61  	var m map[string]any
    62  	if err := nbt.NewDecoderWithEncoding(buf, nbt.LittleEndian).Decode(&m); err != nil {
    63  		return 0, fmt.Errorf("error decoding block palette entry: %w", err)
    64  	}
    65  
    66  	// Decode the name and version of the block entry.
    67  	name, _ := m["name"].(string)
    68  	version, _ := m["version"].(int32)
    69  
    70  	// Now check for a state field.
    71  	stateI, ok := m["states"]
    72  	if !ok {
    73  		// If it doesn't exist, this is likely a pre-1.13 block state, so decode the meta value instead.
    74  		meta, _ := m["val"].(int16)
    75  
    76  		// Upgrade the pre-1.13 state into a post-1.13 state.
    77  		state, ok := upgradeLegacyEntry(name, meta)
    78  		if !ok {
    79  			return 0, fmt.Errorf("cannot find mapping for legacy block entry: %v, %v", name, meta)
    80  		}
    81  
    82  		// Update the name, state, and version.
    83  		name = state.Name
    84  		stateI = state.State
    85  		version = state.Version
    86  	}
    87  	state, ok := stateI.(map[string]any)
    88  	if !ok {
    89  		return 0, fmt.Errorf("invalid state in block entry")
    90  	}
    91  
    92  	// Upgrade the block state if necessary.
    93  	upgraded := blockupgrader.Upgrade(blockupgrader.BlockState{
    94  		Name:       name,
    95  		Properties: state,
    96  		Version:    version,
    97  	})
    98  
    99  	v, ok := StateToRuntimeID(upgraded.Name, upgraded.Properties)
   100  	if !ok {
   101  		return 0, fmt.Errorf("cannot get runtime ID of block state %v{%+v} %v", upgraded.Name, upgraded.Properties, upgraded.Version)
   102  	}
   103  	return v, nil
   104  }
   105  
   106  // diskEncoding implements the Chunk encoding for writing to disk.
   107  type diskEncoding struct{}
   108  
   109  func (diskEncoding) network() byte { return 0 }
   110  func (diskEncoding) encodePalette(buf *bytes.Buffer, p *Palette, e paletteEncoding) {
   111  	if p.size != 0 {
   112  		_ = binary.Write(buf, binary.LittleEndian, uint32(p.Len()))
   113  	}
   114  	for _, v := range p.values {
   115  		e.encode(buf, v)
   116  	}
   117  }
   118  func (diskEncoding) decodePalette(buf *bytes.Buffer, blockSize paletteSize, e paletteEncoding) (*Palette, error) {
   119  	paletteCount := uint32(1)
   120  	if blockSize != 0 {
   121  		if err := binary.Read(buf, binary.LittleEndian, &paletteCount); err != nil {
   122  			return nil, fmt.Errorf("error reading palette entry count: %w", err)
   123  		}
   124  	}
   125  
   126  	var err error
   127  	palette := newPalette(blockSize, make([]uint32, paletteCount))
   128  	for i := uint32(0); i < paletteCount; i++ {
   129  		palette.values[i], err = e.decode(buf)
   130  		if err != nil {
   131  			return nil, err
   132  		}
   133  	}
   134  	if paletteCount == 0 {
   135  		return palette, fmt.Errorf("invalid palette entry count: found 0, but palette with %v bits per block must have at least 1 value", blockSize)
   136  	}
   137  	return palette, nil
   138  }
   139  
   140  // networkEncoding implements the Chunk encoding for sending over network.
   141  type networkEncoding struct{}
   142  
   143  func (networkEncoding) network() byte { return 1 }
   144  func (networkEncoding) encodePalette(buf *bytes.Buffer, p *Palette, _ paletteEncoding) {
   145  	if p.size != 0 {
   146  		_ = protocol.WriteVarint32(buf, int32(p.Len()))
   147  	}
   148  	for _, val := range p.values {
   149  		_ = protocol.WriteVarint32(buf, int32(val))
   150  	}
   151  }
   152  func (networkEncoding) decodePalette(buf *bytes.Buffer, blockSize paletteSize, _ paletteEncoding) (*Palette, error) {
   153  	var paletteCount int32 = 1
   154  	if blockSize != 0 {
   155  		if err := protocol.Varint32(buf, &paletteCount); err != nil {
   156  			return nil, fmt.Errorf("error reading palette entry count: %w", err)
   157  		}
   158  		if paletteCount <= 0 {
   159  			return nil, fmt.Errorf("invalid palette entry count %v", paletteCount)
   160  		}
   161  	}
   162  
   163  	blocks, temp := make([]uint32, paletteCount), int32(0)
   164  	for i := int32(0); i < paletteCount; i++ {
   165  		if err := protocol.Varint32(buf, &temp); err != nil {
   166  			return nil, fmt.Errorf("error decoding palette entry: %w", err)
   167  		}
   168  		blocks[i] = uint32(temp)
   169  	}
   170  	return &Palette{values: blocks, size: blockSize}, nil
   171  }