function connectGame() { if (socket) { socket.close(); } if (typeof pingInterval !== 'undefined' && pingInterval) { clearInterval(pingInterval); } const proto = location.protocol === 'https:' ? 'wss:' : 'ws:'; const url = proto + "//" + location.host + "/ws"; console.log("Verbinde zu:", url); socket = new WebSocket(url); socket.onopen = () => { console.log("๐ŸŸข WS Verbunden. Spiel startet."); // Alles zurรผcksetzen obstacleBuffer = []; platformBuffer = []; obstacles = []; platforms = []; currentLatencyMs = 0; isGameRunning = true; isGameOver = false; isLoaded = true; pingInterval = setInterval(sendPing, 1000); requestAnimationFrame(gameLoop); }; socket.onmessage = (event) => { try { const msg = JSON.parse(event.data); if (msg.type === "pong") { const now = Date.now(); const sentTime = msg.ts; const rtt = now - sentTime; const latency = rtt / 2; if (currentLatencyMs === 0) { currentLatencyMs = latency; } else { currentLatencyMs = (currentLatencyMs * 0.9) + (latency * 0.1); } } if (msg.type === "chunk") { const msPerTick = 1000 / 20; const latencyInTicks = Math.floor(currentLatencyMs / msPerTick); const targetTick = msg.serverTick + latencyInTicks; const drift = targetTick - currentTick; if (Math.abs(drift) > 2) { currentTick = targetTick; } let sTick = msg.serverTick; let currentSpeedPerTick = 15.0 + (sTick / 1000.0) * 1.5; if (currentSpeedPerTick > 36) currentSpeedPerTick = 36; const speedPerMs = currentSpeedPerTick / msPerTick; let dynamicCorrection = (currentLatencyMs * speedPerMs) + 5; if (dynamicCorrection > 100) dynamicCorrection = 100; // Limit if (msg.obstacles) { msg.obstacles.forEach(o => { o.x -= dynamicCorrection; o.prevX = o.x; obstacleBuffer.push(o); }); } if (msg.platforms) { msg.platforms.forEach(p => { p.x -= dynamicCorrection; p.prevX = p.x; platformBuffer.push(p); }); } if (msg.score !== undefined) score = msg.score; if (msg.powerups) { godModeLives = msg.powerups.godLives; hasBat = msg.powerups.hasBat; bootTicks = msg.powerups.bootTicks; } } if (msg.type === "init") { console.log("๐Ÿ“ฉ INIT EMPFANGEN:", msg); // <--- DEBUG LOG if (msg.sessionId) { sessionID = msg.sessionId; // Globale Variable setzen console.log("๐Ÿ”‘ Session ID gesetzt auf:", sessionID); } else { console.error("โŒ INIT FEHLER: Keine sessionId im Paket!", msg); } } if (msg.type === "dead") { console.log("๐Ÿ’€ Server sagt: Game Over"); if (msg.score) score = msg.score; // Verbindung sauber trennen socket.close(); if (pingInterval) clearInterval(pingInterval); gameOver("Vom Server gestoppt"); } if (msg.type === "debug_sync") { let clientSpeed = BASE_SPEED + (currentTick / 1000.0) * 1.5; if (clientSpeed > 36.0) clientSpeed = 36.0; let serverSpeed = msg.currentSpeed || 0; let diffSpeed = clientSpeed - serverSpeed; let speedIcon = Math.abs(diffSpeed) < 0.01 ? "โœ…" : "โŒ"; console.group(`๐Ÿ“Š SYNC REPORT (Tick: ${currentTick} vs Server: ${msg.serverTick})`); // --- DER NEUE SPEED CHECK --- console.log(`๐Ÿš€ SPEED CHECK: ${speedIcon}`); console.log(` Client: ${clientSpeed.toFixed(4)} px/tick (Basis: Tick ${currentTick})`); console.log(` Server: ${serverSpeed.toFixed(4)} px/tick (Basis: Tick ${msg.serverTick})`); if (Math.abs(diffSpeed) > 0.01) { console.warn(`โš ๏ธ ACHTUNG: Geschwindigkeiten weichen ab! Diff: ${diffSpeed.toFixed(4)}`); console.warn("Ursache: Client nutzt 'Score', Server nutzt 'Ticks'. Sind diese synchron?"); } generateSyncTable("Obstacles", obstacles, msg.obstacles); generateSyncTable("Platforms", platforms, msg.platforms); console.groupEnd(); } } catch (e) { console.error("Fehler beim Verarbeiten der Nachricht:", e); } }; socket.onclose = () => { console.log("๐Ÿ”ด WS Verbindung getrennt."); if (pingInterval) clearInterval(pingInterval); }; socket.onerror = (error) => { console.error("WS Fehler:", error); }; } function sendPing() { if (socket && socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ type: "ping", tick: Date.now() // Timestamp als Integer })); } } function sendInput(type, action) { if (socket && socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ type: "input", input: action })); } } // Helper fรผr die Tabelle function generateSyncTable(label, clientList, serverList) { if (!serverList) serverList = []; console.log(`--- ${label} Analyse (Ping: ${Math.round(currentLatencyMs)}ms) ---`); const report = []; const matchedServerIndices = new Set(); const msPerTick = 50; let debugSpeed = 15.0 + (score / 1000.0) * 1.5; if (debugSpeed > 36) debugSpeed = 36; const speedPerMs = debugSpeed / msPerTick; const latencyPx = currentLatencyMs * speedPerMs; clientList.forEach((cObj) => { let bestMatch = null; let bestDist = 9999; let bestSIdx = -1; const cID = cObj.def ? cObj.def.id : (cObj.id || "unknown"); serverList.forEach((sObj, sIdx) => { if (matchedServerIndices.has(sIdx)) return; const sID = sObj.id || "unknown"; const sPosCorrected = sObj.x - latencyPx; const dist = Math.abs(cObj.x - sPosCorrected); const isTypeMatch = (label === "Platforms") || (cID === sID); // Toleranter Suchradius (500px), falls Drift groรŸ ist if (isTypeMatch && dist < bestDist && dist < 500) { bestDist = dist; bestMatch = sObj; bestSIdx = sIdx; } }); // Datenzeile bauen let serverXRaw = "---"; let serverXCorrected = "---"; let diffReal = "---"; let status = "๐Ÿ‘ป GHOST (Client only)"; if (bestMatch) { matchedServerIndices.add(bestSIdx); serverXRaw = bestMatch.x; serverXCorrected = bestMatch.x - latencyPx; diffReal = cObj.x - serverXCorrected; const absDiff = Math.abs(diffReal); if (absDiff < 20) status = "โœ… PERFECT"; else if (absDiff < 60) status = "๐Ÿ†— OK"; else if (absDiff < 150) status = "โš ๏ธ DRIFT"; else status = "๐Ÿ”ฅ BROKEN"; } report.push({ "ID": cID, "Client X": Math.round(cObj.x), "Server X (Raw)": Math.round(serverXRaw), "Server X (Sim)": Math.round(serverXCorrected), // Wo es sein sollte "Diff (Real)": typeof diffReal === 'number' ? Math.round(diffReal) : "---", "Status": status }); }); serverList.forEach((sObj, sIdx) => { if (!matchedServerIndices.has(sIdx)) { const sPosCorrected = sObj.x - latencyPx; let status = "โŒ MISSING"; if (sPosCorrected > 850) status = "๐Ÿ”ฎ FUTURE (Buffer)"; // Noch rechts vom Screen if (sPosCorrected < -100) status = "๐Ÿ—‘๏ธ OLD (Server lag)"; // Schon links raus report.push({ "ID": sObj.id || "?", "Client X": "---", "Server X (Raw)": Math.round(sObj.x), "Server X (Sim)": Math.round(sPosCorrected), "Diff (Real)": "---", "Status": status }); } }); report.sort((a, b) => { const valA = (typeof a["Client X"] === 'number') ? a["Client X"] : a["Server X (Sim)"]; const valB = (typeof b["Client X"] === 'number') ? b["Client X"] : b["Server X (Sim)"]; return valA - valB; }); if (report.length > 0) console.table(report); else console.log("Leer."); } function sendPhysicsSync(y, vy) { if (socket && socket.readyState === WebSocket.OPEN) { socket.send(JSON.stringify({ type: "sync", y: y, vy: vy, tick: currentTick })); } }