Convert to templates
Signed-off-by: jolheiser <john.olheiser@gmail.com>
This commit is contained in:
@ -6,147 +6,17 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/token"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"text/template"
|
||||
|
||||
"github.com/iancoleman/strcase"
|
||||
)
|
||||
|
||||
const (
|
||||
infoURL = "https://raw.githubusercontent.com/PrismarineJS/minecraft-data/master/data/pc/1.17/blocks.json"
|
||||
)
|
||||
|
||||
type Block struct {
|
||||
ID uint32 `json:"id"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Hardness float64 `json:"hardness"`
|
||||
Diggable bool `json:"diggable"`
|
||||
DropIDs []uint32 `json:"drops"`
|
||||
NeedsTools map[uint32]bool `json:"harvestTools"`
|
||||
|
||||
MinStateID uint32 `json:"minStateId"`
|
||||
MaxStateID uint32 `json:"maxStateId"`
|
||||
|
||||
Transparent bool `json:"transparent"`
|
||||
FilterLightLevel int `json:"filterLight"`
|
||||
EmitLightLevel int `json:"emitLight"`
|
||||
}
|
||||
|
||||
func downloadInfo() ([]Block, error) {
|
||||
resp, err := http.Get(infoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var data []Block
|
||||
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func makeBlockDeclaration(blocks []Block) *ast.DeclStmt {
|
||||
out := &ast.DeclStmt{Decl: &ast.GenDecl{Tok: token.VAR}}
|
||||
|
||||
for _, b := range blocks {
|
||||
t := reflect.TypeOf(b)
|
||||
fields := make([]ast.Expr, t.NumField())
|
||||
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
ft := t.Field(i)
|
||||
|
||||
var val ast.Expr
|
||||
switch ft.Type.Kind() {
|
||||
case reflect.Uint32, reflect.Int:
|
||||
val = &ast.BasicLit{Kind: token.INT, Value: fmt.Sprint(reflect.ValueOf(b).Field(i))}
|
||||
case reflect.Float64:
|
||||
val = &ast.BasicLit{Kind: token.FLOAT, Value: fmt.Sprint(reflect.ValueOf(b).Field(i))}
|
||||
case reflect.String:
|
||||
val = &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(reflect.ValueOf(b).Field(i).String())}
|
||||
case reflect.Bool:
|
||||
val = &ast.BasicLit{Kind: token.IDENT, Value: fmt.Sprint(reflect.ValueOf(b).Field(i).Bool())}
|
||||
|
||||
case reflect.Slice:
|
||||
val = &ast.CompositeLit{
|
||||
Type: &ast.ArrayType{
|
||||
Elt: &ast.BasicLit{Kind: token.IDENT, Value: ft.Type.Elem().Name()},
|
||||
},
|
||||
}
|
||||
v := reflect.ValueOf(b).Field(i)
|
||||
switch ft.Type.Elem().Kind() {
|
||||
case reflect.Uint32, reflect.Int:
|
||||
for x := 0; x < v.Len(); x++ {
|
||||
val.(*ast.CompositeLit).Elts = append(val.(*ast.CompositeLit).Elts, &ast.BasicLit{
|
||||
Kind: token.INT,
|
||||
Value: fmt.Sprint(v.Index(x)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Map:
|
||||
// Must be the NeedsTools map of type map[uint32]bool.
|
||||
m := &ast.CompositeLit{
|
||||
Type: &ast.MapType{
|
||||
Key: &ast.BasicLit{Kind: token.IDENT, Value: ft.Type.Key().Name()},
|
||||
Value: &ast.BasicLit{Kind: token.IDENT, Value: ft.Type.Elem().Name()},
|
||||
},
|
||||
}
|
||||
iter := reflect.ValueOf(b).Field(i).MapRange()
|
||||
for iter.Next() {
|
||||
m.Elts = append(m.Elts, &ast.KeyValueExpr{
|
||||
Key: &ast.BasicLit{Kind: token.INT, Value: fmt.Sprint(iter.Key().Uint())},
|
||||
Value: &ast.BasicLit{Kind: token.IDENT, Value: fmt.Sprint(iter.Value().Bool())},
|
||||
})
|
||||
}
|
||||
|
||||
val = m
|
||||
}
|
||||
|
||||
fields[i] = &ast.KeyValueExpr{
|
||||
Key: &ast.Ident{Name: ft.Name},
|
||||
Value: val,
|
||||
}
|
||||
}
|
||||
|
||||
out.Decl.(*ast.GenDecl).Specs = append(out.Decl.(*ast.GenDecl).Specs, &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{Name: strcase.ToCamel(b.Name)}},
|
||||
Values: []ast.Expr{
|
||||
&ast.CompositeLit{
|
||||
Type: &ast.Ident{Name: reflect.TypeOf(b).Name()},
|
||||
Elts: fields,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
//go:generate go run $GOFILE
|
||||
//go:generate go fmt block.go
|
||||
func main() {
|
||||
blocks, err := downloadInfo()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
f, err := os.Create("block.go")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fmt.Fprintln(f, `// Code generated by gen_blocks.go; DO NOT EDIT.
|
||||
//language=gohtml
|
||||
blockTmpl = `// Code generated by gen_block.go; DO NOT EDIT.
|
||||
|
||||
// Package block stores information about blocks in Minecraft.
|
||||
package block
|
||||
@ -181,29 +51,100 @@ type Block struct {
|
||||
EmitLightLevel int
|
||||
}
|
||||
|
||||
`)
|
||||
format.Node(f, token.NewFileSet(), makeBlockDeclaration(blocks))
|
||||
var (
|
||||
{{- range .}}
|
||||
{{.CamelName}} = Block{
|
||||
ID: {{.ID}},
|
||||
DisplayName: "{{.DisplayName}}",
|
||||
Name: "{{.Name}}",
|
||||
Hardness: {{.Hardness}},
|
||||
Diggable: {{.Diggable}},
|
||||
DropIDs: []uint32{ {{- range .DropIDs}}{{.}},{{end -}} },
|
||||
NeedsTools: map[uint32]bool{ {{- range $key, $val := .NeedsTools}}{{$key}}: {{$val}},{{end -}} },
|
||||
MinStateID: {{.MinStateID}},
|
||||
MaxStateID: {{.MaxStateID}},
|
||||
Transparent: {{.Transparent}},
|
||||
FilterLightLevel: {{.FilterLightLevel}},
|
||||
EmitLightLevel: {{.EmitLightLevel}},
|
||||
}{{end}}
|
||||
)
|
||||
|
||||
fmt.Fprintln(f)
|
||||
fmt.Fprintln(f)
|
||||
fmt.Fprintln(f, "// ByID is an index of minecraft blocks by their ID.")
|
||||
fmt.Fprintln(f, "var ByID = map[ID]*Block{")
|
||||
for _, b := range blocks {
|
||||
fmt.Fprintf(f, " %d: &%s,\n", b.ID, strcase.ToCamel(b.Name))
|
||||
}
|
||||
fmt.Fprintln(f, "}")
|
||||
|
||||
fmt.Fprintln(f)
|
||||
fmt.Fprintln(f, "// StateID maps all possible state IDs to a corresponding block ID.")
|
||||
fmt.Fprintln(f, "var StateID = map[uint32]ID{")
|
||||
for _, b := range blocks {
|
||||
if b.MinStateID == b.MaxStateID {
|
||||
fmt.Fprintf(f, " %d: %d,\n", b.MinStateID, b.ID)
|
||||
} else {
|
||||
for i := b.MinStateID; i <= b.MaxStateID; i++ {
|
||||
fmt.Fprintf(f, " %d: %d,\n", i, b.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(f, "}")
|
||||
// ByID is an index of minecraft blocks by their ID.
|
||||
var ByID = map[ID]*Block{ {{range .}}
|
||||
{{.ID}}: &{{.CamelName}},{{end}}
|
||||
}
|
||||
|
||||
// StateID maps all possible state IDs to a corresponding block ID.
|
||||
var StateID = map[uint32]ID{ {{range $block := .}}
|
||||
{{- range .States}}
|
||||
{{.}}: {{$block.ID}},
|
||||
{{- end}}{{end}}
|
||||
}`
|
||||
)
|
||||
|
||||
type Block struct {
|
||||
ID uint32 `json:"id"`
|
||||
CamelName string `json:"-"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Hardness float64 `json:"hardness"`
|
||||
Diggable bool `json:"diggable"`
|
||||
DropIDs []uint32 `json:"drops"`
|
||||
NeedsTools map[uint32]bool `json:"harvestTools"`
|
||||
|
||||
MinStateID uint32 `json:"minStateId"`
|
||||
MaxStateID uint32 `json:"maxStateId"`
|
||||
|
||||
Transparent bool `json:"transparent"`
|
||||
FilterLightLevel int `json:"filterLight"`
|
||||
EmitLightLevel int `json:"emitLight"`
|
||||
}
|
||||
|
||||
func (b Block) States() []uint32 {
|
||||
if b.MinStateID == b.MaxStateID {
|
||||
return []uint32{b.MinStateID}
|
||||
}
|
||||
states := make([]uint32, 0)
|
||||
for i := b.MinStateID; i <= b.MaxStateID; i++ {
|
||||
states = append(states, i)
|
||||
}
|
||||
return states
|
||||
}
|
||||
|
||||
func downloadInfo() ([]*Block, error) {
|
||||
resp, err := http.Get(infoURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var data []*Block
|
||||
if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, d := range data {
|
||||
d.CamelName = strcase.ToCamel(d.Name)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
//go:generate go run $GOFILE
|
||||
//go:generate go fmt block.go
|
||||
func main() {
|
||||
fmt.Println("generating block.go")
|
||||
blocks, err := downloadInfo()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
f, err := os.Create("block.go")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := template.Must(template.New("").Parse(blockTmpl)).Execute(f, blocks); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user