Commit 317f8d20 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix: wire match-live into Chess and Ludo — enables reconnect on refresh

Chess game scene:
- Imports and calls matchLive.start(matchId, 'chess', callbacks)
- Creates localStorage entry → browser refresh auto-resumes
- matchLive.session.destroy() on endGame → clears recovery

Ludo game scene:
- Same pattern: matchLive.start(matchId, 'ludo', callbacks)
- Clears session on endGame

Now the flow works:
1. Player enters live game → matchLive.start() saves to localStorage
2. Player refreshes browser → engine boot finds recovery → verifies server → auto-rejoins
3. Game ends normally → matchLive.session.destroy() clears localStorage
4. Player goes to homepage after game → no recovery popup (correct)
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 95be7796
ludo-playtest/01-home.png

103 KB | W: | H:

ludo-playtest/01-home.png

140 KB | W: | H:

ludo-playtest/01-home.png
ludo-playtest/01-home.png
ludo-playtest/01-home.png
ludo-playtest/01-home.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -13,6 +13,7 @@ import { getMaterialAdvantage, formatAdvantage } from '../logic/material.js'; ...@@ -13,6 +13,7 @@ import { getMaterialAdvantage, formatAdvantage } from '../logic/material.js';
import * as emoteSystem from '../components/emotes.js'; import * as emoteSystem from '../components/emotes.js';
import * as mp from '../../../core/multiplayer.js'; import * as mp from '../../../core/multiplayer.js';
import { emoji } from '../../../core/theme.js'; import { emoji } from '../../../core/theme.js';
import * as matchLive from '../../../core/match-live.js';
let board, clock, gameState; let board, clock, gameState;
...@@ -186,8 +187,18 @@ export function mountGame(el, params) { ...@@ -186,8 +187,18 @@ export function mountGame(el, params) {
requestBotMove(el); requestBotMove(el);
} }
// Live mode: start polling for opponent moves // Live mode: start match session (enables reconnection on refresh)
if (mode === 'live' && matchId) { if (mode === 'live' && matchId) {
matchLive.start(matchId, 'chess', {
onMove: (data) => {
// Handled by existing polling — this is backup via match-live
mp.updateConnectionStatus(true);
},
onGameEnd: (data) => {
if (!gameState.gameOver) endGame('loss', 'abandon');
}
});
startLivePolling(el); startLivePolling(el);
if (playerColor === 'b') { if (playerColor === 'b') {
gameState.isPlayerTurn = false; gameState.isPlayerTurn = false;
...@@ -568,6 +579,7 @@ function endGame(result, reason) { ...@@ -568,6 +579,7 @@ function endGame(result, reason) {
if (gameState.gameOver) return; if (gameState.gameOver) return;
stopLivePolling(); stopLivePolling();
mp.cleanup(); mp.cleanup();
matchLive.session.destroy(); // Clear recovery so homepage doesn't try to rejoin
gameState.gameOver = true; gameState.gameOver = true;
clock.stop(); clock.stop();
board.interactive = false; board.interactive = false;
......
...@@ -10,6 +10,7 @@ import { getPiecePosition, getHomeBasePosition, SAFE_SQUARES, HOME_COLUMNS, SHAR ...@@ -10,6 +10,7 @@ import { getPiecePosition, getHomeBasePosition, SAFE_SQUARES, HOME_COLUMNS, SHAR
import * as emoteSystem from '../../chess/components/emotes.js'; import * as emoteSystem from '../../chess/components/emotes.js';
import * as mp from '../../../core/multiplayer.js'; import * as mp from '../../../core/multiplayer.js';
import { emoji, getAsset } from '../../../core/theme.js'; import { emoji, getAsset } from '../../../core/theme.js';
import * as matchLive from '../../../core/match-live.js';
import * as net from '../../../core/net.js'; import * as net from '../../../core/net.js';
let game, validMoves, ctx, canvas, boardSize, cellSize; let game, validMoves, ctx, canvas, boardSize, cellSize;
...@@ -108,6 +109,10 @@ export function mountGame(el, params) { ...@@ -108,6 +109,10 @@ export function mountGame(el, params) {
// Live mode setup — full multiplayer integration // Live mode setup — full multiplayer integration
if (mode === 'live' && matchId) { if (mode === 'live' && matchId) {
matchLive.start(matchId, 'ludo', {
onMove: (data) => { mp.updateConnectionStatus(true); },
onGameEnd: () => { if (!game.gameOver) { game.gameOver = true; scene.exitGameMode(); scene.replace('ludo-result', { result: 'loss' }); } }
});
mp.startDisconnectWatch(matchId, 'ludo', 60000); mp.startDisconnectWatch(matchId, 'ludo', 60000);
mp.onEmoteReceived((emote) => { mp.onEmoteReceived((emote) => {
// Animate from OPPONENT's panel position to center // Animate from OPPONENT's panel position to center
...@@ -717,6 +722,7 @@ function renderMiniDice(miniDice, value) { ...@@ -717,6 +722,7 @@ function renderMiniDice(miniDice, value) {
function endGame(el) { function endGame(el) {
game.gameOver = true; game.gameOver = true;
matchLive.session.destroy(); // Clear session so homepage doesn't try to rejoin
const result = game.winners[0] === 0 ? 'win' : 'loss'; const result = game.winners[0] === 0 ? 'win' : 'loss';
if (result === 'win') { juice.confetti(window.innerWidth/2, window.innerHeight/3, 40); juice.hapticSuccess(); audio.play('win','reward'); } if (result === 'win') { juice.confetti(window.innerWidth/2, window.innerHeight/3, 40); juice.hapticSuccess(); audio.play('win','reward'); }
else { audio.play('lose','game'); juice.hapticError(); } else { audio.play('lose','game'); juice.hapticError(); }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment