update gophertunnel, add void toggle, fix map zoom

This commit is contained in:
olebeck 2022-09-02 14:43:56 +02:00
parent 90b3ef2604
commit 57e1ab483f
5 changed files with 103 additions and 75 deletions

2
go.mod
View File

@ -21,7 +21,7 @@ require (
//replace github.com/df-mc/dragonfly => ./dragonfly
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.24.8-2
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.24.8-3
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.8.2-6

2
go.sum
View File

@ -51,6 +51,8 @@ github.com/olebeck/gophertunnel v1.24.8-1 h1:ECZs6y/ZtvUjhIPlu3RjJr8c5QkOdxdQnoO
github.com/olebeck/gophertunnel v1.24.8-1/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
github.com/olebeck/gophertunnel v1.24.8-2 h1:T7WY2M/GrKTOgcH1RcDiB8LNlhK+PEzGdHSaYP4V518=
github.com/olebeck/gophertunnel v1.24.8-2/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
github.com/olebeck/gophertunnel v1.24.8-3 h1:qR5PCFWUAcUureCt36tLqaXWOjHVsFx66PiKm1obtkY=
github.com/olebeck/gophertunnel v1.24.8-3/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
github.com/olebeck/gophertunnel v1.24.8 h1:jdqBOABDAE1yISqzm9IxIrI+/lJApLBjTieynXUSalw=
github.com/olebeck/gophertunnel v1.24.8/go.mod h1:dMOw79FHxr2azEqiGH20AwdljisAN1kqwu5SjPBnZ5k=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=

View File

@ -3,7 +3,6 @@ package main
import (
"bytes"
"image"
"image/color"
"image/draw"
"math"
"os"
@ -40,7 +39,7 @@ var MAP_ITEM_PACKET packet.InventoryContent = packet.InventoryContent{
type MapUI struct {
img *image.RGBA // rendered image
zoom int // chunks per row
minZoom bool // 1 pixel per block
chunks_images map[protocol.ChunkPos]*image.RGBA // prerendered chunks
needRedraw bool // when the map has updated this is true
send_lock *sync.Mutex
@ -49,7 +48,7 @@ type MapUI struct {
func NewMapUI() MapUI {
return MapUI{
img: image.NewRGBA(image.Rect(0, 0, 128, 128)),
zoom: 64,
minZoom: true,
chunks_images: make(map[protocol.ChunkPos]*image.RGBA),
needRedraw: true,
send_lock: &sync.Mutex{},
@ -64,11 +63,7 @@ func (m *MapUI) Reset() {
// ChangeZoom adds to the zoom value and goes around to 32 once it hits 128
func (m *MapUI) ChangeZoom() {
if m.zoom >= 128 {
m.zoom = 32 // min
} else {
m.zoom += 32
}
m.minZoom = !m.minZoom
m.SchedRedraw()
}
@ -121,15 +116,17 @@ func (m *MapUI) Redraw(w *WorldState) {
chunks_x := int(max[0] - min[0] + 1) // how many chunk lengths is x coordinate
chunks_y := int(max[1] - min[1] + 1)
chunks_per_line := math.Min(16*math.Ceil(math.Min(float64(chunks_x), float64(m.zoom))/16), 32) // either zoom or how many there actually are
px_per_block := float64(128 / chunks_per_line / 16) // how many pixels per block
chunks_per_line := 16 * math.Ceil(math.Min(float64(chunks_x), 32)/16)
if m.minZoom {
chunks_per_line = 8
}
px_per_block := float64(128 / chunks_per_line / 16) // how many pixels per block
sz_chunk := int(math.Ceil(px_per_block * 16))
for i := 0; i < len(m.img.Pix); i++ { // clear canvas
m.img.Pix[i] = 0
}
//
for _ch := range m.chunks_images {
relative_middle_x := float64(_ch.X()*16 - middle.X())
relative_middle_z := float64(_ch.Z()*16 - middle.Z())
@ -137,9 +134,8 @@ func (m *MapUI) Redraw(w *WorldState) {
X: int(math.Floor(relative_middle_x*px_per_block)) + 64,
Y: int(math.Floor(relative_middle_z*px_per_block)) + 64,
}
sz_chunk := int(math.Ceil(px_per_block * 16))
px_upper := px_pos.Add(image.Point{sz_chunk, sz_chunk})
if px_pos.In(m.img.Rect) || px_upper.In(m.img.Rect) {
if !m.img.Rect.Intersect(image.Rect(px_pos.X, px_pos.Y, px_pos.X+sz_chunk, px_pos.Y+sz_chunk)).Empty() {
draw_img_scaled_pos(m.img, m.chunks_images[_ch], image.Point{
px_pos.X, px_pos.Y,
}, sz_chunk)
@ -168,7 +164,7 @@ func (m *MapUI) Redraw(w *WorldState) {
}
buf := bytes.NewBuffer(nil)
bmp.Encode(buf, img2)
os.WriteFile("test.bmp", buf.Bytes(), 0777)
os.WriteFile("test.bmp", buf.Bytes(), 0o777)
}
}
@ -184,21 +180,12 @@ func (m *MapUI) Send(w *WorldState) error {
m.Redraw(w)
}
// (ugh)
pixels := make([][]color.RGBA, 128)
for y := 0; y < 128; y++ {
pixels[y] = make([]color.RGBA, 128)
for x := 0; x < 128; x++ {
pixels[y][x] = m.img.At(x, y).(color.RGBA)
}
}
m.send_lock.Unlock()
return w.ClientConn.WritePacket(&packet.ClientBoundMapItemData{
MapID: VIEW_MAP_ID,
Width: 128,
Height: 128,
Pixels: pixels,
Pixels: img2rgba(m.img),
UpdateFlags: 2,
})
}

View File

@ -8,6 +8,8 @@ import (
"context"
"encoding/base64"
"fmt"
"image"
"image/color"
"io"
"io/fs"
"log"
@ -18,7 +20,7 @@ import (
"reflect"
"regexp"
"strings"
"time"
"unsafe"
"github.com/sandertv/gophertunnel/minecraft"
//"github.com/sandertv/gophertunnel/minecraft/gatherings"
@ -179,6 +181,7 @@ func (p dummyProto) Packets() packet.Pool { return packet.NewPool() }
func (p dummyProto) ConvertToLatest(pk packet.Packet, _ *minecraft.Conn) []packet.Packet {
return []packet.Packet{pk}
}
func (p dummyProto) ConvertFromLatest(pk packet.Packet, _ *minecraft.Conn) []packet.Packet {
return []packet.Packet{pk}
}
@ -241,17 +244,17 @@ func create_proxy(ctx context.Context, server_address string) (l *minecraft.List
clientConn.Close()
l.Close()
})
go func() {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
clientConn.WritePacket(&packet.Text{
TextType: packet.TextTypeTip,
Message: a + "\n\n\n\n\n\n",
})
}
}()
/*
go func() {
for i := 0; i < 10; i++ {
time.Sleep(1 * time.Second)
clientConn.WritePacket(&packet.Text{
TextType: packet.TextTypeTip,
Message: a + "\n\n\n\n\n\n",
})
}
}()
*/
return l, clientConn, serverConn, nil
}
@ -337,9 +340,9 @@ func unpack_zip(r io.ReaderAt, size int64, unpack_folder string) {
for _, src_file := range zr.File {
out_path := path.Join(unpack_folder, src_file.Name)
if src_file.Mode().IsDir() {
os.Mkdir(out_path, 0755)
os.Mkdir(out_path, 0o755)
} else {
os.MkdirAll(path.Dir(out_path), 0755)
os.MkdirAll(path.Dir(out_path), 0o755)
fr, _ := src_file.Open()
f, _ := os.Create(path.Join(unpack_folder, src_file.Name))
io.Copy(f, fr)
@ -428,3 +431,10 @@ func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
}
fmt.Printf("%s 0x%x, %s\n", dir, pk.ID(), pk_name)
}
func img2rgba(img *image.RGBA) []color.RGBA {
header := *(*reflect.SliceHeader)(unsafe.Pointer(&img.Pix))
header.Len /= 4
header.Cap /= 4
return *(*[]color.RGBA)(unsafe.Pointer(&header))
}

View File

@ -72,25 +72,60 @@ func NewWorldState() *WorldState {
}
}
var setname_command = protocol.Command{
Name: "setname",
Description: "set user defined name for this world",
Overloads: []protocol.CommandOverload{
{
Parameters: []protocol.CommandParameter{
type IngameCommand struct {
exec func(w *WorldState, cmdline []string) bool
cmd protocol.Command
}
var IngameCommands = map[string]IngameCommand{
"setname": {
exec: setnameCommand,
cmd: protocol.Command{
Name: "setname",
Description: "set user defined name for this world",
Overloads: []protocol.CommandOverload{
{
Name: "name",
Type: protocol.CommandArgTypeFilepath,
Optional: false,
Parameters: []protocol.CommandParameter{
{
Name: "name",
Type: protocol.CommandArgTypeFilepath,
Optional: false,
},
},
},
},
},
},
"void": {
exec: toggleVoid,
cmd: protocol.Command{
Name: "void",
Description: "toggle if void generator should be used",
},
},
}
var black_16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
func setnameCommand(w *WorldState, cmdline []string) bool {
w.WorldName = strings.Join(cmdline, " ")
send_message(w.ClientConn, fmt.Sprintf("worldName is now: %s", w.WorldName))
return true
}
func toggleVoid(w *WorldState, cmdline []string) bool {
w.voidgen = !w.voidgen
send_message(w.ClientConn, fmt.Sprintf("using void generator: %t", w.voidgen))
return true
}
var (
black_16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
Offset_table [24]protocol.SubChunkOffset
)
func init() {
for i := range Offset_table {
Offset_table[i] = protocol.SubChunkOffset{0, int8(i), 0}
}
draw.Draw(black_16x16, image.Rect(0, 0, 16, 16), image.Black, image.Point{}, draw.Src)
cs := crc32.ChecksumIEEE([]byte(a))
if cs != 0x9747c04f {
@ -100,9 +135,9 @@ func init() {
}
type WorldCMD struct {
server_address string
packs bool
enableGenerator bool
server_address string
packs bool
enableVoid bool
}
func (*WorldCMD) Name() string { return "worlds" }
@ -111,8 +146,9 @@ func (*WorldCMD) Synopsis() string { return "download a world from a server" }
func (p *WorldCMD) SetFlags(f *flag.FlagSet) {
f.StringVar(&p.server_address, "address", "", "remote server address")
f.BoolVar(&p.packs, "packs", false, "save resourcepacks to the worlds")
f.BoolVar(&p.enableGenerator, "gen", false, "if true, doesnt make the saved world a void world")
f.BoolVar(&p.enableVoid, "void", true, "if false, saves with default flat generator")
}
func (c *WorldCMD) Usage() string {
return c.Name() + ": " + c.Synopsis() + "\n" + SERVER_ADDRESS_HELP
}
@ -168,16 +204,7 @@ func (w *WorldState) ProcessLevelChunk(pk *packet.LevelChunk) {
} else {
// request all the subchunks
var Offset_table = []protocol.SubChunkOffset{
{0, 0, 0}, {0, 1, 0}, {0, 2, 0}, {0, 3, 0},
{0, 4, 0}, {0, 5, 0}, {0, 6, 0}, {0, 7, 0},
{0, 8, 0}, {0, 9, 0}, {0, 10, 0}, {0, 11, 0},
{0, 12, 0}, {0, 13, 0}, {0, 14, 0}, {0, 15, 0},
{0, 16, 0}, {0, 17, 0}, {0, 18, 0}, {0, 19, 0},
{0, 20, 0}, {0, 21, 0}, {0, 22, 0}, {0, 23, 0},
}
max := len(Offset_table) - 1
max := w.Dim.Range().Height() / 16
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLimited {
max = int(pk.HighestSubChunk)
}
@ -227,7 +254,6 @@ func (w *WorldState) ProcessSubChunk(pk *packet.SubChunk) {
func (w *WorldState) ProcessAnimate(pk *packet.Animate) {
if pk.ActionType == packet.AnimateActionSwingArm {
w.ui.ChangeZoom()
send_popup(w.ClientConn, fmt.Sprintf("Zoom: %d", w.ui.zoom))
w.ui.Send(w)
}
}
@ -249,10 +275,9 @@ func (w *WorldState) ProcessChangeDimension(pk *packet.ChangeDimension) {
func (w *WorldState) ProcessCommand(pk *packet.CommandRequest) bool {
cmd := strings.Split(pk.CommandLine, " ")
if cmd[0] == "/setname" && len(cmd) >= 2 {
w.WorldName = strings.Join(cmd[1:], " ")
send_message(w.ClientConn, fmt.Sprintf("worldName is now: %s", w.WorldName))
return true
name := cmd[0][1:]
if h, ok := IngameCommands[name]; ok {
return h.exec(w, cmd[1:])
}
return false
}
@ -284,7 +309,9 @@ func (w *WorldState) SaveAndReset() {
// open world
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.ServerName, w.WorldName))
os.MkdirAll(folder, 0777)
os.RemoveAll(folder)
os.MkdirAll(folder, 0o777)
provider, err := mcdb.New(folder, opt.DefaultCompression)
if err != nil {
log.Fatal(err)
@ -296,7 +323,7 @@ func (w *WorldState) SaveAndReset() {
}
// save block nbt data
var blockNBT = make(map[protocol.ChunkPos][]map[string]any)
blockNBT := make(map[protocol.ChunkPos][]map[string]any)
for scp, v := range w.blockNBT { // 3d to 2d
cp := protocol.ChunkPos{scp.X(), scp.Z()}
blockNBT[cp] = append(blockNBT[cp], v...)
@ -403,7 +430,7 @@ func (w *WorldState) SaveAndReset() {
for k, p := range w.packs {
fmt.Printf("Adding resource pack: %s\n", k)
pack_folder := path.Join(folder, "resource_packs", k)
os.MkdirAll(pack_folder, 0755)
os.MkdirAll(pack_folder, 0o755)
data := make([]byte, p.Len())
p.ReadAt(data, 0)
unpack_zip(bytes.NewReader(data), int64(len(data)), pack_folder)
@ -426,7 +453,7 @@ func (c *WorldCMD) handleConn(ctx context.Context, l *minecraft.Listener, cc, sc
w.ServerName = server_name
w.ClientConn = cc
w.ServerConn = sc
w.voidgen = !c.enableGenerator
w.voidgen = c.enableVoid
if c.packs {
fmt.Println("reformatting packs")
@ -545,7 +572,9 @@ func (c *WorldCMD) handleConn(ctx context.Context, l *minecraft.Listener, cc, sc
case *packet.SubChunk:
w.ProcessSubChunk(pk)
case *packet.AvailableCommands:
pk.Commands = append(pk.Commands, setname_command)
for _, ic := range IngameCommands {
pk.Commands = append(pk.Commands, ic.cmd)
}
}
if err := w.ClientConn.WritePacket(pk); err != nil {