-
Notifications
You must be signed in to change notification settings - Fork 150
/
creative.go
100 lines (92 loc) · 3.14 KB
/
creative.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
package creative
import (
_ "embed"
"github.com/df-mc/dragonfly/server/internal/nbtconv"
// The following three imports are essential for this package: They make sure this package is loaded after
// all these imports. This ensures that all items are registered before the creative items are registered
// in the init function in this package.
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
"github.com/sandertv/gophertunnel/minecraft/nbt"
)
// Items returns a list with all items that have been registered as a creative item. These items will
// be accessible by players in-game who have creative mode enabled.
func Items() []item.Stack {
return creativeItemStacks
}
// RegisterItem registers an item as a creative item, exposing it in the creative inventory.
func RegisterItem(item item.Stack) {
creativeItemStacks = append(creativeItemStacks, item)
}
var (
//go:embed creative_items.nbt
creativeItemData []byte
// creativeItemStacks holds a list of all item stacks that were registered to the creative inventory using
// RegisterItem.
creativeItemStacks []item.Stack
)
// creativeItemEntry holds data of a creative item as present in the creative inventory.
type creativeItemEntry struct {
Name string `nbt:"name"`
Meta int16 `nbt:"meta"`
NBT map[string]any `nbt:"nbt,omitempty"`
BlockProperties map[string]any `nbt:"block_properties,omitempty"`
}
// init initialises the creative items, registering all creative items that have also been registered as
// normal items and are present in vanilla.
func init() {
var m []creativeItemEntry
if err := nbt.Unmarshal(creativeItemData, &m); err != nil {
panic(err)
}
for _, data := range m {
var (
it world.Item
ok bool
)
if len(data.BlockProperties) > 0 {
// Item with a block, try parsing the block, then try asserting that to an item. Blocks no longer
// have their metadata sent, but we still need to get that metadata in order to be able to register
// different block states as different items.
if b, ok := world.BlockByName(data.Name, data.BlockProperties); ok {
if it, ok = b.(world.Item); !ok {
continue
}
}
} else {
if it, ok = world.ItemByName(data.Name, data.Meta); !ok {
// The item wasn't registered, so don't register it as a creative item.
continue
}
if _, resultingMeta := it.EncodeItem(); resultingMeta != data.Meta {
// We found an item registered with that ID and a meta of 0, but we only need items with strictly
// the same meta here.
continue
}
}
if n, ok := it.(world.NBTer); ok {
if len(data.NBT) > 0 {
it = n.DecodeNBT(data.NBT).(world.Item)
}
}
st := item.NewStack(it, 1)
if len(data.NBT) > 0 {
var invalid bool
for _, e := range nbtconv.Slice(data.NBT, "ench") {
if v, ok := e.(map[string]any); ok {
t, ok := item.EnchantmentByID(int(nbtconv.Int16(v, "id")))
if !ok {
invalid = true
break
}
st = st.WithEnchantments(item.NewEnchantment(t, int(nbtconv.Int16(v, "lvl"))))
}
}
if invalid {
// Invalid enchantment, skip this item.
continue
}
}
RegisterItem(st)
}
}