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 :

Logique :

  1. Identifie les gagnants (dernier survivant ou équipe gagnante)
  2. Filtre les joueurs réels (exclut les bots)
  3. Détecte le mode de jeu (Classic ou CTF)
  4. 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 :

Retour : Promise

private getWinners(game: OnGoingGame)

Description : Identifie les joueurs gagnants selon le mode de jeu.
Paramètres :

Logique :

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 :

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

Méthodes principales

addPlayerToStatsRoom(gameCode: string, firebaseUid: string): void

Description : Ajoute un joueur à la stats room.
Paramètres :

Actions :

Retour : void

async removePlayerFromStatsRoom(gameCode: string, firebaseUid: string)

Description : Retire un joueur de la stats room.
Paramètres :

Actions :

  1. Retire le joueur du Set
  2. Si dernier joueur :
    • Supprime le canal de partie via deletePartyChannel()
    • Supprime l'OnGoingGame de la mémoire
    • Supprime la stats room

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 :

  1. Supprime le canal via ChannelService.deletePartyChannel()
  2. 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 :

  1. Retire via ChannelService.removeUserFromChannel()
  2. Envoie événement chat:user-should-leave-party-channel
  3. Envoie événement chat:user-should-reload-channels
  4. 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 :

Retour : void

private async handleJoinStatsRoom(socket: Socket, data: any)

Description : Gère la jointure d'une stats room.
Données requises :

{ gameCode: string }

Actions :

  1. Valide l'utilisateur authentifié
  2. Ajoute à la stats room via StatsRoomService
  3. Join Socket.IO room stats:{gameCode}
  4. 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 :

  1. Retire de la stats room
  2. Leave Socket.IO room
  3. Nettoyage si dernier joueur
  4. 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 :

  1. Suppression du canal de partie : ChannelService.deletePartyChannel(gameCode)
  2. Suppression de l'OnGoingGame : OnGoingGameService.removeGame(gameCode)
  3. Suppression de la stats room : statsRooms.delete(gameCode)

Raisons :

Déconnexion en stats room

Si un joueur se déconnecte pendant qu'il est dans la stats room :

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é :

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 :

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

Achievements

Leaderboards