Compare commits

...

18 Commits

Author SHA1 Message Date
olebeck c0b14f3dd9 revert to before, because broken palette 2023-07-16 16:41:52 +02:00
olebeck 39be9c678b experimental transfer handler 2023-07-16 16:18:15 +02:00
olebeck f3d1a80985 fix pool being nil before the server connection finishes 2023-06-27 22:07:21 +02:00
olebeck 3455793b8a update gophertunnel 2023-06-25 16:44:26 +02:00
olebeck d3dc870a8a fix build tag 2023-06-24 13:42:08 +02:00
olebeck bf0197dbc4 add geometry json file for every skin 2023-06-24 11:02:58 +02:00
olebeck 6d95fdd1b3 display the link number in the ui, add realms to address selection 2023-06-16 20:01:28 +02:00
olebeck 4d27ac0e47 dont warn about empty geometry 2023-06-13 22:19:01 +02:00
olebeck 4e625223a7 fix gui build 2023-06-07 20:49:10 +02:00
olebeck d29f246921 1.20 support 2023-06-07 20:09:05 +02:00
olebeck eecbecd8fe make pack icon error a warning 2023-06-05 00:00:49 +02:00
olebeck 920c639866 support comments 2023-06-04 20:00:33 +02:00
olebeck f769573900 remove test thing 2023-05-30 16:35:38 +02:00
olebeck ef1b2b7025 build fix 2023-05-26 17:26:39 +02:00
olebeck fd02dd5d16 update to fix accidentally pushed broken code 2023-05-26 17:23:12 +02:00
olebeck a18548ffc2 gui capture button not hooked up lol 2023-05-15 01:17:09 +02:00
olebeck 405bb64850 add input validation to cli 2023-05-05 19:52:18 +02:00
olebeck f2c45d379d add updating to the ui 2023-05-04 16:00:51 +02:00
40 changed files with 996 additions and 403 deletions

View File

@ -5,6 +5,7 @@ import (
"context"
"flag"
"fmt"
"io"
"os"
"os/signal"
"runtime/debug"
@ -12,6 +13,7 @@ import (
"time"
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/bedrock-tool/bedrocktool/ui/messages"
"github.com/bedrock-tool/bedrocktool/utils"
"gopkg.in/square/go-jose.v2/json"
@ -30,9 +32,31 @@ type CLI struct {
func (c *CLI) Init() bool {
utils.SetCurrentUI(c)
utils.Auth.LoginWithMicrosoftCallback = func(r io.Reader) {
io.Copy(os.Stdout, r)
}
return true
}
/*
var m = &worlds.Map{}
func (c *CLI) Message(data interface{}) messages.MessageResponse {
switch me := data.(type) {
case messages.CanShowImages:
return messages.MessageResponse{Ok: true}
case messages.UpdateMap:
m.Update(&me)
}
return messages.MessageResponse{
Ok: false,
Data: nil,
}
}
*/
func (c *CLI) Start(ctx context.Context, cancel context.CancelFunc) error {
flag.Parse()
subcommands.Execute(ctx)
@ -80,17 +104,6 @@ func main() {
logrus.Infof(locale.Loc("bedrocktool_version", locale.Strmap{"Version": utils.Version}))
}
go func() {
newVersion, err := utils.Updater.UpdateAvailable()
if err != nil {
logrus.Error(err)
}
if newVersion != "" && utils.Version != "" {
logrus.Infof(locale.Loc("update_available", locale.Strmap{"Version": newVersion}))
}
}()
ctx, cancel := context.WithCancel(context.Background())
flag.StringVar(&utils.RealmsEnv, "realms-env", "", "realms env")
@ -116,6 +129,23 @@ func main() {
ui = &CLI{}
}
utils.CurrentUI = ui
if utils.Version != "" {
go func() {
newVersion, err := utils.Updater.UpdateAvailable()
if err != nil {
logrus.Error(err)
}
if newVersion != "" {
logrus.Infof(locale.Loc("update_available", locale.Strmap{"Version": newVersion}))
utils.UpdateAvailable = newVersion
ui.Message(messages.UpdateAvailable{Version: newVersion})
}
}()
}
// exit cleanup
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
@ -155,7 +185,7 @@ func (c *TransCMD) Execute(_ context.Context, ui utils.UI) error {
Reset = "\033[0m"
)
if c.auth {
utils.GetTokenSource()
utils.Auth.GetTokenSource()
}
fmt.Println(BlackFg + Bold + Blue + " Trans " + Pink + " Rights " + White + " Are " + Pink + " Human " + Blue + " Rights " + Reset)
return nil

70
go.mod
View File

@ -3,45 +3,47 @@ module github.com/bedrock-tool/bedrocktool
go 1.20
//replace github.com/sandertv/gophertunnel => ./gophertunnel
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.29.0-1
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.30.0-3
//replace github.com/df-mc/dragonfly => ./dragonfly
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.4-13
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.6-2
//replace gioui.org => ./gio
replace gioui.org => github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d
replace gioui.org => github.com/olebeck/gio v0.0.0-20230607184051-9ab60b08f083
require (
gioui.org v0.0.0-20230427133431-816bda7ac7bd
gioui.org/x v0.0.0-20230426160849-752f112c7a59
gioui.org v0.0.0-20230526230622-e3ef98dda382
gioui.org/x v0.0.0-20230523210033-8432ec5563bb
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
github.com/df-mc/dragonfly v0.9.4
github.com/df-mc/dragonfly v0.9.6
github.com/df-mc/goleveldb v1.1.9
github.com/fatih/color v1.15.0
github.com/flytam/filenamify v1.1.2
github.com/flytam/filenamify v1.1.3
github.com/go-gl/mathgl v1.0.0
github.com/google/subcommands v1.2.0
github.com/google/uuid v1.3.0
github.com/jinzhu/copier v0.3.5
github.com/miekg/dns v1.1.53
github.com/miekg/dns v1.1.54
github.com/nicksnyder/go-i18n/v2 v2.2.1
github.com/repeale/fp-go v0.11.1
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49
github.com/sandertv/go-raknet v1.12.0
github.com/sandertv/gophertunnel v1.29.0
github.com/shirou/gopsutil/v3 v3.23.3
github.com/sirupsen/logrus v1.9.0
github.com/sandertv/gophertunnel v1.30.0
github.com/shirou/gopsutil/v3 v3.23.5
github.com/sirupsen/logrus v1.9.3
golang.design/x/lockfree v0.0.1
golang.org/x/crypto v0.8.0
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
golang.org/x/oauth2 v0.7.0
golang.org/x/crypto v0.9.0
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/oauth2 v0.8.0
golang.org/x/term v0.8.0
golang.org/x/text v0.9.0
gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v3 v3.0.1
)
require (
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 // indirect
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7 // indirect
gioui.org/shader v1.0.6 // indirect
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 // indirect
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 // indirect
@ -49,33 +51,33 @@ require (
github.com/changkun/lockfree v0.0.1 // indirect
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 // indirect
github.com/df-mc/atomic v1.10.0 // indirect
github.com/df-mc/worldupgrader v1.0.3 // indirect
github.com/dlclark/regexp2 v1.9.0 // indirect
github.com/df-mc/worldupgrader v1.0.7 // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-text/typesetting v0.0.0-20230413204129-b4f0492bf7ae // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/go-text/typesetting v0.0.0-20230606200221-26abc51a6c27 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/klauspost/compress v1.15.15 // indirect
github.com/klauspost/compress v1.16.5 // indirect
github.com/kr/binarydist v0.1.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/shoenig/go-m1cpu v0.1.4 // indirect
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/segmentio/fasthash v1.0.3 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.uber.org/atomic v1.10.0 // indirect
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.uber.org/atomic v1.11.0 // indirect
golang.org/x/image v0.7.0 // indirect
golang.org/x/mod v0.8.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/tools v0.9.3 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/inconshreveable/go-update.v0 v0.0.0-20150814200126-d8b0b1d421aa // indirect
)

141
go.sum
View File

@ -1,11 +1,11 @@
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2 h1:AGDDxsJE1RpcXTAxPG2B4jrwVUJGFDjINIPi1jtO6pc=
gioui.org/cpu v0.0.0-20210817075930-8d6a761490d2/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7 h1:tNJdnP5CgM39PRc+KWmBRRYX/zJ+rd5XaYxY5d5veqA=
gioui.org/cpu v0.0.0-20220412190645-f1e9e8c3b1f7/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
gioui.org/shader v1.0.6 h1:cvZmU+eODFR2545X+/8XucgZdTtEjR3QWW6W65b0q5Y=
gioui.org/shader v1.0.6/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
gioui.org/x v0.0.0-20230426160849-752f112c7a59 h1:IdvHx1hSmuL9xs/p3rppWJnH01RXcBhz5HvB7pj9LAg=
gioui.org/x v0.0.0-20230426160849-752f112c7a59/go.mod h1:nMctdnZS2HKxfSXb+bCPnhw1n2LLsXoxtTarZjtIBuI=
gioui.org/x v0.0.0-20230523210033-8432ec5563bb h1:VnqXLYSd8UsVh6hrJJi6HjYl8Ow+iyDQTnwdKTp6lvY=
gioui.org/x v0.0.0-20230523210033-8432ec5563bb/go.mod h1:nMctdnZS2HKxfSXb+bCPnhw1n2LLsXoxtTarZjtIBuI=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr9PPB5aw8SjcOWWila7ZI=
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
@ -29,27 +29,27 @@ github.com/df-mc/atomic v1.10.0 h1:0ZuxBKwR/hxcFGorKiHIp+hY7hgY+XBTzhCYD2NqSEg=
github.com/df-mc/atomic v1.10.0/go.mod h1:Gw9rf+rPIbydMjA329Jn4yjd/O2c/qusw3iNp4tFGSc=
github.com/df-mc/goleveldb v1.1.9 h1:ihdosZyy5jkQKrxucTQmN90jq/2lUwQnJZjIYIC/9YU=
github.com/df-mc/goleveldb v1.1.9/go.mod h1:+NHCup03Sci5q84APIA21z3iPZCuk6m6ABtg4nANCSk=
github.com/df-mc/worldupgrader v1.0.3 h1:3nbthy6vfSNQZdqHBR+E5Fh3mCeWmCwLtqrYDiPUG5I=
github.com/df-mc/worldupgrader v1.0.3/go.mod h1:6ybkJ/BV9b0XkcPzcLmvgT9Nv/xgBXdDQTmRhu7b8zQ=
github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI=
github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/df-mc/worldupgrader v1.0.7 h1:t9kIiwZy8usH+H6TIkP3fvhIdDb+HRdQ3L/sEr2++Mc=
github.com/df-mc/worldupgrader v1.0.7/go.mod h1:tsSOLTRm9mpG7VHvYpAjjZrkRHWmSbKZAm9bOLNnlDk=
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/flytam/filenamify v1.1.2 h1:dGlfWU4zrhDlsmvob4IFcfgjG5vIjfo4UwLyec6Wx94=
github.com/flytam/filenamify v1.1.2/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
github.com/flytam/filenamify v1.1.3 h1:9k2R19mB/Nn5IrdozfiX4mnMW1WGXCF9KRD+25eDkv8=
github.com/flytam/filenamify v1.1.3/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-gl/mathgl v1.0.0 h1:t9DznWJlXxxjeeKLIdovCOVJQk/GzDEL7h/h+Ro2B68=
github.com/go-gl/mathgl v1.0.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-text/typesetting v0.0.0-20230413204129-b4f0492bf7ae h1:LCcaQgYrnS+sx9Tc3oGUvbRBRt+5oFnKWakaxeAvNVI=
github.com/go-text/typesetting v0.0.0-20230413204129-b4f0492bf7ae/go.mod h1:KmrpWuSMFcO2yjmyhGpnBGQHSKAoEgMTSSzvLDzCuEA=
github.com/go-text/typesetting v0.0.0-20230606200221-26abc51a6c27 h1:eIFR7h3qIaR3W3EbpMwWY8d9yk2L/oQVNtMlxhpWtyc=
github.com/go-text/typesetting v0.0.0-20230606200221-26abc51a6c27/go.mod h1:KmrpWuSMFcO2yjmyhGpnBGQHSKAoEgMTSSzvLDzCuEA=
github.com/go-text/typesetting-utils v0.0.0-20230412163830-89e4bcfa3ecc h1:9Kf84pnrmmjdRzZIkomfjowmGUhHs20jkrWYw/I6CYc=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
@ -68,29 +68,38 @@ github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo=
github.com/kr/binarydist v0.1.0/go.mod h1:DY7S//GCoz1BCd0B0EVrinCKAZN3pXe+MDaIZbXQVgM=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a h1:N9zuLhTvBSRt0gWSiJswwQ2HqDmtX/ZCDJURnKUt1Ik=
github.com/lufia/plan9stats v0.0.0-20230326075908-cb1d2100619a/go.mod h1:JKx41uQRwqlTZabZc+kILPrO/3jlKnQ2Z8b7YiVw5cE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/muhammadmuzzammil1998/jsonc v1.0.0 h1:8o5gBQn4ZA3NBA9DlTujCj2a4w0tqWrPVjDwhzkgTIs=
github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
github.com/nicksnyder/go-i18n/v2 v2.2.1 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
github.com/olebeck/dragonfly v0.9.4-13 h1:JF72hfG3/BBCXU1GSBaEKKXQy/gt+0mEOua3RdKXdJ8=
github.com/olebeck/dragonfly v0.9.4-13/go.mod h1:ZNcbAATEeTNyN3Cumtwzox7STtFve469HHzL5c1K3nY=
github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d h1:D+Ryca52xv37/p0FsEWfGwAGUZ1vPWpvimA2eMfBijc=
github.com/olebeck/gio v0.0.0-20230427194143-c9c9d8bc704d/go.mod h1:8CFQM/4LurRd9G3NUYdacFb9j2pK0LrAyVO2mAZo4mw=
github.com/olebeck/gophertunnel v1.29.0-1 h1:3x2cZoe8O54xVFgEZqTBJpFEXlzbjlLFoo/d9cWGv+g=
github.com/olebeck/gophertunnel v1.29.0-1/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
github.com/olebeck/dragonfly v0.9.6-2 h1:q4+5qGQ40nt9zy+/ooJKm0UyvklskjkVKKiZos1SY68=
github.com/olebeck/dragonfly v0.9.6-2/go.mod h1:/KIJwvuamZQsEcly1Eu6gDIfyAAmtC30pYWRnMYVzno=
github.com/olebeck/gio v0.0.0-20230607184051-9ab60b08f083 h1:ZnL97gNzNlVxNj7X3fhBqi70OALUVRbw1qw97vpYyso=
github.com/olebeck/gio v0.0.0-20230607184051-9ab60b08f083/go.mod h1:8CFQM/4LurRd9G3NUYdacFb9j2pK0LrAyVO2mAZo4mw=
github.com/olebeck/gophertunnel v1.30.0-1 h1:GUI2WX48cJKK/UcTLSIRU1O+nG6iURV8/l2KS8GsMsk=
github.com/olebeck/gophertunnel v1.30.0-1/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
github.com/olebeck/gophertunnel v1.30.0-2 h1:JbkADJTfpCfC7nL9O08LON0k8OBahfmOdByN3dy/CQE=
github.com/olebeck/gophertunnel v1.30.0-2/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
github.com/olebeck/gophertunnel v1.30.0-3 h1:D3PP7ttzZWgyHmacVMiPslWsTj3UNeRvO1x+5kA97wE=
github.com/olebeck/gophertunnel v1.30.0-3/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
github.com/olebeck/gophertunnel v1.31.0-1 h1:MeBwKKFT9SAe8FoeAT8o53TgrkPRJL5uAxLqWY3at5A=
github.com/olebeck/gophertunnel v1.31.0-1/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
github.com/olebeck/gophertunnel v1.31.0-2 h1:m/rUr/gjMTs/pSS5jPKlSxBJlC1WVjnxu8MHrVWfdkc=
github.com/olebeck/gophertunnel v1.31.0-2/go.mod h1:HxQfl/8mZzvjzhekEH8RO6xLAgan9i/wIyrQzw0tIPY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
@ -98,24 +107,27 @@ github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/repeale/fp-go v0.11.1 h1:Q/e+gNyyHaxKAyfdbBqvip3DxhVWH453R+kthvSr9Mk=
github.com/repeale/fp-go v0.11.1/go.mod h1:4KrwQJB1VRY+06CA+jTc4baZetr6o2PeuqnKr5ybQUc=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49 h1:LuxslTBxJrrNeKfqoywIERWWhH43TgiVAiPEVlhgNBA=
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49/go.mod h1:fY313ZGG810aWruFYcyq3coFpHDrWJVoMfSRI81y1r4=
github.com/sandertv/go-raknet v1.12.0 h1:olUzZlIJyX/pgj/mrsLCZYjKLNDsYiWdvQ4NIm3z0DA=
github.com/sandertv/go-raknet v1.12.0/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y=
github.com/shirou/gopsutil/v3 v3.23.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE=
github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU=
github.com/shoenig/go-m1cpu v0.1.4 h1:SZPIgRM2sEF9NJy50mRHu9PKGwxyyTTJIWvCtgVbozs=
github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ=
github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c=
github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y=
github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -124,48 +136,50 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.design/x/lockfree v0.0.1 h1:IHFNwZgM5bnZYWkEbzn5lWHMYr8WsRBdCJ/RBVY0xMM=
golang.design/x/lockfree v0.0.1/go.mod h1:iaZUx6UgZaOdePjzI6wFd+seYMl1i0rsG8+xKvA8c4I=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 h1:ryT6Nf0R83ZgD8WnFFdfI8wCeyqgdXWN4+CkFVNPAT0=
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91/go.mod h1:VjAR7z0ngyATZTELrBSkxOOHhhlnVUxDye4mcjx5h/8=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1 h1:NxHSRPlbeyFGDc6rU7YsvxV/4bXS9XhuvUt5pP63XUs=
golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:UH99kUObWAZkDnWqppdQe5ZhPYESUw8I0zVV1uWBR+0=
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -179,11 +193,13 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -195,16 +211,17 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=

View File

@ -46,7 +46,6 @@ var MutedPackets = []string{
var dirS2C = color.GreenString("S") + "->" + color.CyanString("C")
var dirC2S = color.CyanString("C") + "->" + color.GreenString("S")
var pool = packet.NewPool()
func NewDebugLogger(extraVerbose bool) *utils.ProxyHandler {
var logPlain, logCrypt, logCryptEnc io.WriteCloser
@ -71,13 +70,23 @@ func NewDebugLogger(extraVerbose bool) *utils.ProxyHandler {
var proxy *utils.ProxyContext
serverPool := packet.NewServerPool()
clientPool := packet.NewClientPool()
pool := make(packet.Pool)
for k, v := range serverPool {
pool[k] = v
}
for k, v := range clientPool {
pool[k] = v
}
return &utils.ProxyHandler{
Name: "Debug",
ProxyRef: func(pc *utils.ProxyContext) {
proxy = pc
},
PacketFunc: func(header packet.Header, payload []byte, src, dst net.Addr) {
pk := utils.DecodePacket(header, payload)
pk := utils.DecodePacket(pool, header, payload)
if pk == nil {
return
}

View File

@ -39,7 +39,7 @@ func (s *secondaryUser) processLevelChunk(pk *packet.LevelChunk) {
subChunkCount = int(pk.SubChunkCount)
}
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, s.dimension.Range(), s.ispre118, s.hasCustomBlocks)
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, s.ispre118, s.dimension.Range())
if err != nil {
logrus.Error(err)
return

View File

@ -1,8 +1,6 @@
package seconduser
import (
"sync"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
"github.com/google/uuid"
@ -14,7 +12,6 @@ type provider struct {
func (p *provider) Settings() *world.Settings {
return &world.Settings{
Mutex: sync.Mutex{},
Name: "world",
Spawn: cube.Pos{0, 0, 0},
DefaultGameMode: world.GameModeCreative,

View File

@ -22,9 +22,7 @@ type secondaryUser struct {
server *server.Server
proxy *utils.ProxyContext
ispre118 bool
hasCustomBlocks bool
ispre118 bool
chunks map[world.ChunkPos]*chunk.Chunk
blockNBTs map[protocol.BlockPos][]map[string]any
dimension world.Dimension

View File

@ -37,7 +37,7 @@ func (w *worldsHandler) processLevelChunk(pk *packet.LevelChunk) {
subChunkCount = int(pk.SubChunkCount)
}
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, w.worldState.dimension.Range(), w.serverState.ispre118, w.bp.HasBlocks())
ch, blockNBTs, err := chunk.NetworkDecode(world.AirRID(), pk.RawPayload, subChunkCount, w.serverState.ispre118, w.worldState.dimension.Range())
if err != nil {
logrus.Error(err)
return

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

View File

@ -1,53 +0,0 @@
package worlds_test
import (
"image/png"
"os"
"runtime/pprof"
"testing"
"github.com/bedrock-tool/bedrocktool/utils"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world/chunk"
)
func Test(t *testing.T) {
data, _ := os.ReadFile("chunk.bin")
ch, _, _ := chunk.NetworkDecode(33, data, 6, cube.Range{0, 255}, true, false)
i := utils.Chunk2Img(ch)
f, _ := os.Create("chunk.png")
png.Encode(f, i)
f.Close()
}
func Benchmark_chunk_decode(b *testing.B) {
data, _ := os.ReadFile("chunk.bin")
cf, _ := os.Create("cpu.pprof")
err := pprof.StartCPUProfile(cf)
if err != nil {
b.Error(err)
}
for i := 0; i < b.N; i++ {
_, _, err := chunk.NetworkDecode(33, data, 6, cube.Range{0, 255}, true, false)
if err != nil {
b.Error(err)
}
}
pprof.StopCPUProfile()
}
func Benchmark_render_chunk(b *testing.B) {
data, _ := os.ReadFile("chunk.bin")
ch, _, _ := chunk.NetworkDecode(33, data, 6, cube.Range{0, 255}, true, false)
cf, _ := os.Create("cpu.pprof")
err := pprof.StartCPUProfile(cf)
if err != nil {
b.Error(err)
}
for i := 0; i < b.N; i++ {
utils.Chunk2Img(ch)
}
pprof.StopCPUProfile()
}

View File

@ -205,14 +205,23 @@ func (s *entityState) ToServerEntity() serverEntity {
}
entityMetadataToNBT(s.Metadata, e.EntityType.NBT)
if s.Helmet != nil || s.Chestplate != nil || s.Leggings != nil || s.Boots != nil {
e.EntityType.NBT["Armor"] = []map[string]any{
nbtconv.WriteItem(stackToItem(s.Helmet.Stack), true),
nbtconv.WriteItem(stackToItem(s.Chestplate.Stack), true),
nbtconv.WriteItem(stackToItem(s.Leggings.Stack), true),
nbtconv.WriteItem(stackToItem(s.Boots.Stack), true),
if false {
armor := make([]map[string]any, 4)
if s.Helmet != nil {
armor[0] = nbtconv.WriteItem(stackToItem(s.Helmet.Stack), true)
}
if s.Chestplate != nil {
armor[1] = nbtconv.WriteItem(stackToItem(s.Chestplate.Stack), true)
}
if s.Leggings != nil {
armor[2] = nbtconv.WriteItem(stackToItem(s.Leggings.Stack), true)
}
if s.Boots != nil {
armor[3] = nbtconv.WriteItem(stackToItem(s.Boots.Stack), true)
}
e.EntityType.NBT["Armor"] = armor
}
return e
}

View File

@ -4,7 +4,6 @@ import (
"context"
"flag"
seconduser "github.com/bedrock-tool/bedrocktool/handlers/second-user"
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/bedrock-tool/bedrocktool/utils"
)
@ -31,7 +30,6 @@ func (c *DebugProxyCMD) Execute(ctx context.Context, ui utils.UI) error {
if err != nil {
return err
}
proxy.AddHandler(seconduser.NewSecondUser())
return proxy.Run(ctx, address, hostname)
}

View File

@ -45,6 +45,10 @@ func (c *SkinCMD) Execute(ctx context.Context, ui utils.UI) error {
OnClientConnect: func(conn minecraft.IConn) {
ui.Message(messages.SetUIState(messages.UIStateConnecting))
},
OnServerConnect: func() (cancel bool) {
ui.Message(messages.SetUIState(messages.UIStateMain))
return false
},
})
if proxy.WithClient {

View File

@ -55,7 +55,6 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
SaveImage: c.SaveImage,
}))
ui.Message(messages.SetUIState(messages.UIStateConnect))
err = proxy.Run(ctx, serverAddress, hostname)
if err != nil {
return err

View File

@ -1,10 +1,12 @@
//go:build gui || android
//go:build gui
package ui
import (
"bufio"
"context"
"image/color"
"io"
"gioui.org/app"
"gioui.org/font/gofont"
@ -17,6 +19,7 @@ import (
"github.com/bedrock-tool/bedrocktool/ui/gui/pages/packs"
"github.com/bedrock-tool/bedrocktool/ui/gui/pages/settings"
"github.com/bedrock-tool/bedrocktool/ui/gui/pages/skins"
"github.com/bedrock-tool/bedrocktool/ui/gui/pages/update"
"github.com/bedrock-tool/bedrocktool/ui/gui/pages/worlds"
"github.com/bedrock-tool/bedrocktool/ui/messages"
"github.com/bedrock-tool/bedrocktool/utils"
@ -26,12 +29,14 @@ import (
type GUI struct {
utils.BaseUI
router pages.Router
cancel context.CancelFunc
router pages.Router
cancel context.CancelFunc
authPopup bool
authPopupText string
}
func (g *GUI) Init() bool {
utils.SetCurrentUI(g)
utils.Auth.LoginWithMicrosoftCallback = g.LoginWithMicrosoftCallback
return true
}
@ -53,7 +58,7 @@ func (g *GUI) Start(ctx context.Context, cancel context.CancelFunc) (err error)
g.cancel = cancel
w := app.NewWindow(
app.Title("Bedrocktool"),
app.Title("Bedrocktool " + utils.Version),
)
th := material.NewTheme(gofont.Collection())
@ -70,25 +75,19 @@ func (g *GUI) Start(ctx context.Context, cancel context.CancelFunc) (err error)
}
g.router = pages.NewRouter(ctx, w.Invalidate, th)
g.router.Register("Settings", settings.New(&g.router))
g.router.Register("worlds", worlds.New(&g.router))
g.router.Register("skins", skins.New(&g.router))
g.router.Register("packs", packs.New(&g.router))
g.router.Register("update", update.New(&g.router))
g.router.SwitchTo("Settings")
go func() {
err = g.run(w)
}()
go func() {
app.Main()
}()
<-ctx.Done()
return err
return g.run(w)
}
func (g *GUI) run(w *app.Window) error {
@ -104,7 +103,20 @@ func (g *GUI) run(w *app.Window) error {
return e.Err
case system.FrameEvent:
gtx := layout.NewContext(&ops, e)
g.router.Layout(gtx, g.router.Theme)
layout.Stack{
Alignment: layout.Center,
}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
return g.router.Layout(gtx, g.router.Theme)
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
if g.authPopup {
return g.AuthPopup(gtx)
}
return layout.Dimensions{}
}),
)
e.Frame(gtx.Ops)
}
case <-g.router.Ctx.Done():
@ -135,6 +147,29 @@ func (g *GUI) Message(data interface{}) messages.MessageResponse {
return r
}
func (g *GUI) AuthPopup(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Max = gtx.Constraints.Max.Div(2)
return layout.Center.Layout(gtx, material.Body1(g.router.Theme, g.authPopupText).Layout)
}
func (g *GUI) LoginWithMicrosoftCallback(r io.Reader) {
g.authPopup = true
b := bufio.NewReader(r)
for {
line, _, err := b.ReadLine()
if err != nil {
panic(err)
}
println(string(line))
g.authPopupText += string(line) + "\n"
g.router.Invalidate()
if string(line) == "Authentication successful." {
break
}
}
g.authPopup = false
}
func init() {
utils.MakeGui = func() utils.UI {
return &GUI{}

16
ui/gui/icons/main.go Normal file
View File

@ -0,0 +1,16 @@
package icons
import (
"gioui.org/widget"
"golang.org/x/exp/shiny/materialdesign/icons"
)
func mustIcon(data []byte) widget.Icon {
ic, err := widget.NewIcon(data)
if err != nil {
panic(err)
}
return *ic
}
var ActionUpdate = mustIcon(icons.ActionUpdate)

View File

@ -96,7 +96,6 @@ func drawPackIcon(gtx C, hasImage bool, imageOp paint.ImageOp, bounds image.Poin
}
return D{Size: bounds}
})
}
func MulAlpha(c color.NRGBA, alpha uint8) color.NRGBA {
@ -197,14 +196,12 @@ func (p *Page) layoutFinished(gtx C, th *material.Theme) D {
}
func (p *Page) Layout(gtx C, th *material.Theme) D {
margin := layout.Inset{
return layout.Inset{
Top: unit.Dp(25),
Bottom: unit.Dp(25),
Right: unit.Dp(35),
Left: unit.Dp(35),
}
return margin.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
switch p.State {
case messages.UIStateConnecting:
return layout.Center.Layout(gtx, material.Label(th, 100, "Connecting").Layout)

View File

@ -8,9 +8,12 @@ import (
"gioui.org/layout"
"gioui.org/op/paint"
"gioui.org/widget"
"gioui.org/widget/material"
"gioui.org/x/component"
"github.com/bedrock-tool/bedrocktool/ui/messages"
"github.com/bedrock-tool/bedrocktool/utils"
"github.com/sirupsen/logrus"
)
type HandlerFunc = func(data interface{}) messages.MessageResponse
@ -39,6 +42,8 @@ type Router struct {
*component.AppBar
*component.ModalLayer
NonModalDrawer, BottomBar bool
UpdateButton *widget.Clickable
}
func NewRouter(ctx context.Context, invalidate func(), th *material.Theme) Router {
@ -63,6 +68,8 @@ func NewRouter(ctx context.Context, invalidate func(), th *material.Theme) Route
ModalNavDrawer: modalNav,
AppBar: bar,
NavAnim: na,
UpdateButton: &widget.Clickable{},
}
}
@ -90,6 +97,10 @@ func (r *Router) SwitchTo(tag string) {
}
func (r *Router) Layout(gtx layout.Context, th *material.Theme) layout.Dimensions {
if r.UpdateButton.Clicked() {
r.SwitchTo("update")
}
for _, event := range r.AppBar.Events(gtx) {
switch event := event.(type) {
case component.AppBarNavigationClicked:
@ -141,6 +152,18 @@ func (r *Router) Handler(data interface{}) messages.MessageResponse {
return messages.MessageResponse{}
}
func (r *Router) Execute(cmd utils.Command) {
r.Wg.Add(1)
go func() {
defer r.Wg.Done()
err := cmd.Execute(r.Ctx, utils.CurrentUI)
if err != nil {
logrus.Error(err)
}
}()
}
var Pages = map[string]func(*Router) Page{}
func Register(name string, fun func(*Router) Page) {

View File

@ -9,6 +9,7 @@ import (
"gioui.org/widget"
"gioui.org/widget/material"
"gioui.org/x/component"
"github.com/bedrock-tool/bedrocktool/ui/gui/icons"
"github.com/bedrock-tool/bedrocktool/ui/gui/pages"
"github.com/bedrock-tool/bedrocktool/ui/gui/settings"
"github.com/bedrock-tool/bedrocktool/ui/messages"
@ -33,6 +34,8 @@ type Page struct {
}
startButton widget.Clickable
actions []component.AppBarAction
}
func New(router *pages.Router) *Page {
@ -50,6 +53,10 @@ func New(router *pages.Router) *Page {
p.cmdMenu.items = make(map[string]*widget.Clickable, len(utils.ValidCMDs))
options := make([]func(layout.Context) layout.Dimensions, 0, len(utils.ValidCMDs))
for _, name := range cmdNames {
if _, ok := settings.Settings[name]; !ok {
continue
}
item := &widget.Clickable{}
p.cmdMenu.items[name] = item
options = append(options, component.MenuItem(router.Theme, item, name).Layout)
@ -70,7 +77,7 @@ func New(router *pages.Router) *Page {
var _ pages.Page = &Page{}
func (p *Page) Actions() []component.AppBarAction {
return []component.AppBarAction{}
return p.actions
}
func (p *Page) Overflow() []component.OverflowAction {
@ -97,16 +104,7 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
}
p.Router.SwitchTo(p.cmdMenu.selected)
p.Router.Wg.Add(1)
go func() {
defer p.Router.Wg.Done()
err := cmd.Execute(p.Router.Ctx, utils.CurrentUI)
if err != nil {
logrus.Error(err)
}
}()
p.Router.Execute(cmd)
}
}
@ -173,7 +171,17 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
})
}
func (p *Page) Handler(any) messages.MessageResponse {
func (p *Page) Handler(m any) messages.MessageResponse {
switch m.(type) {
case messages.UpdateAvailable:
p.actions = []component.AppBarAction{
component.SimpleIconAction(p.Router.UpdateButton, &icons.ActionUpdate, component.OverflowAction{}),
}
p.Router.AppBar.SetActions(p.actions, nil)
p.Router.Invalidate()
}
return messages.MessageResponse{
Ok: false,
Data: nil,

View File

@ -55,27 +55,24 @@ func (p *Page) NavItem() component.NavItem {
}
func (p *Page) Layout(gtx C, th *material.Theme) D {
margin := layout.Inset{
return layout.Inset{
Top: unit.Dp(25),
Bottom: unit.Dp(25),
Right: unit.Dp(35),
Left: unit.Dp(35),
}
switch p.State {
case messages.UIStateConnect:
// display login page
return margin.Layout(gtx, material.Label(th, 100, "connect Client").Layout)
case messages.UIStateConnecting:
// display connecting to server
return margin.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
case messages.UIStateMain:
// show the main ui
return margin.Layout(gtx, func(gtx C) D {
}.Layout(gtx, func(gtx C) D {
switch p.State {
case messages.UIStateConnect:
// display login page
return material.Label(th, 100, "connect Client").Layout(gtx)
case messages.UIStateConnecting:
// display connecting to server
return material.Label(th, 100, "Connecting").Layout(gtx)
case messages.UIStateMain:
// show the main ui
return layout.Flex{
Axis: layout.Vertical,
}.Layout(gtx,
layout.Rigid(material.Label(th, 20, "Skin Basic UI").Layout),
layout.Flexed(1, func(gtx C) D {
p.l.Lock()
defer p.l.Unlock()
@ -89,10 +86,9 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
})
}),
)
})
}
return layout.Flex{}.Layout(gtx)
}
return D{}
})
}
func (p *Page) Handler(data interface{}) messages.MessageResponse {

View File

@ -0,0 +1,107 @@
package update
import (
"fmt"
"gioui.org/layout"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"gioui.org/x/component"
"github.com/bedrock-tool/bedrocktool/ui/gui/pages"
"github.com/bedrock-tool/bedrocktool/ui/messages"
"github.com/bedrock-tool/bedrocktool/utils"
)
type (
C = layout.Context
D = layout.Dimensions
)
type Page struct {
*pages.Router
State messages.UIState
startButton widget.Clickable
err error
updating bool
}
func New(router *pages.Router) *Page {
return &Page{
Router: router,
State: messages.UIStateMain,
}
}
var _ pages.Page = &Page{}
func (p *Page) Actions() []component.AppBarAction {
return []component.AppBarAction{}
}
func (p *Page) Overflow() []component.OverflowAction {
return []component.OverflowAction{}
}
func (p *Page) NavItem() component.NavItem {
return component.NavItem{
Name: "Update",
//Icon: icon.OtherIcon,
}
}
func (p *Page) Layout(gtx C, th *material.Theme) D {
if p.startButton.Clicked() && !p.updating {
p.updating = true
go func() {
p.err = utils.Updater.Update()
if p.err == nil {
p.State = messages.UIStateFinished
}
p.updating = false
p.Router.Invalidate()
}()
}
return layout.Inset{
Top: unit.Dp(25),
Bottom: unit.Dp(25),
Right: unit.Dp(35),
Left: unit.Dp(35),
}.Layout(gtx, func(gtx C) D {
if p.err != nil {
return layout.Center.Layout(gtx, material.H1(th, p.err.Error()).Layout)
}
if p.updating {
return layout.Center.Layout(gtx, material.H3(th, "Updating...").Layout)
}
switch p.State {
case messages.UIStateMain:
// show the main ui
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(material.Label(th, 20, fmt.Sprintf("Current: %s\nNew: %s", utils.Version, utils.UpdateAvailable)).Layout),
layout.Rigid(material.Button(th, &p.startButton, "Do Update").Layout),
)
case messages.UIStateFinished:
return layout.Center.Layout(gtx, func(gtx C) D {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(material.H3(th, "Update Finished").Layout),
layout.Rigid(func(gtx C) D {
return layout.Center.Layout(gtx, material.Label(th, th.TextSize, "restart the app").Layout)
}),
)
})
}
return D{}
})
}
func (p *Page) Handler(data interface{}) messages.MessageResponse {
r := messages.MessageResponse{
Ok: false,
Data: nil,
}
return r
}

View File

@ -41,7 +41,7 @@ func (m *Map) HandlePointerEvent(e pointer.Event) {
case pointer.Release:
m.grabbed = false
case pointer.Scroll:
scaleFactor := -float32(math.Pow(1.01, float64(e.Scroll.Y)))
scaleFactor := float32(math.Pow(1.01, float64(e.Scroll.Y)))
m.transform = m.transform.Scale(e.Position.Sub(m.center), f32.Pt(scaleFactor, scaleFactor))
m.scaleFactor *= scaleFactor
}
@ -122,8 +122,7 @@ func (m *Map) Update(u *messages.UpdateMap) {
}
} else {
for _, pos := range u.UpdatedTiles {
tile := u.Tiles[pos]
drawTile(m.MapImage, m.BoundsMin, pos, tile)
drawTile(m.MapImage, m.BoundsMin, pos, u.Tiles[pos])
}
}

View File

@ -91,9 +91,7 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
return layout.Center.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
case messages.UIStateMain:
// show the main ui
return layout.Flex{
Axis: layout.Vertical,
}.Layout(gtx,
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
//layout.Rigid(material.Label(th, th.TextSize, p.worldName).Layout),
layout.Flexed(1, func(gtx C) D {
return layout.Center.Layout(gtx, p.worldMap.Layout)

View File

@ -0,0 +1,128 @@
package settings
import (
"context"
"fmt"
"image"
"image/color"
"sync"
"gioui.org/layout"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"github.com/bedrock-tool/bedrocktool/utils"
"github.com/sandertv/gophertunnel/minecraft/realms"
"github.com/sirupsen/logrus"
)
type addressInput struct {
Editor widget.Editor
showRealmsList widget.Bool
l sync.Mutex
realmsList widget.List
realms []realms.Realm
realmsButtons map[int]*widget.Clickable
loading bool
}
var AddressInput = &addressInput{
Editor: widget.Editor{
SingleLine: true,
},
realmsList: widget.List{
List: layout.List{
Axis: layout.Vertical,
},
},
}
func (a *addressInput) Value() string {
return a.Editor.Text()
}
func (a *addressInput) getRealms() {
var err error
a.loading = true
a.realms, err = utils.GetRealmsAPI().Realms(context.Background())
a.realmsButtons = make(map[int]*widget.Clickable)
for _, r := range a.realms {
a.realmsButtons[r.ID] = &widget.Clickable{}
}
a.loading = false
if err != nil {
logrus.Error(err)
}
}
func MulAlpha(c color.NRGBA, alpha uint8) color.NRGBA {
c.A = uint8(uint32(c.A) * uint32(alpha) / 0xFF)
return c
}
func (a *addressInput) Layout(th *material.Theme) layout.Widget {
for k, c := range a.realmsButtons {
if c.Clicked() {
for _, r := range a.realms {
if r.ID == k {
a.Editor.SetText(fmt.Sprintf("realm:%s:%d", r.Name, r.ID))
}
}
}
}
return func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
e := material.Editor(th, &a.Editor, "server Address")
return layout.UniformInset(5).Layout(gtx, e.Layout)
}),
layout.Rigid(layout.Spacer{Width: unit.Dp(10)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical, Alignment: layout.Middle}.Layout(gtx,
layout.Rigid(material.Label(th, th.TextSize, "list realms").Layout),
layout.Rigid(material.Switch(th, &a.showRealmsList, "realms").Layout),
)
}),
)
}),
layout.Flexed(0.5, func(gtx layout.Context) layout.Dimensions {
if a.loading {
return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Max = image.Pt(20, 20)
return material.Loader(th).Layout(gtx)
})
}
if a.showRealmsList.Value {
if a.showRealmsList.Changed() {
go a.getRealms()
}
a.l.Lock()
defer a.l.Unlock()
if len(a.realms) == 0 {
return material.Label(th, th.TextSize, "you have no realms").Layout(gtx)
}
return material.List(th, &a.realmsList).Layout(gtx, len(a.realms), func(gtx layout.Context, index int) layout.Dimensions {
entry := a.realms[index]
return material.ButtonLayoutStyle{
Background: MulAlpha(th.Palette.Bg, 0x60),
Button: a.realmsButtons[entry.ID],
CornerRadius: 3,
}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.UniformInset(15).Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
layout.Rigid(material.Label(th, th.TextSize, entry.Name).Layout),
)
})
})
})
}
return layout.Dimensions{}
}),
)
}
}

View File

@ -2,7 +2,6 @@ package settings
import (
"gioui.org/layout"
"gioui.org/widget"
"gioui.org/widget/material"
"github.com/bedrock-tool/bedrocktool/subcommands"
"github.com/bedrock-tool/bedrocktool/utils"
@ -11,21 +10,21 @@ import (
type packsSettings struct {
packs *subcommands.ResourcePackCMD
serverAddress widget.Editor
serverAddress *addressInput
}
func (s *packsSettings) Init() {
s.packs = utils.ValidCMDs["packs"].(*subcommands.ResourcePackCMD)
s.serverAddress.SingleLine = true
s.serverAddress = AddressInput
}
func (s *packsSettings) Apply() {
s.packs.ServerAddress = s.serverAddress.Text()
s.packs.ServerAddress = s.serverAddress.Value()
}
func (s *packsSettings) Layout(gtx layout.Context, th *material.Theme) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(material.Editor(th, &s.serverAddress, "Server Address").Layout),
layout.Rigid(s.serverAddress.Layout(th)),
)
}

View File

@ -14,12 +14,12 @@ type skinsSettings struct {
Filter widget.Editor
Proxy widget.Bool
serverAddress widget.Editor
serverAddress *addressInput
}
func (s *skinsSettings) Init() {
s.skins = utils.ValidCMDs["skins"].(*skins.SkinCMD)
s.serverAddress.SingleLine = true
s.serverAddress = AddressInput
s.Filter.SingleLine = true
s.Proxy.Value = true
}
@ -27,7 +27,7 @@ func (s *skinsSettings) Init() {
func (s *skinsSettings) Apply() {
s.skins.Filter = s.Filter.Text()
s.skins.NoProxy = !s.Proxy.Value
s.skins.ServerAddress = s.serverAddress.Text()
s.skins.ServerAddress = s.serverAddress.Value()
}
func (s *skinsSettings) Layout(gtx layout.Context, th *material.Theme) layout.Dimensions {
@ -35,7 +35,7 @@ func (s *skinsSettings) Layout(gtx layout.Context, th *material.Theme) layout.Di
layout.Rigid(material.CheckBox(th, &s.Proxy, "Enable Proxy").Layout),
layout.Rigid(material.Editor(th, &s.Filter, "Player name filter").Layout),
layout.Rigid(layout.Spacer{Height: unit.Dp(15)}.Layout),
layout.Rigid(material.Editor(th, &s.serverAddress, "server Address").Layout),
layout.Rigid(s.serverAddress.Layout(th)),
)
}

View File

@ -15,12 +15,12 @@ type worldSettings struct {
voidGen widget.Bool
saveImage widget.Bool
PacketCapture widget.Bool
serverAddress widget.Editor
serverAddress *addressInput
}
func (s *worldSettings) Init() {
s.worlds = utils.ValidCMDs["worlds"].(*world.WorldCMD)
s.serverAddress.SingleLine = true
s.serverAddress = AddressInput
s.voidGen.Value = true
s.PacketCapture.Value = false
}
@ -29,9 +29,10 @@ func (s *worldSettings) Apply() {
s.worlds.Packs = s.withPacks.Value
s.worlds.EnableVoid = s.voidGen.Value
s.worlds.SaveImage = s.saveImage.Value
s.worlds.ServerAddress = s.serverAddress.Text()
s.worlds.ServerAddress = s.serverAddress.Value()
s.worlds.SaveEntities = true
s.worlds.SaveInventories = true
utils.Options.Capture = s.PacketCapture.Value
}
func (s *worldSettings) Layout(gtx layout.Context, th *material.Theme) layout.Dimensions {
@ -40,7 +41,7 @@ func (s *worldSettings) Layout(gtx layout.Context, th *material.Theme) layout.Di
layout.Rigid(material.CheckBox(th, &s.voidGen, "void Generator").Layout),
layout.Rigid(material.CheckBox(th, &s.saveImage, "save image").Layout),
layout.Rigid(material.CheckBox(th, &s.PacketCapture, "packet capture").Layout),
layout.Rigid(material.Editor(th, &s.serverAddress, "server Address").Layout),
layout.Rigid(s.serverAddress.Layout(th)),
)
}

View File

@ -96,3 +96,7 @@ type DownloadedPack struct {
type FinishedDownloadingPacks struct {
Packs []*DownloadedPack
}
type UpdateAvailable struct {
Version string
}

View File

@ -3,35 +3,102 @@ package utils
import (
"encoding/json"
"fmt"
"io"
"os"
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/sandertv/gophertunnel/minecraft/auth"
"github.com/sandertv/gophertunnel/minecraft/realms"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
)
const TokenFile = "token.json"
var gTokenSrc oauth2.TokenSource
type authsrv struct {
t *oauth2.Token
src oauth2.TokenSource
func GetTokenSource() oauth2.TokenSource {
if gTokenSrc != nil {
return gTokenSrc
}
token := getToken()
gTokenSrc = auth.RefreshTokenSource(&token)
newToken, err := gTokenSrc.Token()
LoginWithMicrosoftCallback func(io.Reader)
}
var Auth authsrv
func (a *authsrv) HaveToken() bool {
_, err := os.Stat(TokenFile)
return err == nil
}
func (a *authsrv) Refresh() error {
a.src = auth.RefreshTokenSource(a.t)
return nil
}
func (a *authsrv) writeToken() error {
f, err := os.Create(TokenFile)
if err != nil {
panic(err)
}
if !token.Valid() {
logrus.Info(locale.Loc("refreshed_token", nil))
writeToken(newToken)
return err
}
defer f.Close()
e := json.NewEncoder(f)
return e.Encode(a.t)
}
return gTokenSrc
func (a *authsrv) readToken() error {
var token oauth2.Token
f, err := os.Open(TokenFile)
if err != nil {
return err
}
defer f.Close()
e := json.NewDecoder(f)
err = e.Decode(&token)
if err != nil {
return err
}
a.t = &token
return nil
}
func (a *authsrv) GetTokenSource() (src oauth2.TokenSource, err error) {
if a.src != nil {
return a.src, nil
}
if !a.HaveToken() {
// request a new token
r, w := io.Pipe()
go a.LoginWithMicrosoftCallback(r)
a.t, err = auth.RequestLiveTokenWriter(w)
if err != nil {
return nil, err
}
err := a.writeToken()
if err != nil {
return nil, err
}
} else {
// read the existing token
err := a.readToken()
if err != nil {
return nil, err
}
}
// refresh the token if necessary
err = a.Refresh()
if err != nil {
return nil, err
}
// if the old token isnt valid save the new one
if !a.t.Valid() {
newToken, err := a.src.Token()
if err != nil {
return nil, err
}
a.t = newToken
err = a.writeToken()
if err != nil {
return nil, err
}
}
return a.src, nil
}
var RealmsEnv string
@ -43,37 +110,7 @@ func GetRealmsAPI() *realms.Client {
if RealmsEnv != "" {
realms.RealmsAPIBase = fmt.Sprintf("https://pocket-%s.realms.minecraft.net/", RealmsEnv)
}
gRealmsAPI = realms.NewClient(GetTokenSource())
gRealmsAPI = realms.NewClient(Auth.src)
}
return gRealmsAPI
}
func writeToken(token *oauth2.Token) {
buf, err := json.Marshal(token)
if err != nil {
panic(err)
}
os.WriteFile(TokenFile, buf, 0o755)
}
func getToken() oauth2.Token {
var token oauth2.Token
if _, err := os.Stat(TokenFile); err == nil {
f, err := os.Open(TokenFile)
if err != nil {
panic(err)
}
defer f.Close()
if err := json.NewDecoder(f).Decode(&token); err != nil {
panic(err)
}
} else {
_token, err := auth.RequestLiveToken()
if err != nil {
panic(err)
}
writeToken(_token)
token = *_token
}
return token
}

View File

@ -54,17 +54,16 @@ func (bp *BehaviourPack) AddEntity(entity EntityIn) {
}
for _, av := range entity.Attr {
switch av.Name {
case "minecraft:health":
entry.MinecraftEntity.Components["minecraft:health"] = map[string]int{
"value": int(av.Value),
"max": int(av.Max),
}
case "minecraft:movement":
entry.MinecraftEntity.Components["minecraft:movement"] = map[string]any{
"value": av.Value,
}
m := map[string]int{
"value": int(av.Value),
"min": int(av.Min),
}
if av.Max > 0 && av.Max < 0xffffff {
m["max"] = int(av.Max)
}
entry.MinecraftEntity.Components[av.Name] = m
}
if scale, ok := entity.Meta[protocol.EntityDataKeyScale].(float32); ok {
@ -86,8 +85,7 @@ func (bp *BehaviourPack) AddEntity(entity EntityIn) {
AlwaysShowName := entity.Meta.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagAlwaysShowName)
if AlwaysShowName {
entry.MinecraftEntity.Components["minecraft:nameable"] = map[string]any{
"always_show": true,
"allow_name_tag_renaming": false,
"always_show": true,
}
}
}

View File

@ -1,26 +1,84 @@
package utils
import (
"bufio"
"context"
"fmt"
"net"
"os"
"regexp"
"strings"
"sync/atomic"
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/sirupsen/logrus"
"golang.org/x/term"
)
func UserInput(ctx context.Context, q string) (string, bool) {
func UserInput(ctx context.Context, q string, validator func(string) bool) (string, bool) {
c := make(chan string)
oldState, _ := term.MakeRaw(int(os.Stdin.Fd()))
defer term.Restore(int(os.Stdin.Fd()), oldState)
go func() {
fmt.Print(q)
reader := bufio.NewReader(os.Stdin)
answer, _ := reader.ReadString('\n')
r, _ := regexp.Compile(`[\n\r]`)
answer = string(r.ReplaceAll([]byte(answer), []byte("")))
var answerb []byte
var b [1]byte
var valid bool
var validatorRunning atomic.Bool
var validatorQueued atomic.Bool
for {
os.Stdin.Read(b[:])
done := false
switch b[0] {
case 0x3:
c <- ""
return
case 0xA:
fallthrough
case 0xD:
done = true
case 0x8:
fallthrough
case 0x7F:
if len(answerb) > 0 {
answerb = answerb[:len(answerb)-1]
}
default:
if b[0] >= 0x20 {
answerb = append(answerb, b[0])
}
}
if done {
break
}
fmt.Printf("\r%s%s\033[K", q, string(answerb))
if validator != nil {
validatorQueued.Store(true)
if validatorRunning.CompareAndSwap(false, true) {
go func() {
for validatorQueued.Load() {
validatorQueued.Store(false)
valid = validator(string(answerb))
validatorRunning.Store(false)
var st = "❌"
if valid {
st = "✅"
}
fmt.Printf("\r%s%s %s\033[K\033[%dD", q, string(answerb), st, 4)
}
}()
}
}
}
print("\n\r")
answer := string(answerb)
c <- answer
}()
@ -28,6 +86,9 @@ func UserInput(ctx context.Context, q string) (string, bool) {
case <-ctx.Done():
return "", true
case a := <-c:
if a == "" {
return a, true
}
return a, false
}
}
@ -60,7 +121,7 @@ func ServerInput(ctx context.Context, server string) (string, string, error) {
// no arg provided, interactive input
if server == "" {
var cancelled bool
server, cancelled = UserInput(ctx, locale.Loc("enter_server", nil))
server, cancelled = UserInput(ctx, locale.Loc("enter_server", nil), ValidateServerInput)
if cancelled {
return "", "", context.Canceled
}
@ -94,3 +155,28 @@ func ServerInput(ctx context.Context, server string) (string, string, error) {
}
return server, serverGetHostname(server), nil
}
func ValidateServerInput(server string) bool {
if pcapRegex.MatchString(server) {
return true
}
if realmRegex.MatchString(server) {
return true // todo
}
host, _, err := net.SplitHostPort(server)
if err != nil {
if strings.Contains(err.Error(), "missing port in address") {
host = server
}
}
ip := net.ParseIP(host)
if ip != nil {
return true
}
ips, _ := net.LookupIP(host)
return len(ips) > 0
}

View File

@ -63,7 +63,14 @@ func (c *InteractiveCLI) Start(ctx context.Context, cancel context.CancelFunc) e
}
fmt.Println(locale.Loc("use_to_run_command", nil))
cmd, cancelled := UserInput(ctx, locale.Loc("input_command", nil))
cmd, cancelled := UserInput(ctx, locale.Loc("input_command", nil), func(s string) bool {
for k := range ValidCMDs {
if s == k {
return true
}
}
return false
})
if cancelled {
cancel()
return nil

View File

@ -15,13 +15,14 @@ import (
"time"
"github.com/bedrock-tool/bedrocktool/locale"
"github.com/repeale/fp-go"
"github.com/bedrock-tool/bedrocktool/ui/messages"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/login"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"github.com/sandertv/gophertunnel/minecraft/resource"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
)
var DisconnectReason = "Connection lost"
@ -93,6 +94,8 @@ type ProxyContext struct {
commands map[string]IngameCommand
handlers []*ProxyHandler
reconnectHandler *ProxyHandler
}
func NewProxy() (*ProxyContext, error) {
@ -101,6 +104,7 @@ func NewProxy() (*ProxyContext, error) {
AlwaysGetPacks: false,
WithClient: true,
IgnoreDisconnect: false,
reconnectHandler: NewTransferHandler(),
}
if Options.PathCustomUserData != "" {
if err := p.LoadCustomUserData(Options.PathCustomUserData); err != nil {
@ -245,6 +249,8 @@ func (p *ProxyContext) proxyLoop(ctx context.Context, toServer bool) error {
c2 = p.Client
}
var transferingErr error = nil
for {
if ctx.Err() != nil {
return ctx.Err()
@ -260,7 +266,12 @@ func (p *ProxyContext) proxyLoop(ctx context.Context, toServer bool) error {
if handler.PacketCB != nil {
pk, err = handler.PacketCB(pk, toServer, time.Now())
if err != nil {
return err
if errors.Is(err, transferingErr) {
transferingErr = err
err = nil
} else {
return err
}
}
if pk == nil {
logrus.Tracef("Dropped Packet: %s", pkName)
@ -277,6 +288,10 @@ func (p *ProxyContext) proxyLoop(ctx context.Context, toServer bool) error {
return err
}
}
if transferingErr != nil {
return transferingErr
}
}
}
@ -309,13 +324,11 @@ func (p *ProxyContext) IsClient(addr net.Addr) bool {
var NewDebugLogger func(bool) *ProxyHandler
var NewPacketCapturer func() *ProxyHandler
func (p *ProxyContext) connectClient(ctx context.Context, serverAddress string, cdpp **login.ClientData) (err error) {
GetTokenSource() // ask for login before listening
func (p *ProxyContext) connectClient(ctx context.Context, serverAddress string, cdpp **login.ClientData, tokenSource oauth2.TokenSource) (err error) {
var packs []*resource.Pack
if Options.Preload {
logrus.Info(locale.Loc("preloading_packs", nil))
serverConn, err := connectServer(ctx, serverAddress, nil, true, func(header packet.Header, payload []byte, src, dst net.Addr) {})
serverConn, err := connectServer(ctx, serverAddress, nil, true, nil, tokenSource)
if err != nil {
return fmt.Errorf(locale.Loc("failed_to_connect", locale.Strmap{"Address": serverAddress, "Err": err}))
}
@ -354,27 +367,19 @@ func (p *ProxyContext) connectClient(ctx context.Context, serverAddress string,
return nil
}
func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err error) {
if Options.Debug || Options.ExtraDebug {
p.AddHandler(NewDebugLogger(Options.ExtraDebug))
func (p *ProxyContext) packetFunc(header packet.Header, payload []byte, src, dst net.Addr) {
if header.PacketID == packet.IDRequestNetworkSettings {
p.clientAddr = src
}
if Options.Capture {
p.AddHandler(NewPacketCapturer())
}
p.AddHandler(&ProxyHandler{
Name: "Commands",
PacketCB: p.CommandHandlerPacketCB,
})
for _, handler := range p.handlers {
if handler.AddressAndName != nil {
handler.AddressAndName(serverAddress, name)
}
if handler.ProxyRef != nil {
handler.ProxyRef(p)
if handler.PacketFunc == nil {
continue
}
handler.PacketFunc(header, payload, src, dst)
}
}
func (p *ProxyContext) connect(ctx context.Context, serverAddress string) (err error) {
defer func() {
for _, handler := range p.handlers {
if handler.OnEnd != nil {
@ -388,9 +393,19 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
isReplay = true
}
var tokenSource oauth2.TokenSource
if !isReplay {
// ask for login before listening
tokenSource, err = Auth.GetTokenSource()
if err != nil {
return err
}
}
var cdp *login.ClientData = nil
if p.WithClient && !isReplay {
err = p.connectClient(ctx, serverAddress, &cdp)
CurrentUI.Message(messages.SetUIState(messages.UIStateConnect))
err = p.connectClient(ctx, serverAddress, &cdp, tokenSource)
if err != nil {
return err
}
@ -400,7 +415,6 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
if p.Client != nil {
p.Listener.Disconnect(p.Client.(*minecraft.Conn), DisconnectReason)
}
p.Listener.Close()
}
}()
}
@ -416,25 +430,13 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
handler.OnClientConnect(p.Client)
}
packetFunc := func(header packet.Header, payload []byte, src, dst net.Addr) {
if header.PacketID == packet.IDRequestNetworkSettings {
p.clientAddr = src
}
for _, handler := range p.handlers {
if handler.PacketFunc == nil {
continue
}
handler.PacketFunc(header, payload, src, dst)
}
}
if isReplay {
p.Server, err = createReplayConnector(serverAddress[5:], packetFunc)
p.Server, err = createReplayConnector(serverAddress[5:], p.packetFunc)
if err != nil {
return err
}
} else {
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, packetFunc)
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, p.packetFunc, tokenSource)
}
if err != nil {
for _, handler := range p.handlers {
@ -488,56 +490,95 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err
}
}
ctx2, cancel := context.WithCancelCause(ctx)
wg := sync.WaitGroup{}
doProxy := func(client bool, onErr func()) {
doProxy := func(client bool) {
defer wg.Done()
if err := p.proxyLoop(ctx, client); err != nil {
logrus.Error(err)
if err := p.proxyLoop(ctx2, client); err != nil {
cancel(err)
return
}
}
// server to client
wg.Add(1)
go doProxy(false, func() {
p.DisconnectClient()
})
go doProxy(false)
// client to server
if p.Client != nil {
wg.Add(1)
go doProxy(true, func() {
p.DisconnectServer()
})
go doProxy(true)
}
go func() {
wg.Wait()
if ctx.Err() == nil {
cancel(nil)
}
}()
/*
wantSecondary := fp.Filter(func(handler *ProxyHandler) bool {
return handler.SecondaryClientCB != nil
})(p.handlers)
if len(wantSecondary) > 0 {
go func() {
for {
c, err := p.Listener.Accept()
if err != nil {
logrus.Error(err)
return
}
for _, handler := range wantSecondary {
go handler.SecondaryClientCB(c.(*minecraft.Conn))
}
}
}()
}
*/
<-ctx2.Done()
err = ctx2.Err()
if err, ok := err.(*transferingErr); ok {
logrus.Infof("Redirect to %s", err.To)
if p.Client != nil {
p.Listener.Disconnect(p.Client.(*minecraft.Conn), "please reconnect")
}
return p.connect(ctx, err.To)
}
wantSecondary := fp.Filter(func(handler *ProxyHandler) bool {
return handler.SecondaryClientCB != nil
})(p.handlers)
if len(wantSecondary) > 0 {
go func() {
for {
c, err := p.Listener.Accept()
if err != nil {
logrus.Error(err)
return
}
for _, handler := range wantSecondary {
go handler.SecondaryClientCB(c.(*minecraft.Conn))
}
}
}()
}
wg.Wait()
return err
return nil
}
var pool = packet.NewPool()
func (p *ProxyContext) Run(ctx context.Context, serverAddress, name string) (err error) {
if Options.Debug || Options.ExtraDebug {
p.AddHandler(NewDebugLogger(Options.ExtraDebug))
}
if Options.Capture {
p.AddHandler(NewPacketCapturer())
}
p.AddHandler(&ProxyHandler{
Name: "Commands",
PacketCB: p.CommandHandlerPacketCB,
})
func DecodePacket(header packet.Header, payload []byte) packet.Packet {
p.AddHandler(p.reconnectHandler)
for _, handler := range p.handlers {
if handler.AddressAndName != nil {
handler.AddressAndName(serverAddress, name)
}
if handler.ProxyRef != nil {
handler.ProxyRef(p)
}
}
return p.connect(ctx, serverAddress)
}
func DecodePacket(pool packet.Pool, header packet.Header, payload []byte) packet.Packet {
var pk packet.Packet
if pkFunc, ok := pool[header.PacketID]; ok {
pk = pkFunc()
@ -550,6 +591,6 @@ func DecodePacket(header packet.Header, payload []byte) packet.Packet {
logrus.Errorf("%T: %s", pk, recoveredErr.(error))
}
}()
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0, false))
return pk
}

View File

@ -285,7 +285,7 @@ func (r *replayConnector) loop() {
func createReplayConnector(filename string, packetFunc PacketFunc) (r *replayConnector, err error) {
r = &replayConnector{
pool: packet.NewPool(),
pool: minecraft.DefaultProtocol.Packets(true),
proto: minecraft.DefaultProtocol,
packetFunc: packetFunc,
spawn: make(chan struct{}),
@ -315,6 +315,14 @@ func createReplayConnector(filename string, packetFunc PacketFunc) (r *replayCon
return r, nil
}
func (r *replayConnector) DisconnectOnInvalidPacket() bool {
return false
}
func (r *replayConnector) DisconnectOnUnknownPacket() bool {
return false
}
func (r *replayConnector) Close() error {
r.once.Do(func() {
close(r.close)

View File

@ -18,12 +18,22 @@ type Skin struct {
}
type SkinGeometry struct {
SkinGeometryDescription
Bones []any `json:"bones"`
}
type SkinGeometryDescription struct {
Identifier string `json:"identifier,omitempty"`
Texturewidth int `json:"texturewidth"`
Textureheight int `json:"textureheight"`
VisibleBoundsWidth float64 `json:"visible_bounds_width"`
VisibleBoundsHeight float64 `json:"visible_bounds_height"`
VisibleBoundsOffset []float64 `json:"visible_bounds_offset,omitempty"`
Bones []any `json:"bones"`
}
type SkinGeometry_1_12 struct {
Description SkinGeometryDescription `json:"description"`
Bones []any `json:"bones"`
}
func (skin *Skin) Hash() uuid.UUID {
@ -31,7 +41,7 @@ func (skin *Skin) Hash() uuid.UUID {
return uuid.NewSHA1(uuid.NameSpaceURL, h)
}
func (skin *Skin) getGeometry() (*SkinGeometry, string, error) {
func (skin *Skin) getGeometry() (*SkinGeometry_1_12, string, error) {
if !skin.HaveGeometry() {
return nil, "", errors.New("no geometry")
}
@ -41,6 +51,10 @@ func (skin *Skin) getGeometry() (*SkinGeometry, string, error) {
return nil, "", err
}
if len(data) == 0 {
return nil, "", nil
}
arr, ok := data["minecraft:geometry"].([]any)
if !ok {
return nil, "", errors.New("invalid geometry")
@ -61,13 +75,16 @@ func (skin *Skin) getGeometry() (*SkinGeometry, string, error) {
visible_bounds_height, _ := desc["visible_bounds_height"].(float64)
visibleOffset, _ := desc["visible_bounds_offset"].([]float64)
return &SkinGeometry{
Texturewidth: int(texture_width),
Textureheight: int(texture_height),
VisibleBoundsWidth: visible_bounds_width,
VisibleBoundsHeight: visible_bounds_height,
VisibleBoundsOffset: visibleOffset,
Bones: geom["bones"].([]any),
return &SkinGeometry_1_12{
Description: SkinGeometryDescription{
Identifier: desc["identifier"].(string),
Texturewidth: int(texture_width),
Textureheight: int(texture_height),
VisibleBoundsWidth: visible_bounds_width,
VisibleBoundsHeight: visible_bounds_height,
VisibleBoundsOffset: visibleOffset,
},
Bones: geom["bones"].([]any),
}, desc["identifier"].(string), nil
}

View File

@ -103,9 +103,26 @@ func (s *SkinPack) Save(fpath, serverName string) error {
if s2.skin.HaveGeometry() {
geometry, geometryName, err := s2.skin.getGeometry()
if err != nil {
logrus.Warnf("failed to decode geometry %s", skinName)
} else {
geometryJson[geometryName] = *geometry
logrus.Warnf("failed to decode geometry %s %v", skinName, err)
} else if geometry != nil {
f, err := os.Create(path.Join(fpath, fmt.Sprintf("geometry-%s.json", geometryName)))
if err != nil {
return err
}
e := json.NewEncoder(f)
e.SetIndent("", "\t")
if err := e.Encode(map[string]any{
"format_version": "1.12.0",
"minecraft:geometry": []*SkinGeometry_1_12{geometry},
}); err != nil {
f.Close()
return err
}
f.Close()
geometryJson[geometryName] = SkinGeometry{
SkinGeometryDescription: geometry.Description,
Bones: geometry.Bones,
}
entry.Geometry = geometryName
}
}
@ -120,8 +137,10 @@ func (s *SkinPack) Save(fpath, serverName string) error {
e := json.NewEncoder(f)
e.SetIndent("", "\t")
if err := e.Encode(geometryJson); err != nil {
f.Close()
return err
}
f.Close()
}
{ // skins.json
@ -132,8 +151,10 @@ func (s *SkinPack) Save(fpath, serverName string) error {
e := json.NewEncoder(f)
e.SetIndent("", "\t")
if err := e.Encode(skinsJson); err != nil {
f.Close()
return err
}
f.Close()
}
{ // manifest.json

53
utils/transfer.go Normal file
View File

@ -0,0 +1,53 @@
package utils
import (
"fmt"
"net"
"strconv"
"time"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
type transferingErr struct {
To string
}
func (transferingErr) Error() string {
return "transferingErr"
}
type transferHandler struct {
p *ProxyContext
}
func NewTransferHandler() *ProxyHandler {
t := &transferHandler{}
return &ProxyHandler{
Name: "transfer",
ProxyRef: func(pc *ProxyContext) {
t.p = pc
},
PacketCB: t.packetCB,
}
}
func (t *transferHandler) packetCB(pk packet.Packet, toServer bool, timeReceived time.Time) (packet.Packet, error) {
switch pk := pk.(type) {
case *packet.Transfer:
var pk2 packet.Packet = nil
if t.p.Client != nil {
host, port, err := net.SplitHostPort(t.p.Client.ClientData().ServerAddress)
if err != nil {
return nil, err
}
_port, _ := strconv.Atoi(port)
pk2 = &packet.Transfer{Address: host, Port: uint16(_port)}
}
return pk2, &transferingErr{
To: fmt.Sprintf("%s:%d", pk.Address, pk.Port),
}
}
return pk, nil
}

View File

@ -15,6 +15,8 @@ import (
var Version string
var CmdName = "bedrocktool"
var UpdateAvailable string
const updateServer = "https://updates.yuv.pink/"
type trequester struct {

View File

@ -22,6 +22,7 @@ import (
"github.com/google/uuid"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sirupsen/logrus"
"golang.org/x/oauth2"
//"github.com/sandertv/gophertunnel/minecraft/gatherings"
@ -57,7 +58,7 @@ func CleanupName(name string) string {
// connections
func connectServer(ctx context.Context, address string, ClientData *login.ClientData, wantPacks bool, packetFunc PacketFunc) (serverConn *minecraft.Conn, err error) {
func connectServer(ctx context.Context, address string, ClientData *login.ClientData, wantPacks bool, packetFunc PacketFunc, tokenSource oauth2.TokenSource) (serverConn *minecraft.Conn, err error) {
cd := login.ClientData{}
if ClientData != nil {
cd = *ClientData
@ -65,7 +66,7 @@ func connectServer(ctx context.Context, address string, ClientData *login.Client
logrus.Info(locale.Loc("connecting", locale.Strmap{"Address": address}))
serverConn, err = minecraft.Dialer{
TokenSource: GetTokenSource(),
TokenSource: tokenSource,
ClientData: cd,
PacketFunc: packetFunc,
DownloadResourcePack: func(id uuid.UUID, version string, current int, total int) bool {
@ -141,6 +142,7 @@ func WriteManifest(manifest *resource.Manifest, fpath string) error {
if err != nil {
return err
}
defer w.Close()
e := json.NewEncoder(w)
e.SetIndent("", "\t")
if err = e.Encode(manifest); err != nil {
@ -188,6 +190,6 @@ func ShowFile(path string) {
return
}
if runtime.GOOS == "linux" {
println(path)
}
}