From f2712bdcec180b4416d7832761ee936e35e923ba Mon Sep 17 00:00:00 2001 From: Mathias Wagner Date: Wed, 14 May 2025 19:27:21 +0200 Subject: [PATCH] Fix automatic advance bug --- .../styles/components/voting-screen.sass | 16 +++++ client/src/components/VotingScreen.jsx | 33 ++++++---- server/game.js | 64 ++++++++++++++++--- server/index.js | 2 +- 4 files changed, 90 insertions(+), 25 deletions(-) diff --git a/client/src/common/styles/components/voting-screen.sass b/client/src/common/styles/components/voting-screen.sass index 6929420..db94b07 100644 --- a/client/src/common/styles/components/voting-screen.sass +++ b/client/src/common/styles/components/voting-screen.sass @@ -124,6 +124,12 @@ color: $accent font-weight: bold text-align: center + + .host-info + margin-top: 0.5rem + color: #fff + font-style: italic + font-size: 0.7rem .video-container margin-top: 1rem @@ -267,6 +273,16 @@ font-family: 'Press Start 2P', monospace font-size: 0.9rem color: $text + + .auto-advance-notice + margin: 1rem auto + max-width: 400px + padding: 0.75rem + background-color: rgba($secondary, 0.2) + border: 2px solid $secondary + text-align: center + color: $text-muted + font-style: italic .votes-count display: flex diff --git a/client/src/components/VotingScreen.jsx b/client/src/components/VotingScreen.jsx index b3c6047..9bfb82c 100644 --- a/client/src/components/VotingScreen.jsx +++ b/client/src/components/VotingScreen.jsx @@ -6,7 +6,7 @@ import { faVoteYea, faTrophy, faMusic, faCheck, faMedal, faCrown } from '@fortaw import YouTubeEmbed from './YouTubeEmbed'; function VotingScreen() { - const { lobby, currentPlayer, submitVote } = useGame(); + const { lobby, currentPlayer, submitVote, isHost } = useGame(); const [hasVoted, setHasVoted] = useState(false); const [selectedSong, setSelectedSong] = useState(null); const [countdown, setCountdown] = useState(null); @@ -65,11 +65,11 @@ function VotingScreen() { // Handle bye round advancement - für automatisches Weiterkommen const handleByeAdvance = async () => { - if (processingByeAdvance) return; + if (processingByeAdvance || !isHost) return; setProcessingByeAdvance(true); try { - // Alle Spieler im Bye-Modus "stimmen" automatisch für das einzige Lied + // Nur der Host kann im Bye-Modus weiterschaltenNNULL if (battle && battle.song1 && !battle.song2 && battle.song1.id) { await submitVote(battle.song1.id); } @@ -122,6 +122,7 @@ function VotingScreen() {

{battle.song1.artist}

Dieses Lied kommt automatisch in die nächste Runde!

+

{isHost ? 'Du kannst als Host zum nächsten Kampf weitergehen.' : 'Warte auf den Host, um fortzufahren.'}

@@ -139,17 +140,21 @@ function VotingScreen() {
- + {isHost ? ( + + ) : ( +

Warte auf den Host, um fortzufahren...

+ )}
); diff --git a/server/game.js b/server/game.js index 78e2b18..b572542 100644 --- a/server/game.js +++ b/server/game.js @@ -539,13 +539,19 @@ class GameManager { return { error: 'No active battle' }; } + // For bye battles (automatic advancement), only allow the host to vote/advance + if (lobby.currentBattle.bye === true && playerId !== lobby.hostId) { + return { error: 'Only the host can advance bye rounds' }; + } + // Check if player has already voted in this battle - if (lobby.currentBattle.votes.has(playerId)) { + if (lobby.currentBattle.votes && lobby.currentBattle.votes.has(playerId)) { return { error: 'Already voted in this battle' }; } // Check if the voted song is part of the current battle - if (songId !== lobby.currentBattle.song1.id && songId !== lobby.currentBattle.song2.id) { + if (songId !== lobby.currentBattle.song1.id && + (lobby.currentBattle.song2 && songId !== lobby.currentBattle.song2.id)) { return { error: 'Invalid song ID' }; } @@ -553,6 +559,11 @@ class GameManager { const player = lobby.players.find(p => p.id === playerId); const playerName = player ? player.name : 'Unknown Player'; + // Initialize votes Map if it doesn't exist + if (!lobby.currentBattle.votes) { + lobby.currentBattle.votes = new Map(); + } + // Record the vote with player name for UI display lobby.currentBattle.votes.set(playerId, { songId, @@ -561,15 +572,38 @@ class GameManager { // Update vote counts if (songId === lobby.currentBattle.song1.id) { - lobby.currentBattle.song1Votes++; - } else { - lobby.currentBattle.song2Votes++; + lobby.currentBattle.song1Votes = (lobby.currentBattle.song1Votes || 0) + 1; + } else if (lobby.currentBattle.song2) { + lobby.currentBattle.song2Votes = (lobby.currentBattle.song2Votes || 0) + 1; } // Add a voteCount attribute for easier UI rendering lobby.currentBattle.voteCount = lobby.currentBattle.votes.size; - // Check if all connected players have voted + // For bye battles, the host's vote is all that's needed + if (lobby.currentBattle.bye === true && playerId === lobby.hostId) { + // Determine winner (in bye battles, it's always song1) + const winnerSongId = lobby.currentBattle.song1.id; + + lobby.currentBattle.winner = winnerSongId; + + // Save battle to history + lobby.battles.push({ + round: lobby.currentBattle.round, + song1: lobby.currentBattle.song1, + song2: lobby.currentBattle.song2, + song1Votes: lobby.currentBattle.song1Votes, + song2Votes: 0, + winner: winnerSongId + }); + + // Move to next battle or finish tournament + this._moveToNextBattle(lobby); + + return { lobby, lobbyId }; + } + + // For regular battles, check if all connected players have voted const connectedPlayers = lobby.players.filter(p => p.isConnected).length; const voteCount = lobby.currentBattle.votes.size; @@ -728,9 +762,10 @@ class GameManager { song1: byeSong, song2: null, // Bye bye: true, - winner: byeSong.id, + winner: null, // Set to null until host advances it song1Votes: 0, - song2Votes: 0 + song2Votes: 0, + votes: new Map() // Initialize votes as a Map }); } @@ -825,9 +860,10 @@ class GameManager { song1: byeSong, song2: null, bye: true, - winner: byeSong.id, + winner: null, // Set to null until host advances it song1Votes: 0, - song2Votes: 0 + song2Votes: 0, + votes: new Map() // Initialize votes as a Map }); } @@ -853,6 +889,14 @@ class GameManager { // Set first battle of new round if (nextRound.length > 0) { lobby.currentBattle = nextRound[0]; + + // Ensure votes is initialized as a Map + if (!lobby.currentBattle.votes) { + lobby.currentBattle.votes = new Map(); + } + + // Initialize vote count for UI + lobby.currentBattle.voteCount = 0; } } diff --git a/server/index.js b/server/index.js index baa13d0..0b66bbb 100644 --- a/server/index.js +++ b/server/index.js @@ -315,7 +315,7 @@ io.on('connection', (socket) => { }); // If battle is finished, notify about new battle - if (result.lobby.currentBattle) { + if (result.lobby.currentBattle && result.lobby.currentBattle !== result.lobby.battles[result.lobby.battles.length - 1]) { io.to(result.lobbyId).emit('new_battle', { battle: result.lobby.currentBattle });