Add support for dimension ranges and network hashes

This commit is contained in:
Javier León
2026-01-03 05:33:35 -03:00
parent 2ad86d772f
commit 7a4d57fa6a
10 changed files with 372 additions and 82 deletions

View File

@@ -21,6 +21,8 @@ type Block interface {
DowngradeBlockActorData(map[string]any)
// UpgradeBlockActorData upgrades the input sub chunk to the latest block actor.
UpgradeBlockActorData(map[string]any)
HashToRuntimeID(hash uint32) (rid uint32, ok bool)
RuntimeIDToHash(rid uint32) (hash uint32, ok bool)
// Adjust adjusts the latest mappings to account for custom states.
Adjust([]protocol.BlockEntry)
Air() uint32
@@ -41,6 +43,9 @@ type DefaultBlockMapping struct {
// infoUpdateRID is the runtime ID of the info_update block in the latest version of the game.
infoUpdateBlockRID uint32
networkhashToRids map[uint32]uint32
ridsToNetworkhash map[uint32]uint32
}
func NewBlockMapping(raw []byte) *DefaultBlockMapping {
@@ -51,6 +56,8 @@ func NewBlockMapping(raw []byte) *DefaultBlockMapping {
runtimeIDToState := make(map[uint32]blockupgrader.BlockState)
var airRID *uint32
var infoUpdateBlockRID *uint32
networkhashToRids := make(map[uint32]uint32)
ridsToNetworkhash := make(map[uint32]uint32)
var s blockupgrader.BlockState
for {
@@ -67,8 +74,11 @@ func NewBlockMapping(raw []byte) *DefaultBlockMapping {
infoUpdateBlockRID = &rid
}
stateRuntimeIDs[internal.HashState(blockupgrader.Upgrade(s))] = rid
upgradedStates := blockupgrader.Upgrade(s)
stateRuntimeIDs[internal.HashState(upgradedStates)] = rid
runtimeIDToState[rid] = s
networkhashToRids[networkBlockHash(upgradedStates.Name, upgradedStates.Properties)] = rid
ridsToNetworkhash[rid] = networkBlockHash(s.Name, s.Properties)
}
if airRID == nil {
panic("couldn't find air")
@@ -83,6 +93,8 @@ func NewBlockMapping(raw []byte) *DefaultBlockMapping {
runtimeIDToState: runtimeIDToState,
airRID: *airRID,
infoUpdateBlockRID: *infoUpdateBlockRID,
networkhashToRids: networkhashToRids,
ridsToNetworkhash: ridsToNetworkhash,
}
}
@@ -114,6 +126,16 @@ func (m *DefaultBlockMapping) UpgradeBlockActorData(actorData map[string]any) {
}
}
func (m *DefaultBlockMapping) RuntimeIDToHash(rid uint32) (uint32, bool) {
hash, found := m.ridsToNetworkhash[rid]
return hash, found
}
func (m *DefaultBlockMapping) HashToRuntimeID(hash uint32) (uint32, bool) {
rid, found := m.networkhashToRids[hash]
return rid, found
}
func (m *DefaultBlockMapping) Adjust(entries []protocol.BlockEntry) {
if len(entries) == 0 {
return

View File

@@ -0,0 +1,97 @@
package mapping
import (
"encoding/binary"
"hash/fnv"
"sort"
"strings"
)
var bufNetworkhash []byte = make([]byte, 0xff)
func networkBlockHash(name string, properties map[string]any) uint32 {
if name == "minecraft:unknown" {
return 0xfffffffe // -2
}
keys := make([]string, 0, len(properties))
for k := range properties {
keys = append(keys, k)
}
sort.Strings(keys)
bufNetworkhash = bufNetworkhash[:0]
var data = bufNetworkhash
writeString := func(str string) {
data = binary.LittleEndian.AppendUint16(data, uint16(len(str)))
data = append(data, []byte(str)...)
}
data = append(data, 10) // compound
data = append(data, 0)
data = append(data, 0)
data = append(data, 8) // string
writeString("name")
writeString(name)
data = append(data, 10) // compound
writeString("states")
for _, k := range keys {
v := properties[k]
switch v := v.(type) {
case string:
data = append(data, 8) // string
writeString(k)
writeString(v)
case uint8:
data = append(data, 1) // tagByte
writeString(k)
data = append(data, byte(v))
case int8:
data = append(data, 1) // tagByte
writeString(k)
data = append(data, byte(v))
case bool:
b := 0
if v {
b = 1
}
data = append(data, 1) // tagByte
writeString(k)
data = append(data, byte(b))
case uint16:
data = append(data, 2) // tagInt16
writeString(k)
data = binary.LittleEndian.AppendUint16(data, uint16(v))
case int16:
data = append(data, 2) // tagInt16
writeString(k)
data = binary.LittleEndian.AppendUint16(data, uint16(v))
case uint32:
data = append(data, 3) // tagInt32
writeString(k)
data = binary.LittleEndian.AppendUint32(data, uint32(v))
case int32:
data = append(data, 3) // tagInt32
writeString(k)
data = binary.LittleEndian.AppendUint32(data, uint32(v))
default:
panic("unhandled nbt type")
}
}
data = append(data, 0) // end
data = append(data, 0) // end
h := fnv.New32a()
h.Write(data)
return h.Sum32()
}
func splitNamespace(identifier string) (ns, name string) {
ns_name := strings.Split(identifier, ":")
return ns_name[0], ns_name[len(ns_name)-1]
}