diff --git a/sockets/arena_socket.js b/sockets/arena_socket.js index c7dca14..866a1c9 100644 --- a/sockets/arena_socket.js +++ b/sockets/arena_socket.js @@ -458,6 +458,7 @@ function registerArenaHandlers(io, socket) { emitToMatch(io, matchId, "arena_ready", { player1: room.names["player1"] || "Spieler 1", player2: room.names["player2"] || "Spieler 2", + boardSync: room.boardCards || [], }); startReadyTimer(io, matchId); } else { @@ -498,10 +499,16 @@ function registerArenaHandlers(io, socket) { if (!matchId || !slot) return; const nextSlot = slot === "player1" ? "player2" : "player1"; - // Direkt an beide Spieler senden – kein Room-Broadcast nötig - emitToMatch(io, matchId, "turn_change", { activeSlot: nextSlot }); + // Board-State mitschicken → beide Clients können Board synchronisieren + const room = io._arenaRooms?.get(matchId); + const boardCards = room?.boardCards || []; - console.log(`[1v1] Zug: ${slot} → ${nextSlot} | Match ${matchId}`); + emitToMatch(io, matchId, "turn_change", { + activeSlot: nextSlot, + boardSync: boardCards, + }); + + console.log(`[1v1] Zug: ${slot} → ${nextSlot} | boardCards=${boardCards.length} | Match ${matchId}`); }); /* ── Karte gespielt → direkt an Gegner senden ── */ @@ -531,8 +538,8 @@ function registerArenaHandlers(io, socket) { io._turnInit.add(matchId); emitToMatch(io, matchId, "turn_change", { activeSlot: starterSlot }); console.log(`[1v1] Startzug: ${starterSlot} | Match ${matchId}`); - // Cleanup nach 10s - setTimeout(() => io._turnInit?.delete(matchId), 10000); + // Cleanup nach 60s (lang genug damit doppelte end_turn_init geblockt bleiben) + setTimeout(() => io._turnInit?.delete(matchId), 60000); }); /* ── 2v2 & 4v4 ── */ diff --git a/views/1v1-battlefield.ejs b/views/1v1-battlefield.ejs index aeb726a..c725896 100644 --- a/views/1v1-battlefield.ejs +++ b/views/1v1-battlefield.ejs @@ -840,6 +840,8 @@ console.log("[Arena] arena_ready:", data); clearTimeout(readyFallbackTimer); document.getElementById("connecting-overlay")?.remove(); + // Board sync falls Karten bereits gespielt wurden + if (data.boardSync) applyBoardSync(data.boardSync); // Gegner-Name: URL-Parameter hat Vorrang (aus match_found, 100% korrekt) // Server-Daten nur als Fallback wenn URL-Name fehlt const oppName = amIPlayer1 ? data.player2 : data.player1; @@ -863,35 +865,36 @@ if (lockOverlay) lockOverlay.style.display = "flex"; }); - /* ── Board-Sync bei Reconnect ──────────────────────────── */ - socket.on("board_sync", (data) => { - if (!data.cards) return; - data.cards.forEach((cardData) => { + /* ── Board synchronisieren (aus boardSync Array) ───────── */ + function applyBoardSync(cards) { + if (!cards || !cards.length) return; + cards.forEach((cardData) => { const slotEl = document.getElementById(cardData.boardSlot); - if (!slotEl || boardState[cardData.boardSlot]) return; // bereits gesetzt + if (!slotEl || boardState[cardData.boardSlot]) return; boardState[cardData.boardSlot] = cardData.card; renderCardOnBoard(slotEl, cardData.card); }); - console.log("[1v1] Board sync:", data.cards.length, "Karten geladen"); + console.log("[1v1] Board sync:", cards.length, "Karten"); + } + + /* ── Board-Sync bei Reconnect ──────────────────────────── */ + socket.on("board_sync", (data) => { + if (data.cards) applyBoardSync(data.cards); }); /* ── Server: Zugwechsel ──────────────────────────────── */ - let lastTurnChangeTs = 0; + let lastTurnChangeActive = null; socket.on("turn_change", (data) => { - // Duplikat-Schutz: identisches Event innerhalb 500ms ignorieren - const now = Date.now(); - if (now - lastTurnChangeTs < 200) return; - lastTurnChangeTs = now; + // Board synchronisieren falls mitgeliefert + if (data.boardSync) applyBoardSync(data.boardSync); const nowMyTurn = data.activeSlot === mySlot; - console.log( - "[1v1] turn_change:", - data.activeSlot, - "| ich bin:", - mySlot, - "| meinZug:", - nowMyTurn, - ); + + // Duplikat-Schutz: gleiche Zustandsänderung nicht doppelt anwenden + if (data.activeSlot === lastTurnChangeActive && nowMyTurn === isMyTurn) return; + lastTurnChangeActive = data.activeSlot; + + console.log("[1v1] turn_change:", data.activeSlot, "| ich:", mySlot, "| meinZug:", nowMyTurn); setTurnState(nowMyTurn); }); @@ -992,15 +995,13 @@ document.getElementById("board-lock-overlay")?.remove(); // Festlegen ob ich der linke Spieler bin - // flip=false: player1=links, flip=true: player1=rechts amILeftPlayer = flip ? mySlot === "player2" : mySlot === "player1"; - // Linker Spieler beginnt - setTurnState(amILeftPlayer); - socket.emit("end_turn_init", { - matchId, - starterSlot: flip ? "player2" : "player1", - }); + // Startspieler NUR vom Server bestimmen lassen – kein lokales setTurnState! + // Nur der erste Spieler sendet end_turn_init, Server entscheidet wer beginnt + const starterSlot = flip ? "player2" : "player1"; + socket.emit("end_turn_init", { matchId, starterSlot }); + // turn_change vom Server setzt dann den korrekten Zustand für beide Spieler } });