update nbtconv
This commit is contained in:
parent
a5f77eca3c
commit
3dadabf706
|
@ -8,11 +8,11 @@ import (
|
||||||
func InvFromNBT(inv *inventory.Inventory, items []any) {
|
func InvFromNBT(inv *inventory.Inventory, items []any) {
|
||||||
for _, itemData := range items {
|
for _, itemData := range items {
|
||||||
data, _ := itemData.(map[string]any)
|
data, _ := itemData.(map[string]any)
|
||||||
it := ReadItem(data, nil)
|
it := Item(data, nil)
|
||||||
if it.Empty() {
|
if it.Empty() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_ = inv.SetItem(int(Map[byte](data, "Slot")), it)
|
_ = inv.SetItem(int(Uint8(data, "Slot")), it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
package nbtconv
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/df-mc/dragonfly/server/block/cube"
|
|
||||||
"github.com/df-mc/dragonfly/server/item"
|
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
|
||||||
"github.com/go-gl/mathgl/mgl64"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Map reads a value of the type T from the map passed. Map never panics. If the key was not found in the map
|
|
||||||
// or if the value was of a different type, the default value of type T is returned.
|
|
||||||
func Map[T any](m map[string]any, key string) T {
|
|
||||||
v, _ := m[key].(T)
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapVec3 converts x, y and z values in an NBT map to an mgl64.Vec3.
|
|
||||||
func MapVec3(x map[string]any, k string) mgl64.Vec3 {
|
|
||||||
if i, ok := x[k].([]any); ok {
|
|
||||||
if len(i) != 3 {
|
|
||||||
return mgl64.Vec3{}
|
|
||||||
}
|
|
||||||
var v mgl64.Vec3
|
|
||||||
for index, f := range i {
|
|
||||||
f32, _ := f.(float32)
|
|
||||||
v[index] = float64(f32)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
} else if i, ok := x[k].([]float32); ok {
|
|
||||||
if len(i) != 3 {
|
|
||||||
return mgl64.Vec3{}
|
|
||||||
}
|
|
||||||
return mgl64.Vec3{float64(i[0]), float64(i[1]), float64(i[2])}
|
|
||||||
}
|
|
||||||
return mgl64.Vec3{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vec3ToFloat32Slice converts an mgl64.Vec3 to a []float32 with 3 elements.
|
|
||||||
func Vec3ToFloat32Slice(x mgl64.Vec3) []float32 {
|
|
||||||
return []float32{float32(x[0]), float32(x[1]), float32(x[2])}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapPos converts x, y and z values in an NBT map to a cube.Pos.
|
|
||||||
func MapPos(x map[string]any, k string) cube.Pos {
|
|
||||||
if i, ok := x[k].([]any); ok {
|
|
||||||
if len(i) != 3 {
|
|
||||||
return cube.Pos{}
|
|
||||||
}
|
|
||||||
var v cube.Pos
|
|
||||||
for index, f := range i {
|
|
||||||
f32, _ := f.(int32)
|
|
||||||
v[index] = int(f32)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
} else if i, ok := x[k].([]int32); ok {
|
|
||||||
if len(i) != 3 {
|
|
||||||
return cube.Pos{}
|
|
||||||
}
|
|
||||||
return cube.Pos{int(i[0]), int(i[1]), int(i[2])}
|
|
||||||
}
|
|
||||||
return cube.Pos{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PosToInt32Slice converts a cube.Pos to a []int32 with 3 elements.
|
|
||||||
func PosToInt32Slice(x cube.Pos) []int32 {
|
|
||||||
return []int32{int32(x[0]), int32(x[1]), int32(x[2])}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapBlock converts a block's name and properties in a map obtained by decoding NBT to a world.Block.
|
|
||||||
func MapBlock(x map[string]any, k string) world.Block {
|
|
||||||
if m, ok := x[k].(map[string]any); ok {
|
|
||||||
return ReadBlock(m)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MapItem converts an item's name, count, damage (and properties when it is a block) in a map obtained by decoding NBT
|
|
||||||
// to a world.Item.
|
|
||||||
func MapItem(x map[string]any, k string) item.Stack {
|
|
||||||
if m, ok := x[k].(map[string]any); ok {
|
|
||||||
s := readItemStack(m)
|
|
||||||
readDamage(m, &s, true)
|
|
||||||
readEnchantments(m, &s)
|
|
||||||
readDisplay(m, &s)
|
|
||||||
readDragonflyData(m, &s)
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return item.Stack{}
|
|
||||||
}
|
|
|
@ -3,78 +3,233 @@ package nbtconv
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||||||
"github.com/df-mc/dragonfly/server/item"
|
"github.com/df-mc/dragonfly/server/item"
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
"github.com/df-mc/dragonfly/server/world"
|
||||||
|
"github.com/go-gl/mathgl/mgl64"
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadItem decodes the data of an item into an item stack.
|
// Bool reads a uint8 value from a map at key k and returns true if it equals 1.
|
||||||
func ReadItem(data map[string]any, s *item.Stack) item.Stack {
|
func Bool(m map[string]any, k string) bool {
|
||||||
disk := s == nil
|
return Uint8(m, k) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uint8 reads a uint8 value from a map at key k.
|
||||||
|
func Uint8(m map[string]any, k string) uint8 {
|
||||||
|
v, _ := m[k].(uint8)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// String reads a string value from a map at key k.
|
||||||
|
func String(m map[string]any, k string) string {
|
||||||
|
v, _ := m[k].(string)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int16 reads an int16 value from a map at key k.
|
||||||
|
func Int16(m map[string]any, k string) int16 {
|
||||||
|
v, _ := m[k].(int16)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int32 reads an int32 value from a map at key k.
|
||||||
|
func Int32(m map[string]any, k string) int32 {
|
||||||
|
v, _ := m[k].(int32)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Int64 reads an int16 value from a map at key k.
|
||||||
|
func Int64(m map[string]any, k string) int64 {
|
||||||
|
v, _ := m[k].(int64)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// TickDuration reads a uint8/int16/in32 value from a map at key k and converts
|
||||||
|
// it from ticks to a time.Duration.
|
||||||
|
func TickDuration[T constraints.Integer](m map[string]any, k string) time.Duration {
|
||||||
|
var v time.Duration
|
||||||
|
switch any(*new(T)).(type) {
|
||||||
|
case uint8:
|
||||||
|
v = time.Duration(Uint8(m, k))
|
||||||
|
case int16:
|
||||||
|
v = time.Duration(Int16(m, k))
|
||||||
|
case int32:
|
||||||
|
v = time.Duration(Int32(m, k))
|
||||||
|
default:
|
||||||
|
panic("invalid tick duration value type")
|
||||||
|
}
|
||||||
|
return v * time.Millisecond * 50
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float32 reads a float32 value from a map at key k.
|
||||||
|
func Float32(m map[string]any, k string) float32 {
|
||||||
|
v, _ := m[k].(float32)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Float64 reads a float64 value from a map at key k.
|
||||||
|
func Float64(m map[string]any, k string) float64 {
|
||||||
|
v, _ := m[k].(float64)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slice reads a []any value from a map at key k.
|
||||||
|
func Slice(m map[string]any, k string) []any {
|
||||||
|
v, _ := m[k].([]any)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vec3 converts x, y and z values in an NBT map to an mgl64.Vec3.
|
||||||
|
func Vec3(x map[string]any, k string) mgl64.Vec3 {
|
||||||
|
if i, ok := x[k].([]any); ok {
|
||||||
|
if len(i) != 3 {
|
||||||
|
return mgl64.Vec3{}
|
||||||
|
}
|
||||||
|
var v mgl64.Vec3
|
||||||
|
for index, f := range i {
|
||||||
|
f32, _ := f.(float32)
|
||||||
|
v[index] = float64(f32)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
} else if i, ok := x[k].([]float32); ok {
|
||||||
|
if len(i) != 3 {
|
||||||
|
return mgl64.Vec3{}
|
||||||
|
}
|
||||||
|
return mgl64.Vec3{float64(i[0]), float64(i[1]), float64(i[2])}
|
||||||
|
}
|
||||||
|
return mgl64.Vec3{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vec3ToFloat32Slice converts an mgl64.Vec3 to a []float32 with 3 elements.
|
||||||
|
func Vec3ToFloat32Slice(x mgl64.Vec3) []float32 {
|
||||||
|
return []float32{float32(x[0]), float32(x[1]), float32(x[2])}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pos converts x, y and z values in an NBT map to a cube.Pos.
|
||||||
|
func Pos(x map[string]any, k string) cube.Pos {
|
||||||
|
if i, ok := x[k].([]any); ok {
|
||||||
|
if len(i) != 3 {
|
||||||
|
return cube.Pos{}
|
||||||
|
}
|
||||||
|
var v cube.Pos
|
||||||
|
for index, f := range i {
|
||||||
|
f32, _ := f.(int32)
|
||||||
|
v[index] = int(f32)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
} else if i, ok := x[k].([]int32); ok {
|
||||||
|
if len(i) != 3 {
|
||||||
|
return cube.Pos{}
|
||||||
|
}
|
||||||
|
return cube.Pos{int(i[0]), int(i[1]), int(i[2])}
|
||||||
|
}
|
||||||
|
return cube.Pos{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PosToInt32Slice converts a cube.Pos to a []int32 with 3 elements.
|
||||||
|
func PosToInt32Slice(x cube.Pos) []int32 {
|
||||||
|
return []int32{int32(x[0]), int32(x[1]), int32(x[2])}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapItem converts an item's name, count, damage (and properties when it is a block) in a map obtained by decoding NBT
|
||||||
|
// to a world.Item.
|
||||||
|
func MapItem(x map[string]any, k string) item.Stack {
|
||||||
|
if m, ok := x[k].(map[string]any); ok {
|
||||||
|
tag, ok := m["tag"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
tag = map[string]any{}
|
||||||
|
}
|
||||||
|
|
||||||
|
s := readItemStack(m, tag)
|
||||||
|
readDamage(tag, &s, true)
|
||||||
|
readEnchantments(tag, &s)
|
||||||
|
readDisplay(tag, &s)
|
||||||
|
readDragonflyData(tag, &s)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return item.Stack{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item decodes the data of an item into an item stack.
|
||||||
|
func Item(data map[string]any, s *item.Stack) item.Stack {
|
||||||
|
disk, tag := s == nil, data
|
||||||
if disk {
|
if disk {
|
||||||
a := readItemStack(data)
|
t, ok := data["tag"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t = map[string]any{}
|
||||||
|
}
|
||||||
|
tag = t
|
||||||
|
|
||||||
|
a := readItemStack(data, tag)
|
||||||
s = &a
|
s = &a
|
||||||
}
|
}
|
||||||
readDamage(data, s, disk)
|
|
||||||
readAnvilCost(data, s)
|
readAnvilCost(tag, s)
|
||||||
readDisplay(data, s)
|
readDamage(tag, s, disk)
|
||||||
readEnchantments(data, s)
|
readDisplay(tag, s)
|
||||||
readDragonflyData(data, s)
|
readDragonflyData(tag, s)
|
||||||
|
readEnchantments(tag, s)
|
||||||
return *s
|
return *s
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadBlock decodes the data of a block into a world.Block.
|
// Block decodes the data of a block into a world.Block.
|
||||||
func ReadBlock(m map[string]any) world.Block {
|
func Block(m map[string]any, k string) world.Block {
|
||||||
name, _ := m["name"].(string)
|
if mk, ok := m[k].(map[string]any); ok {
|
||||||
properties, _ := m["states"].(map[string]any)
|
name, _ := mk["name"].(string)
|
||||||
b, _ := world.BlockByName(name, properties)
|
properties, _ := mk["states"].(map[string]any)
|
||||||
return b
|
b, _ := world.BlockByName(name, properties)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readItemStack reads an item.Stack from the NBT in the map passed.
|
// readItemStack reads an item.Stack from the NBT in the map passed.
|
||||||
func readItemStack(m map[string]any) item.Stack {
|
func readItemStack(m, t map[string]any) item.Stack {
|
||||||
var it world.Item
|
var it world.Item
|
||||||
if blockItem, ok := MapBlock(m, "Block").(world.Item); ok {
|
if blockItem, ok := Block(m, "Block").(world.Item); ok {
|
||||||
it = blockItem
|
it = blockItem
|
||||||
}
|
}
|
||||||
if v, ok := world.ItemByName(Map[string](m, "Name"), Map[int16](m, "Damage")); ok {
|
if v, ok := world.ItemByName(String(m, "Name"), Int16(m, "Damage")); ok {
|
||||||
it = v
|
it = v
|
||||||
}
|
}
|
||||||
if it == nil {
|
if it == nil {
|
||||||
return item.Stack{}
|
return item.Stack{}
|
||||||
}
|
}
|
||||||
if n, ok := it.(world.NBTer); ok {
|
if n, ok := it.(world.NBTer); ok {
|
||||||
it = n.DecodeNBT(m).(world.Item)
|
it = n.DecodeNBT(t).(world.Item)
|
||||||
}
|
}
|
||||||
return item.NewStack(it, int(Map[byte](m, "Count")))
|
return item.NewStack(it, int(Uint8(m, "Count")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// readDamage reads the damage value stored in the NBT with the Damage tag and saves it to the item.Stack passed.
|
// readDamage reads the damage value stored in the NBT with the Damage tag and saves it to the item.Stack passed.
|
||||||
func readDamage(m map[string]any, s *item.Stack, disk bool) {
|
func readDamage(m map[string]any, s *item.Stack, disk bool) {
|
||||||
if disk {
|
if disk {
|
||||||
*s = s.Damage(int(Map[int16](m, "Damage")))
|
*s = s.Damage(int(Int16(m, "Damage")))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
*s = s.Damage(int(Map[int32](m, "Damage")))
|
*s = s.Damage(int(Int32(m, "Damage")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// readAnvilCost ...
|
// readAnvilCost ...
|
||||||
func readAnvilCost(m map[string]any, s *item.Stack) {
|
func readAnvilCost(m map[string]any, s *item.Stack) {
|
||||||
*s = s.WithAnvilCost(int(Map[int32](m, "RepairCost")))
|
*s = s.WithAnvilCost(int(Int32(m, "RepairCost")))
|
||||||
}
|
}
|
||||||
|
|
||||||
// readEnchantments reads the enchantments stored in the ench tag of the NBT passed and stores it into an item.Stack.
|
// readEnchantments reads the enchantments stored in the ench tag of the NBT passed and stores it into an item.Stack.
|
||||||
func readEnchantments(m map[string]any, s *item.Stack) {
|
func readEnchantments(m map[string]any, s *item.Stack) {
|
||||||
enchantments, ok := m["ench"].([]map[string]any)
|
enchantments, ok := m["ench"].([]map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
for _, e := range Map[[]any](m, "ench") {
|
for _, e := range Slice(m, "ench") {
|
||||||
if v, ok := e.(map[string]any); ok {
|
if v, ok := e.(map[string]any); ok {
|
||||||
enchantments = append(enchantments, v)
|
enchantments = append(enchantments, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, ench := range enchantments {
|
for _, ench := range enchantments {
|
||||||
if t, ok := item.EnchantmentByID(int(Map[int16](ench, "id"))); ok {
|
if t, ok := item.EnchantmentByID(int(Int16(ench, "id"))); ok {
|
||||||
*s = s.WithEnchantments(item.NewEnchantment(t, int(Map[int16](ench, "lvl"))))
|
*s = s.WithEnchantments(item.NewEnchantment(t, int(Int16(ench, "lvl"))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,33 +3,35 @@ package nbtconv
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/df-mc/dragonfly/server/item"
|
"github.com/df-mc/dragonfly/server/item"
|
||||||
"github.com/df-mc/dragonfly/server/world"
|
"github.com/df-mc/dragonfly/server/world"
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WriteItem encodes an item stack into a map that can be encoded using NBT.
|
// WriteItem encodes an item stack into a map that can be encoded using NBT.
|
||||||
func WriteItem(s item.Stack, disk bool) map[string]any {
|
func WriteItem(s item.Stack, disk bool) map[string]any {
|
||||||
m := make(map[string]any)
|
tag := make(map[string]any)
|
||||||
if nbt, ok := s.Item().(world.NBTer); ok {
|
if nbt, ok := s.Item().(world.NBTer); ok {
|
||||||
for k, v := range nbt.EncodeNBT() {
|
for k, v := range nbt.EncodeNBT() {
|
||||||
m[k] = v
|
tag[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if disk {
|
writeAnvilCost(tag, s)
|
||||||
writeItemStack(m, s)
|
writeDamage(tag, s, disk)
|
||||||
}
|
writeDisplay(tag, s)
|
||||||
t := make(map[string]any)
|
writeDragonflyData(tag, s)
|
||||||
writeDamage(t, s, disk)
|
writeEnchantments(tag, s)
|
||||||
writeAnvilCost(t, s)
|
|
||||||
writeDisplay(t, s)
|
|
||||||
writeEnchantments(t, s)
|
|
||||||
m["tag"] = t
|
|
||||||
|
|
||||||
writeDragonflyData(m, s)
|
data := make(map[string]any)
|
||||||
return m
|
if disk {
|
||||||
|
writeItemStack(data, tag, s)
|
||||||
|
} else {
|
||||||
|
for k, v := range tag {
|
||||||
|
data[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteBlock encodes a world.Block into a map that can be encoded using NBT.
|
// WriteBlock encodes a world.Block into a map that can be encoded using NBT.
|
||||||
|
@ -43,7 +45,7 @@ func WriteBlock(b world.Block) map[string]any {
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeItemStack writes the name, metadata value, count and NBT of an item to a map ready for NBT encoding.
|
// writeItemStack writes the name, metadata value, count and NBT of an item to a map ready for NBT encoding.
|
||||||
func writeItemStack(m map[string]any, s item.Stack) {
|
func writeItemStack(m, t map[string]any, s item.Stack) {
|
||||||
m["Name"], m["Damage"] = s.Item().EncodeItem()
|
m["Name"], m["Damage"] = s.Item().EncodeItem()
|
||||||
if b, ok := s.Item().(world.Block); ok {
|
if b, ok := s.Item().(world.Block); ok {
|
||||||
v := map[string]any{}
|
v := map[string]any{}
|
||||||
|
@ -51,6 +53,9 @@ func writeItemStack(m map[string]any, s item.Stack) {
|
||||||
m["Block"] = v
|
m["Block"] = v
|
||||||
}
|
}
|
||||||
m["Count"] = byte(s.Count())
|
m["Count"] = byte(s.Count())
|
||||||
|
if len(t) > 0 {
|
||||||
|
m["tag"] = t
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeBlock writes the name, properties and version of a block to a map ready for NBT encoding.
|
// writeBlock writes the name, properties and version of a block to a map ready for NBT encoding.
|
||||||
|
|
Loading…
Reference in New Issue