195 lines
4.0 KiB
Go
195 lines
4.0 KiB
Go
package data
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
)
|
|
|
|
// {
|
|
// "id": 0,
|
|
// "name": "air",
|
|
// "displayName": "Air",
|
|
// "hardness": 0.0,
|
|
// "resistance": 0.0,
|
|
// "stackSize": 64,
|
|
// "diggable": false,
|
|
// "material": "default",
|
|
// "transparent": true,
|
|
// "emitLight": 0,
|
|
// "filterLight": 0,
|
|
// "defaultState": 0,
|
|
// "minStateId": 0,
|
|
// "maxStateId": 0,
|
|
// "states": [],
|
|
// "drops": [],
|
|
// "boundingBox": "empty"
|
|
// },
|
|
|
|
type Block struct {
|
|
Id int
|
|
Name string
|
|
DisplayName string
|
|
Hardness float64
|
|
Resistance float64
|
|
StackSize int
|
|
Diggable bool
|
|
Material string
|
|
Transparent bool
|
|
EmitLight int
|
|
FilterLight int
|
|
DefaultState int32
|
|
MinStateId int32
|
|
MaxStateId int32
|
|
States []BlockState
|
|
Drops []int
|
|
BoundingBox string
|
|
}
|
|
|
|
type BlockState struct {
|
|
Name string
|
|
Type string
|
|
NumValues int32 `json:"num_values"`
|
|
Values []string
|
|
}
|
|
|
|
var BlocksCache = make(map[string][]*Block)
|
|
|
|
func BlocksForVersion(v string) (ret []*Block) {
|
|
var ok bool
|
|
if ret, ok = BlocksCache[v]; ok {
|
|
return
|
|
}
|
|
var b []*Block
|
|
must(LoadVersionedJson(v, "blocks", &b))
|
|
BlocksCache[v] = b
|
|
return b
|
|
}
|
|
|
|
func LookupBlockByStateId(version string, stateId int32) (block *Block, ok bool) {
|
|
for _, b := range BlocksForVersion(version) {
|
|
if b.MinStateId <= stateId && stateId <= b.MaxStateId {
|
|
block = b
|
|
ok = true
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func LookupBlockByName(version string, name string) (block *Block, ok bool) {
|
|
for _, b := range BlocksForVersion(version) {
|
|
if b.Name == name {
|
|
block = b
|
|
ok = true
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func StateIdFromBlocKAndStateMap(version string, name string, stateMap map[string]string) (stateId int32, err error) {
|
|
b, ok := LookupBlockByName(version, name)
|
|
if !ok {
|
|
err = BlockNotFoundErr
|
|
return
|
|
}
|
|
stateId, err = b.IdFromStateMap(stateMap)
|
|
return
|
|
}
|
|
|
|
var BlockStateOutOfRangeErr = errors.New("stateId out of range")
|
|
var BlockNotFoundErr = errors.New("block not found")
|
|
var InvalidBoolValueErr = errors.New("invalid bool value")
|
|
var BadBlockStateTypeErr = errors.New("bad block state type")
|
|
var BadEnumErr = errors.New("bad enum")
|
|
var SupplyAllStatesErr = errors.New("supply all states")
|
|
|
|
func FromBlockState(version string, stateId int32) (b *Block, stateData map[string]string, err error) {
|
|
b, ok := LookupBlockByStateId(version, stateId)
|
|
if !ok {
|
|
err = BlockNotFoundErr
|
|
}
|
|
stateData, err = b.StateMapFromId(stateId)
|
|
return
|
|
}
|
|
|
|
func mcDataBlockStateTypeParse(n int32, s *BlockState) (v string, err error) {
|
|
switch s.Type {
|
|
case "int":
|
|
v = strconv.Itoa(int(n))
|
|
case "enum":
|
|
v = s.Values[n]
|
|
case "bool":
|
|
if n == 0 { // MOJANK: 0 is true, 1 is false
|
|
v = "true"
|
|
} else if n == 1 {
|
|
v = "false"
|
|
} else {
|
|
err = InvalidBoolValueErr
|
|
}
|
|
default:
|
|
err = BadBlockStateTypeErr
|
|
}
|
|
return
|
|
}
|
|
|
|
func mcDataBlockStateTypeSerialize(v string, s *BlockState) (n int32, err error) {
|
|
if v == "true" {
|
|
return 0, nil
|
|
}
|
|
if v == "false" {
|
|
return 1, nil
|
|
}
|
|
n1, errMabye := strconv.Atoi(v)
|
|
if errMabye == nil {
|
|
return int32(n1), nil
|
|
}
|
|
for i, enumValue := range s.Values {
|
|
if enumValue == v {
|
|
return int32(i), nil
|
|
}
|
|
}
|
|
err = BadEnumErr
|
|
return
|
|
}
|
|
|
|
func (b *Block) StateMapFromId(stateId int32) (ret map[string]string, err error) {
|
|
if stateId < b.MinStateId || stateId > b.MaxStateId {
|
|
err = BlockStateOutOfRangeErr
|
|
return
|
|
}
|
|
ret = make(map[string]string)
|
|
stateId -= b.MinStateId
|
|
|
|
a := int32(1)
|
|
for i := range len(b.States) {
|
|
s := b.States[len(b.States)-1-i]
|
|
ret[s.Name], err = mcDataBlockStateTypeParse((stateId/a)%s.NumValues, &s)
|
|
if err != nil {
|
|
return
|
|
}
|
|
a *= s.NumValues
|
|
}
|
|
return
|
|
}
|
|
|
|
func (b *Block) IdFromStateMap(m map[string]string) (ret int32, err error) {
|
|
a := int32(1)
|
|
for i := range len(b.States) {
|
|
s := b.States[len(b.States)-1-i]
|
|
v, found := m[s.Name]
|
|
if !found {
|
|
err = SupplyAllStatesErr
|
|
return
|
|
}
|
|
var n int32
|
|
n, err = mcDataBlockStateTypeSerialize(v, &s)
|
|
if err != nil {
|
|
return
|
|
}
|
|
ret += n * a
|
|
a *= s.NumValues
|
|
}
|
|
ret += b.MinStateId
|
|
return
|
|
}
|