package internal import ( "fmt" "sort" "strings" "unsafe" "github.com/df-mc/worldupgrader/blockupgrader" ) // StateHash is a struct that may be used as a map key for block states. It contains the name of the block state // and an encoded version of the properties. type StateHash struct { Name, Properties string } // HashState produces a hash for the block properties held by the blockState. func HashState(state blockupgrader.BlockState) StateHash { if state.Properties == nil { return StateHash{Name: state.Name} } keys := make([]string, 0, len(state.Properties)) for k := range state.Properties { keys = append(keys, k) } sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] }) var b strings.Builder for _, k := range keys { switch v := state.Properties[k].(type) { case bool: if v { b.WriteByte(1) } else { b.WriteByte(0) } case uint8: b.WriteByte(v) case int32: a := *(*[4]byte)(unsafe.Pointer(&v)) b.Write(a[:]) case string: b.WriteString(v) default: // If block encoding is broken, we want to find out as soon as possible. This saves a lot of time // debugging in-game. panic(fmt.Sprintf("invalid block property type %T for property %v", v, k)) } } return StateHash{Name: state.Name, Properties: b.String()} }