experimental transfer handler
This commit is contained in:
parent
f3d1a80985
commit
39be9c678b
3
go.mod
3
go.mod
|
@ -3,7 +3,7 @@ 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.30.0-3
|
||||
replace github.com/sandertv/gophertunnel => github.com/olebeck/gophertunnel v1.31.0-2
|
||||
|
||||
//replace github.com/df-mc/dragonfly => ./dragonfly
|
||||
replace github.com/df-mc/dragonfly => github.com/olebeck/dragonfly v0.9.6-2
|
||||
|
@ -66,6 +66,7 @@ require (
|
|||
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // 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.1 // indirect
|
||||
|
|
6
go.sum
6
go.sum
|
@ -96,6 +96,10 @@ github.com/olebeck/gophertunnel v1.30.0-2 h1:JbkADJTfpCfC7nL9O08LON0k8OBahfmOdBy
|
|||
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=
|
||||
|
@ -114,6 +118,8 @@ github.com/sanbornm/go-selfupdate v0.0.0-20210106163404-c9b625feac49 h1:LuxslTBx
|
|||
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/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=
|
||||
|
|
Binary file not shown.
153
utils/proxy.go
153
utils/proxy.go
|
@ -16,7 +16,6 @@ import (
|
|||
|
||||
"github.com/bedrock-tool/bedrocktool/locale"
|
||||
"github.com/bedrock-tool/bedrocktool/ui/messages"
|
||||
"github.com/repeale/fp-go"
|
||||
"github.com/sandertv/gophertunnel/minecraft"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/login"
|
||||
|
@ -95,6 +94,8 @@ type ProxyContext struct {
|
|||
|
||||
commands map[string]IngameCommand
|
||||
handlers []*ProxyHandler
|
||||
|
||||
reconnectHandler *ProxyHandler
|
||||
}
|
||||
|
||||
func NewProxy() (*ProxyContext, error) {
|
||||
|
@ -103,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 {
|
||||
|
@ -247,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()
|
||||
|
@ -262,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)
|
||||
|
@ -279,6 +288,10 @@ func (p *ProxyContext) proxyLoop(ctx context.Context, toServer bool) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if transferingErr != nil {
|
||||
return transferingErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -410,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()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@ -426,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, tokenSource)
|
||||
p.Server, err = connectServer(ctx, serverAddress, cdp, p.AlwaysGetPacks, p.packetFunc, tokenSource)
|
||||
}
|
||||
if err != nil {
|
||||
for _, handler := range p.handlers {
|
||||
|
@ -498,51 +490,92 @@ 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)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(wantSecondary) > 0 {
|
||||
go func() {
|
||||
for {
|
||||
c, err := p.Listener.Accept()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
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,
|
||||
})
|
||||
|
||||
for _, handler := range wantSecondary {
|
||||
go handler.SecondaryClientCB(c.(*minecraft.Conn))
|
||||
}
|
||||
}
|
||||
}()
|
||||
p.AddHandler(p.reconnectHandler)
|
||||
|
||||
for _, handler := range p.handlers {
|
||||
if handler.AddressAndName != nil {
|
||||
handler.AddressAndName(serverAddress, name)
|
||||
}
|
||||
if handler.ProxyRef != nil {
|
||||
handler.ProxyRef(p)
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
return err
|
||||
return p.connect(ctx, serverAddress)
|
||||
}
|
||||
|
||||
func DecodePacket(pool packet.Pool, header packet.Header, payload []byte) packet.Packet {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
@ -65,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
|
||||
}
|
||||
|
||||
|
|
|
@ -113,13 +113,16 @@ func (s *SkinPack) Save(fpath, serverName string) error {
|
|||
e.SetIndent("", "\t")
|
||||
if err := e.Encode(map[string]any{
|
||||
"format_version": "1.12.0",
|
||||
"minecraft:geometry": geometry,
|
||||
"minecraft:geometry": []*SkinGeometry_1_12{geometry},
|
||||
}); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
geometryJson[geometryName] = *geometry
|
||||
geometryJson[geometryName] = SkinGeometry{
|
||||
SkinGeometryDescription: geometry.Description,
|
||||
Bones: geometry.Bones,
|
||||
}
|
||||
entry.Geometry = geometryName
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue