Architecture multijoueur
Le mode multijoueur d’En Parlant~ utilise un serveur relais WebSocket pour connecter deux joueurs en temps réel. Il n’y a pas de pair-à-pair — toute la communication passe par le relais. Cela simplifie la couche réseau et fonctionne de manière fiable à travers les pare-feu et les NAT.
Vue d’ensemble de l’architecture
Section intitulée « Vue d’ensemble de l’architecture »Player A (host) Relay Server Player B (joiner) | | | |--- create_game(name) ----------->| | |<-- game_created(code) -----------| | | |<--- join_game(code, name) -----| |<-- game_joined(name) ------------|--- game_joined(name) -------->| | | | |--- game_move(uci, times) ------->|--- game_move(uci, times) --->| |<-- game_move(uci, times) --------|<-- game_move(uci, times) ----| | | | |--- heartbeat ------------------>|--- peer_heartbeat ----------->|Le relais est une fine couche de transfert. Il conserve les salles en mémoire, achemine les événements entre les deux joueurs de chaque salle et gère le nettoyage. Il n’y a aucune logique de jeu ni validation de coups côté serveur — les clients font autorité.
Stack technologique
Section intitulée « Stack technologique »- Frontend (client) : socket.io-client — le client JavaScript standard de Socket.IO
- Backend (relais) : socketioxide — un serveur Socket.IO en Rust construit sur Axum
- Protocole : Socket.IO sur WebSocket (avec repli automatique vers le HTTP long-polling si nécessaire)
Socket.IO a été choisi plutôt que le WebSocket brut car il fournit la reconnexion automatique, la gestion des salles/espaces de noms et le traitement structuré des événements de manière native.
Déroulement d’une partie
Section intitulée « Déroulement d’une partie »1. Création d’une partie
Section intitulée « 1. Création d’une partie »L’hôte clique sur Multijoueur et saisit son nom d’affichage. Le client émet un événement create_game avec le nom. Le serveur :
- Génère un code de salle unique de 6 caractères
- Crée une salle et ajoute l’hôte comme premier joueur
- Répond avec
game_created(code)afin que l’hôte puisse partager le code
2. Rejoindre une partie
Section intitulée « 2. Rejoindre une partie »Le joueur entrant saisit le code de salle et son nom d’affichage. Le client émet join_game(code, name). Le serveur :
- Recherche la salle à partir du code
- Ajoute le joueur entrant comme second joueur
- Envoie
game_joined(name)aux deux joueurs — chacun reçoit le nom d’affichage de l’autre
Une fois les deux joueurs dans la salle :
- L’hôte joue toujours les Blancs, le joueur entrant joue toujours les Noirs. Cela est déterminé par l’ordre d’arrivée, et non par négociation.
- Les coups sont envoyés au format UCI (par exemple,
e2e4) accompagnés des temps de pendule des deux joueurs. - Le relais transfère chaque événement
game_moveà l’adversaire. Les deux joueurs reçoivent également leurs propres coups en retour comme confirmation.
4. Événements de fin de partie
Section intitulée « 4. Événements de fin de partie »Plusieurs événements gèrent les scénarios de fin de partie :
- Abandon — transmis à l’adversaire pour déclencher la boîte de dialogue d’abandon
- Proposition de nulle — transmise à l’adversaire, qui peut accepter ou ignorer
- Acceptation de nulle — transmise aux deux joueurs pour terminer la partie par une nulle
5. Revanche
Section intitulée « 5. Revanche »Après la fin d’une partie, l’un ou l’autre joueur peut envoyer un événement ready pour signaler qu’il souhaite une revanche. Lorsque les deux joueurs ont envoyé ready, les clients réinitialisent l’échiquier et échangent les couleurs (ou les conservent — déterminé côté client).
Codes de salle
Section intitulée « Codes de salle »Les codes de salle comportent 6 caractères, formatés en XX-XX-XX pour faciliter la lecture lors d’un partage oral. Le jeu de caractères exclut les caractères visuellement ambigus :
- Pas de
0ni deO(zéro vs. lettre O) - Pas de
1,IniL(un vs. I majuscule vs. L majuscule)
Cela évite le classique « c’est un zéro ou un O ? » lorsque quelqu’un dicte un code en conversation vocale ou le tape à partir du message d’un ami.
Système de battement de cœur (heartbeat)
Section intitulée « Système de battement de cœur (heartbeat) »Les connexions multijoueur doivent détecter quand un joueur se déconnecte — que ce soit à cause d’une coupure réseau, de la fermeture de l’application ou de la mise en veille de son ordinateur. En Parlant~ utilise un système de heartbeat pour cela :
- Chaque client envoie un événement
heartbeatau serveur toutes les 5 secondes - Le serveur accuse réception du heartbeat et le transfère à l’adversaire sous forme de
peer_heartbeat - Le client enregistre la date de réception du dernier
peer_heartbeatde l’adversaire - La fonction
isPeerAlive(timeoutMs)vérifie si le dernier heartbeat de l’adversaire est dans le seuil acceptable
Cela alimente l’indicateur d’état de connexion dans l’interface. Si les heartbeats cessent d’arriver, le joueur voit que son adversaire s’est peut-être déconnecté et peut choisir d’attendre ou de quitter la partie.
Nettoyage des salles
Section intitulée « Nettoyage des salles »Le serveur relais supprime automatiquement les salles inactives pour éviter les fuites de mémoire :
- Une salle est considérée inactive après 30 minutes sans activité
- Une tâche de nettoyage s’exécute toutes les 60 secondes, balayant les salles ayant dépassé le seuil d’inactivité
- Lorsqu’une salle est nettoyée, toutes les connexions restantes sont fermées
Il n’y a pas de stockage persistant. Si le serveur redémarre, toutes les salles disparaissent. C’est intentionnel — le relais est sans état et éphémère. Les parties en cours devraient être relancées, mais cela est rare en pratique.
Déploiement
Section intitulée « Déploiement »Le relais par défaut fonctionne sur Fly.io, offrant des connexions WebSocket à faible latence avec TLS automatique. Consultez le guide de configuration du serveur multijoueur pour les instructions sur l’hébergement de votre propre relais.
Tests en local
Section intitulée « Tests en local »Pour tester le mode multijoueur pendant le développement :
-
Clonez et lancez le relais :
Fenêtre de terminal git clone https://github.com/DarrellThomas/en-parlant-relay.gitcd en-parlant-relaycargo runLe serveur démarre sur le port 3210.
-
Dans En Parlant~, changez l’URL du serveur relais en
ws://localhost:3210. -
Ouvrez deux instances de l’application (ou une instance et une en mode développement) pour simuler les deux joueurs.
Les coups, les heartbeats et tous les événements fonctionnent de manière identique au relais de production — la seule différence est l’URL de connexion.