From 0fb448dd457c8f68814fef74cbb508f9bc335fc4 Mon Sep 17 00:00:00 2001 From: Vishesh 'ironeagle' Bangotra Date: Wed, 26 Nov 2025 16:09:48 +0530 Subject: [PATCH] feat: add rpc_find_match for basic 2-player matchmaking - Implement rpc_find_match Nakama RPC function - Search for existing authoritative TicTacToe matches via MatchList - Return first match with available slot (size < 2) - Create new match using MatchCreate when none available - Add request/response structs for future extensibility - Log match search, selection, and creation flow - Gracefully handle optional JSON payload and invalid input --- plugins/main.go | 4 +++ plugins/matchmaking.go | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 plugins/matchmaking.go diff --git a/plugins/main.go b/plugins/main.go index 3b60cea..1aaa52d 100644 --- a/plugins/main.go +++ b/plugins/main.go @@ -34,6 +34,10 @@ func InitModule( logger.Error("Failed to register RPC: %v", err) return err } + if err := initializer.RegisterRpc("rpc_find_match", rpcFindMatch); err != nil { + logger.Error("RegisterRpc rpc_find_match failed: %v", err) + return err + } logger.Info("Go module loaded successfully!") return nil diff --git a/plugins/matchmaking.go b/plugins/matchmaking.go new file mode 100644 index 0000000..a89cbcc --- /dev/null +++ b/plugins/matchmaking.go @@ -0,0 +1,70 @@ +package main + +import ( + "context" + "database/sql" + "encoding/json" + + "github.com/heroiclabs/nakama-common/runtime" +) + +type FindMatchRequest struct{} + +type FindMatchResponse struct { + MatchID string `json:"match_id"` +} + +func rpcFindMatch( + ctx context.Context, + logger runtime.Logger, + db *sql.DB, + nk runtime.NakamaModule, + payload string, +) (string, error) { + + logger.Info("rpc_find_match called") + + var req FindMatchRequest + if payload != "" { + if err := json.Unmarshal([]byte(payload), &req); err != nil { + logger.Warn("rpc_find_match: invalid request payload: %v", err) + } + } + + const limit = 10 + authoritative := true + labelFilter := "tictactoe" // must match MatchInit label + var minSize, maxSize *int // nil = no constraint + + matches, err := nk.MatchList( + ctx, + limit, + authoritative, + labelFilter, + minSize, + maxSize, + "", // query + ) + if err != nil { + logger.Error("rpc_find_match: MatchList failed: %v", err) + return "", runtime.NewError("internal error", 13) + } + + for _, m := range matches { + if m.Size < 2 { + logger.Info("rpc_find_match: found match %s with size=%d", m.MatchId, m.Size) + out, _ := json.Marshal(FindMatchResponse{MatchID: m.MatchId}) + return string(out), nil + } + } + + matchID, err := nk.MatchCreate(ctx, "tictactoe", map[string]interface{}{}) + if err != nil { + logger.Error("rpc_find_match: MatchCreate failed: %v", err) + return "", runtime.NewError("internal error", 13) + } + + logger.Info("rpc_find_match: created new match %s", matchID) + out, _ := json.Marshal(FindMatchResponse{MatchID: matchID}) + return string(out), nil +}