initial commit
This commit is contained in:
136
mapping/block.go
Normal file
136
mapping/block.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package mapping
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/akmalfairuz/legacy-version/internal"
|
||||
"sort"
|
||||
|
||||
"github.com/df-mc/worldupgrader/blockupgrader"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/segmentio/fasthash/fnv1"
|
||||
)
|
||||
|
||||
type Block interface {
|
||||
// StateToRuntimeID converts a block state to a runtime ID.
|
||||
StateToRuntimeID(blockupgrader.BlockState) (uint32, bool)
|
||||
// RuntimeIDToState converts a runtime ID to a name and its state properties.
|
||||
RuntimeIDToState(uint32) (blockupgrader.BlockState, bool)
|
||||
// DowngradeBlockActorData downgrades the input sub chunk to a legacy block actor.
|
||||
DowngradeBlockActorData(map[string]any)
|
||||
// UpgradeBlockActorData upgrades the input sub chunk to the latest block actor.
|
||||
UpgradeBlockActorData(map[string]any)
|
||||
// Adjust adjusts the latest mappings to account for custom states.
|
||||
Adjust([]protocol.BlockEntry)
|
||||
Air() uint32
|
||||
}
|
||||
|
||||
type DefaultBlockMapping struct {
|
||||
// states holds a list of all possible vanilla block states.
|
||||
states []blockupgrader.BlockState
|
||||
// stateRuntimeIDs holds a map for looking up the runtime ID of a block by the stateHash it produces.
|
||||
stateRuntimeIDs map[internal.StateHash]uint32
|
||||
// runtimeIDToState holds a map for looking up the blockState of a block by its runtime ID.
|
||||
runtimeIDToState map[uint32]blockupgrader.BlockState
|
||||
upgrader, downgrader func(map[string]any) map[string]any
|
||||
|
||||
// airRID is the runtime ID of the air block in the latest version of the game.
|
||||
airRID uint32
|
||||
}
|
||||
|
||||
func NewBlockMapping(raw []byte) *DefaultBlockMapping {
|
||||
dec := nbt.NewDecoder(bytes.NewBuffer(raw))
|
||||
|
||||
var states []blockupgrader.BlockState
|
||||
stateRuntimeIDs := make(map[internal.StateHash]uint32)
|
||||
runtimeIDToState := make(map[uint32]blockupgrader.BlockState)
|
||||
var airRID *uint32
|
||||
|
||||
var s blockupgrader.BlockState
|
||||
for {
|
||||
if err := dec.Decode(&s); err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
rid := uint32(len(states))
|
||||
states = append(states, s)
|
||||
if s.Name == "minecraft:air" {
|
||||
airRID = &rid
|
||||
}
|
||||
|
||||
stateRuntimeIDs[internal.HashState(blockupgrader.Upgrade(s))] = rid
|
||||
runtimeIDToState[rid] = s
|
||||
}
|
||||
if airRID == nil {
|
||||
panic("couldn't find air")
|
||||
}
|
||||
|
||||
return &DefaultBlockMapping{
|
||||
states: states,
|
||||
stateRuntimeIDs: stateRuntimeIDs,
|
||||
runtimeIDToState: runtimeIDToState,
|
||||
airRID: *airRID,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) WithBlockActorRemapper(downgrader, upgrader func(map[string]any) map[string]any) *DefaultBlockMapping {
|
||||
m.downgrader = downgrader
|
||||
m.upgrader = upgrader
|
||||
return m
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) StateToRuntimeID(state blockupgrader.BlockState) (uint32, bool) {
|
||||
rid, ok := m.stateRuntimeIDs[internal.HashState(blockupgrader.Upgrade(state))]
|
||||
return rid, ok
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) RuntimeIDToState(runtimeId uint32) (blockupgrader.BlockState, bool) {
|
||||
state, found := m.runtimeIDToState[runtimeId]
|
||||
return state, found
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) DowngradeBlockActorData(actorData map[string]any) {
|
||||
if m.downgrader != nil {
|
||||
m.downgrader(actorData)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) UpgradeBlockActorData(actorData map[string]any) {
|
||||
if m.upgrader != nil {
|
||||
m.upgrader(actorData)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) Adjust(entries []protocol.BlockEntry) {
|
||||
if len(entries) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
customStates := convert(entries)
|
||||
var newStates []blockupgrader.BlockState
|
||||
for _, state := range customStates {
|
||||
if _, ok := m.StateToRuntimeID(state); !ok {
|
||||
newStates = append(newStates, state)
|
||||
}
|
||||
}
|
||||
if len(newStates) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
adjustedStates := append(m.states, customStates...)
|
||||
sort.SliceStable(adjustedStates, func(i, j int) bool {
|
||||
stateOne, stateTwo := adjustedStates[i], adjustedStates[j]
|
||||
return stateOne.Name != stateTwo.Name && fnv1.HashString64(stateOne.Name) < fnv1.HashString64(stateTwo.Name)
|
||||
})
|
||||
|
||||
m.stateRuntimeIDs = make(map[internal.StateHash]uint32, len(adjustedStates))
|
||||
m.runtimeIDToState = make(map[uint32]blockupgrader.BlockState, len(adjustedStates))
|
||||
for rid, state := range adjustedStates {
|
||||
m.stateRuntimeIDs[internal.HashState(blockupgrader.Upgrade(state))] = uint32(rid)
|
||||
m.runtimeIDToState[uint32(rid)] = state
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DefaultBlockMapping) Air() uint32 {
|
||||
return m.airRID
|
||||
}
|
||||
Reference in New Issue
Block a user