mirror of
https://github.com/CosmicStar98/bedrocktool.git
synced 2024-06-17 05:29:44 +00:00
149 lines
3.9 KiB
Go
149 lines
3.9 KiB
Go
package nbtconv
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/gob"
|
|
"github.com/df-mc/dragonfly/server/item"
|
|
"github.com/df-mc/dragonfly/server/world"
|
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
|
"sort"
|
|
)
|
|
|
|
// WriteItem encodes an item stack into a map that can be encoded using NBT.
|
|
func WriteItem(s item.Stack, disk bool) map[string]any {
|
|
tag := make(map[string]any)
|
|
if nbt, ok := s.Item().(world.NBTer); ok {
|
|
for k, v := range nbt.EncodeNBT() {
|
|
tag[k] = v
|
|
}
|
|
}
|
|
writeAnvilCost(tag, s)
|
|
writeDamage(tag, s, disk)
|
|
writeDisplay(tag, s)
|
|
writeDragonflyData(tag, s)
|
|
writeEnchantments(tag, s)
|
|
|
|
data := make(map[string]any)
|
|
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.
|
|
func WriteBlock(b world.Block) map[string]any {
|
|
name, properties := b.EncodeBlock()
|
|
return map[string]any{
|
|
"name": name,
|
|
"states": properties,
|
|
"version": chunk.CurrentBlockVersion,
|
|
}
|
|
}
|
|
|
|
// writeItemStack writes the name, metadata value, count and NBT of an item to a map ready for NBT encoding.
|
|
func writeItemStack(m, t map[string]any, s item.Stack) {
|
|
m["Name"], m["Damage"] = s.Item().EncodeItem()
|
|
if b, ok := s.Item().(world.Block); ok {
|
|
v := map[string]any{}
|
|
writeBlock(v, b)
|
|
m["Block"] = v
|
|
}
|
|
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.
|
|
func writeBlock(m map[string]any, b world.Block) {
|
|
m["name"], m["states"] = b.EncodeBlock()
|
|
m["version"] = chunk.CurrentBlockVersion
|
|
}
|
|
|
|
// writeDragonflyData writes additional data associated with an item.Stack to a map for NBT encoding.
|
|
func writeDragonflyData(m map[string]any, s item.Stack) {
|
|
if v := s.Values(); len(v) != 0 {
|
|
buf := new(bytes.Buffer)
|
|
if err := gob.NewEncoder(buf).Encode(mapToSlice(v)); err != nil {
|
|
panic("error encoding item user data: " + err.Error())
|
|
}
|
|
m["dragonflyData"] = buf.Bytes()
|
|
}
|
|
}
|
|
|
|
// mapToSlice converts a map to a slice of the type mapValue and orders the slice by the keys in the map to ensure a
|
|
// deterministic order.
|
|
func mapToSlice(m map[string]any) []mapValue {
|
|
values := make([]mapValue, 0, len(m))
|
|
for k, v := range m {
|
|
values = append(values, mapValue{K: k, V: v})
|
|
}
|
|
sort.Slice(values, func(i, j int) bool {
|
|
return values[i].K < values[j].K
|
|
})
|
|
return values
|
|
}
|
|
|
|
// mapValue represents a value in a map. It is used to convert maps to a slice and order the slice before encoding to
|
|
// NBT to ensure a deterministic output.
|
|
type mapValue struct {
|
|
K string
|
|
V any
|
|
}
|
|
|
|
// writeEnchantments writes the enchantments of an item to a map for NBT encoding.
|
|
func writeEnchantments(m map[string]any, s item.Stack) {
|
|
if len(s.Enchantments()) != 0 {
|
|
var enchantments []map[string]any
|
|
for _, e := range s.Enchantments() {
|
|
if eType, ok := item.EnchantmentID(e.Type()); ok {
|
|
enchantments = append(enchantments, map[string]any{
|
|
"id": int16(eType),
|
|
"lvl": int16(e.Level()),
|
|
})
|
|
}
|
|
}
|
|
m["ench"] = enchantments
|
|
}
|
|
}
|
|
|
|
// writeDisplay writes the display name and lore of an item to a map for NBT encoding.
|
|
func writeDisplay(m map[string]any, s item.Stack) {
|
|
name, lore := s.CustomName(), s.Lore()
|
|
v := map[string]any{}
|
|
if name != "" {
|
|
v["Name"] = name
|
|
}
|
|
if len(lore) != 0 {
|
|
v["Lore"] = lore
|
|
}
|
|
if len(v) != 0 {
|
|
m["display"] = v
|
|
}
|
|
}
|
|
|
|
// writeDamage writes the damage to an item.Stack (either an int16 for disk or int32 for network) to a map for NBT
|
|
// encoding.
|
|
func writeDamage(m map[string]any, s item.Stack, disk bool) {
|
|
if v, ok := m["Damage"]; !ok || v.(int16) == 0 {
|
|
if _, ok := s.Item().(item.Durable); ok {
|
|
if disk {
|
|
m["Damage"] = int16(s.MaxDurability() - s.Durability())
|
|
} else {
|
|
m["Damage"] = int32(s.MaxDurability() - s.Durability())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// writeAnvilCost ...
|
|
func writeAnvilCost(m map[string]any, s item.Stack) {
|
|
if cost := s.AnvilCost(); cost > 0 {
|
|
m["RepairCost"] = int32(cost)
|
|
}
|
|
}
|