document.addEventListener('DOMContentLoaded', () => { const config = document.getElementById('game-waiting-config'); if (!config) { return; } const publicUrl = config.dataset.mercurePublicUrl; const topic = config.dataset.topic; const readyAt = config.dataset.readyAt; let reloading = false; const reloadOnce = (eventSource) => { if (reloading) { return; } reloading = true; if (eventSource) { eventSource.close(); } window.location.reload(); }; if (publicUrl && topic) { const url = new URL(publicUrl); url.searchParams.append('topic', topic); const eventSource = new EventSource(url); eventSource.onmessage = event => { const data = JSON.parse(event.data); if (data.type === 'all_ready' || data.type === 'player_ready') { reloadOnce(eventSource); } }; } // Our own ready status expires 60s after we set it - proactively tell the // server as close to that deadline as possible, so the other players find // out live instead of only whenever someone else's request happens to // trigger the lazy check. if (readyAt) { const timeoutMs = 61000; // slightly more than the server-side 60s const readyAtMs = readyAt * 1000; const countdownEl = document.getElementById('ready-countdown'); const expireForm = document.getElementById('expire-ready-form'); const updateCountdown = () => { const remaining = Math.max(0, Math.ceil((readyAtMs + timeoutMs - Date.now()) / 1000)); if (countdownEl) { const m = Math.floor(remaining / 60); const s = remaining % 60; countdownEl.textContent = m + ':' + s.toString().padStart(2, '0'); } return remaining; }; const remaining = updateCountdown(); if (remaining <= 0) { expireForm?.submit(); } else { const countdownInterval = setInterval(() => { if (updateCountdown() <= 0) { clearInterval(countdownInterval); expireForm?.submit(); } }, 1000); } } });