Files
legacy-version/mapping/item.go

180 lines
5.1 KiB
Go

package mapping
import (
"encoding/base64"
"encoding/json"
"github.com/sandertv/gophertunnel/minecraft/nbt"
"sync"
)
type Item interface {
// ItemRuntimeIDToName converts an item runtime ID to a string ID.
ItemRuntimeIDToName(int32) (string, bool)
// ItemNameToRuntimeID converts a string ID to an item runtime ID.
ItemNameToRuntimeID(string) (int32, bool)
// ItemRuntimeIDToVersion converts an item runtime ID to its version.
ItemRuntimeIDToVersion(int32) (uint8, bool)
// ItemRuntimeIDToData converts an item runtime ID to its data.
ItemRuntimeIDToData(int32) (map[string]any, bool)
RegisterEntry(string) int32
RegisterEntryRID(string, int32, uint8, map[string]any)
Air() int32
ItemVersion() uint16
ItemEntries() []ItemEntry
}
type ItemEntry struct {
Name string
RuntimeID int16
ComponentBased bool
Version uint8
Data map[string]any
}
type DefaultItemMapping struct {
mu sync.Mutex
// 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
// itemRuntimeIDToVersion holds a map to translate item runtime IDs to versions.
itemRuntimeIDToVersion map[int32]uint8
// itemRuntimeIDToData holds a map to translate item runtime IDs to data.
itemRuntimeIDToData map[int32]map[string]any
// itemEntries holds a map to translate item string IDs to runtime IDs.
itemEntries []ItemEntry
airRID int32
itemVersion uint16
}
func NewItemMapping(requiredItemList []byte, itemVersion uint16) *DefaultItemMapping {
itemRuntimeIDsToNames := make(map[int32]string)
itemNamesToRuntimeIDs := make(map[string]int32)
itemRuntimeIDToVersion := make(map[int32]uint8)
itemRuntimeIDToData := make(map[int32]map[string]any)
itemEntries := make([]ItemEntry, 0, 1600)
var airRID *int32
var m map[string]struct {
RuntimeID int16 `json:"runtime_id"`
ComponentBased bool `json:"component_based"`
Version *uint8 `json:"version"`
Data string `json:"component_nbt,omitempty"`
}
if err := json.Unmarshal(requiredItemList, &m); err != nil {
panic(err)
}
for name, data := range m {
rid := int32(data.RuntimeID)
if name == "minecraft:air" {
airRID = &rid
}
entry := ItemEntry{
Name: name,
RuntimeID: data.RuntimeID,
ComponentBased: data.ComponentBased,
}
itemNamesToRuntimeIDs[name] = rid
itemRuntimeIDsToNames[rid] = name
if data.Version != nil {
itemRuntimeIDToVersion[rid] = *data.Version
entry.Version = *data.Version
}
if data.Data != "" {
var nbtData map[string]any
nbtBytes, err := base64.StdEncoding.DecodeString(data.Data)
if err != nil {
panic(err)
}
if err := nbt.Unmarshal(nbtBytes, &nbtData); err != nil {
panic(err)
}
itemRuntimeIDToData[rid] = nbtData
entry.Data = nbtData
}
itemEntries = append(itemEntries, entry)
}
if airRID == nil {
panic("couldn't find air")
}
return &DefaultItemMapping{itemRuntimeIDsToNames: itemRuntimeIDsToNames, itemNamesToRuntimeIDs: itemNamesToRuntimeIDs, itemRuntimeIDToVersion: itemRuntimeIDToVersion, airRID: *airRID, itemVersion: itemVersion, itemRuntimeIDToData: itemRuntimeIDToData, itemEntries: itemEntries}
}
func (m *DefaultItemMapping) ItemRuntimeIDToName(runtimeID int32) (name string, found bool) {
defer m.mu.Unlock()
m.mu.Lock()
name, ok := m.itemRuntimeIDsToNames[runtimeID]
return name, ok
}
func (m *DefaultItemMapping) ItemNameToRuntimeID(name string) (runtimeID int32, found bool) {
defer m.mu.Unlock()
m.mu.Lock()
rid, ok := m.itemNamesToRuntimeIDs[name]
return rid, ok
}
func (m *DefaultItemMapping) ItemRuntimeIDToVersion(runtimeID int32) (version uint8, found bool) {
defer m.mu.Unlock()
m.mu.Lock()
v, ok := m.itemRuntimeIDToVersion[runtimeID]
return v, ok
}
func (m *DefaultItemMapping) ItemRuntimeIDToData(runtimeID int32) (data map[string]any, found bool) {
defer m.mu.Unlock()
m.mu.Lock()
d, ok := m.itemRuntimeIDToData[runtimeID]
return d, ok
}
func (m *DefaultItemMapping) RegisterEntry(name string) int32 {
defer m.mu.Unlock()
m.mu.Lock()
if rid, ok := m.itemNamesToRuntimeIDs[name]; ok {
return rid
}
nextRID := int32(len(m.itemRuntimeIDsToNames))
m.itemNamesToRuntimeIDs[name] = nextRID
m.itemRuntimeIDsToNames[nextRID] = name
return nextRID
}
func (m *DefaultItemMapping) RegisterEntryRID(name string, rid int32, version uint8, data map[string]any) {
defer m.mu.Unlock()
m.mu.Lock()
if _, ok := m.itemNamesToRuntimeIDs[name]; !ok {
m.itemNamesToRuntimeIDs[name] = rid
m.itemRuntimeIDsToNames[rid] = name
m.itemRuntimeIDToVersion[rid] = version
if data != nil {
m.itemRuntimeIDToData[rid] = data
}
}
}
func (m *DefaultItemMapping) Air() int32 {
defer m.mu.Unlock()
m.mu.Lock()
return m.airRID
}
func (m *DefaultItemMapping) ItemVersion() uint16 {
defer m.mu.Unlock()
m.mu.Lock()
return m.itemVersion
}
func (m *DefaultItemMapping) ItemEntries() []ItemEntry {
defer m.mu.Unlock()
m.mu.Lock()
entries := make([]ItemEntry, len(m.itemEntries))
copy(entries, m.itemEntries)
return entries
}