github.com/df-mc/dragonfly@v0.9.13/server/item/creative/creative.go (about) 1 package creative 2 3 import ( 4 _ "embed" 5 "github.com/df-mc/dragonfly/server/internal/nbtconv" 6 // The following three imports are essential for this package: They make sure this package is loaded after 7 // all these imports. This ensures that all items are registered before the creative items are registered 8 // in the init function in this package. 9 "github.com/df-mc/dragonfly/server/item" 10 "github.com/df-mc/dragonfly/server/world" 11 "github.com/sandertv/gophertunnel/minecraft/nbt" 12 ) 13 14 // Items returns a list with all items that have been registered as a creative item. These items will 15 // be accessible by players in-game who have creative mode enabled. 16 func Items() []item.Stack { 17 return creativeItemStacks 18 } 19 20 // RegisterItem registers an item as a creative item, exposing it in the creative inventory. 21 func RegisterItem(item item.Stack) { 22 creativeItemStacks = append(creativeItemStacks, item) 23 } 24 25 var ( 26 //go:embed creative_items.nbt 27 creativeItemData []byte 28 // creativeItemStacks holds a list of all item stacks that were registered to the creative inventory using 29 // RegisterItem. 30 creativeItemStacks []item.Stack 31 ) 32 33 // creativeItemEntry holds data of a creative item as present in the creative inventory. 34 type creativeItemEntry struct { 35 Name string `nbt:"name"` 36 Meta int16 `nbt:"meta"` 37 NBT map[string]any `nbt:"nbt,omitempty"` 38 BlockProperties map[string]any `nbt:"block_properties,omitempty"` 39 } 40 41 // init initialises the creative items, registering all creative items that have also been registered as 42 // normal items and are present in vanilla. 43 func init() { 44 var m []creativeItemEntry 45 if err := nbt.Unmarshal(creativeItemData, &m); err != nil { 46 panic(err) 47 } 48 for _, data := range m { 49 var ( 50 it world.Item 51 ok bool 52 ) 53 if len(data.BlockProperties) > 0 { 54 // Item with a block, try parsing the block, then try asserting that to an item. Blocks no longer 55 // have their metadata sent, but we still need to get that metadata in order to be able to register 56 // different block states as different items. 57 if b, ok := world.BlockByName(data.Name, data.BlockProperties); ok { 58 if it, ok = b.(world.Item); !ok { 59 continue 60 } 61 } 62 } else { 63 if it, ok = world.ItemByName(data.Name, data.Meta); !ok { 64 // The item wasn't registered, so don't register it as a creative item. 65 continue 66 } 67 if _, resultingMeta := it.EncodeItem(); resultingMeta != data.Meta { 68 // We found an item registered with that ID and a meta of 0, but we only need items with strictly 69 // the same meta here. 70 continue 71 } 72 } 73 74 if n, ok := it.(world.NBTer); ok { 75 if len(data.NBT) > 0 { 76 it = n.DecodeNBT(data.NBT).(world.Item) 77 } 78 } 79 80 st := item.NewStack(it, 1) 81 if len(data.NBT) > 0 { 82 var invalid bool 83 for _, e := range nbtconv.Slice(data.NBT, "ench") { 84 if v, ok := e.(map[string]any); ok { 85 t, ok := item.EnchantmentByID(int(nbtconv.Int16(v, "id"))) 86 if !ok { 87 invalid = true 88 break 89 } 90 st = st.WithEnchantments(item.NewEnchantment(t, int(nbtconv.Int16(v, "lvl")))) 91 } 92 } 93 if invalid { 94 // Invalid enchantment, skip this item. 95 continue 96 } 97 } 98 RegisterItem(st) 99 } 100 }