From 828481533794f3c518d9da369c101c3b573ae304 Mon Sep 17 00:00:00 2001 From: Vishesh 'ironeagle' Bangotra Date: Fri, 28 Nov 2025 16:40:28 +0530 Subject: [PATCH] feat(matchmaking): add automatic requeue on match rejection - Detect Nakama error code 3 ("No match ID or token found") when a match is rejected due to incompatible match properties (e.g., mode mismatch). - Preserve last selected game mode using a ref so client can requeue automatically without user interaction. - Implement fallback logic to call joinMatchmaker() again after server rejection. - Improve robustness of matchmaking flow by ensuring players remain in queue until a valid match is formed. --- src/tictactoe/providers/NakamaProvider.tsx | 26 +++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/tictactoe/providers/NakamaProvider.tsx b/src/tictactoe/providers/NakamaProvider.tsx index 2daab52..5531361 100644 --- a/src/tictactoe/providers/NakamaProvider.tsx +++ b/src/tictactoe/providers/NakamaProvider.tsx @@ -47,6 +47,8 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) { const [session, setSession] = useState(null); const [socket, setSocket] = useState(null); const [matchId, setMatchId] = useState(null); + const lastModeRef = React.useRef(null); + const socketRef = React.useRef(null); // ---------------------------------------------------- // LOGIN @@ -62,17 +64,32 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) { const s = client.createSocket(undefined, undefined); // no SSL on localhost await s.connect(newSession, true); setSocket(s); + socketRef.current = s; console.log("[Nakama] WebSocket connected"); // MATCHMAKER MATCHED CALLBACK s.onmatchmakermatched = async (matched: MatchmakerMatched) => { + // 1) If match_id is empty → server rejected the group. + if (!matched.match_id) { + console.warn("[Nakama] Match rejected by server. Auto-requeueing..."); + + if (lastModeRef.current) { + try { + await joinMatchmaker(lastModeRef.current); + } catch (e) { + console.error("[Nakama] Requeue failed:", e); + } + } + + return; + } + + // 2) Valid match: continue as usual. console.log("[Nakama] MATCHED:", matched); - - setMatchId(matched.match_id); - try { await s.joinMatch(matched.match_id); + setMatchId(matched.match_id); console.log("[Nakama] Auto-joined match:", matched.match_id); } catch (err) { console.error("[Nakama] Failed to join match:", err); @@ -84,6 +101,7 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) { // MATCHMAKING // ---------------------------------------------------- async function joinMatchmaker(mode: string) { + const socket = socketRef.current; if (!socket) throw new Error("socket missing"); console.log(`[Nakama] Matchmaking... with +mode:"${mode}"`); @@ -94,6 +112,8 @@ export function NakamaProvider({ children }: { children: React.ReactNode }) { { mode } // stringProperties ); + lastModeRef.current = mode; + return ticket.ticket; }