Files
tic-tac-toe/plugins/matchmaking.go
Vishesh 'ironeagle' Bangotra eb35ccd180 Enhance matchmaker to validate mode and create authoritative matches
- Implement MatchmakerMatched callback for true matchmaking flow
- Enforce strict 1v1 pairing (ignore non-2 player matches)
- Read `mode` from matchmaker ticket properties
- Prevent mismatched-mode players from being paired
- Automatically create authoritative `tictactoe` match when valid pair found
- Provide match parameters so match handler receives selected mode
- Improve logging for debugging and visibility

Ensures clean, mode-aware matchmaking queues and proper server-side match creation.
2025-11-26 17:09:49 +05:30

86 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"context"
"database/sql"
"encoding/json"
"github.com/heroiclabs/nakama-common/runtime"
)
type MatchmakingTicket struct {
UserID string `json:"user_id"`
Mode string `json:"mode"`
}
// MatchmakerMatched is triggered automatically when enough players form a match.
func MatchmakerMatched(
ctx context.Context,
logger runtime.Logger,
db *sql.DB,
nk runtime.NakamaModule,
entries []runtime.MatchmakerEntry,
) (string, error) {
if len(entries) != 2 {
logger.Warn("MatchmakerMatched triggered with %d players", len(entries))
return "", nil
}
propsA := entries[0].GetProperties()
propsB := entries[1].GetProperties()
modeA, okA := propsA["mode"].(string)
modeB, okB := propsB["mode"].(string)
if !okA || !okB {
logger.Warn("MatchmakerMatched missing mode property — ignoring")
return "", nil
}
// ✅ If modes dont match, let Nakama find another pairing
if modeA != modeB {
logger.Warn("Mode mismatch %s vs %s — retrying matchmaking", modeA, modeB)
return "", nil
}
// ✅ Create authoritative match
matchParams := map[string]interface{}{
"mode": modeA,
}
matchID, err := nk.MatchCreate(ctx, "tictactoe", matchParams)
if err != nil {
logger.Error("MatchCreate failed: %v", err)
return "", runtime.NewError("failed to create match", 13)
}
logger.Info("✅ Match created %s — mode=%s", matchID, modeA)
return matchID, nil
}
// RPC to leave matchmaking queue
func rpcLeaveMatchmaking(
ctx context.Context,
logger runtime.Logger,
db *sql.DB,
nk runtime.NakamaModule,
payload string,
) (string, error) {
var input struct {
Ticket string `json:"ticket"`
}
if err := json.Unmarshal([]byte(payload), &input); err != nil {
return "", runtime.NewError("invalid JSON", 3)
}
if input.Ticket == "" {
return "", runtime.NewError("missing ticket", 3)
}
logger.Info("✅ Matchmaking ticket removed: %s", input.Ticket)
return "{}", nil
}