github.com/df-mc/dragonfly@v0.9.13/server/internal/nbtconv/read.go (about) 1 package nbtconv 2 3 import ( 4 "bytes" 5 "encoding/gob" 6 "github.com/df-mc/dragonfly/server/block/cube" 7 "github.com/df-mc/dragonfly/server/item" 8 "github.com/df-mc/dragonfly/server/world" 9 "github.com/go-gl/mathgl/mgl64" 10 "golang.org/x/exp/constraints" 11 "time" 12 ) 13 14 // Bool reads a uint8 value from a map at key k and returns true if it equals 1. 15 func Bool(m map[string]any, k string) bool { 16 return Uint8(m, k) == 1 17 } 18 19 // Uint8 reads a uint8 value from a map at key k. 20 func Uint8(m map[string]any, k string) uint8 { 21 v, _ := m[k].(uint8) 22 return v 23 } 24 25 // String reads a string value from a map at key k. 26 func String(m map[string]any, k string) string { 27 v, _ := m[k].(string) 28 return v 29 } 30 31 // Int16 reads an int16 value from a map at key k. 32 func Int16(m map[string]any, k string) int16 { 33 v, _ := m[k].(int16) 34 return v 35 } 36 37 // Int32 reads an int32 value from a map at key k. 38 func Int32(m map[string]any, k string) int32 { 39 v, _ := m[k].(int32) 40 return v 41 } 42 43 // Int64 reads an int16 value from a map at key k. 44 func Int64(m map[string]any, k string) int64 { 45 v, _ := m[k].(int64) 46 return v 47 } 48 49 // TickDuration reads a uint8/int16/in32 value from a map at key k and converts 50 // it from ticks to a time.Duration. 51 func TickDuration[T constraints.Integer](m map[string]any, k string) time.Duration { 52 var v time.Duration 53 switch any(*new(T)).(type) { 54 case uint8: 55 v = time.Duration(Uint8(m, k)) 56 case int16: 57 v = time.Duration(Int16(m, k)) 58 case int32: 59 v = time.Duration(Int32(m, k)) 60 default: 61 panic("invalid tick duration value type") 62 } 63 return v * time.Millisecond * 50 64 } 65 66 // Float32 reads a float32 value from a map at key k. 67 func Float32(m map[string]any, k string) float32 { 68 v, _ := m[k].(float32) 69 return v 70 } 71 72 // Rotation reads a cube.Rotation from the map passed. 73 func Rotation(m map[string]any) cube.Rotation { 74 return cube.Rotation{float64(Float32(m, "Yaw")), float64(Float32(m, "Pitch"))} 75 } 76 77 // Float64 reads a float64 value from a map at key k. 78 func Float64(m map[string]any, k string) float64 { 79 v, _ := m[k].(float64) 80 return v 81 } 82 83 // Slice reads a []any value from a map at key k. 84 func Slice(m map[string]any, k string) []any { 85 v, _ := m[k].([]any) 86 return v 87 } 88 89 // Vec3 converts x, y and z values in an NBT map to an mgl64.Vec3. 90 func Vec3(x map[string]any, k string) mgl64.Vec3 { 91 if i, ok := x[k].([]any); ok { 92 if len(i) != 3 { 93 return mgl64.Vec3{} 94 } 95 var v mgl64.Vec3 96 for index, f := range i { 97 f32, _ := f.(float32) 98 v[index] = float64(f32) 99 } 100 return v 101 } else if i, ok := x[k].([]float32); ok { 102 if len(i) != 3 { 103 return mgl64.Vec3{} 104 } 105 return mgl64.Vec3{float64(i[0]), float64(i[1]), float64(i[2])} 106 } 107 return mgl64.Vec3{} 108 } 109 110 // Vec3ToFloat32Slice converts an mgl64.Vec3 to a []float32 with 3 elements. 111 func Vec3ToFloat32Slice(x mgl64.Vec3) []float32 { 112 return []float32{float32(x[0]), float32(x[1]), float32(x[2])} 113 } 114 115 // Pos converts x, y and z values in an NBT map to a cube.Pos. 116 func Pos(x map[string]any, k string) cube.Pos { 117 if i, ok := x[k].([]any); ok { 118 if len(i) != 3 { 119 return cube.Pos{} 120 } 121 var v cube.Pos 122 for index, f := range i { 123 f32, _ := f.(int32) 124 v[index] = int(f32) 125 } 126 return v 127 } else if i, ok := x[k].([]int32); ok { 128 if len(i) != 3 { 129 return cube.Pos{} 130 } 131 return cube.Pos{int(i[0]), int(i[1]), int(i[2])} 132 } 133 return cube.Pos{} 134 } 135 136 // PosToInt32Slice converts a cube.Pos to a []int32 with 3 elements. 137 func PosToInt32Slice(x cube.Pos) []int32 { 138 return []int32{int32(x[0]), int32(x[1]), int32(x[2])} 139 } 140 141 // MapItem converts an item's name, count, damage (and properties when it is a block) in a map obtained by decoding NBT 142 // to a world.Item. 143 func MapItem(x map[string]any, k string) item.Stack { 144 if m, ok := x[k].(map[string]any); ok { 145 tag, ok := m["tag"].(map[string]any) 146 if !ok { 147 tag = map[string]any{} 148 } 149 150 s := readItemStack(m, tag) 151 readDamage(tag, &s, true) 152 readEnchantments(tag, &s) 153 readDisplay(tag, &s) 154 readDragonflyData(tag, &s) 155 return s 156 } 157 return item.Stack{} 158 } 159 160 // Item decodes the data of an item into an item stack. 161 func Item(data map[string]any, s *item.Stack) item.Stack { 162 disk, tag := s == nil, data 163 if disk { 164 t, ok := data["tag"].(map[string]any) 165 if !ok { 166 t = map[string]any{} 167 } 168 tag = t 169 170 a := readItemStack(data, tag) 171 s = &a 172 } 173 174 readAnvilCost(tag, s) 175 readDamage(tag, s, disk) 176 readDisplay(tag, s) 177 readDragonflyData(tag, s) 178 readEnchantments(tag, s) 179 return *s 180 } 181 182 // Block decodes the data of a block into a world.Block. 183 func Block(m map[string]any, k string) world.Block { 184 if mk, ok := m[k].(map[string]any); ok { 185 name, _ := mk["name"].(string) 186 properties, _ := mk["states"].(map[string]any) 187 b, _ := world.BlockByName(name, properties) 188 return b 189 } 190 return nil 191 } 192 193 // readItemStack reads an item.Stack from the NBT in the map passed. 194 func readItemStack(m, t map[string]any) item.Stack { 195 var it world.Item 196 if blockItem, ok := Block(m, "Block").(world.Item); ok { 197 it = blockItem 198 } 199 if v, ok := world.ItemByName(String(m, "Name"), Int16(m, "Damage")); ok { 200 it = v 201 } 202 if it == nil { 203 return item.Stack{} 204 } 205 if n, ok := it.(world.NBTer); ok { 206 it = n.DecodeNBT(t).(world.Item) 207 } 208 return item.NewStack(it, int(Uint8(m, "Count"))) 209 } 210 211 // readDamage reads the damage value stored in the NBT with the Damage tag and saves it to the item.Stack passed. 212 func readDamage(m map[string]any, s *item.Stack, disk bool) { 213 if disk { 214 *s = s.Damage(int(Int16(m, "Damage"))) 215 return 216 } 217 *s = s.Damage(int(Int32(m, "Damage"))) 218 } 219 220 // readAnvilCost ... 221 func readAnvilCost(m map[string]any, s *item.Stack) { 222 *s = s.WithAnvilCost(int(Int32(m, "RepairCost"))) 223 } 224 225 // readEnchantments reads the enchantments stored in the ench tag of the NBT passed and stores it into an item.Stack. 226 func readEnchantments(m map[string]any, s *item.Stack) { 227 enchantments, ok := m["ench"].([]map[string]any) 228 if !ok { 229 for _, e := range Slice(m, "ench") { 230 if v, ok := e.(map[string]any); ok { 231 enchantments = append(enchantments, v) 232 } 233 } 234 } 235 for _, ench := range enchantments { 236 if t, ok := item.EnchantmentByID(int(Int16(ench, "id"))); ok { 237 *s = s.WithEnchantments(item.NewEnchantment(t, int(Int16(ench, "lvl")))) 238 } 239 } 240 } 241 242 // readDisplay reads the display data present in the display field in the NBT. It includes a custom name of the item 243 // and the lore. 244 func readDisplay(m map[string]any, s *item.Stack) { 245 if display, ok := m["display"].(map[string]any); ok { 246 if name, ok := display["Name"].(string); ok { 247 // Only add the custom name if actually set. 248 *s = s.WithCustomName(name) 249 } 250 if lore, ok := display["Lore"].([]string); ok { 251 *s = s.WithLore(lore...) 252 } else if lore, ok := display["Lore"].([]any); ok { 253 loreLines := make([]string, 0, len(lore)) 254 for _, l := range lore { 255 loreLines = append(loreLines, l.(string)) 256 } 257 *s = s.WithLore(loreLines...) 258 } 259 } 260 } 261 262 // readDragonflyData reads data written to the dragonflyData field in the NBT of an item and adds it to the item.Stack 263 // passed. 264 func readDragonflyData(m map[string]any, s *item.Stack) { 265 if customData, ok := m["dragonflyData"]; ok { 266 d, ok := customData.([]byte) 267 if !ok { 268 if itf, ok := customData.([]any); ok { 269 for _, v := range itf { 270 b, _ := v.(byte) 271 d = append(d, b) 272 } 273 } 274 } 275 var values []mapValue 276 if err := gob.NewDecoder(bytes.NewBuffer(d)).Decode(&values); err != nil { 277 panic("error decoding item user data: " + err.Error()) 278 } 279 for _, val := range values { 280 *s = s.WithValue(val.K, val.V) 281 } 282 } 283 }