Compare commits
15 Commits
7a6061dba2
...
d7b559a7a8
Author | SHA1 | Date |
---|---|---|
olebeck | d7b559a7a8 | |
olebeck | 75a3ad3674 | |
olebeck | b98b509907 | |
olebeck | ed910330e8 | |
olebeck | 5742a6b850 | |
olebeck | 21566df29f | |
olebeck | 68890eddd2 | |
olebeck | b21ed74bea | |
olebeck | 75956eabcb | |
olebeck | 8f88c7f576 | |
olebeck | 82de60369a | |
olebeck | 83a38c57cc | |
olebeck | 073407346e | |
olebeck | a2653cffad | |
olebeck | d10805f4eb |
|
@ -24,6 +24,7 @@ keys.db
|
||||||
/updates/
|
/updates/
|
||||||
/fyne-cross/
|
/fyne-cross/
|
||||||
/tmp/
|
/tmp/
|
||||||
|
/cmd/test
|
||||||
|
|
||||||
packets.log.gpg
|
packets.log.gpg
|
||||||
customdata.json
|
customdata.json
|
||||||
|
|
10
go.mod
10
go.mod
|
@ -3,10 +3,12 @@ module github.com/bedrock-tool/bedrocktool
|
||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
//replace github.com/sandertv/gophertunnel => ./gophertunnel
|
//replace github.com/sandertv/gophertunnel => ./gophertunnel
|
||||||
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.27.4-3
|
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.28.1-1
|
||||||
|
|
||||||
//replace github.com/df-mc/dragonfly => ./dragonfly
|
//replace github.com/df-mc/dragonfly => ./dragonfly
|
||||||
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.3-3
|
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.3-8
|
||||||
|
|
||||||
|
replace gioui.org => github.com/olebeck/gio v0.0.0-20230321105529-d424f1a59af9
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gioui.org v0.0.0-20221219171716-c455f0f342ef
|
gioui.org v0.0.0-20221219171716-c455f0f342ef
|
||||||
|
@ -24,12 +26,11 @@ require (
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
github.com/nicksnyder/go-i18n/v2 v2.2.1
|
||||||
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49
|
github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49
|
||||||
github.com/sandertv/go-raknet v1.12.0
|
github.com/sandertv/go-raknet v1.12.0
|
||||||
github.com/sandertv/gophertunnel v1.27.4
|
github.com/sandertv/gophertunnel v1.28.1
|
||||||
github.com/sirupsen/logrus v1.9.0
|
github.com/sirupsen/logrus v1.9.0
|
||||||
golang.design/x/lockfree v0.0.1
|
golang.design/x/lockfree v0.0.1
|
||||||
golang.org/x/crypto v0.7.0
|
golang.org/x/crypto v0.7.0
|
||||||
golang.org/x/exp v0.0.0-20230304125523-9ff063c70017
|
golang.org/x/exp v0.0.0-20230304125523-9ff063c70017
|
||||||
golang.org/x/image v0.6.0
|
|
||||||
golang.org/x/oauth2 v0.6.0
|
golang.org/x/oauth2 v0.6.0
|
||||||
golang.org/x/text v0.8.0
|
golang.org/x/text v0.8.0
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
|
@ -56,6 +57,7 @@ require (
|
||||||
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
|
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 // indirect
|
golang.org/x/exp/shiny v0.0.0-20220827204233-334a2380cb91 // indirect
|
||||||
|
golang.org/x/image v0.6.0 // indirect
|
||||||
golang.org/x/mod v0.8.0 // indirect
|
golang.org/x/mod v0.8.0 // indirect
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
|
|
24
go.sum
24
go.sum
|
@ -12,6 +12,7 @@ git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0 h1:bGG/g4ypjrCJoSvFrP5hafr
|
||||||
git.wow.st/gmp/jni v0.0.0-20210610011705-34026c7e22d0/go.mod h1:+axXBRUTIDlCeE73IKeD/os7LoEnTKdkp8/gQOFjqyo=
|
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=
|
github.com/BurntSushi/toml v1.0.0 h1:dtDWrepsVPfW9H/4y7dDgFc2MBUSeJhlaDtK13CxFlU=
|
||||||
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
github.com/BurntSushi/toml v1.0.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
|
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||||
github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
|
github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
|
||||||
github.com/benoitkugler/textlayout v0.3.0 h1:2ehWXEkgb6RUokTjXh1LzdGwG4dRP6X3dqhYYDYhUVk=
|
github.com/benoitkugler/textlayout v0.3.0 h1:2ehWXEkgb6RUokTjXh1LzdGwG4dRP6X3dqhYYDYhUVk=
|
||||||
github.com/benoitkugler/textlayout v0.3.0/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w=
|
github.com/benoitkugler/textlayout v0.3.0/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w=
|
||||||
|
@ -19,6 +20,8 @@ github.com/benoitkugler/textlayout-testdata v0.1.1 h1:AvFxBxpfrQd8v55qH59mZOJOQj
|
||||||
github.com/benoitkugler/textlayout-testdata v0.1.1/go.mod h1:i/qZl09BbUOtd7Bu/W1CAubRwTWrEXWq6JwMkw8wYxo=
|
github.com/benoitkugler/textlayout-testdata v0.1.1/go.mod h1:i/qZl09BbUOtd7Bu/W1CAubRwTWrEXWq6JwMkw8wYxo=
|
||||||
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 h1:/G0ghZwrhou0Wq21qc1vXXMm/t/aKWkALWwITptKbE0=
|
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 h1:/G0ghZwrhou0Wq21qc1vXXMm/t/aKWkALWwITptKbE0=
|
||||||
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9/go.mod h1:TOk10ahXejq9wkEaym3KPRNeuR/h5Jx+s8QRWIa2oTM=
|
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9/go.mod h1:TOk10ahXejq9wkEaym3KPRNeuR/h5Jx+s8QRWIa2oTM=
|
||||||
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/changkun/lockfree v0.0.1 h1:5WefVJLglY4IHRqOQmh6Ao6wkJYaJkarshKU8VUtId4=
|
github.com/changkun/lockfree v0.0.1 h1:5WefVJLglY4IHRqOQmh6Ao6wkJYaJkarshKU8VUtId4=
|
||||||
github.com/changkun/lockfree v0.0.1/go.mod h1:3bKiaXn/iNzIPlSvSOMSVbRQUQtAp8qUAyBUtzU11s4=
|
github.com/changkun/lockfree v0.0.1/go.mod h1:3bKiaXn/iNzIPlSvSOMSVbRQUQtAp8qUAyBUtzU11s4=
|
||||||
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk=
|
github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk=
|
||||||
|
@ -77,14 +80,22 @@ github.com/muhammadmuzzammil1998/jsonc v1.0.0 h1:8o5gBQn4ZA3NBA9DlTujCj2a4w0tqWr
|
||||||
github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU=
|
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 h1:aOzRCdwsJuoExfZhoiXHy4bjruwCMdt5otbYojM/PaA=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
github.com/nicksnyder/go-i18n/v2 v2.2.1/go.mod h1:fF2++lPHlo+/kPaj3nB0uxtPwzlPm+BlgwGX7MkeGj0=
|
||||||
github.com/olebeck/dragonfly v0.9.3-2 h1:FBO5raxeQvA286L+mUhnAsUSWxVfKmVFoofw0KdJlXA=
|
github.com/olebeck/dragonfly v0.9.3-5 h1:8MUpzKz1UZ0K+DJrywBV6C/ydGMggTxGg1n9VFAZPpI=
|
||||||
github.com/olebeck/dragonfly v0.9.3-2/go.mod h1:ODAzVcmM7KvKgPB89hoYndQiVVgTm9FlDXUko1H3YVs=
|
github.com/olebeck/dragonfly v0.9.3-5/go.mod h1:ODAzVcmM7KvKgPB89hoYndQiVVgTm9FlDXUko1H3YVs=
|
||||||
github.com/olebeck/dragonfly v0.9.3-3 h1:sv4TJjdgFoCBRMd5mS0g5NyPeMsVfUifhxIlJPTj6xg=
|
github.com/olebeck/dragonfly v0.9.3-6 h1:ots1osXxuP6fQg4C8tt3y8xfpc+JNqOarI5zufisKFs=
|
||||||
github.com/olebeck/dragonfly v0.9.3-3/go.mod h1:ODAzVcmM7KvKgPB89hoYndQiVVgTm9FlDXUko1H3YVs=
|
github.com/olebeck/dragonfly v0.9.3-6/go.mod h1:ODAzVcmM7KvKgPB89hoYndQiVVgTm9FlDXUko1H3YVs=
|
||||||
github.com/olebeck/gophertunnel v1.27.4-1 h1:rtB5wksJBKk3sy9lBFZ1aH2giCathINj4zQkl1rPTMg=
|
github.com/olebeck/dragonfly v0.9.3-7 h1:zIMWsox18efEe7R+VmJOTJRePU9x2YN3CE1uzfse1AM=
|
||||||
github.com/olebeck/gophertunnel v1.27.4-1/go.mod h1:ekREo7U9TPHh86kbuPMaWA93NMyWsfVvP/iNT3XhAb8=
|
github.com/olebeck/dragonfly v0.9.3-7/go.mod h1:nnnmYWgSTNQb9x33nBthqN/2vyHlUaijfo+e2y3W5j4=
|
||||||
|
github.com/olebeck/dragonfly v0.9.3-8 h1:w514gGVTK2iv3TDI8EuzSCDHrF2Hv2f+/lIicW0J6Bg=
|
||||||
|
github.com/olebeck/dragonfly v0.9.3-8/go.mod h1:nnnmYWgSTNQb9x33nBthqN/2vyHlUaijfo+e2y3W5j4=
|
||||||
|
github.com/olebeck/gio v0.0.0-20230321105529-d424f1a59af9 h1:TqDsMHwjW5ZYfh+RE8ussT62m0qXqo+QjzSXb7BCVA4=
|
||||||
|
github.com/olebeck/gio v0.0.0-20230321105529-d424f1a59af9/go.mod h1:+W1Kpf96YcfissZocFqIp6O42FDTuphkObbEybp+Ffc=
|
||||||
github.com/olebeck/gophertunnel v1.27.4-3 h1:RktAdTNTvCFn6PQou0H3RyqrTo3/xH0bqODrHb/oXAs=
|
github.com/olebeck/gophertunnel v1.27.4-3 h1:RktAdTNTvCFn6PQou0H3RyqrTo3/xH0bqODrHb/oXAs=
|
||||||
github.com/olebeck/gophertunnel v1.27.4-3/go.mod h1:ekREo7U9TPHh86kbuPMaWA93NMyWsfVvP/iNT3XhAb8=
|
github.com/olebeck/gophertunnel v1.27.4-3/go.mod h1:ekREo7U9TPHh86kbuPMaWA93NMyWsfVvP/iNT3XhAb8=
|
||||||
|
github.com/olebeck/gophertunnel v1.27.4-4 h1:ZzmZquRW0WdoH/smsOk91O+40dotn7574bID+BkHbuk=
|
||||||
|
github.com/olebeck/gophertunnel v1.27.4-4/go.mod h1:ekREo7U9TPHh86kbuPMaWA93NMyWsfVvP/iNT3XhAb8=
|
||||||
|
github.com/olebeck/gophertunnel v1.28.1-1 h1:bw2jeMz94YHF5qQYhq1Yq/6fALkklGu7k26YbPI4DSs=
|
||||||
|
github.com/olebeck/gophertunnel v1.28.1-1/go.mod h1:ekREo7U9TPHh86kbuPMaWA93NMyWsfVvP/iNT3XhAb8=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
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 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
@ -98,6 +109,7 @@ github.com/sandertv/go-raknet v1.12.0 h1:olUzZlIJyX/pgj/mrsLCZYjKLNDsYiWdvQ4NIm3
|
||||||
github.com/sandertv/go-raknet v1.12.0/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y=
|
github.com/sandertv/go-raknet v1.12.0/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y=
|
||||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
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=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
|
|
@ -43,13 +43,13 @@ func (c *ChatLogCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
proxy.PacketCB = func(pk packet.Packet, proxy *utils.ProxyContext, toServer bool, _ time.Time) (packet.Packet, error) {
|
proxy.PacketCB = func(pk packet.Packet, toServer bool, t time.Time) (packet.Packet, error) {
|
||||||
if text, ok := pk.(*packet.Text); ok {
|
if text, ok := pk.(*packet.Text); ok {
|
||||||
logLine := text.Message
|
logLine := text.Message
|
||||||
if c.Verbose {
|
if c.Verbose {
|
||||||
logLine += fmt.Sprintf(" (TextType: %d | XUID: %s | PlatformChatID: %s)", text.TextType, text.XUID, text.PlatformChatID)
|
logLine += fmt.Sprintf(" (TextType: %d | XUID: %s | PlatformChatID: %s)", text.TextType, text.XUID, text.PlatformChatID)
|
||||||
}
|
}
|
||||||
f.WriteString(fmt.Sprintf("[%s] ", time.Now().Format(time.RFC3339)))
|
f.WriteString(fmt.Sprintf("[%s] ", t.Format(time.RFC3339)))
|
||||||
logrus.Info(logLine)
|
logrus.Info(logLine)
|
||||||
if toServer {
|
if toServer {
|
||||||
f.WriteString("SENT: ")
|
f.WriteString("SENT: ")
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package subcommands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bedrock-tool/bedrocktool/locale"
|
||||||
|
"github.com/bedrock-tool/bedrocktool/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RealmListCMD struct{}
|
||||||
|
|
||||||
|
func (*RealmListCMD) Name() string { return "list-realms" }
|
||||||
|
func (*RealmListCMD) Synopsis() string { return locale.Loc("list_realms_synopsis", nil) }
|
||||||
|
func (c *RealmListCMD) SetFlags(f *flag.FlagSet) {}
|
||||||
|
func (c *RealmListCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
|
realms, err := utils.GetRealmsAPI().Realms(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, realm := range realms {
|
||||||
|
fmt.Println(locale.Loc("realm_list_line", locale.Strmap{"Name": realm.Name, "Id": realm.ID}))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
utils.RegisterCommand(&RealmListCMD{})
|
||||||
|
}
|
Binary file not shown.
|
@ -148,10 +148,10 @@ func (c *SkinCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
|
|
||||||
proxy, _ := utils.NewProxy()
|
proxy, _ := utils.NewProxy()
|
||||||
proxy.WithClient = !c.NoProxy
|
proxy.WithClient = !c.NoProxy
|
||||||
proxy.OnClientConnect = func(proxy *utils.ProxyContext, hasClient bool) {
|
proxy.OnClientConnect = func(hasClient bool) {
|
||||||
ui.Message(messages.SetUIState, messages.UIStateConnecting)
|
ui.Message(messages.SetUIState, messages.UIStateConnecting)
|
||||||
}
|
}
|
||||||
proxy.ConnectCB = func(proxy *utils.ProxyContext, err error) bool {
|
proxy.ConnectCB = func(err error) bool {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ func (c *SkinCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
|
|
||||||
s := NewSkinsSession(proxy, hostname, outPathBase)
|
s := NewSkinsSession(proxy, hostname, outPathBase)
|
||||||
|
|
||||||
proxy.PacketCB = func(pk packet.Packet, _ *utils.ProxyContext, toServer bool, _ time.Time) (packet.Packet, error) {
|
proxy.PacketCB = func(pk packet.Packet, toServer bool, _ time.Time) (packet.Packet, error) {
|
||||||
if !toServer {
|
if !toServer {
|
||||||
for _, s := range s.ProcessPacket(pk) {
|
for _, s := range s.ProcessPacket(pk) {
|
||||||
ui.Message(messages.NewSkin, messages.NewSkinPayload{
|
ui.Message(messages.NewSkin, messages.NewSkinPayload{
|
||||||
|
|
|
@ -44,29 +44,14 @@ func (w *WorldState) processLevelChunk(pk *packet.LevelChunk) {
|
||||||
pk.Position.X(), 0, pk.Position.Z(),
|
pk.Position.X(), 0, pk.Position.Z(),
|
||||||
}] = blockNBTs
|
}] = blockNBTs
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if chunk is empty
|
|
||||||
empty := true
|
|
||||||
for _, sub := range ch.Sub() {
|
|
||||||
if !sub.Empty() {
|
|
||||||
empty = false
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.chunks[pk.Position] = ch
|
w.chunks[pk.Position] = ch
|
||||||
|
|
||||||
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLegacy {
|
max := w.Dim.Range().Height() / 16
|
||||||
if !empty {
|
switch pk.SubChunkCount {
|
||||||
w.mapUI.SetChunk(pk.Position, ch)
|
case protocol.SubChunkRequestModeLimited:
|
||||||
}
|
max = int(pk.HighestSubChunk)
|
||||||
} else {
|
fallthrough
|
||||||
// request all the subchunks
|
case protocol.SubChunkRequestModeLimitless:
|
||||||
max := w.Dim.Range().Height() / 16
|
|
||||||
if pk.SubChunkRequestMode == protocol.SubChunkRequestModeLimited {
|
|
||||||
max = int(pk.HighestSubChunk)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
|
w.proxy.Server.WritePacket(&packet.SubChunkRequest{
|
||||||
Dimension: int32(w.Dim.EncodeDimension()),
|
Dimension: int32(w.Dim.EncodeDimension()),
|
||||||
Position: protocol.SubChunkPos{
|
Position: protocol.SubChunkPos{
|
||||||
|
@ -74,6 +59,18 @@ func (w *WorldState) processLevelChunk(pk *packet.LevelChunk) {
|
||||||
},
|
},
|
||||||
Offsets: offsetTable[:max],
|
Offsets: offsetTable[:max],
|
||||||
})
|
})
|
||||||
|
default:
|
||||||
|
// legacy
|
||||||
|
empty := true
|
||||||
|
for _, sub := range ch.Sub() {
|
||||||
|
if !sub.Empty() {
|
||||||
|
empty = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !empty {
|
||||||
|
w.mapUI.SetChunk(pk.Position, ch)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,33 +12,45 @@ import (
|
||||||
"github.com/df-mc/dragonfly/server/world/chunk"
|
"github.com/df-mc/dragonfly/server/world/chunk"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func isBlockLightblocking(b world.Block) bool {
|
||||||
|
d, isDiffuser := b.(block.LightDiffuser)
|
||||||
|
_, isSlab := b.(block.Slab)
|
||||||
|
noDiffuse := isDiffuser && d.LightDiffusionLevel() == 0
|
||||||
|
return noDiffuse && !isSlab
|
||||||
|
}
|
||||||
|
|
||||||
func blockColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) (blockColor color.RGBA) {
|
func blockColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) (blockColor color.RGBA) {
|
||||||
|
if y <= int16(c.Range().Min()) {
|
||||||
|
return color.RGBA{0, 0, 0, 0}
|
||||||
|
}
|
||||||
blockColor = color.RGBA{255, 0, 255, 255}
|
blockColor = color.RGBA{255, 0, 255, 255}
|
||||||
rid := c.Block(x, y, z, 0)
|
rid := c.Block(x, y, z, 0)
|
||||||
if rid == 0 && y == 0 { // void
|
if rid == 0 && y == int16(c.Range().Min()) { // void
|
||||||
blockColor = color.RGBA{0, 0, 0, 255}
|
blockColor = color.RGBA{0, 0, 0, 255}
|
||||||
} else {
|
} else {
|
||||||
b, found := world.BlockByRuntimeID(rid)
|
b, found := world.BlockByRuntimeID(rid)
|
||||||
if found {
|
if found {
|
||||||
if d, ok := b.(block.LightDiffuser); ok && d.LightDiffusionLevel() == 0 && y > int16(c.Range().Min()) {
|
if isBlockLightblocking(b) {
|
||||||
return blockColorAt(c, x, y-1, z)
|
return blockColorAt(c, x, y-1, z)
|
||||||
}
|
}
|
||||||
if _, ok := b.(block.Water); ok {
|
_, isWater := b.(block.Water)
|
||||||
y2 := c.HeightMap().At(x, z)
|
if !isWater {
|
||||||
depth := y - y2
|
return b.Color()
|
||||||
if depth > 0 {
|
|
||||||
blockColor = blockColorAt(c, x, y2, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
bw := (&block.Water{}).Color()
|
|
||||||
bw.A = uint8(utils.Clamp(int(150+depth*7), 255))
|
|
||||||
blockColor = utils.BlendColors(blockColor, bw)
|
|
||||||
blockColor.R -= uint8(depth * 2)
|
|
||||||
blockColor.G -= uint8(depth * 2)
|
|
||||||
blockColor.B -= uint8(depth * 2)
|
|
||||||
} else {
|
|
||||||
blockColor = b.Color()
|
|
||||||
}
|
}
|
||||||
|
// get the first non water block at the position
|
||||||
|
heightBlock := c.HeightMap().At(x, z)
|
||||||
|
depth := y - heightBlock
|
||||||
|
if depth > 0 {
|
||||||
|
blockColor = blockColorAt(c, x, heightBlock, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
// blend that blocks color with water depending on depth
|
||||||
|
waterColor := (&block.Water{}).Color()
|
||||||
|
waterColor.A = uint8(utils.Clamp(int(150+depth*7), 255))
|
||||||
|
blockColor = utils.BlendColors(blockColor, waterColor)
|
||||||
|
blockColor.R -= uint8(depth * 2)
|
||||||
|
blockColor.G -= uint8(depth * 2)
|
||||||
|
blockColor.B -= uint8(depth * 2)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if blockColor.R == 0 || blockColor.R == 255 && blockColor.B == 255 {
|
if blockColor.R == 0 || blockColor.R == 255 && blockColor.B == 255 {
|
||||||
|
@ -52,39 +64,37 @@ func blockColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) (blockColor color.R
|
||||||
}
|
}
|
||||||
|
|
||||||
func chunkGetColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) color.RGBA {
|
func chunkGetColorAt(c *chunk.Chunk, x uint8, y int16, z uint8) color.RGBA {
|
||||||
p := cube.Pos{int(x), int(y), int(z)}
|
|
||||||
haveUp := false
|
haveUp := false
|
||||||
p.Side(cube.FaceUp).Neighbours(func(neighbour cube.Pos) {
|
cube.Pos{int(x), int(y), int(z)}.
|
||||||
if neighbour.X() < 0 || neighbour.X() >= 16 || neighbour.Z() < 0 || neighbour.Z() >= 16 || neighbour.Y() > c.Range().Max() {
|
Side(cube.FaceUp).
|
||||||
return
|
Neighbours(func(neighbour cube.Pos) {
|
||||||
}
|
if neighbour.X() < 0 || neighbour.X() >= 16 || neighbour.Z() < 0 || neighbour.Z() >= 16 || neighbour.Y() > c.Range().Max() || haveUp {
|
||||||
if !haveUp {
|
return
|
||||||
|
}
|
||||||
blockRid := c.Block(uint8(neighbour[0]), int16(neighbour[1]), uint8(neighbour[2]), 0)
|
blockRid := c.Block(uint8(neighbour[0]), int16(neighbour[1]), uint8(neighbour[2]), 0)
|
||||||
if blockRid > 0 {
|
if blockRid > 0 {
|
||||||
b, found := world.BlockByRuntimeID(blockRid)
|
b, found := world.BlockByRuntimeID(blockRid)
|
||||||
if found {
|
if found {
|
||||||
if _, ok := b.(block.Air); !ok {
|
if isBlockLightblocking(b) {
|
||||||
haveUp = true
|
haveUp = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, cube.Range{int(y + 1), int(y + 1)})
|
||||||
}, cube.Range{int(y + 1), int(y + 1)})
|
|
||||||
|
|
||||||
col := blockColorAt(c, x, y, z)
|
|
||||||
|
|
||||||
|
blockColor := blockColorAt(c, x, y, z)
|
||||||
if haveUp {
|
if haveUp {
|
||||||
if col.R > 10 {
|
if blockColor.R > 10 {
|
||||||
col.R -= 10
|
blockColor.R -= 10
|
||||||
}
|
}
|
||||||
if col.G > 10 {
|
if blockColor.G > 10 {
|
||||||
col.G -= 10
|
blockColor.G -= 10
|
||||||
}
|
}
|
||||||
if col.B > 10 {
|
if blockColor.B > 10 {
|
||||||
col.B -= 10
|
blockColor.B -= 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return col
|
return blockColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func Chunk2Img(c *chunk.Chunk) *image.RGBA {
|
func Chunk2Img(c *chunk.Chunk) *image.RGBA {
|
||||||
|
@ -93,9 +103,10 @@ func Chunk2Img(c *chunk.Chunk) *image.RGBA {
|
||||||
|
|
||||||
for x := uint8(0); x < 16; x++ {
|
for x := uint8(0); x < 16; x++ {
|
||||||
for z := uint8(0); z < 16; z++ {
|
for z := uint8(0); z < 16; z++ {
|
||||||
height := hm.At(x, z)
|
img.SetRGBA(
|
||||||
col := chunkGetColorAt(c, x, height, z)
|
int(x), int(z),
|
||||||
img.SetRGBA(int(x), int(z), col)
|
chunkGetColorAt(c, x, hm.At(x, z), z),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return img
|
return img
|
||||||
|
|
|
@ -23,7 +23,6 @@ type entityState struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type serverEntityType struct {
|
type serverEntityType struct {
|
||||||
world.SaveableEntityType
|
|
||||||
Encoded string
|
Encoded string
|
||||||
NBT map[string]any
|
NBT map[string]any
|
||||||
}
|
}
|
||||||
|
@ -44,15 +43,13 @@ func (t serverEntityType) EncodeNBT(e world.Entity) map[string]any {
|
||||||
return t.NBT
|
return t.NBT
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t serverEntityType) UniqueID() int64 {
|
|
||||||
return t.NBT["UniqueID"].(int64)
|
|
||||||
}
|
|
||||||
|
|
||||||
type serverEntity struct {
|
type serverEntity struct {
|
||||||
world.Entity
|
world.Entity
|
||||||
EntityType serverEntityType
|
EntityType serverEntityType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ world.SaveableEntityType = &serverEntityType{}
|
||||||
|
|
||||||
func (e serverEntity) Type() world.EntityType {
|
func (e serverEntity) Type() world.EntityType {
|
||||||
return e.EntityType
|
return e.EntityType
|
||||||
}
|
}
|
||||||
|
@ -138,7 +135,6 @@ func (w *WorldState) ProcessEntityPackets(pk packet.Packet) packet.Packet {
|
||||||
case *packet.AddActor:
|
case *packet.AddActor:
|
||||||
w.processAddActor(pk)
|
w.processAddActor(pk)
|
||||||
case *packet.RemoveActor:
|
case *packet.RemoveActor:
|
||||||
delete(w.entities, uint64(pk.EntityUniqueID))
|
|
||||||
case *packet.SetActorData:
|
case *packet.SetActorData:
|
||||||
e, ok := w.entities[pk.EntityRuntimeID]
|
e, ok := w.entities[pk.EntityRuntimeID]
|
||||||
if ok {
|
if ok {
|
||||||
|
|
|
@ -18,77 +18,84 @@ type itemContainer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
func (w *WorldState) processItemPacketsServer(pk packet.Packet) packet.Packet {
|
||||||
|
if !w.experimentInventory {
|
||||||
|
return pk
|
||||||
|
}
|
||||||
|
|
||||||
switch pk := pk.(type) {
|
switch pk := pk.(type) {
|
||||||
case *packet.ContainerOpen:
|
case *packet.ContainerOpen:
|
||||||
if w.experimentInventory {
|
// add to open containers
|
||||||
// add to open containers
|
existing, ok := w.openItemContainers[pk.WindowID]
|
||||||
existing, ok := w.openItemContainers[pk.WindowID]
|
if !ok {
|
||||||
if !ok {
|
existing = &itemContainer{}
|
||||||
existing = &itemContainer{}
|
|
||||||
}
|
|
||||||
w.openItemContainers[pk.WindowID] = &itemContainer{
|
|
||||||
OpenPacket: pk,
|
|
||||||
Content: existing.Content,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
w.openItemContainers[pk.WindowID] = &itemContainer{
|
||||||
|
OpenPacket: pk,
|
||||||
|
Content: existing.Content,
|
||||||
|
}
|
||||||
|
|
||||||
case *packet.InventoryContent:
|
case *packet.InventoryContent:
|
||||||
if w.experimentInventory {
|
// save content
|
||||||
// save content
|
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
||||||
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
if !ok {
|
||||||
if !ok {
|
if pk.WindowID == 0x0 { // inventory
|
||||||
if pk.WindowID == 0x0 { // inventory
|
w.openItemContainers[byte(pk.WindowID)] = &itemContainer{
|
||||||
w.openItemContainers[byte(pk.WindowID)] = &itemContainer{
|
Content: pk,
|
||||||
Content: pk,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
existing.Content = pk
|
||||||
|
|
||||||
|
case *packet.ContainerClose:
|
||||||
|
// find container info
|
||||||
|
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
||||||
|
|
||||||
|
switch pk.WindowID {
|
||||||
|
case protocol.WindowIDArmour: // todo handle
|
||||||
|
case protocol.WindowIDOffHand: // todo handle
|
||||||
|
case protocol.WindowIDUI:
|
||||||
|
case protocol.WindowIDInventory: // todo handle
|
||||||
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
existing.Content = pk
|
|
||||||
}
|
|
||||||
case *packet.ContainerClose:
|
|
||||||
if w.experimentInventory {
|
|
||||||
switch pk.WindowID {
|
|
||||||
case protocol.WindowIDArmour: // todo handle
|
|
||||||
case protocol.WindowIDOffHand: // todo handle
|
|
||||||
case protocol.WindowIDUI:
|
|
||||||
case protocol.WindowIDInventory: // todo handle
|
|
||||||
default:
|
|
||||||
// find container info
|
|
||||||
existing, ok := w.openItemContainers[byte(pk.WindowID)]
|
|
||||||
if !ok {
|
|
||||||
logrus.Warn(locale.Loc("warn_window_closed_not_open", nil))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if existing.Content == nil {
|
default:
|
||||||
break
|
if !ok {
|
||||||
}
|
logrus.Warn(locale.Loc("warn_window_closed_not_open", nil))
|
||||||
|
break
|
||||||
pos := existing.OpenPacket.ContainerPosition
|
|
||||||
cp := protocol.SubChunkPos{pos.X() << 4, pos.Z() << 4}
|
|
||||||
|
|
||||||
// create inventory
|
|
||||||
inv := inventory.New(len(existing.Content.Content), nil)
|
|
||||||
for i, c := range existing.Content.Content {
|
|
||||||
item := stackToItem(c.Stack)
|
|
||||||
inv.SetItem(i, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
// put into subchunk
|
|
||||||
nbts := w.blockNBT[cp]
|
|
||||||
for i, v := range nbts {
|
|
||||||
NBTPos := protocol.BlockPos{v["x"].(int32), v["y"].(int32), v["z"].(int32)}
|
|
||||||
if NBTPos == pos {
|
|
||||||
w.blockNBT[cp][i]["Items"] = nbtconv.InvToNBT(inv)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
w.proxy.SendMessage(locale.Loc("saved_block_inv", nil))
|
|
||||||
|
|
||||||
// remove it again
|
|
||||||
delete(w.openItemContainers, byte(pk.WindowID))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if existing.Content == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := existing.OpenPacket.ContainerPosition
|
||||||
|
cp := protocol.SubChunkPos{pos.X() << 4, pos.Z() << 4}
|
||||||
|
|
||||||
|
// create inventory
|
||||||
|
inv := inventory.New(len(existing.Content.Content), nil)
|
||||||
|
for i, c := range existing.Content.Content {
|
||||||
|
item := stackToItem(c.Stack)
|
||||||
|
inv.SetItem(i, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// put into subchunk
|
||||||
|
nbts := w.blockNBT[cp]
|
||||||
|
for i, v := range nbts {
|
||||||
|
NBTPos := protocol.BlockPos{v["x"].(int32), v["y"].(int32), v["z"].(int32)}
|
||||||
|
if NBTPos == pos {
|
||||||
|
w.blockNBT[cp][i]["Items"] = nbtconv.InvToNBT(inv)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.proxy.SendMessage(locale.Loc("saved_block_inv", nil))
|
||||||
|
|
||||||
|
// remove it again
|
||||||
|
delete(w.openItemContainers, byte(pk.WindowID))
|
||||||
}
|
}
|
||||||
|
|
||||||
case *packet.ItemComponent:
|
case *packet.ItemComponent:
|
||||||
w.bp.ApplyComponentEntries(pk.Items)
|
w.bp.ApplyComponentEntries(pk.Items)
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,19 +100,18 @@ func (m *MapUI) Start() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// init map
|
// init map
|
||||||
if m.w.proxy.Client != nil {
|
err := m.w.proxy.ClientWritePacket(&packet.ClientBoundMapItemData{
|
||||||
if err := m.w.proxy.Client.WritePacket(&packet.ClientBoundMapItemData{
|
MapID: ViewMapID,
|
||||||
MapID: ViewMapID,
|
Scale: 4,
|
||||||
Scale: 4,
|
MapsIncludedIn: []int64{ViewMapID},
|
||||||
MapsIncludedIn: []int64{ViewMapID},
|
Width: 0,
|
||||||
Width: 0,
|
Height: 0,
|
||||||
Height: 0,
|
Pixels: nil,
|
||||||
Pixels: nil,
|
UpdateFlags: packet.MapUpdateFlagInitialisation,
|
||||||
UpdateFlags: packet.MapUpdateFlagInitialisation,
|
})
|
||||||
}); err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.ticker = time.NewTicker(33 * time.Millisecond)
|
m.ticker = time.NewTicker(33 * time.Millisecond)
|
||||||
|
@ -122,18 +121,16 @@ func (m *MapUI) Start() {
|
||||||
m.needRedraw = false
|
m.needRedraw = false
|
||||||
m.Redraw()
|
m.Redraw()
|
||||||
|
|
||||||
if m.w.proxy.Client != nil {
|
if err := m.w.proxy.ClientWritePacket(&packet.ClientBoundMapItemData{
|
||||||
if err := m.w.proxy.Client.WritePacket(&packet.ClientBoundMapItemData{
|
MapID: ViewMapID,
|
||||||
MapID: ViewMapID,
|
Scale: 4,
|
||||||
Scale: 4,
|
Width: 128,
|
||||||
Width: 128,
|
Height: 128,
|
||||||
Height: 128,
|
Pixels: utils.Img2rgba(m.img),
|
||||||
Pixels: utils.Img2rgba(m.img),
|
UpdateFlags: packet.MapUpdateFlagTexture,
|
||||||
UpdateFlags: packet.MapUpdateFlagTexture,
|
}); err != nil {
|
||||||
}); err != nil {
|
logrus.Error(err)
|
||||||
logrus.Error(err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,12 +141,10 @@ func (m *MapUI) Start() {
|
||||||
if m.w.ctx.Err() != nil {
|
if m.w.ctx.Err() != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if m.w.proxy.Client != nil {
|
err := m.w.proxy.ClientWritePacket(&MapItemPacket)
|
||||||
err := m.w.proxy.Client.WritePacket(&MapItemPacket)
|
if err != nil {
|
||||||
if err != nil {
|
logrus.Error(err)
|
||||||
logrus.Error(err)
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
|
@ -48,6 +48,7 @@ type WorldState struct {
|
||||||
bp *behaviourpack.BehaviourPack
|
bp *behaviourpack.BehaviourPack
|
||||||
|
|
||||||
// save state
|
// save state
|
||||||
|
ChunkRadius int
|
||||||
chunks map[protocol.ChunkPos]*chunk.Chunk
|
chunks map[protocol.ChunkPos]*chunk.Chunk
|
||||||
blockNBT map[protocol.SubChunkPos][]map[string]any
|
blockNBT map[protocol.SubChunkPos][]map[string]any
|
||||||
openItemContainers map[byte]*itemContainer
|
openItemContainers map[byte]*itemContainer
|
||||||
|
@ -155,10 +156,10 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
|
|
||||||
proxy.AlwaysGetPacks = true
|
proxy.AlwaysGetPacks = true
|
||||||
proxy.ConnectCB = w.OnConnect
|
proxy.ConnectCB = w.OnConnect
|
||||||
proxy.OnClientConnect = func(proxy *utils.ProxyContext, hasClient bool) {
|
proxy.OnClientConnect = func(hasClient bool) {
|
||||||
w.gui.Message(messages.SetUIState, messages.UIStateConnecting)
|
w.gui.Message(messages.SetUIState, messages.UIStateConnecting)
|
||||||
}
|
}
|
||||||
proxy.PacketCB = func(pk packet.Packet, proxy *utils.ProxyContext, toServer bool, _ time.Time) (packet.Packet, error) {
|
proxy.PacketCB = func(pk packet.Packet, toServer bool, _ time.Time) (packet.Packet, error) {
|
||||||
forward := true
|
forward := true
|
||||||
|
|
||||||
if toServer {
|
if toServer {
|
||||||
|
@ -167,6 +168,11 @@ func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
|
||||||
pk = w.processMapPacketsClient(pk, &forward)
|
pk = w.processMapPacketsClient(pk, &forward)
|
||||||
} else {
|
} else {
|
||||||
// from server
|
// from server
|
||||||
|
switch pk := pk.(type) {
|
||||||
|
case *packet.ChunkRadiusUpdated:
|
||||||
|
w.ChunkRadius = int(pk.ChunkRadius)
|
||||||
|
pk.ChunkRadius = 80
|
||||||
|
}
|
||||||
pk = w.processItemPacketsServer(pk)
|
pk = w.processItemPacketsServer(pk)
|
||||||
pk = w.ProcessChunkPackets(pk)
|
pk = w.ProcessChunkPackets(pk)
|
||||||
pk = w.ProcessEntityPackets(pk)
|
pk = w.ProcessEntityPackets(pk)
|
||||||
|
@ -257,11 +263,12 @@ func (w *WorldState) Reset() {
|
||||||
|
|
||||||
// SaveAndReset writes the world to a folder, resets all the chunks
|
// SaveAndReset writes the world to a folder, resets all the chunks
|
||||||
func (w *WorldState) SaveAndReset() {
|
func (w *WorldState) SaveAndReset() {
|
||||||
|
|
||||||
|
// cull empty chunks
|
||||||
keys := make([]protocol.ChunkPos, 0, len(w.chunks))
|
keys := make([]protocol.ChunkPos, 0, len(w.chunks))
|
||||||
for cp := range w.chunks {
|
for cp := range w.chunks {
|
||||||
keys = append(keys, cp)
|
keys = append(keys, cp)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, cp := range keys {
|
for _, cp := range keys {
|
||||||
has_any := false
|
has_any := false
|
||||||
for _, sc := range w.chunks[cp].Sub() {
|
for _, sc := range w.chunks[cp].Sub() {
|
||||||
|
@ -274,7 +281,6 @@ func (w *WorldState) SaveAndReset() {
|
||||||
delete(w.chunks, cp)
|
delete(w.chunks, cp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(w.chunks) == 0 {
|
if len(w.chunks) == 0 {
|
||||||
w.Reset()
|
w.Reset()
|
||||||
return
|
return
|
||||||
|
@ -310,6 +316,7 @@ func (w *WorldState) SaveAndReset() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save entities
|
||||||
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
chunkEntities := make(map[world.ChunkPos][]world.Entity)
|
||||||
for _, es := range w.entities {
|
for _, es := range w.entities {
|
||||||
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
|
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
|
||||||
|
@ -499,6 +506,8 @@ func (w *WorldState) SaveAndReset() {
|
||||||
f.Close()
|
f.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
// zip it
|
// zip it
|
||||||
filename := folder + ".mcworld"
|
filename := folder + ".mcworld"
|
||||||
if err := utils.ZipFolder(filename, folder); err != nil {
|
if err := utils.ZipFolder(filename, folder); err != nil {
|
||||||
|
@ -509,14 +518,14 @@ func (w *WorldState) SaveAndReset() {
|
||||||
w.Reset()
|
w.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WorldState) OnConnect(proxy *utils.ProxyContext, err error) bool {
|
func (w *WorldState) OnConnect(err error) bool {
|
||||||
w.gui.Message(messages.SetUIState, messages.UIStateMain)
|
w.gui.Message(messages.SetUIState, messages.UIStateMain)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
w.proxy = proxy
|
|
||||||
gd := w.proxy.Server.GameData()
|
gd := w.proxy.Server.GameData()
|
||||||
|
w.ChunkRadius = int(gd.ChunkRadius)
|
||||||
|
|
||||||
world.InsertCustomItems(gd.Items)
|
world.InsertCustomItems(gd.Items)
|
||||||
|
|
||||||
|
@ -561,9 +570,7 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext, err error) bool {
|
||||||
|
|
||||||
w.proxy.SendMessage(locale.Loc("use_setname", nil))
|
w.proxy.SendMessage(locale.Loc("use_setname", nil))
|
||||||
|
|
||||||
w.mapUI.Start()
|
w.proxy.AddCommand(utils.IngameCommand{
|
||||||
|
|
||||||
proxy.AddCommand(utils.IngameCommand{
|
|
||||||
Exec: func(cmdline []string) bool {
|
Exec: func(cmdline []string) bool {
|
||||||
return w.setWorldName(strings.Join(cmdline, " "), false)
|
return w.setWorldName(strings.Join(cmdline, " "), false)
|
||||||
},
|
},
|
||||||
|
@ -584,7 +591,7 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext, err error) bool {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
proxy.AddCommand(utils.IngameCommand{
|
w.proxy.AddCommand(utils.IngameCommand{
|
||||||
Exec: func(cmdline []string) bool {
|
Exec: func(cmdline []string) bool {
|
||||||
return w.setVoidGen(!w.voidGen, false)
|
return w.setVoidGen(!w.voidGen, false)
|
||||||
},
|
},
|
||||||
|
@ -594,5 +601,10 @@ func (w *WorldState) OnConnect(proxy *utils.ProxyContext, err error) bool {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
w.mapUI.Start()
|
||||||
|
|
||||||
|
w.proxy.ClientWritePacket(&packet.ChunkRadiusUpdated{
|
||||||
|
ChunkRadius: 80,
|
||||||
|
})
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package settings
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
|
@ -40,19 +41,24 @@ func New(router *pages.Router) *Page {
|
||||||
startButton: widget.Clickable{},
|
startButton: widget.Clickable{},
|
||||||
}
|
}
|
||||||
|
|
||||||
options := make([]func(layout.Context) layout.Dimensions, 0, len(utils.ValidCMDs))
|
cmdNames := []string{}
|
||||||
p.cmdMenu.items = make(map[string]*widget.Clickable, len(utils.ValidCMDs))
|
|
||||||
for k := range utils.ValidCMDs {
|
for k := range utils.ValidCMDs {
|
||||||
|
cmdNames = append(cmdNames, k)
|
||||||
|
}
|
||||||
|
sort.Strings(cmdNames)
|
||||||
|
|
||||||
|
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 {
|
||||||
item := &widget.Clickable{}
|
item := &widget.Clickable{}
|
||||||
p.cmdMenu.items[k] = item
|
p.cmdMenu.items[name] = item
|
||||||
options = append(options, component.MenuItem(router.Theme, item, k).Layout)
|
options = append(options, component.MenuItem(router.Theme, item, name).Layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.cmdMenu.state = &component.MenuState{
|
p.cmdMenu.state = &component.MenuState{
|
||||||
OptionList: layout.List{},
|
OptionList: layout.List{},
|
||||||
Options: options,
|
Options: options,
|
||||||
}
|
}
|
||||||
//p.cmdMenu.selected = "worlds"
|
|
||||||
|
|
||||||
for _, su := range settings.Settings {
|
for _, su := range settings.Settings {
|
||||||
su.Init()
|
su.Init()
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package skins
|
package skins
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/unit"
|
"gioui.org/unit"
|
||||||
|
"gioui.org/widget"
|
||||||
"gioui.org/widget/material"
|
"gioui.org/widget/material"
|
||||||
"gioui.org/x/component"
|
"gioui.org/x/component"
|
||||||
"github.com/bedrock-tool/bedrocktool/ui/gui"
|
"github.com/bedrock-tool/bedrocktool/ui/gui"
|
||||||
|
@ -18,12 +21,20 @@ type (
|
||||||
type Page struct {
|
type Page struct {
|
||||||
*pages.Router
|
*pages.Router
|
||||||
|
|
||||||
State messages.UIState
|
State messages.UIState
|
||||||
|
SkinsList widget.List
|
||||||
|
l sync.Mutex
|
||||||
|
Skins []messages.NewSkinPayload
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(router *pages.Router) *Page {
|
func New(router *pages.Router) *Page {
|
||||||
return &Page{
|
return &Page{
|
||||||
Router: router,
|
Router: router,
|
||||||
|
SkinsList: widget.List{
|
||||||
|
List: layout.List{
|
||||||
|
Axis: layout.Vertical,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +77,18 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
Axis: layout.Vertical,
|
Axis: layout.Vertical,
|
||||||
}.Layout(gtx,
|
}.Layout(gtx,
|
||||||
layout.Rigid(material.Label(th, 20, "Skin Basic UI").Layout),
|
layout.Rigid(material.Label(th, 20, "Skin Basic UI").Layout),
|
||||||
|
layout.Flexed(1, func(gtx C) D {
|
||||||
|
p.l.Lock()
|
||||||
|
defer p.l.Unlock()
|
||||||
|
return material.List(th, &p.SkinsList).Layout(gtx, len(p.Skins), func(gtx C, index int) D {
|
||||||
|
entry := p.Skins[len(p.Skins)-index-1]
|
||||||
|
return layout.UniformInset(25).Layout(gtx, func(gtx C) D {
|
||||||
|
return layout.Flex{Axis: layout.Horizontal}.Layout(gtx,
|
||||||
|
layout.Rigid(material.Label(th, th.TextSize, entry.PlayerName).Layout),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -73,7 +96,7 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
return layout.Flex{}.Layout(gtx)
|
return layout.Flex{}.Layout(gtx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Page) handler(name string, data interface{}) messages.MessageResponse {
|
func (p *Page) handler(name string, data interface{}) messages.MessageResponse {
|
||||||
r := messages.MessageResponse{
|
r := messages.MessageResponse{
|
||||||
Ok: false,
|
Ok: false,
|
||||||
Data: nil,
|
Data: nil,
|
||||||
|
@ -82,8 +105,8 @@ func (u *Page) handler(name string, data interface{}) messages.MessageResponse {
|
||||||
switch name {
|
switch name {
|
||||||
case messages.SetUIState:
|
case messages.SetUIState:
|
||||||
state := data.(messages.UIState)
|
state := data.(messages.UIState)
|
||||||
u.State = state
|
p.State = state
|
||||||
u.Router.Invalidate()
|
p.Router.Invalidate()
|
||||||
r.Ok = true
|
r.Ok = true
|
||||||
|
|
||||||
case messages.Init:
|
case messages.Init:
|
||||||
|
@ -91,6 +114,13 @@ func (u *Page) handler(name string, data interface{}) messages.MessageResponse {
|
||||||
_ = init
|
_ = init
|
||||||
r.Ok = true
|
r.Ok = true
|
||||||
|
|
||||||
|
case messages.NewSkin:
|
||||||
|
p.l.Lock()
|
||||||
|
new_skin := data.(messages.NewSkinPayload)
|
||||||
|
p.Skins = append(p.Skins, new_skin)
|
||||||
|
r.Ok = true
|
||||||
|
p.l.Unlock()
|
||||||
|
p.Router.Invalidate()
|
||||||
}
|
}
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,13 @@ package worlds
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"time"
|
"math"
|
||||||
|
|
||||||
"gioui.org/f32"
|
"gioui.org/f32"
|
||||||
"gioui.org/gesture"
|
|
||||||
"gioui.org/io/pointer"
|
"gioui.org/io/pointer"
|
||||||
"gioui.org/layout"
|
"gioui.org/layout"
|
||||||
"gioui.org/op"
|
"gioui.org/op"
|
||||||
|
"gioui.org/op/clip"
|
||||||
"gioui.org/op/paint"
|
"gioui.org/op/paint"
|
||||||
"github.com/bedrock-tool/bedrocktool/ui/messages"
|
"github.com/bedrock-tool/bedrocktool/ui/messages"
|
||||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||||
|
@ -17,68 +17,83 @@ import (
|
||||||
|
|
||||||
type Map struct {
|
type Map struct {
|
||||||
click f32.Point
|
click f32.Point
|
||||||
mapPos f32.Point
|
|
||||||
pos f32.Point
|
|
||||||
imageOp paint.ImageOp
|
imageOp paint.ImageOp
|
||||||
zoom float32
|
|
||||||
|
|
||||||
drag gesture.Drag
|
scaleFactor float32
|
||||||
scroll gesture.Scroll
|
center f32.Point
|
||||||
|
transform f32.Affine2D
|
||||||
|
grabbed bool
|
||||||
|
|
||||||
MapImage *image.RGBA
|
MapImage *image.RGBA
|
||||||
BoundsMin protocol.ChunkPos
|
BoundsMin protocol.ChunkPos
|
||||||
BoundsMax protocol.ChunkPos
|
BoundsMax protocol.ChunkPos
|
||||||
Rotation float32
|
}
|
||||||
|
|
||||||
|
func (m *Map) HandlePointerEvent(e pointer.Event) {
|
||||||
|
switch e.Type {
|
||||||
|
case pointer.Press:
|
||||||
|
m.click = e.Position
|
||||||
|
m.grabbed = true
|
||||||
|
case pointer.Drag:
|
||||||
|
m.transform = m.transform.Offset(e.Position.Sub(m.click))
|
||||||
|
m.click = e.Position
|
||||||
|
case pointer.Release:
|
||||||
|
m.grabbed = false
|
||||||
|
case pointer.Scroll:
|
||||||
|
m.HandleScrollEvent(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Map) HandleScrollEvent(e pointer.Event) {
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Map) Layout(gtx layout.Context) layout.Dimensions {
|
func (m *Map) Layout(gtx layout.Context) layout.Dimensions {
|
||||||
// here we loop through all the events associated with this button.
|
// here we loop through all the events associated with this button.
|
||||||
for _, e := range m.drag.Events(gtx.Metric, gtx.Queue, gesture.Both) {
|
for _, e := range gtx.Events(m) {
|
||||||
switch e.Type {
|
if e, ok := e.(pointer.Event); ok {
|
||||||
case pointer.Press:
|
m.HandlePointerEvent(e)
|
||||||
m.click = e.Position
|
|
||||||
case pointer.Drag:
|
|
||||||
m.pos = m.mapPos.Sub(m.click).Add(e.Position)
|
|
||||||
case pointer.Release:
|
|
||||||
m.mapPos = m.pos
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scrollDist := m.scroll.Scroll(gtx.Metric, gtx.Queue, time.Now(), gesture.Vertical)
|
|
||||||
|
|
||||||
m.zoom -= float32(scrollDist) / 20
|
|
||||||
if m.zoom < 0.2 {
|
|
||||||
m.zoom = 0.2
|
|
||||||
}
|
|
||||||
|
|
||||||
size := gtx.Constraints.Max
|
|
||||||
|
|
||||||
if m.MapImage != nil {
|
if m.MapImage != nil {
|
||||||
m.imageOp.Add(gtx.Ops)
|
// Calculate the size of the widget based on the size of the image and the current scale factor.
|
||||||
b := m.MapImage.Bounds()
|
dx := float32(m.MapImage.Bounds().Dx())
|
||||||
sx := float32(b.Dx() / 2)
|
dy := float32(m.MapImage.Bounds().Dy())
|
||||||
sy := float32(b.Dy() / 2)
|
size := f32.Pt(dx*m.scaleFactor, dy*m.scaleFactor)
|
||||||
|
|
||||||
op.Affine(
|
m.center = f32.Pt(
|
||||||
f32.Affine2D{}.
|
float32(gtx.Constraints.Max.X),
|
||||||
Scale(f32.Pt(sx, sy), f32.Pt(m.zoom, m.zoom)).
|
float32(gtx.Constraints.Max.Y),
|
||||||
Offset(m.pos),
|
).Div(2)
|
||||||
).Add(gtx.Ops)
|
|
||||||
|
// Calculate the offset required to center the image within the widget.
|
||||||
|
offset := m.center.Sub(size.Div(2))
|
||||||
|
|
||||||
|
// Draw the image at the correct position and scale.
|
||||||
|
defer clip.Rect{Max: gtx.Constraints.Max}.Push(gtx.Ops).Pop()
|
||||||
|
op.Affine(m.transform.Offset(offset)).Add(gtx.Ops)
|
||||||
|
m.imageOp.Add(gtx.Ops)
|
||||||
paint.PaintOp{}.Add(gtx.Ops)
|
paint.PaintOp{}.Add(gtx.Ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.drag.Add(gtx.Ops)
|
size := gtx.Constraints.Max
|
||||||
m.scroll.Add(gtx.Ops, image.Rect(-size.X, -size.Y, size.X, size.Y))
|
pointer.InputOp{
|
||||||
|
Tag: m,
|
||||||
|
Grab: m.grabbed,
|
||||||
|
Types: pointer.Scroll | pointer.Drag | pointer.Press | pointer.Release,
|
||||||
|
ScrollBounds: image.Rect(-size.X, -size.Y, size.X, size.Y),
|
||||||
|
}.Add(gtx.Ops)
|
||||||
|
|
||||||
return layout.Dimensions{
|
return layout.Dimensions{Size: size}
|
||||||
Size: size,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawTile(img *image.RGBA, min, pos protocol.ChunkPos, tile *image.RGBA) {
|
func drawTile(img *image.RGBA, min, pos protocol.ChunkPos, tile *image.RGBA) {
|
||||||
px := image.Pt(
|
px := image.Pt(
|
||||||
int((pos.X()-min[0])*16),
|
int((pos.X()-min[0])*16),
|
||||||
int((pos.Z()-min[0])*16),
|
int((pos.Z()-min[1])*16),
|
||||||
)
|
)
|
||||||
draw.Draw(img, image.Rect(
|
draw.Draw(img, image.Rect(
|
||||||
px.X, px.Y,
|
px.X, px.Y,
|
||||||
|
@ -88,7 +103,7 @@ func drawTile(img *image.RGBA, min, pos protocol.ChunkPos, tile *image.RGBA) {
|
||||||
|
|
||||||
func (m *Map) Update(u *messages.UpdateMapPayload) {
|
func (m *Map) Update(u *messages.UpdateMapPayload) {
|
||||||
if m.MapImage == nil {
|
if m.MapImage == nil {
|
||||||
m.zoom = 1
|
m.scaleFactor = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
needNewImage := false
|
needNewImage := false
|
||||||
|
@ -115,5 +130,5 @@ func (m *Map) Update(u *messages.UpdateMapPayload) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.imageOp = paint.NewImageOp(m.MapImage)
|
m.imageOp = paint.NewImageOpFilter(m.MapImage, paint.FilterNearest)
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,16 +66,14 @@ func (p *Page) Layout(gtx C, th *material.Theme) D {
|
||||||
return margin.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
|
return margin.Layout(gtx, material.Label(th, 100, "Connecting").Layout)
|
||||||
case messages.UIStateMain:
|
case messages.UIStateMain:
|
||||||
// show the main ui
|
// show the main ui
|
||||||
return margin.Layout(gtx, func(gtx C) D {
|
return layout.Flex{
|
||||||
return layout.Flex{
|
Axis: layout.Vertical,
|
||||||
Axis: layout.Vertical,
|
}.Layout(gtx,
|
||||||
}.Layout(gtx,
|
layout.Rigid(material.Label(th, 20, "World Downloader Basic UI").Layout),
|
||||||
layout.Rigid(material.Label(th, 20, "World Downloader Basic UI").Layout),
|
layout.Flexed(1, func(gtx C) D {
|
||||||
layout.Flexed(1, func(gtx C) D {
|
return layout.Center.Layout(gtx, p.worldMap.Layout)
|
||||||
return layout.Center.Layout(gtx, p.worldMap.Layout)
|
}),
|
||||||
}),
|
)
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return layout.Flex{}.Layout(gtx)
|
return layout.Flex{}.Layout(gtx)
|
||||||
|
|
|
@ -73,12 +73,5 @@ func (bp *BehaviourPack) AddEntity(entity EntityIn) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hasCollision := entity.Meta.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagHasCollision)
|
|
||||||
hasGravity := entity.Meta.Flag(protocol.EntityDataKeyFlags, protocol.EntityDataFlagHasGravity)
|
|
||||||
entry.MinecraftEntity.Components["minecraft:physics"] = map[string]any{
|
|
||||||
"has_collision": hasCollision,
|
|
||||||
"has_gravity": hasGravity,
|
|
||||||
}
|
|
||||||
|
|
||||||
bp.entities[entity.Identifier] = entry
|
bp.entities[entity.Identifier] = entry
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
package encryptor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"math/rand"
|
||||||
|
"path/filepath"
|
||||||
|
"testing/fstest"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type contentItem struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Key string `json:"key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Content struct {
|
||||||
|
Content []contentItem `json:"content"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var StaticKey = []byte("s5s5ejuDru4uchuF2drUFuthaspAbepE")
|
||||||
|
|
||||||
|
func GenerateKey() (out []byte) {
|
||||||
|
out = make([]byte, 32)
|
||||||
|
var vocab = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||||
|
for i := 0; i < 32; i++ {
|
||||||
|
out[i] = vocab[rand.Intn(len(vocab))]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func encryptCfb(data []byte, key []byte) {
|
||||||
|
b, _ := aes.NewCipher(key)
|
||||||
|
s := cipher.NewCFBEncrypter(b, key[0:16])
|
||||||
|
s.XORKeyStream(data, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canEncrypt(path string) bool {
|
||||||
|
if path == "manifest.json" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
s := filepath.SplitList(path)
|
||||||
|
if s[0] == "texts" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if s[len(s)-1] == "contents.json" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func enc(fsys fs.FS, fsyso fstest.MapFS, contentsJson *Content, dir string) error {
|
||||||
|
// get all files in this folder
|
||||||
|
matches, err := fs.Glob(fsys, dir+"**")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, path := range matches {
|
||||||
|
// create output file
|
||||||
|
ifo, err := fs.Stat(fsys, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fo := &fstest.MapFile{
|
||||||
|
ModTime: ifo.ModTime(),
|
||||||
|
Mode: ifo.Mode(),
|
||||||
|
}
|
||||||
|
fsyso[path] = fo
|
||||||
|
|
||||||
|
// recurse
|
||||||
|
if ifo.IsDir() {
|
||||||
|
return enc(fsys, fsyso, contentsJson, path+"/")
|
||||||
|
}
|
||||||
|
|
||||||
|
// read data
|
||||||
|
var data []byte
|
||||||
|
data, err = fs.ReadFile(fsys, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt if needed
|
||||||
|
if canEncrypt(path) {
|
||||||
|
key := GenerateKey()
|
||||||
|
it := contentItem{
|
||||||
|
Path: path,
|
||||||
|
Key: hex.EncodeToString(key),
|
||||||
|
}
|
||||||
|
contentsJson.Content = append(contentsJson.Content, it)
|
||||||
|
encryptCfb(data, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to output
|
||||||
|
fo.Data = data
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Enc(fsys fs.FS, id *uuid.UUID, ContentKey []byte) (fs.FS, error) {
|
||||||
|
var manifest map[string]any
|
||||||
|
|
||||||
|
// read the manifest
|
||||||
|
f, err := fsys.Open("manifest.json")
|
||||||
|
if err == nil {
|
||||||
|
dec := json.NewDecoder(f)
|
||||||
|
err = dec.Decode(&manifest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
header, ok := manifest["header"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("no header")
|
||||||
|
}
|
||||||
|
|
||||||
|
// get id from manifest if not specified, else change it in the manifet
|
||||||
|
if id == nil {
|
||||||
|
idstr, ok := header["uuid"].(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("no id")
|
||||||
|
}
|
||||||
|
_id, err := uuid.Parse(idstr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
id = &_id
|
||||||
|
} else {
|
||||||
|
header["uuid"] = id.String()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if id != nil {
|
||||||
|
// create a manifest
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fsyso := fstest.MapFS{}
|
||||||
|
// encrypt
|
||||||
|
var contentsJson Content
|
||||||
|
err = enc(fsys, fsyso, &contentsJson, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write new manifest
|
||||||
|
manifestData, _ := json.MarshalIndent(manifest, "", "\t")
|
||||||
|
fsyso["manifest.json"] = &fstest.MapFile{
|
||||||
|
Data: manifestData,
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the contents.json encrypted
|
||||||
|
contentsBuf := bytes.NewBuffer(nil)
|
||||||
|
binary.Write(contentsBuf, binary.LittleEndian, uint32(0))
|
||||||
|
binary.Write(contentsBuf, binary.LittleEndian, uint32(0x9bcfb9fc))
|
||||||
|
binary.Write(contentsBuf, binary.LittleEndian, uint64(0))
|
||||||
|
contentsBuf.WriteByte(byte(len(id.String())))
|
||||||
|
contentsBuf.Write([]byte(id.String()))
|
||||||
|
contentsBuf.Write(make([]byte, 0xff-contentsBuf.Len()))
|
||||||
|
contentsData, _ := json.Marshal(&contentsJson)
|
||||||
|
encryptCfb(contentsData, ContentKey)
|
||||||
|
contentsBuf.Write(contentsData)
|
||||||
|
fsyso["contents.json"] = &fstest.MapFile{
|
||||||
|
Data: contentsBuf.Bytes(),
|
||||||
|
Mode: 0775,
|
||||||
|
ModTime: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return fsyso, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fstozip(fsys fs.FS, zw *zip.Writer, dir string) error {
|
||||||
|
// get files in this folder
|
||||||
|
matches, err := fs.Glob(fsys, dir+"**")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, path := range matches {
|
||||||
|
// if this path is a folder, recurse
|
||||||
|
ifo, _ := fs.Stat(fsys, path)
|
||||||
|
if ifo.IsDir() {
|
||||||
|
return fstozip(fsys, zw, path+"/")
|
||||||
|
}
|
||||||
|
// copy the file to the zip
|
||||||
|
w, err := zw.CreateHeader(&zip.FileHeader{
|
||||||
|
Name: ifo.Name(),
|
||||||
|
Modified: ifo.ModTime(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
data, err := fs.ReadFile(fsys, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
w.Write(data)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FSToZip(fsys fs.FS, w io.Writer) error {
|
||||||
|
zw := zip.NewWriter(w)
|
||||||
|
err := fstozip(fsys, zw, "")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
zw.Close()
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -162,6 +162,8 @@ func DumpStruct(data interface{}) {
|
||||||
FLog.Write([]byte("\n\n\n"))
|
FLog.Write([]byte("\n\n\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ClientAddr net.Addr
|
||||||
|
|
||||||
func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||||
var pk packet.Packet
|
var pk packet.Packet
|
||||||
if pkFunc, ok := pool[header.PacketID]; ok {
|
if pkFunc, ok := pool[header.PacketID]; ok {
|
||||||
|
@ -176,11 +178,11 @@ func PacketLogger(header packet.Header, payload []byte, src, dst net.Addr) {
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if recoveredErr := recover(); recoveredErr != nil {
|
if recoveredErr := recover(); recoveredErr != nil {
|
||||||
logrus.Errorf("%T: %w", pk, recoveredErr)
|
logrus.Errorf("%T: %s", pk, recoveredErr.(error))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
pk.Unmarshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
|
pk.Marshal(protocol.NewReader(bytes.NewBuffer(payload), 0))
|
||||||
|
|
||||||
if FLog != nil {
|
if FLog != nil {
|
||||||
dmpLock.Lock()
|
dmpLock.Lock()
|
||||||
|
|
|
@ -41,9 +41,9 @@ func (p dummyProto) ConvertFromLatest(pk packet.Packet, _ *minecraft.Conn) []pac
|
||||||
|
|
||||||
type (
|
type (
|
||||||
PacketFunc func(header packet.Header, payload []byte, src, dst net.Addr)
|
PacketFunc func(header packet.Header, payload []byte, src, dst net.Addr)
|
||||||
PacketCallback func(pk packet.Packet, proxy *ProxyContext, toServer bool, timeReceived time.Time) (packet.Packet, error)
|
PacketCallback func(pk packet.Packet, toServer bool, timeReceived time.Time) (packet.Packet, error)
|
||||||
ClientConnectCallback func(proxy *ProxyContext, hasClient bool)
|
ClientConnectCallback func(hasClient bool)
|
||||||
ConnectCallback func(proxy *ProxyContext, err error) bool
|
ConnectCallback func(err error) bool
|
||||||
IngameCommand struct {
|
IngameCommand struct {
|
||||||
Exec func(cmdline []string) bool
|
Exec func(cmdline []string) bool
|
||||||
Cmd protocol.Command
|
Cmd protocol.Command
|
||||||
|
@ -161,25 +161,28 @@ func (p *ProxyContext) LoadCustomUserData(path string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyContext) SendMessage(text string) {
|
func (p *ProxyContext) ClientWritePacket(pk packet.Packet) error {
|
||||||
if p.Client != nil {
|
if p.Client == nil {
|
||||||
p.Client.WritePacket(&packet.Text{
|
return nil
|
||||||
TextType: packet.TextTypeSystem,
|
|
||||||
Message: "§8[§bBedrocktool§8]§r " + text,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
return p.Client.WritePacket(pk)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ProxyContext) SendMessage(text string) {
|
||||||
|
p.ClientWritePacket(&packet.Text{
|
||||||
|
TextType: packet.TextTypeSystem,
|
||||||
|
Message: "§8[§bBedrocktool§8]§r " + text,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyContext) SendPopup(text string) {
|
func (p *ProxyContext) SendPopup(text string) {
|
||||||
if p.Client != nil {
|
p.ClientWritePacket(&packet.Text{
|
||||||
p.Client.WritePacket(&packet.Text{
|
TextType: packet.TextTypePopup,
|
||||||
TextType: packet.TextTypePopup,
|
Message: text,
|
||||||
Message: text,
|
})
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *ProxyContext) CommandHandlerPacketCB(pk packet.Packet, proxy *ProxyContext, toServer bool, _ time.Time) (packet.Packet, error) {
|
func (p *ProxyContext) CommandHandlerPacketCB(pk packet.Packet, toServer bool, _ time.Time) (packet.Packet, error) {
|
||||||
switch _pk := pk.(type) {
|
switch _pk := pk.(type) {
|
||||||
case *packet.CommandRequest:
|
case *packet.CommandRequest:
|
||||||
cmd := strings.Split(_pk.CommandLine, " ")
|
cmd := strings.Split(_pk.CommandLine, " ")
|
||||||
|
@ -223,7 +226,7 @@ func (p *ProxyContext) proxyLoop(ctx context.Context, toServer bool, packetCBs [
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, packetCB := range packetCBs {
|
for _, packetCB := range packetCBs {
|
||||||
pk, err = packetCB(pk, p, toServer, time.Now())
|
pk, err = packetCB(pk, toServer, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -240,11 +243,9 @@ func (p *ProxyContext) proxyLoop(ctx context.Context, toServer bool, packetCBs [
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ClientAddr net.Addr
|
|
||||||
|
|
||||||
func (p *ProxyContext) Run(ctx context.Context, serverAddress string) (err error) {
|
func (p *ProxyContext) Run(ctx context.Context, serverAddress string) (err error) {
|
||||||
if strings.HasPrefix(serverAddress, "PCAP!") {
|
if strings.HasPrefix(serverAddress, "PCAP!") {
|
||||||
return createReplayConnection(ctx, serverAddress[5:], p.ConnectCB, p.PacketCB)
|
return createReplayConnection(ctx, serverAddress[5:], p)
|
||||||
}
|
}
|
||||||
|
|
||||||
GetTokenSource() // ask for login before listening
|
GetTokenSource() // ask for login before listening
|
||||||
|
@ -298,7 +299,7 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress string) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.OnClientConnect != nil {
|
if p.OnClientConnect != nil {
|
||||||
p.OnClientConnect(p, p.WithClient)
|
p.OnClientConnect(p.WithClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.CustomClientData != nil {
|
if p.CustomClientData != nil {
|
||||||
|
@ -308,7 +309,7 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress string) (err error
|
||||||
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, p.PacketFunc)
|
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, p.PacketFunc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if p.ConnectCB != nil {
|
if p.ConnectCB != nil {
|
||||||
if p.ConnectCB(p, err) {
|
if p.ConnectCB(err) {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +325,7 @@ func (p *ProxyContext) Run(ctx context.Context, serverAddress string) (err error
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.ConnectCB != nil {
|
if p.ConnectCB != nil {
|
||||||
if !p.ConnectCB(p, nil) {
|
if !p.ConnectCB(nil) {
|
||||||
return errors.New("Cancelled")
|
return errors.New("Cancelled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,8 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bedrock-tool/bedrocktool/locale"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func getRealm(ctx context.Context, realmName, id string) (name string, address string, err error) {
|
func getRealm(ctx context.Context, realmName, id string) (name string, address string, err error) {
|
||||||
|
@ -29,23 +26,3 @@ func getRealm(ctx context.Context, realmName, id string) (name string, address s
|
||||||
}
|
}
|
||||||
return "", "", fmt.Errorf("realm not found")
|
return "", "", fmt.Errorf("realm not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
type RealmListCMD struct{}
|
|
||||||
|
|
||||||
func (*RealmListCMD) Name() string { return "list-realms" }
|
|
||||||
func (*RealmListCMD) Synopsis() string { return locale.Loc("list_realms_synopsis", nil) }
|
|
||||||
func (c *RealmListCMD) SetFlags(f *flag.FlagSet) {}
|
|
||||||
func (c *RealmListCMD) Execute(ctx context.Context, ui UI) error {
|
|
||||||
realms, err := GetRealmsAPI().Realms(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, realm := range realms {
|
|
||||||
fmt.Println(locale.Loc("realm_list_line", locale.Strmap{"Name": realm.Name, "Id": realm.ID}))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
RegisterCommand(&RealmListCMD{})
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ func WriteReplayHeader(f io.Writer) {
|
||||||
binary.Write(f, binary.LittleEndian, &header)
|
binary.Write(f, binary.LittleEndian, &header)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createReplayConnection(ctx context.Context, filename string, onConnect ConnectCallback, packetCB PacketCallback) error {
|
func createReplayConnection(ctx context.Context, filename string, proxy *ProxyContext) error {
|
||||||
logrus.Infof("Reading replay %s", filename)
|
logrus.Infof("Reading replay %s", filename)
|
||||||
|
|
||||||
f, err := os.Open(filename)
|
f, err := os.Open(filename)
|
||||||
|
@ -63,7 +63,6 @@ func createReplayConnection(ctx context.Context, filename string, onConnect Conn
|
||||||
f.Seek(-4, io.SeekCurrent)
|
f.Seek(-4, io.SeekCurrent)
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy, _ := NewProxy()
|
|
||||||
proxy.Server = minecraft.NewConn()
|
proxy.Server = minecraft.NewConn()
|
||||||
|
|
||||||
gameStarted := false
|
gameStarted := false
|
||||||
|
@ -129,8 +128,8 @@ func createReplayConnection(ctx context.Context, filename string, onConnect Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
if gameStarted {
|
if gameStarted {
|
||||||
if packetCB != nil {
|
if proxy.PacketCB != nil {
|
||||||
packetCB(pk, proxy, toServer, timeReceived)
|
proxy.PacketCB(pk, toServer, timeReceived)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch pk := pk.(type) {
|
switch pk := pk.(type) {
|
||||||
|
@ -165,8 +164,8 @@ func createReplayConnection(ctx context.Context, filename string, onConnect Conn
|
||||||
DisablePlayerInteractions: pk.DisablePlayerInteractions,
|
DisablePlayerInteractions: pk.DisablePlayerInteractions,
|
||||||
})
|
})
|
||||||
gameStarted = true
|
gameStarted = true
|
||||||
if onConnect != nil {
|
if proxy.ConnectCB != nil {
|
||||||
onConnect(proxy, nil)
|
proxy.ConnectCB(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,8 @@ func UnpackZip(r io.ReaderAt, size int64, unpackFolder string) {
|
||||||
fr, _ := srcFile.Open()
|
fr, _ := srcFile.Open()
|
||||||
f, _ := os.Create(path.Join(unpackFolder, srcName))
|
f, _ := os.Create(path.Join(unpackFolder, srcName))
|
||||||
io.Copy(f, fr)
|
io.Copy(f, fr)
|
||||||
|
f.Close()
|
||||||
|
fr.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue