Statistiques
Cette section détaille le système de statistiques de jeu, incluant le tracking des performances par mode de jeu et la gestion des stats rooms post-partie.
UserStatsService (user-stats.service.ts)
Service qui met à jour les statistiques des joueurs en fin de partie.
Méthodes principales
async updateStatsForGame(game: OnGoingGame, duration: number)
Description : Met à jour les statistiques pour tous les joueurs réels d'une partie.
Paramètres :
game: Partie terminéeduration: Durée de la partie en secondes
Logique :
- Identifie les gagnants (dernier survivant ou équipe gagnante)
- Filtre les joueurs réels (exclut les bots)
- Détecte le mode de jeu (Classic ou CTF)
- Met à jour les stats pour chaque joueur :
- Total games played
- Total games won (si gagnant)
- Games played par mode
- Games won par mode
- Durée totale par mode
Modes supportés :
Classic: Battle royale, dernier survivantCTF: Capture the Flag, équipe atteint l'objectif
Retour : Promise
private getWinners(game: OnGoingGame)
Description : Identifie les joueurs gagnants selon le mode de jeu.
Paramètres :
game: Partie terminée
Logique :
- Mode Classic : Dernier joueur vivant (
!hasQuit && isAlive) - Mode CTF : Équipe ayant atteint l'objectif (
team.score >= game.objective)
Retour : Liste des gagnants ({ name: string; isBot: boolean; team?: Team }[])
private async mapPlayersToFirebaseUids(playerNames: string[])
Description : Associe les noms de joueurs à leurs Firebase UIDs.
Retour : Promise<Map<string, string>> (nom du joueur → Firebase UID)
Statistiques trackées
Structure User.stats
{
totalGamesPlayed: number, // Total parties jouées (tous modes)
totalGamesWon: number, // Total parties gagnées (tous modes)
gamesPlayedClassic: number, // Parties Classic jouées
gamesWonClassic: number, // Parties Classic gagnées
gamesPlayedCTF: number, // Parties CTF jouées
gamesWonCTF: number, // Parties CTF gagnées
totalDurationClassic: number, // Durée totale Classic (secondes)
totalDurationCTF: number, // Durée totale CTF (secondes)
totalDurationTotal: number // Durée totale tous modes (secondes)
}
Calculs dérivés
Le client peut calculer :
- Taux de victoire :
totalGamesWon / totalGamesPlayed - Taux de victoire Classic :
gamesWonClassic / gamesPlayedClassic - Taux de victoire CTF :
gamesWonCTF / gamesPlayedCTF - Durée moyenne :
totalDurationTotal / totalGamesPlayed - Durée moyenne Classic :
totalDurationClassic / gamesPlayedClassic - Durée moyenne CTF :
totalDurationCTF / gamesPlayedCTF
StatsRoomService (stats-room.service.ts)
Service qui gère les stats rooms post-partie, permettant aux joueurs de rester connectés après la fin de partie.
Propriétés
public statsRooms: Map<string, Set<string>> - Mapping gameCode → Set de Firebase UIDs
Méthodes principales
addPlayerToStatsRoom(gameCode: string, firebaseUid: string): void
Description : Ajoute un joueur à la stats room.
Paramètres :
gameCode: Code de la partiefirebaseUid: Firebase UID du joueur
Actions :
- Initialise le Set si nécessaire
- Ajoute le joueur au Set
Retour : void
async removePlayerFromStatsRoom(gameCode: string, firebaseUid: string)
Description : Retire un joueur de la stats room.
Paramètres :
gameCode: Code de la partiefirebaseUid: Firebase UID du joueur
Actions :
- Retire le joueur du Set
- Si dernier joueur :
- Supprime le canal de partie via
deletePartyChannel() - Supprime l'OnGoingGame de la mémoire
- Supprime la stats room
- Supprime le canal de partie via
Retour : Promise
getStatsRoomPlayerCount(gameCode: string): number
Description : Retourne le nombre de joueurs dans la stats room.
Retour : number
isPlayerInStatsRoom(gameCode: string, firebaseUid: string): boolean
Description : Vérifie si un joueur est dans la stats room.
Retour : boolean
getStatsRoomPlayers(gameCode: string): string[]
Description : Retourne la liste des Firebase UIDs dans la stats room.
Retour : string[]
cleanupStatsRoom(gameCode: string): void
Description : Nettoie une stats room (suppression forcée).
Retour : void
private async deletePartyChannel(gameCode: string)
Description : Supprime le canal de partie.
Actions :
- Supprime le canal via
ChannelService.deletePartyChannel() - Envoie événement
chat:user-should-leave-channelà tous les participants
Retour : Promise
private async removePlayerFromPartyChannel(gameCode: string, firebaseUid: string)
Description : Retire un joueur du canal de partie.
Actions :
- Retire via
ChannelService.removeUserFromChannel() - Envoie événement
chat:user-should-leave-party-channel - Envoie événement
chat:user-should-reload-channels - Notifie mise à jour participants
Retour : Promise
StatsRoomSocketService (stats-room-socket.service.ts)
Service qui gère les événements Socket.IO pour les stats rooms.
Méthodes
handleSocket(socket: Socket): void
Description : Configure les gestionnaires d'événements pour les stats rooms.
Événements écoutés :
stats:join-room: Rejoindre stats roomstats:leave-room: Quitter stats room
Retour : void
private async handleJoinStatsRoom(socket: Socket, data: any)
Description : Gère la jointure d'une stats room.
Données requises :
{ gameCode: string }
Actions :
- Valide l'utilisateur authentifié
- Ajoute à la stats room via
StatsRoomService - Join Socket.IO room
stats:{gameCode} - Envoie mise à jour du nombre de joueurs
Retour : Promise
private async handleLeaveStatsRoom(socket: Socket, data: any)
Description : Gère la sortie d'une stats room.
Actions :
- Retire de la stats room
- Leave Socket.IO room
- Nettoyage si dernier joueur
- Envoie mise à jour du nombre de joueurs
Retour : Promise
Flux de statistiques
1. Fin de partie
GameEnds
↓
PrizePoolService.distributePrizePool()
↓
UserStatsService.updateStatsForGame(game, duration)
↓
Mise à jour MongoDB User.stats pour chaque joueur
2. Navigation vers stats page
Client → Navigate to Stats Page
↓
Client → Emit 'stats:join-room' { gameCode }
↓
Server → StatsRoomService.addPlayerToStatsRoom()
↓
Server → Socket join room 'stats:{gameCode}'
↓
Server → Emit 'stats:player-count-updated'
3. Joueur quitte stats page
Client → Navigate away from Stats Page
↓
Client → Emit 'stats:leave-room' { gameCode }
↓
Server → StatsRoomService.removePlayerFromStatsRoom()
↓
Server → Check if last player
↓
If last:
├─ Delete party channel
├─ Remove OnGoingGame from memory
└─ Cleanup stats room
Events Socket.IO
Events émis
| Event | Description | Destinataires |
|---|---|---|
stats:player-count-updated |
Nombre de joueurs dans stats room | Room stats:{gameCode} |
stats:room-closed |
Stats room fermée (dernier joueur quitté) | Room stats:{gameCode} |
Events reçus
| Event | Description | Données |
|---|---|---|
stats:join-room |
Rejoindre stats room | { gameCode: string } |
stats:leave-room |
Quitter stats room | { gameCode: string } |
Nettoyage automatique
Dernier joueur quitte
Lorsque le dernier joueur quitte la stats room :
- Suppression du canal de partie :
ChannelService.deletePartyChannel(gameCode) - Suppression de l'OnGoingGame :
OnGoingGameService.removeGame(gameCode) - Suppression de la stats room :
statsRooms.delete(gameCode)
Raisons :
- Libération de la mémoire
- Nettoyage des ressources
- Empêcher l'accumulation de parties terminées
Déconnexion en stats room
Si un joueur se déconnecte pendant qu'il est dans la stats room :
- Géré automatiquement par le handler de déconnexion
- Appelle
removePlayerFromStatsRoom() - Nettoyage si nécessaire
Intégration avec OnGoingGameService
Après la fin de partie, l'OnGoingGame reste en mémoire jusqu'à ce que tous les joueurs quittent la stats room.
Utilité :
- Afficher les statistiques finales
- Historique de la partie
- Détails des joueurs
Suppression : Via StatsRoomService.removePlayerFromStatsRoom() quand dernier joueur quitte
Initialisation des stats
Pour les nouveaux utilisateurs, les stats sont initialisées à :
{
totalGamesPlayed: 0,
totalGamesWon: 0,
gamesPlayedClassic: 0,
gamesWonClassic: 0,
gamesPlayedCTF: 0,
gamesWonCTF: 0,
totalDurationClassic: 0,
totalDurationCTF: 0,
totalDurationTotal: 0
}
Compatibilité des modes
Le service détecte le mode de jeu via des comparaisons multiples pour compatibilité :
const isClassicMode = gameModeNormalized === GameMode.Classic
|| gameModeNormalized === 'Classic'
|| gameModeNormalized === 'Classique'
|| gameModeNormalized.toLowerCase() === 'classic'
|| gameModeNormalized.toLowerCase() === 'classique';
Raisons :
- Support anciennes parties (legacy)
- Support i18n (FR/EN)
- Robustesse
Logging
Toutes les mises à jour de stats sont loggées :
[UserStatsService] Game mode detected: "Classic" -> Classic
[UserStatsService] Updated Classic stats for player123: games=5, wins=2
[StatsRoomService] Player player456 left stats room ABCD
[StatsRoomService] Last player left stats room ABCD, cleaning up
Extensions possibles
Stats avancées
- Kills / Deaths
- Damage dealt / received
- Items collected
- Distance traveled
- Doors toggled
Achievements
- "First Win"
- "10 Games Played"
- "Win Streak"
- Récompenses en coins
Leaderboards
- Top joueurs par mode
- Win rate global
- Temps de jeu total
- Rankings saisonniers