From 268b156c63d6585a89aeeb8fa1251394ccf06df0 Mon Sep 17 00:00:00 2001 From: Robin Date: Mon, 18 Dec 2023 20:11:42 +0100 Subject: [PATCH] finish backendConfigSessionHandler --- .../java/proxy/session_backend_config.go | 25 ++++++++++- .../java/proxy/session_client_config.go | 43 +++++++++++++++++++ pkg/internal/oncetrue/oncetrue.go | 42 ++++++++++++++++++ 3 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 pkg/internal/oncetrue/oncetrue.go diff --git a/pkg/edition/java/proxy/session_backend_config.go b/pkg/edition/java/proxy/session_backend_config.go index 7447360f..0e51f748 100644 --- a/pkg/edition/java/proxy/session_backend_config.go +++ b/pkg/edition/java/proxy/session_backend_config.go @@ -2,9 +2,11 @@ package proxy import ( "errors" + "github.com/go-logr/logr" "go.minekube.com/gate/pkg/edition/java/netmc" "go.minekube.com/gate/pkg/edition/java/proto/packet" "go.minekube.com/gate/pkg/edition/java/proto/packet/config" + "go.minekube.com/gate/pkg/edition/java/proto/packet/plugin" "go.minekube.com/gate/pkg/edition/java/proto/state" "go.minekube.com/gate/pkg/edition/java/proto/version" "go.minekube.com/gate/pkg/edition/java/proxy/tablist" @@ -20,6 +22,7 @@ type backendConfigSessionHandler struct { state backendConfigSessionState resourcePackToApply *ResourcePackInfo playerConfigSessionHandler *clientConfigSessionHandler + log logr.Logger nopSessionHandler } @@ -39,6 +42,7 @@ func newBackendConfigSessionHandler( state: backendConfigSessionStateStart, requestCtx: requestCtx, playerConfigSessionHandler: clientSession, + log: serverConn.log.WithName("backendConfigSessionHandler"), }, nil } @@ -76,6 +80,14 @@ func (b *backendConfigSessionHandler) HandlePacket(pc *proto.PacketContext) { b.forwardToPlayer(pc, nil) case *config.RegistrySync: b.forwardToPlayer(pc, nil) + case *plugin.Message: + b.handlePluginMessage(pc, p) + case *packet.Disconnect: + b.serverConn.disconnect() + result := disconnectResultForPacket(b.log.V(1), p, + b.serverConn.player.Protocol(), b.serverConn.server, true, + ) + b.requestCtx.result(result, nil) default: b.forwardToPlayer(pc, nil) } @@ -109,7 +121,7 @@ func (b *backendConfigSessionHandler) handleResourcePackRequest(p *packet.Resour handleResourcePacketRequest(p, b.serverConn, b.proxy().Event()) } -func (b *backendConfigSessionHandler) handleFinishedUpdate(_ *config.FinishedUpdate) { +func (b *backendConfigSessionHandler) handleFinishedUpdate(p *config.FinishedUpdate) { smc, ok := b.serverConn.ensureConnected() if !ok { return @@ -118,7 +130,7 @@ func (b *backendConfigSessionHandler) handleFinishedUpdate(_ *config.FinishedUpd configHandler := b.playerConfigSessionHandler smc.SetState(state.Play) - configHandler.handleBackendFinishUpdate(b.serverConn, func() { + configHandler.handleBackendFinishUpdate(b.serverConn, p, func() { if b.serverConn == player.connectedServer() { smc.SetActiveSessionHandler(state.Play) @@ -146,6 +158,15 @@ func (b *backendConfigSessionHandler) handleFinishedUpdate(_ *config.FinishedUpd }) } +func (b *backendConfigSessionHandler) handlePluginMessage(pc *proto.PacketContext, p *plugin.Message) { + if plugin.McBrand(p) { + _ = b.serverConn.player.WritePacket(plugin.RewriteMinecraftBrand(p, + b.serverConn.player.Protocol())) + } else { + b.forwardToPlayer(pc, nil) + } +} + // forwardToPlayer forwards packets to the player. It prefers PacketContext over Packet. // Since we already have the packet's payload we can simply forward it on, // instead of encoding a Packet again each time. This increases throughput & decreases CPU and memory usage. diff --git a/pkg/edition/java/proxy/session_client_config.go b/pkg/edition/java/proxy/session_client_config.go index c9515db2..b74d8ba6 100644 --- a/pkg/edition/java/proxy/session_client_config.go +++ b/pkg/edition/java/proxy/session_client_config.go @@ -1,4 +1,47 @@ package proxy +import ( + "bytes" + "go.minekube.com/gate/pkg/edition/java/proto/packet/config" + "go.minekube.com/gate/pkg/edition/java/proto/packet/plugin" + "go.minekube.com/gate/pkg/edition/java/proto/util" + "go.minekube.com/gate/pkg/internal/oncetrue" +) + type clientConfigSessionHandler struct { + player *connectedPlayer + brandChannel string + + configSwitchDone oncetrue.OnceWhenTrue +} + +// handleBackendFinishUpdate handles the backend finishing the config stage. +func (h *clientConfigSessionHandler) handleBackendFinishUpdate( + serverConn *serverConnection, + p *config.FinishedUpdate, + onConfigSwitch func(), +) { + smc, ok := serverConn.ensureConnected() + if ok { + brand := serverConn.player.ClientBrand() + if brand == "" && h.brandChannel != "" { + buf := new(bytes.Buffer) + _ = util.WriteString(buf, brand) + + brandPacket := &plugin.Message{ + Channel: h.brandChannel, + Data: buf.Bytes(), + } + _ = smc.WritePacket(brandPacket) + } + err := smc.WritePacket(p) + if err != nil { + return + } + } + if err := h.player.WritePacket(p); err != nil { + return + } + + h.configSwitchDone.DoWhenTrue(onConfigSwitch) } diff --git a/pkg/internal/oncetrue/oncetrue.go b/pkg/internal/oncetrue/oncetrue.go new file mode 100644 index 00000000..3ba25db9 --- /dev/null +++ b/pkg/internal/oncetrue/oncetrue.go @@ -0,0 +1,42 @@ +package oncetrue + +import ( + "sync" +) + +type OnceWhenTrue struct { + condition bool + onTrue func() + called bool + mu sync.Mutex +} + +func NewOnceWhenTrue() *OnceWhenTrue { + return &OnceWhenTrue{} +} + +func (o *OnceWhenTrue) DoWhenTrue(onTrue func()) { + o.mu.Lock() + defer o.mu.Unlock() + + o.onTrue = onTrue + + // If condition is true and onTrue hasn't been called, call it + if o.condition && !o.called { + o.onTrue() + o.called = true + } +} + +func (o *OnceWhenTrue) SetTrue() { + o.mu.Lock() + defer o.mu.Unlock() + + o.condition = true + + // If onTrue is set and hasn't been called, call it + if o.onTrue != nil && !o.called { + o.onTrue() + o.called = true + } +}