Skip to content

Commit 9e71e41

Browse files
committed
Revert "Merge pull request #13 from TigerAppsOrg/feature/private-match-play-again"
This reverts commit f7f1a51, reversing changes made to 9f1aaf3.
1 parent f7f1a51 commit 9e71e41

File tree

4 files changed

+2
-216
lines changed

4 files changed

+2
-216
lines changed

client/src/components/Results.jsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import ProfileModal from './ProfileModal.jsx';
1212

1313
function Results({ onShowLeaderboard }) {
1414
const navigate = useNavigate();
15-
const { raceState, typingState, resetRace, joinPublicRace, playAgain } = useRace();
15+
const { raceState, typingState, resetRace, joinPublicRace } = useRace();
1616
const { isRunning, endTutorial } = useTutorial();
1717
const { user } = useAuth();
1818
// State for profile modal
@@ -353,20 +353,13 @@ function Results({ onShowLeaderboard }) {
353353

354354
{raceState.type === 'practice' ? renderPracticeResults() : renderRaceResults()}
355355

356-
{/* Play Again button for private match host */}
357-
{raceState.type === 'private' && raceState.completed && user?.netid === raceState.hostNetId && (
358-
<button className="back-btn" onClick={playAgain}>
359-
Play Again
360-
</button>
361-
)}
362-
363356
{/* Queue Next Race button for quick matches */}
364357
{raceState.type === 'public' && (
365358
<button className="back-btn" onClick={handleQueueNext}>
366359
Queue Another Race
367360
</button>
368361
)}
369-
362+
370363
<button className="back-btn back-to-menu-btn" onClick={handleBack}>
371364
Back to Menu
372365
</button>

client/src/context/RaceContext.jsx

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -567,36 +567,6 @@ export const RaceProvider = ({ children }) => {
567567
resetAnticheatState();
568568
};
569569

570-
// Handle play again – host created a new lobby and all players are migrated
571-
const handleLobbyPlayAgain = (data) => {
572-
console.log('Play again – joining new lobby:', data.code);
573-
resetAnticheatState();
574-
setTypingState({
575-
input: '', position: 0, correctChars: 0, errors: 0,
576-
completed: false, wpm: 0, accuracy: 0, lockedPosition: 0
577-
});
578-
setRaceState({
579-
code: data.code,
580-
type: data.type || 'private',
581-
lobbyId: data.lobbyId,
582-
hostNetId: data.hostNetId,
583-
snippet: data.snippet ? { ...data.snippet, text: sanitizeSnippetText(data.snippet.text) } : null,
584-
players: data.players || [],
585-
startTime: null,
586-
inProgress: false,
587-
completed: false,
588-
results: [],
589-
manuallyStarted: false,
590-
timedTest: {
591-
enabled: data.settings?.testMode === 'timed',
592-
duration: data.settings?.testDuration || 15
593-
},
594-
snippetFilters: data.settings?.snippetFilters || { difficulty: 'all', type: 'all', department: 'all' },
595-
settings: data.settings || { testMode: 'snippet', testDuration: 15 },
596-
countdown: null
597-
});
598-
};
599-
600570
// Register event listeners
601571
socket.on('race:joined', handleRaceJoined);
602572
socket.on('race:playersUpdate', handlePlayersUpdate);
@@ -618,7 +588,6 @@ export const RaceProvider = ({ children }) => {
618588
socket.on('race:playerLeft', handlePlayerLeft);
619589
socket.on('anticheat:lock', handleAnticheatLock);
620590
socket.on('anticheat:reset', handleAnticheatReset);
621-
socket.on('lobby:playAgain', handleLobbyPlayAgain);
622591

623592
// Clean up on unmount
624593
return () => {
@@ -642,7 +611,6 @@ export const RaceProvider = ({ children }) => {
642611
socket.off('race:playerLeft', handlePlayerLeft);
643612
socket.off('anticheat:lock', handleAnticheatLock);
644613
socket.off('anticheat:reset', handleAnticheatReset);
645-
socket.off('lobby:playAgain', handleLobbyPlayAgain);
646614
socket.off('snippetNotFound', handleSnippetNotFound); // Cleanup snippet not found listener
647615
};
648616
// Add raceState.snippet?.id to dependency array to reset typing state on snippet change
@@ -1112,16 +1080,6 @@ export const RaceProvider = ({ children }) => {
11121080
});
11131081
};
11141082

1115-
const playAgain = () => {
1116-
if (!socket || !connected || !raceState.code || raceState.type !== 'private') return;
1117-
socket.emit('lobby:playAgain', { code: raceState.code }, (response) => {
1118-
if (!response.success) {
1119-
console.error('Failed to play again:', response.error);
1120-
}
1121-
// State update handled by lobby:playAgain listener
1122-
});
1123-
};
1124-
11251083
// joinPrivateLobby is declared earlier with useCallback to avoid TDZ
11261084

11271085
const kickPlayer = (targetNetId) => {
@@ -1234,7 +1192,6 @@ export const RaceProvider = ({ children }) => {
12341192
kickPlayer,
12351193
updateLobbySettings,
12361194
startPrivateRace,
1237-
playAgain,
12381195
setPlayerReady,
12391196
handleInput,
12401197
updateProgress,

client/src/pages/Race.jsx

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,19 +70,6 @@ function Race() {
7070
navigate('/home', { replace: true });
7171
}
7272
}, [raceState.code, navigate]);
73-
74-
// After play again, navigate back to the new private lobby
75-
useEffect(() => {
76-
if (
77-
raceState.type === 'private' &&
78-
raceState.code &&
79-
!raceState.inProgress &&
80-
!raceState.completed &&
81-
raceState.countdown === null
82-
) {
83-
navigate(`/lobby/${raceState.code}`, { replace: true });
84-
}
85-
}, [raceState.code, raceState.type, raceState.inProgress, raceState.completed, raceState.countdown, navigate]);
8673

8774
// Handle back button
8875
const handleBack = () => {

server/controllers/socket-handlers.js

Lines changed: 0 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,157 +1315,6 @@ const initialize = (io) => {
13151315
}
13161316
});
13171317

1318-
// Handle "Play Again" for private lobbies (host only)
1319-
// Creates a new lobby with the same settings and migrates all connected players
1320-
socket.on('lobby:playAgain', async (data, callback) => {
1321-
const { user: hostNetid, userId: hostUserId } = socket.userInfo;
1322-
const { code: oldCode } = data;
1323-
1324-
try {
1325-
console.log(`Host ${hostNetid} requesting play again for lobby ${oldCode}`);
1326-
const oldRace = activeRaces.get(oldCode);
1327-
const oldPlayers = racePlayers.get(oldCode);
1328-
1329-
if (!oldRace || oldRace.type !== 'private') {
1330-
throw new Error('Lobby not found or not private.');
1331-
}
1332-
1333-
if (oldRace.hostId !== hostUserId) {
1334-
throw new Error('Only the host can start a new match.');
1335-
}
1336-
1337-
if (oldRace.status !== 'finished') {
1338-
throw new Error('Race has not finished yet.');
1339-
}
1340-
1341-
// Use previous lobby settings to generate a new snippet
1342-
const prevSettings = oldRace.settings || {};
1343-
let snippetId = null;
1344-
let snippet = null;
1345-
1346-
if (prevSettings.testMode === 'timed' && prevSettings.testDuration) {
1347-
const duration = parseInt(prevSettings.testDuration) || 30;
1348-
snippet = createTimedTestSnippet(duration);
1349-
} else {
1350-
const { difficulty, type, department } = prevSettings.snippetFilters || {};
1351-
const difficultyMap = { Easy: 1, Medium: 2, Hard: 3 };
1352-
const numericDifficulty = difficultyMap[difficulty] || null;
1353-
const category = type && type !== 'all'
1354-
? (type === 'course_reviews' ? 'course-reviews' : type)
1355-
: null;
1356-
const subject = category === 'course-reviews' && department && department !== 'all'
1357-
? department
1358-
: null;
1359-
const combos = [];
1360-
if (numericDifficulty != null && category && subject) combos.push({ difficulty: numericDifficulty, category, subject });
1361-
if (numericDifficulty != null && category) combos.push({ difficulty: numericDifficulty, category });
1362-
if (numericDifficulty != null && subject) combos.push({ difficulty: numericDifficulty, subject });
1363-
if (numericDifficulty != null) combos.push({ difficulty: numericDifficulty });
1364-
if (category && subject) combos.push({ category, subject });
1365-
if (category) combos.push({ category });
1366-
combos.push({});
1367-
1368-
let found = null;
1369-
for (const f of combos) {
1370-
const candidate = await SnippetModel.getRandom(f);
1371-
if (candidate) {
1372-
found = candidate;
1373-
break;
1374-
}
1375-
}
1376-
if (!found) throw new Error('Failed to load snippet for new match.');
1377-
snippet = found;
1378-
snippetId = snippet.id;
1379-
}
1380-
1381-
// Create a new lobby in the database
1382-
const newLobby = await RaceModel.create('private', snippetId, hostUserId);
1383-
console.log(`Created new private lobby ${newLobby.code} (play again from ${oldCode})`);
1384-
1385-
// Build new race info in memory
1386-
const newRaceInfo = {
1387-
id: newLobby.id,
1388-
code: newLobby.code,
1389-
snippet: {
1390-
id: snippet?.id,
1391-
text: sanitizeSnippetText(snippet.text),
1392-
is_timed_test: snippet.is_timed_test || false,
1393-
duration: snippet.duration || null,
1394-
princeton_course_url: snippet.princeton_course_url || null,
1395-
course_name: snippet.course_name || null
1396-
},
1397-
status: 'waiting',
1398-
type: 'private',
1399-
hostId: hostUserId,
1400-
hostNetId: hostNetid,
1401-
startTime: null,
1402-
settings: { ...prevSettings }
1403-
};
1404-
activeRaces.set(newLobby.code, newRaceInfo);
1405-
1406-
// Migrate all connected players from the old lobby to the new one
1407-
const newPlayers = [];
1408-
const connectedOldPlayers = oldPlayers || [];
1409-
1410-
for (const player of connectedOldPlayers) {
1411-
const playerSocket = io.sockets.sockets.get(player.id);
1412-
if (!playerSocket) continue; // Skip disconnected players
1413-
1414-
// Leave old socket room, join new one
1415-
playerSocket.leave(oldCode);
1416-
playerSocket.join(newLobby.code);
1417-
1418-
const isHost = player.userId === hostUserId;
1419-
const newPlayer = {
1420-
id: player.id,
1421-
netid: player.netid,
1422-
userId: player.userId,
1423-
ready: isHost, // Host is implicitly ready
1424-
lobbyId: newLobby.id,
1425-
snippetId: snippetId
1426-
};
1427-
newPlayers.push(newPlayer);
1428-
1429-
// Add player to the new lobby in DB
1430-
try {
1431-
await RaceModel.addPlayerToLobby(newLobby.id, player.userId, isHost);
1432-
} catch (dbErr) {
1433-
console.error(`Error adding player ${player.netid} to new lobby:`, dbErr);
1434-
}
1435-
}
1436-
1437-
racePlayers.set(newLobby.code, newPlayers);
1438-
1439-
// Build client data for all players
1440-
const playersClientData = await Promise.all(newPlayers.map(p => getPlayerClientData(p)));
1441-
1442-
const joinedData = {
1443-
code: newLobby.code,
1444-
type: 'private',
1445-
lobbyId: newLobby.id,
1446-
hostNetId: hostNetid,
1447-
snippet: newRaceInfo.snippet,
1448-
settings: newRaceInfo.settings,
1449-
players: playersClientData
1450-
};
1451-
1452-
// Notify all players in the new room about the new lobby
1453-
io.to(newLobby.code).emit('lobby:playAgain', joinedData);
1454-
1455-
// Clean up old lobby from memory
1456-
activeRaces.delete(oldCode);
1457-
racePlayers.delete(oldCode);
1458-
1459-
console.log(`Play again: migrated ${newPlayers.length} players from ${oldCode} to ${newLobby.code}`);
1460-
if (callback) callback({ success: true, lobby: joinedData });
1461-
1462-
} catch (err) {
1463-
console.error(`Error in play again for lobby ${oldCode}:`, err);
1464-
socket.emit('error', { message: err.message || 'Failed to start new match' });
1465-
if (callback) callback({ success: false, error: err.message || 'Failed to start new match' });
1466-
}
1467-
});
1468-
14691318
// --- End Private Lobby Handlers ---
14701319

14711320
// Handle player ready status

0 commit comments

Comments
 (0)