From e30a8516d14c07e1a491ad5b417d3a1b235fcd03 Mon Sep 17 00:00:00 2001 From: AkmalFairuz Date: Thu, 20 Mar 2025 21:39:20 +0700 Subject: [PATCH 1/2] refactor: optimize client packet handling by using a map for ClientDecode --- session/handler.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/session/handler.go b/session/handler.go index f9bf27f..b8efb9f 100644 --- a/session/handler.go +++ b/session/handler.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - "slices" "time" packet2 "github.com/cooldogedev/spectrum/server/packet" @@ -90,6 +89,11 @@ func handleClient(s *Session) { } } + clientDecode := make(map[uint32]struct{}, len(s.opts.ClientDecode)) + for _, id := range s.opts.ClientDecode { + clientDecode[id] = struct{}{} + } + loop: for { select { @@ -105,7 +109,7 @@ loop: break loop } - if err := handleClientPacket(s, header, pool, shieldID, payload); err != nil { + if err := handleClientPacket(s, header, pool, shieldID, payload, clientDecode); err != nil { s.Server().CloseWithError(fmt.Errorf("failed to write packet to server: %w", err)) } } @@ -131,14 +135,14 @@ loop: } // handleClientPacket processes and forwards the provided packet from the client to the server. -func handleClientPacket(s *Session, header *packet.Header, pool packet.Pool, shieldID int32, payload []byte) (err error) { +func handleClientPacket(s *Session, header *packet.Header, pool packet.Pool, shieldID int32, payload []byte, clientDecode map[uint32]struct{}) (err error) { ctx := NewContext() buf := bytes.NewBuffer(payload) if err := header.Read(buf); err != nil { return errors.New("failed to decode header") } - if !slices.Contains(s.opts.ClientDecode, header.PacketID) { + if _, ok := clientDecode[header.PacketID]; !ok { s.processor.ProcessClientEncoded(ctx, &payload) if !ctx.Cancelled() { return s.Server().Write(payload) From e98f0eb396697af99167c95b9ca9b0bedab0354b Mon Sep 17 00:00:00 2001 From: AkmalFairuz Date: Thu, 20 Mar 2025 23:34:17 +0700 Subject: [PATCH 2/2] compatibility with session.SetOpts --- session/handler.go | 11 +++-------- session/session.go | 5 +++++ util/opts.go | 9 +++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/session/handler.go b/session/handler.go index 49543d5..4bea5b5 100644 --- a/session/handler.go +++ b/session/handler.go @@ -93,11 +93,6 @@ func handleClient(s *Session) { } } - clientDecode := make(map[uint32]struct{}, len(s.opts.ClientDecode)) - for _, id := range s.opts.ClientDecode { - clientDecode[id] = struct{}{} - } - loop: for { select { @@ -113,7 +108,7 @@ loop: break loop } - if err := handleClientPacket(s, header, pool, shieldID, payload, clientDecode); err != nil { + if err := handleClientPacket(s, header, pool, shieldID, payload); err != nil { s.Server().CloseWithError(fmt.Errorf("failed to write packet to server: %w", err)) } } @@ -139,14 +134,14 @@ loop: } // handleClientPacket processes and forwards the provided packet from the client to the server. -func handleClientPacket(s *Session, header *packet.Header, pool packet.Pool, shieldID int32, payload []byte, clientDecode map[uint32]struct{}) (err error) { +func handleClientPacket(s *Session, header *packet.Header, pool packet.Pool, shieldID int32, payload []byte) (err error) { ctx := NewContext() buf := bytes.NewBuffer(payload) if err := header.Read(buf); err != nil { return errors.New("failed to decode header") } - if _, ok := clientDecode[header.PacketID]; !ok { + if _, ok := s.clientDecode[header.PacketID]; !ok { s.processor.ProcessClientEncoded(ctx, &payload) if !ctx.Cancelled() { return s.Server().Write(payload) diff --git a/session/session.go b/session/session.go index 1777817..70675a6 100644 --- a/session/session.go +++ b/session/session.go @@ -44,6 +44,8 @@ type Session struct { latency atomic.Int64 transferring atomic.Bool once sync.Once + + clientDecode map[uint32]struct{} } // NewSession creates a new Session instance using the provided minecraft.Conn. @@ -61,6 +63,8 @@ func NewSession(client *minecraft.Conn, logger *slog.Logger, registry *Registry, animation: &animation.Dimension{}, processor: NopProcessor{}, tracker: newTracker(), + + clientDecode: opts.ClientDecodeAsMap(), } s.ctx, s.cancelFunc = context.WithCancelCause(client.Context()) return s @@ -234,6 +238,7 @@ func (s *Session) Opts() util.Opts { // SetOpts updates the session options. func (s *Session) SetOpts(opts util.Opts) { s.opts = opts + s.clientDecode = opts.ClientDecodeAsMap() } // Processor returns the current processor. diff --git a/util/opts.go b/util/opts.go index 641fc34..fc88702 100644 --- a/util/opts.go +++ b/util/opts.go @@ -21,6 +21,15 @@ type Opts struct { Token string `yaml:"token"` } +// ClientDecodeAsMap converts the ClientDecode slice to a map for faster lookups. +func (opts *Opts) ClientDecodeAsMap() map[uint32]struct{} { + m := make(map[uint32]struct{}, len(opts.ClientDecode)) + for _, id := range opts.ClientDecode { + m[id] = struct{}{} + } + return m +} + // DefaultOpts returns the default configuration options for Spectrum. func DefaultOpts() *Opts { return &Opts{