function getCookie(name) { const value = `; ${document.cookie}`; const parts = value.split(`; ${name}=`); if (parts.length === 2) return parts.pop().split(';').shift(); return ''; } function getScreenCoordinates(clientX, clientY, canvas, screenWidth, screenHeight) { const rect = canvas.getBoundingClientRect(); const canvasX = clientX - rect.left; const canvasY = clientY - rect.top; const scaleX = screenWidth / rect.width; const scaleY = screenHeight / rect.height; const screenX = Math.floor(canvasX * scaleX); const screenY = Math.floor(canvasY * scaleY); return { x: screenX, y: screenY }; } function createReconnectingWebSocket(url, options = {}) { const { onOpen = () => {}, onClose = () => {}, onMessage = () => {}, onError = () => {}, maxDelay = 30000 } = options; let ws = null; let reconnectDelay = 1000; let reconnectTimer = null; let isManualClose = false; function connect() { ws = new WebSocket(url); ws.onopen = () => { reconnectDelay = 1000; onOpen(ws); }; ws.onmessage = (e) => { onMessage(e, ws); }; ws.onclose = () => { onClose(); if (!isManualClose) { reconnectTimer = setTimeout(() => { reconnectDelay = Math.min(reconnectDelay * 2, maxDelay); connect(); }, reconnectDelay); } }; ws.onerror = (err) => { onError(err); }; } function close() { isManualClose = true; if (reconnectTimer) { clearTimeout(reconnectTimer); } if (ws) { ws.close(); } } function getWebSocket() { return ws; } function isReady() { return ws && ws.readyState === WebSocket.OPEN; } connect(); return { getWebSocket, isReady, close }; }