1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
| class GameReconnectManager { constructor() { this.maxRetryCount = 5; this.currentRetry = 0; this.retryDelays = [1000, 2000, 5000, 10000, 20000]; this.reconnectState = ReconnectState.IDLE; }
async attemptReconnect() { if (this.currentRetry >= this.maxRetryCount) { this.onReconnectFailed(); return; }
this.reconnectState = ReconnectState.RECONNECTING; const delay = this.retryDelays[this.currentRetry] || 30000;
console.log(`Reconnect attempt ${this.currentRetry + 1}/${this.maxRetryCount} in ${delay}ms`);
setTimeout(async () => { try { await this.doReconnect(); } catch (error) { console.error('Reconnect failed:', error); this.currentRetry++; this.attemptReconnect(); } }, delay); }
async doReconnect() { const socket = await this.connectWebSocket();
const authResult = await this.authenticate(socket); if (!authResult.success) { throw new Error('Authentication failed'); }
const hasSavedGame = await this.checkSavedGame(authResult.userId);
if (hasSavedGame) { await this.restoreGame(socket, authResult.userId); } else { this.onReconnectToLobby(); }
this.onReconnectSuccess(); }
async restoreGame(socket, userId) { socket.emit('restoreGame', { userId }, async (response) => { if (response.success) { const snapshot = response.snapshot;
if (await this.validateGameState(snapshot)) { await this.applyGameSnapshot(snapshot);
await this.syncLatestState(socket, response.serverTime);
this.onGameRestored(snapshot); } else { this.onGameEnded(snapshot.result); } } else { this.onReconnectToLobby(); } }); }
async validateGameState(snapshot) { const now = Date.now(); const elapsed = now - snapshot.timestamp;
if (elapsed > GAME_CONFIG.MAX_DISCONNECT_TIME) { return false; }
if (snapshot.gameState.status === 'ended') { return false; }
return true; }
async syncLatestState(socket, serverTime) { socket.emit('syncMissedEvents', { lastKnownTime: serverTime }, (response) => { for (const event of response.missedEvents) { this.replayEvent(event); } }); } }
const ReconnectState = { IDLE: 'idle', DISCONNECTED: 'disconnected', RECONNECTING: 'reconnecting', RESTORING: 'restoring', SYNCING: 'syncing', RESTORED: 'restored', FAILED: 'failed' };
|