26ed99fda6
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
133 lines
4.2 KiB
Go
133 lines
4.2 KiB
Go
package world
|
|
|
|
import (
|
|
_ "embed"
|
|
"fmt"
|
|
"github.com/df-mc/dragonfly/server/item/category"
|
|
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
|
"image"
|
|
)
|
|
|
|
// Item represents an item that may be added to an inventory. It has a method to encode the item to an ID and
|
|
// a metadata value.
|
|
type Item interface {
|
|
// EncodeItem encodes the item to its Minecraft representation, which consists of a numerical ID and a
|
|
// metadata value.
|
|
EncodeItem() (name string, meta int16)
|
|
}
|
|
|
|
// CustomItem represents an item that is non-vanilla and requires a resource pack and extra steps to show it
|
|
// to the client.
|
|
type CustomItem interface {
|
|
Item
|
|
// Name is the name that will be displayed on the item to all clients.
|
|
Name() string
|
|
// Texture is the Image of the texture for this item.
|
|
Texture() image.Image
|
|
// Category is the category the item will be listed under in the creative inventory.
|
|
Category() category.Category
|
|
}
|
|
|
|
// RegisterItem registers an item with the ID and meta passed. Once registered, items may be obtained from an
|
|
// ID and metadata value using itemByID().
|
|
// If an item with the ID and meta passed already exists, RegisterItem panics.
|
|
func RegisterItem(item Item) {
|
|
name, meta := item.EncodeItem()
|
|
h := itemHash{name: name, meta: meta}
|
|
|
|
if _, ok := items[h]; ok {
|
|
panic(fmt.Sprintf("item registered with name %v and meta %v already exists", name, meta))
|
|
}
|
|
if c, ok := item.(CustomItem); ok {
|
|
nextRID := int32(len(itemNamesToRuntimeIDs))
|
|
itemRuntimeIDsToNames[nextRID] = name
|
|
itemNamesToRuntimeIDs[name] = nextRID
|
|
|
|
customItems = append(customItems, c)
|
|
}
|
|
if _, ok := itemNamesToRuntimeIDs[name]; !ok {
|
|
panic(fmt.Sprintf("item name %v does not have a runtime ID", name))
|
|
}
|
|
items[h] = item
|
|
}
|
|
|
|
// itemHash is a combination of an item's name and metadata. It is used as a key in hash maps.
|
|
type itemHash struct {
|
|
name string
|
|
meta int16
|
|
}
|
|
|
|
var (
|
|
//go:embed vanilla_items.nbt
|
|
itemRuntimeIDData []byte
|
|
// items holds a list of all registered items, indexed using the itemHash created when calling
|
|
// Item.EncodeItem.
|
|
items = map[itemHash]Item{}
|
|
// customItems holds a list of all registered custom items.
|
|
customItems []CustomItem
|
|
// itemRuntimeIDsToNames holds a map to translate item runtime IDs to string IDs.
|
|
itemRuntimeIDsToNames = map[int32]string{}
|
|
// itemNamesToRuntimeIDs holds a map to translate item string IDs to runtime IDs.
|
|
itemNamesToRuntimeIDs = map[string]int32{}
|
|
)
|
|
|
|
// init reads all item entries from the resource JSON, and sets the according values in the runtime ID maps.
|
|
func init() {
|
|
var m map[string]struct {
|
|
RuntimeID int32 `nbt:"runtime_id"`
|
|
ComponentBased bool `nbt:"component_based"`
|
|
Version int32 `nbt:"version"`
|
|
Data map[string]any `nbt:"data,omitempty"`
|
|
}
|
|
err := nbt.Unmarshal(itemRuntimeIDData, &m)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
for name, e := range m {
|
|
itemNamesToRuntimeIDs[name] = e.RuntimeID
|
|
itemRuntimeIDsToNames[e.RuntimeID] = name
|
|
}
|
|
}
|
|
|
|
// ItemByName attempts to return an item by a name and a metadata value.
|
|
func ItemByName(name string, meta int16) (Item, bool) {
|
|
it, ok := items[itemHash{name: name, meta: meta}]
|
|
if !ok {
|
|
// Also try obtaining the item with a metadata value of 0, for cases with durability.
|
|
it, ok = items[itemHash{name: name}]
|
|
}
|
|
return it, ok
|
|
}
|
|
|
|
// ItemRuntimeID attempts to return the runtime ID of the Item passed. False is returned if the Item is not
|
|
// registered.
|
|
func ItemRuntimeID(i Item) (rid int32, meta int16, ok bool) {
|
|
name, meta := i.EncodeItem()
|
|
rid, ok = itemNamesToRuntimeIDs[name]
|
|
return rid, meta, ok
|
|
}
|
|
|
|
// ItemByRuntimeID attempts to return an Item by the runtime ID passed. If no item with that runtime ID exists,
|
|
// false is returned. ItemByRuntimeID also tries to find the item with a metadata value of 0.
|
|
func ItemByRuntimeID(rid int32, meta int16) (Item, bool) {
|
|
name, ok := itemRuntimeIDsToNames[rid]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
return ItemByName(name, meta)
|
|
}
|
|
|
|
// Items returns a slice of all registered items.
|
|
func Items() []Item {
|
|
m := make([]Item, 0, len(items))
|
|
for _, i := range items {
|
|
m = append(m, i)
|
|
}
|
|
return m
|
|
}
|
|
|
|
// CustomItems returns a slice of all registered custom items.
|
|
func CustomItems() []CustomItem {
|
|
return customItems
|
|
}
|