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 }