github.com/df-mc/dragonfly@v0.9.13/server/world/item.go (about) 1 package world 2 3 import ( 4 _ "embed" 5 "fmt" 6 "github.com/df-mc/dragonfly/server/item/category" 7 "github.com/sandertv/gophertunnel/minecraft/nbt" 8 "image" 9 ) 10 11 // Item represents an item that may be added to an inventory. It has a method to encode the item to an ID and 12 // a metadata value. 13 type Item interface { 14 // EncodeItem encodes the item to its Minecraft representation, which consists of a numerical ID and a 15 // metadata value. 16 EncodeItem() (name string, meta int16) 17 } 18 19 // CustomItem represents an item that is non-vanilla and requires a resource pack and extra steps to show it 20 // to the client. 21 type CustomItem interface { 22 Item 23 // Name is the name that will be displayed on the item to all clients. 24 Name() string 25 // Texture is the Image of the texture for this item. 26 Texture() image.Image 27 // Category is the category the item will be listed under in the creative inventory. 28 Category() category.Category 29 } 30 31 // RegisterItem registers an item with the ID and meta passed. Once registered, items may be obtained from an 32 // ID and metadata value using itemByID(). 33 // If an item with the ID and meta passed already exists, RegisterItem panics. 34 func RegisterItem(item Item) { 35 name, meta := item.EncodeItem() 36 h := itemHash{name: name, meta: meta} 37 38 if _, ok := items[h]; ok { 39 panic(fmt.Sprintf("item registered with name %v and meta %v already exists", name, meta)) 40 } 41 if c, ok := item.(CustomItem); ok { 42 nextRID := int32(len(itemNamesToRuntimeIDs)) 43 itemRuntimeIDsToNames[nextRID] = name 44 itemNamesToRuntimeIDs[name] = nextRID 45 46 customItems = append(customItems, c) 47 } 48 if _, ok := itemNamesToRuntimeIDs[name]; !ok { 49 panic(fmt.Sprintf("item name %v does not have a runtime ID", name)) 50 } 51 items[h] = item 52 } 53 54 // itemHash is a combination of an item's name and metadata. It is used as a key in hash maps. 55 type itemHash struct { 56 name string 57 meta int16 58 } 59 60 var ( 61 //go:embed item_runtime_ids.nbt 62 itemRuntimeIDData []byte 63 // items holds a list of all registered items, indexed using the itemHash created when calling 64 // Item.EncodeItem. 65 items = map[itemHash]Item{} 66 // customItems holds a list of all registered custom items. 67 customItems []CustomItem 68 // itemRuntimeIDsToNames holds a map to translate item runtime IDs to string IDs. 69 itemRuntimeIDsToNames = map[int32]string{} 70 // itemNamesToRuntimeIDs holds a map to translate item string IDs to runtime IDs. 71 itemNamesToRuntimeIDs = map[string]int32{} 72 ) 73 74 // init reads all item entries from the resource JSON, and sets the according values in the runtime ID maps. 75 func init() { 76 var m map[string]int32 77 err := nbt.Unmarshal(itemRuntimeIDData, &m) 78 if err != nil { 79 panic(err) 80 } 81 for name, rid := range m { 82 itemNamesToRuntimeIDs[name] = rid 83 itemRuntimeIDsToNames[rid] = name 84 } 85 } 86 87 // ItemByName attempts to return an item by a name and a metadata value. 88 func ItemByName(name string, meta int16) (Item, bool) { 89 it, ok := items[itemHash{name: name, meta: meta}] 90 if !ok { 91 // Also try obtaining the item with a metadata value of 0, for cases with durability. 92 it, ok = items[itemHash{name: name}] 93 } 94 return it, ok 95 } 96 97 // ItemRuntimeID attempts to return the runtime ID of the Item passed. False is returned if the Item is not 98 // registered. 99 func ItemRuntimeID(i Item) (rid int32, meta int16, ok bool) { 100 name, meta := i.EncodeItem() 101 rid, ok = itemNamesToRuntimeIDs[name] 102 return rid, meta, ok 103 } 104 105 // ItemByRuntimeID attempts to return an Item by the runtime ID passed. If no item with that runtime ID exists, 106 // false is returned. ItemByRuntimeID also tries to find the item with a metadata value of 0. 107 func ItemByRuntimeID(rid int32, meta int16) (Item, bool) { 108 name, ok := itemRuntimeIDsToNames[rid] 109 if !ok { 110 return nil, false 111 } 112 return ItemByName(name, meta) 113 } 114 115 // Items returns a slice of all registered items. 116 func Items() []Item { 117 m := make([]Item, 0, len(items)) 118 for _, i := range items { 119 m = append(m, i) 120 } 121 return m 122 } 123 124 // CustomItems returns a slice of all registered custom items. 125 func CustomItems() []CustomItem { 126 return customItems 127 }