320 lines
9.3 KiB
JavaScript
320 lines
9.3 KiB
JavaScript
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
|
|
}));
|
|
}
|
|
} |