@@ -37,6 +37,10 @@ const MAX_ALLOWED_WPM = 350; // anything above is flagged
3737const MIN_COMPLETION_TIME_MS = 2500 ; // cannot finish faster than this
3838const playAgainTransitions = new Set ( ) ; // lobbyCode -> transition in progress
3939
40+ // Store session win tallies for private lobbies across play-again cycles
41+ // lobbyCode -> { netid: winCount }
42+ const sessionWins = new Map ( ) ;
43+
4044// Store host disconnect timers for private lobbies
4145const HOST_RECONNECT_GRACE_PERIOD = 15000 ; // 15 seconds
4246const hostDisconnectTimers = new Map ( ) ; // lobbyCode -> { timer: NodeJS.Timeout, userId: number }
@@ -237,6 +241,7 @@ const forceDisconnectExistingSessions = async (io, newSocket, userIdToDisconnect
237241 console . log ( `Lobby ${ code } empty after forced disconnect. Cleaning up.` ) ;
238242 racePlayers . delete ( code ) ;
239243 activeRaces . delete ( code ) ;
244+ sessionWins . delete ( code ) ;
240245 // Attempt to terminate private lobbies in DB
241246 if ( race && race . type === 'private' ) {
242247 try { await RaceModel . softTerminate ( race . id ) ; } catch ( e ) { /* ignore */ }
@@ -333,6 +338,7 @@ const leaveCurrentRace = async (io, socket, netid) => {
333338 if ( players . length === 0 ) {
334339 racePlayers . delete ( code ) ;
335340 activeRaces . delete ( code ) ;
341+ sessionWins . delete ( code ) ;
336342 console . log ( `Cleaned up empty race ${ code } ` ) ;
337343 } else {
338344 racePlayers . set ( code , players ) ;
@@ -871,6 +877,9 @@ const initialize = (io) => {
871877 }
872878 } ) ;
873879
880+ // Initialize session win tally for new private lobby
881+ sessionWins . set ( lobby . code , { } ) ;
882+
874883 // Fetch avatar for the host
875884 await fetchUserAvatar ( userId , socket . id ) ;
876885
@@ -883,7 +892,8 @@ const initialize = (io) => {
883892 hostNetId : netid , // Include host netid
884893 snippet : activeRaces . get ( lobby . code ) . snippet ,
885894 settings : activeRaces . get ( lobby . code ) . settings ,
886- players : [ hostClientDataCreate ] // Use renamed variable
895+ players : [ hostClientDataCreate ] , // Use renamed variable
896+ sessionWins : { }
887897 } ;
888898 socket . emit ( 'race:joined' , joinedDataCreate ) ; // Use renamed variable
889899
@@ -1061,7 +1071,8 @@ const initialize = (io) => {
10611071 hostNetId : raceInfo . hostNetId ,
10621072 snippet : raceInfo . snippet ,
10631073 settings : raceInfo . settings ,
1064- players : currentPlayersClientDataJoin // Use resolved data
1074+ players : currentPlayersClientDataJoin , // Use resolved data
1075+ sessionWins : sessionWins . get ( lobby . code ) || { }
10651076 } ;
10661077 socket . emit ( 'race:joined' , joinedDataJoin ) ; // Use renamed variable
10671078
@@ -1518,14 +1529,19 @@ const initialize = (io) => {
15181529 // Build client data for all players
15191530 const playersClientData = await Promise . all ( newPlayers . map ( p => getPlayerClientData ( p ) ) ) ;
15201531
1532+ // Carry session wins forward to the new lobby
1533+ const prevWins = sessionWins . get ( oldCode ) || { } ;
1534+ sessionWins . set ( newLobby . code , { ...prevWins } ) ;
1535+
15211536 const joinedData = {
15221537 code : newLobby . code ,
15231538 type : 'private' ,
15241539 lobbyId : newLobby . id ,
15251540 hostNetId : hostNetid ,
15261541 snippet : newRaceInfo . snippet ,
15271542 settings : newRaceInfo . settings ,
1528- players : playersClientData
1543+ players : playersClientData ,
1544+ sessionWins : { ...prevWins }
15291545 } ;
15301546
15311547 // Notify migrated players directly so the room join can't race the event
@@ -1537,6 +1553,7 @@ const initialize = (io) => {
15371553 clearLobbyTransientState ( oldCode ) ;
15381554 activeRaces . delete ( oldCode ) ;
15391555 racePlayers . delete ( oldCode ) ;
1556+ sessionWins . delete ( oldCode ) ;
15401557
15411558 console . log ( `Play again: migrated ${ newPlayers . length } players from ${ oldCode } to ${ newLobby . code } ` ) ;
15421559 if ( callback ) callback ( { success : true , lobby : joinedData } ) ;
@@ -2022,6 +2039,7 @@ const initialize = (io) => {
20222039 activeRaces . delete ( code ) ;
20232040 }
20242041 racePlayers . delete ( code ) ; // Ensure players map is cleared
2042+ sessionWins . delete ( code ) ;
20252043 return ; // Exit timer callback
20262044 }
20272045
@@ -2105,6 +2123,7 @@ const initialize = (io) => {
21052123 console . log ( `No players left in race ${ code } , cleaning up` ) ;
21062124 racePlayers . delete ( code ) ;
21072125 activeRaces . delete ( code ) ;
2126+ sessionWins . delete ( code ) ;
21082127 if ( race && race . type === 'private' ) {
21092128 try { await RaceModel . softTerminate ( race . id ) ; } catch ( e ) { /* ignore */ }
21102129 }
@@ -2461,8 +2480,25 @@ const endRace = async (io, code) => {
24612480 console . error ( `Error getting final results for race ${ code } :` , dbErr ) ;
24622481 }
24632482
2464- // Broadcast race end signal (without results payload)
2465- io . to ( code ) . emit ( 'race:end' , { code } ) ;
2483+ // Update session win tally for private lobbies
2484+ if ( race . type === 'private' ) {
2485+ const players = racePlayers . get ( code ) || [ ] ;
2486+ // Find the winner: completed player with fastest completion time
2487+ const completedPlayers = players
2488+ . filter ( p => p . completed && playerProgress . has ( p . id ) )
2489+ . map ( p => ( { netid : p . netid , completion_time : playerProgress . get ( p . id ) . completion_time } ) )
2490+ . sort ( ( a , b ) => a . completion_time - b . completion_time ) ;
2491+ if ( completedPlayers . length > 0 ) {
2492+ const winnerNetid = completedPlayers [ 0 ] . netid ;
2493+ const wins = sessionWins . get ( code ) || { } ;
2494+ wins [ winnerNetid ] = ( wins [ winnerNetid ] || 0 ) + 1 ;
2495+ sessionWins . set ( code , wins ) ;
2496+ console . log ( `Session wins for ${ code } :` , wins ) ;
2497+ }
2498+ }
2499+
2500+ // Broadcast race end signal with session wins
2501+ io . to ( code ) . emit ( 'race:end' , { code, sessionWins : sessionWins . get ( code ) || { } } ) ;
24662502 console . log ( `Broadcasted race end signal for ${ code } ` ) ;
24672503
24682504 } catch ( err ) {
0 commit comments