94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
|
|
package world
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/binary"
|
||
|
|
"fmt"
|
||
|
|
"sort"
|
||
|
|
|
||
|
|
"github.com/segmentio/fasthash/fnv1a"
|
||
|
|
)
|
||
|
|
|
||
|
|
// networkBlockHash produces the canonical "network block hash" for a (name, properties) block state.
|
||
|
|
// This hash is used for mapping network palette entries back to runtime IDs.
|
||
|
|
//
|
||
|
|
// The scratch slice is used to reduce allocations. The returned slice should be passed back in on subsequent calls to
|
||
|
|
// reuse the same backing array.
|
||
|
|
func networkBlockHash(name string, properties map[string]any, scratch []byte) (uint32, []byte) {
|
||
|
|
if name == "minecraft:unknown" {
|
||
|
|
return 0xfffffffe, scratch // -2
|
||
|
|
}
|
||
|
|
|
||
|
|
keys := make([]string, 0, len(properties))
|
||
|
|
for k := range properties {
|
||
|
|
keys = append(keys, k)
|
||
|
|
}
|
||
|
|
sort.Strings(keys)
|
||
|
|
|
||
|
|
data := scratch[:0]
|
||
|
|
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(fmt.Sprintf("unhandled nbt type: %T", v))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
data = append(data, 0) // end
|
||
|
|
data = append(data, 0) // end
|
||
|
|
|
||
|
|
return fnv1a.HashBytes32(data), data
|
||
|
|
}
|