forked from df-mc/dragonfly
/
item.go
199 lines (185 loc) · 5.8 KB
/
item.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
package nbtconv
import (
"bytes"
"encoding/gob"
"github.com/sunproxy/sunfly/dragonfly/item"
"github.com/sunproxy/sunfly/dragonfly/item/inventory"
"github.com/sunproxy/sunfly/dragonfly/world"
_ "unsafe" // Imported for compiler directives.
)
//go:linkname world_itemByName github.com/sunproxy/sunfly/dragonfly/world.itemByName
//noinspection ALL
func world_itemByName(name string, meta int16) (world.Item, bool)
//go:linkname world_itemToName github.com/sunproxy/sunfly/dragonfly/world.itemToName
//noinspection ALL
func world_itemToName(it world.Item) (name string, meta int16)
//go:linkname item_enchantmentByID github.com/sunproxy/sunfly/dragonfly/item.enchantmentByID
//noinspection ALL
func item_enchantmentByID(id int) (item.Enchantment, bool)
//go:linkname item_idByEnchantment github.com/sunproxy/sunfly/dragonfly/item.idByEnchantment
//noinspection ALL
func item_idByEnchantment(ench item.Enchantment) (int, bool)
//go:linkname item_values github.com/sunproxy/sunfly/dragonfly/item.values
//noinspection ALL
func item_values(s item.Stack) map[string]interface{}
// ItemFromNBT decodes the data of an item into an item stack.
func ItemFromNBT(data map[string]interface{}, s *item.Stack) item.Stack {
disk := s == nil
if disk {
it, ok := world_itemByName(readString(data, "Name"), readInt16(data, "Damage"))
if !ok {
return item.Stack{}
}
if nbt, ok := it.(world.NBTer); ok {
it = nbt.DecodeNBT(data).(world.Item)
}
a := item.NewStack(it, int(readByte(data, "Count")))
s = &a
if _, ok := s.Item().(item.Durable); ok {
*s = s.Damage(int(readInt16(data, "Damage")))
}
} else if !disk {
if _, ok := s.Item().(item.Durable); ok {
*s = s.Damage(int(readInt32(data, "Damage")))
}
}
if displayInterface, ok := data["display"]; ok {
display, ok := displayInterface.(map[string]interface{})
if ok {
if nameInterface, ok := display["Name"]; ok {
if name, ok := nameInterface.(string); ok {
*s = s.WithCustomName(name)
}
}
if loreInterface, ok := display["Lore"]; ok {
if lore, ok := loreInterface.([]string); ok {
*s = s.WithLore(lore...)
}
}
}
}
if enchantmentList, ok := data["ench"]; ok {
enchantments, ok := enchantmentList.([]map[string]interface{})
if ok {
for _, ench := range enchantments {
if e, ok := item_enchantmentByID(int(readInt16(ench, "id"))); ok {
e = e.WithLevel(int(readInt16(ench, "lvl")))
*s = s.WithEnchantment(e)
}
}
}
}
if customData, ok := data["dragonflyData"]; ok {
d, _ := customData.([]byte)
var m map[string]interface{}
if err := gob.NewDecoder(bytes.NewBuffer(d)).Decode(&m); err != nil {
panic("error decoding item user data: " + err.Error())
}
for k, v := range m {
*s = s.WithValue(k, v)
}
}
return *s
}
// ItemToNBT encodes an item stack to its NBT representation.
func ItemToNBT(s item.Stack, network bool) map[string]interface{} {
m := make(map[string]interface{})
if nbt, ok := s.Item().(world.NBTer); ok {
m = nbt.EncodeNBT()
}
if !network {
m["Name"], m["Damage"] = world_itemToName(s.Item())
m["Count"] = byte(s.Count())
if _, ok := s.Item().(item.Durable); ok {
m["Damage"] = int16(s.MaxDurability() - s.Durability())
}
} else if network {
if _, ok := s.Item().(item.Durable); ok {
m["Damage"] = int32(s.MaxDurability() - s.Durability())
}
}
if s.CustomName() != "" {
m["display"] = map[string]interface{}{"Name": s.CustomName()}
}
if len(s.Lore()) != 0 {
if display, ok := m["display"]; ok {
display.(map[string]interface{})["Lore"] = s.Lore()
} else {
m["display"] = map[string]interface{}{"Lore": s.Lore()}
}
}
if len(s.Enchantments()) != 0 {
var enchantments []map[string]interface{}
for _, ench := range s.Enchantments() {
if enchType, ok := item_idByEnchantment(ench); ok {
enchantments = append(enchantments, map[string]interface{}{
"id": int16(enchType),
"lvl": int16(ench.Level()),
})
}
}
m["ench"] = enchantments
}
if len(item_values(s)) != 0 {
buf := new(bytes.Buffer)
if err := gob.NewEncoder(buf).Encode(item_values(s)); err != nil {
panic("error encoding item user data: " + err.Error())
}
m["dragonflyData"] = buf.Bytes()
}
return m
}
// InvFromNBT decodes the data of an NBT slice into the inventory passed.
func InvFromNBT(inv *inventory.Inventory, items []interface{}) {
for _, itemData := range items {
data, _ := itemData.(map[string]interface{})
it := ItemFromNBT(data, nil)
if it.Empty() {
continue
}
_ = inv.SetItem(int(readByte(data, "Slot")), it)
}
}
// InvToNBT encodes an inventory to a data slice which may be encoded as NBT.
func InvToNBT(inv *inventory.Inventory) []map[string]interface{} {
var items []map[string]interface{}
for index, i := range inv.All() {
if i.Empty() {
continue
}
data := ItemToNBT(i, false)
data["Slot"] = byte(index)
items = append(items, data)
}
return items
}
// readByte reads a byte from a map at the key passed.
func readByte(m map[string]interface{}, key string) byte {
v := m[key]
b, _ := v.(byte)
return b
}
// readInt16 reads an int16 from a map at the key passed.
//noinspection GoCommentLeadingSpace
func readInt16(m map[string]interface{}, key string) int16 {
//lint:ignore S1005 Double assignment is done explicitly to prevent panics.
v, _ := m[key]
b, _ := v.(int16)
return b
}
// readInt32 reads an int32 from a map at the key passed.
//noinspection GoCommentLeadingSpace
func readInt32(m map[string]interface{}, key string) int32 {
//lint:ignore S1005 Double assignment is done explicitly to prevent panics.
v, _ := m[key]
b, _ := v.(int32)
return b
}
// readString reads a string from a map at the key passed.
//noinspection GoCommentLeadingSpace
func readString(m map[string]interface{}, key string) string {
//lint:ignore S1005 Double assignment is done explicitly to prevent panics.
v, _ := m[key]
b, _ := v.(string)
return b
}