diff --git a/bot/mcbot.go b/bot/mcbot.go index 654cc54..cf8e09c 100644 --- a/bot/mcbot.go +++ b/bot/mcbot.go @@ -6,6 +6,7 @@ package bot import ( "context" + "errors" "net" "strconv" @@ -34,11 +35,14 @@ func (c *Client) JoinServerWithDialer(d *net.Dialer, addr string) (err error) { func parseAddress(r *net.Resolver, addr string) (string, error) { const missingPort = "missing port in address" var port uint16 + var addrErr *net.AddrError host, portStr, err := net.SplitHostPort(addr) - if addrErr, ok := err.(*net.AddrError); ok && addrErr.Err == missingPort { - host, port = addr, DefaultPort - } else if err != nil { - return "", err + if err != nil { + if errors.As(err, &addrErr) { + host, port = addr, DefaultPort + } else { + return "", err + } } else { if portInt, err := strconv.ParseUint(portStr, 10, 16); err != nil { port = DefaultPort diff --git a/examples/genmaps/colors.gob b/examples/genmaps/colors.gob new file mode 100644 index 0000000..1ea2afd Binary files /dev/null and b/examples/genmaps/colors.gob differ diff --git a/examples/genmaps/genmaps.go b/examples/genmaps/genmaps.go new file mode 100644 index 0000000..40a4a08 --- /dev/null +++ b/examples/genmaps/genmaps.go @@ -0,0 +1,130 @@ +package main + +import ( + "flag" + "fmt" + "github.com/Tnze/go-mc/data/block" + "github.com/Tnze/go-mc/save" + "github.com/Tnze/go-mc/save/region" + "image" + "image/color" + "image/draw" + "log" + "os" + "path/filepath" + "unsafe" +) + +var colors []color.RGBA64 + +var ( + regionsFold = flag.String("region", filepath.Join(os.Getenv("AppData"), ".minecraft", "saves", "World", "region"), "region directory path") +) + +func main() { + flag.Usage = usage + flag.Parse() + + de, err := os.ReadDir(*regionsFold) + if err != nil { + log.Fatal(err) + } + + var min, max [2]int + updateMinMax := func(pos [2]int) { + mkmax(&max[0], &pos[0]) + mkmax(&max[1], &pos[1]) + mkmin(&min[0], &pos[0]) + mkmin(&min[1], &pos[1]) + } + + // Open mca files + var rs = make(map[[2]int]*region.Region, len(de)) + for _, dir := range de { + name := dir.Name() + path := filepath.Join(*regionsFold, name) + var pos [2]int // {x, z} + if _, err := fmt.Sscanf(name, "r.%d.%d.mca", &pos[0], &pos[1]); err != nil { + log.Printf("Error parsing file name of %s: %v, ignoring", name, err) + continue + } + updateMinMax(pos) + + r, err := region.Open(path) + if err != nil { + log.Printf("Error when opening %s: %v, ignoring", name, err) + continue + } + rs[pos] = r + } + // To close mca files + defer func() { + for pos, r := range rs { + if err := r.Close(); err != nil { + log.Printf("Close r.%d.%d.mca error: %v", pos[0], pos[1], err) + } + } + }() + + for pos, r := range rs { + var column save.Column + img := image.NewRGBA(image.Rect(0, 0, 32*16, 32*16)) + for x := 0; x < 32; x++ { + for z := 0; z < 32; z++ { + if !r.ExistSector(x, z) { + continue + } + data, err := r.ReadSector(x, z) + if err != nil { + log.Printf("Read sector (%d.%d) error: %v", x, z, err) + } + if err := column.Load(data); err != nil { + log.Printf("Decode column (%d.%d) error: %v", x, z, err) + } + + draw.Draw( + img, image.Rect(x*16, z*16, x*16+16, z*16+16), + drawColumn(&column), image.Pt(0, 0), + draw.Over, + ) + } + } + savePng(img, fmt.Sprintf("r.%d.%d.png", pos[0], pos[1])) + log.Print(pos, r) + } +} + +func drawColumn(column *save.Column) (img *image.RGBA) { + img = image.NewRGBA(image.Rect(0, 0, 16, 16)) + + s := column.Level.Sections + for i := range s { + s := s[i] + // calculate bits per block + bpb := len(s.BlockStates) * 64 / (16 * 16 * 16) + // skip empty + if len(s.BlockStates) == 0 { + continue + } + // decode section + //n := int(math.Max(4, math.Ceil(math.Log2(float64(len(s.Palette)))))) + + // decode status + data := *(*[]uint64)(unsafe.Pointer(&s.BlockStates)) // convert []int64 into []uint64 + bs := save.NewBitStorage(bpb, 4096, data) + for y := 0; y < 16; y++ { + layerImg := image.NewRGBA(image.Rect(0, 0, 16, 16)) + for i := 16*16 - 1; i >= 0; i-- { + b := block.ByID[block.StateID[uint32(bs.Get(y*16*16+i))]] + c := colors[b.ID] + layerImg.Set(i/16, i%16, c) + } + draw.Draw( + img, image.Rect(0, 0, 16, 16), + layerImg, image.Pt(0, 0), + draw.Over, + ) + } + } + return +} diff --git a/examples/genmaps/util_funcs.go b/examples/genmaps/util_funcs.go new file mode 100644 index 0000000..a2299c1 --- /dev/null +++ b/examples/genmaps/util_funcs.go @@ -0,0 +1,53 @@ +package main + +import ( + "bytes" + _ "embed" + "encoding/gob" + "fmt" + "image" + "image/png" + "log" + "os" +) + +func savePng(img image.Image, name string) { + f, err := os.Create(name) + if err != nil { + log.Fatal(err) + } + + if err := png.Encode(f, img); err != nil { + f.Close() + log.Fatal(err) + } + + if err := f.Close(); err != nil { + log.Fatal(err) + } +} + +//go:embed colors.gob +var colorsBin []byte // gob([]color.RGBA64) + +func init() { + if err := gob.NewDecoder(bytes.NewReader(colorsBin)).Decode(&colors); err != nil { + panic(err) + } +} + +func usage() { + _, _ = fmt.Fprintf(os.Stderr, "usage: %s [-region ] \n", os.Args[0]) + os.Exit(1) +} + +func mkmax(c, n *int) { + if *c < *n { + *c = *n + } +} +func mkmin(c, n *int) { + if *c > *n { + *c = *n + } +} diff --git a/save/save.go b/save/save.go deleted file mode 100644 index 16890c0..0000000 --- a/save/save.go +++ /dev/null @@ -1 +0,0 @@ -package save