multiplayer-game

Par rivet-dev · skills

Modèles pragmatiques pour la création de jeux multijoueurs : matchmaking, boucles de tick, état temps réel, gestion de l'intérêt et validation.

npx skills add https://github.com/rivet-dev/skills --skill multiplayer-game

Jeu Multijoueur

IMPORTANT : Avant de faire quoi que ce soit, vous DEVEZ lire BASE_SKILL.md dans le répertoire de cette compétence. Il contient des conseils essentiels sur le débogage, la gestion des erreurs, la gestion d'état, le déploiement et la configuration du projet. Ces règles et modèles s'appliquent à tous les travaux RivetKit. Tout ce qui suit suppose que vous avez déjà lu et compris ces informations.

Modèles pour construire des jeux multijoueurs avec RivetKit, destinés à être une checklist pratique que vous pouvez adapter par genre.

Code de démarrage

Commencez par l'un des exemples fonctionnels sur GitHub et adaptez-le à votre jeu. Ne commencez pas de zéro pour les flux d'appairage et de cycle de vie.

Classification de jeu Code de démarrage Exemples courants
Battle Royale GitHub Fortnite, Apex Legends, PUBG, Warzone
Arena GitHub Call of Duty TDM/FFA, Halo Slayer, Counter-Strike casual, VALORANT unrated, Overwatch Quick Play, Rocket League
IO Style GitHub Agar.io, Slither.io, surviv.io
Open World GitHub Serveurs de survie Minecraft, mondes style Rust, mondes zone/chunk MMO
Party GitHub Lobbies privés Fall Guys, salons de jeu personnalisés, sessions de party sociales
Physics 2D GitHub Jeux de baston physics top-down, jeux d'arène 2D, combattants plateforme
Physics 3D GitHub Sessions sandbox physiques, jeux d'arène 3D, terrains de jeu mouvement
Ranked GitHub Échelles d'échecs, jeux de cartes compétitifs, files d'attente arènes duel classées
Turn-Based GitHub Correspondance d'échecs, Words With Friends, jeux de plateau asynchrones
Idle GitHub Cookie Clicker, Idle Miner Tycoon, Adventure Capitalist

Simulation serveur

Boucle de jeu et fréquences de tick

Modèle À utiliser quand Guidance d'implémentation
Boucle temps réel fixe Battle Royale, Arena, IO Style, Open World, Ranked Exécuter dans run avec sleep(tickMs) et quitter sur c.aborted.
Mises à jour basées sur les actions Party, Turn-Based Muter et diffuser uniquement sur les actions/événements plutôt que sur des ticks planifiés.
Progression hors ligne grossière N'importe quel mode avec progression idle Utiliser c.schedule.after(...) avec des fenêtres grossières (par exemple 5 à 15 minutes) et appliquer rattrapage à partir du temps écoulé.

Physics

Commencez par une logique cinématique personnalisée pour les jeux simples. Passez à un moteur physics complet lorsque vous avez besoin de joints, corps empilés, haute densité de collision ou formes complexes (polygones tournés, capsules, enveloppes convexes, mailles triangulaires).

Choisissez un moteur par simulation. Gardez les libs frontend hors des chemins de simulation backend et traitez l'état serveur comme faisant autorité.

Dimension Moteur principal Moteurs de secours Code exemple
2D @dimforge/rapier2d planck-js, matter-js GitHub
3D @dimforge/rapier3d cannon-es, ammo.js GitHub

Indexation spatiale

Pour les requêtes spatiales non-physics, utilisez un index dédié au lieu de vérifications naïves O(n^2) :

Type d'index Recommandation
Index AABB Pour AOI, visibilité et entités non-collider, utilisez rbush pour les ensembles dynamiques ou flatbush pour les ensembles statiques-ish.
Index point Pour requêtes plus proche voisin ou dans-rayon, utilisez d3-quadtree.

Réseautage et synchronisation d'état

Netcode

Modèle Quand l'utiliser Implémentation
Hybride (mouvement client, combat serveur) Shooters, sports d'action, duels classés Le client possède le mouvement et envoie les mises à jour de position à débit limité. Le serveur valide pour l'anti-cheat. Le combat (projectiles, coups, dégâts) est entièrement sous autorité serveur.
Autorité serveur avec interpolation IO Style, mondes persistants Le client envoie les commandes d'entrée. Le serveur simule sur des ticks fixes et publie des snapshots faisant autorité. Le client interpole entre les snapshots.
Autorité serveur (logique basique) Turn-based, event-driven Le serveur valide et applique les actions discrètes (tours, transitions de phase, votes). Le client affiche l'état confirmé.

Modèle de données temps réel

  • Snapshots et diffs : Publiez l'état comme événements. Envoyez un snapshot complet à la connexion/resync, puis des diffs par tick pour les mises à jour régulières.
  • Batch par tick : Gardez les événements petits et typés. Groupez les mises à jour haute fréquence par tick.
  • Évitez l'état du framework UI pour les mises à jour de jeu : Utilisez requestAnimationFrame ou une boucle Canvas/Three.js pour la simulation, pas l'état React. Réservez l'état du framework UI pour les menus, HUD et formulaires.
  • Broadcast vs par-connexion : Utilisez c.broadcast(...) pour les mises à jour partagées et conn.send(...) pour les données privées/par-joueur.

Logique de simulation partagée

La logique de simulation partagée s'exécute à la fois sur le client et sur le serveur. Par exemple, une fonction applyInput(state, input, dt) qui intègre la vélocité et limite aux limites du monde peut s'exécuter sur le client pour la prédiction et sur le serveur pour la validation.

  • Modes hybrides : Le client exécute le mouvement partagé comme autorité principale, le serveur l'exécute pour la validation anti-cheat.
  • Modes sous autorité serveur : Le client utilise la logique partagée pour l'interpolation et la prédiction uniquement.
  • Gardez-la pure : Intégration de mouvement, transformations d'entrée, assistants de collision et constantes uniquement.
  • Mettez le code partagé dans src/shared/ : Gardez les assistants déterministes dans src/shared/sim/* sans effets secondaires.

Gestion des intérêts

Contrôlez ce que chaque client reçoit pour réduire la bande passante et empêcher les fuites d'informations.

Filtres de réplication par joueur

  • Filtrez par pertinence : Envoyez à chaque client uniquement l'état pertinent pour ce joueur (proximité, line-of-sight, équipe ou phase de jeu).
  • Shooters et jeux d'action : Limitez la réplication par proximité et vérifications optionnelles de champ de vision.
  • Côté serveur uniquement : Les clients ne doivent jamais recevoir de données qu'ils ne devraient pas voir.

Mondes fragmentés

  • Partitionnez les grands mondes : Utilisez des acteurs chunk avec clé worldId:chunkX:chunkY.
  • Abonnez-vous aux chunks proches : Les clients se connectent uniquement aux partitions proches (par exemple une fenêtre chunk 3x3).
  • À utiliser avec parcimonie : Seulement quand le monde est grand et lourd en état (constructeurs sandbox, MMO), pas par défaut pour les petits matchs.

Infrastructure backend

Persistance

  • État en mémoire : Idéal pour l'état du jeu temps réel qui change chaque tick (positions des joueurs, entrées, phase du match, scores).
  • SQLite (rivetkit/db) : Mieux pour l'état volumineux ou table-like qui nécessite des requêtes, index ou persistance long-terme (tuiles, inventaire, pools d'appairage). Sérialisez le travail DB via une queue puisque plusieurs actions peuvent frapper le même acteur simultanément.

Modèles d'appairage

Blocs de construction communs utilisés dans les modèles d'architecture ci-dessous.

Topologie d'acteur

Primitive À utiliser quand Propriété typique
matchmaker["main"] + match[matchId] Multijoueur basé sur session (battle royale, arena, ranked, party, turn-based) Le matchmaker possède la découverte/assignment. Match possède le cycle de vie et l'état de gameplay.
chunk[worldId,chunkX,chunkY] Grands mondes continus qui nécessitent une fragmentation Chaque chunk possède les joueurs locaux, l'état chunk et la simulation locale.
world[playerId] Boucles de progression par joueur (état monde solo/idle) Ressources par joueur, bâtiments, minuteurs et progression.
player[username] Profil canonique/note réutilisée dans les matchs Stats durables du joueur (par exemple note et win/loss).
leaderboard["main"] Classements partagés dans de nombreux matchs/joueurs Lignes de score ordonnées globales et listes top.

Stratégie de file d'attente

  • Plusieurs joueurs peuvent frapper le matchmaker en même temps, donc les actions comme find/create, queue/unqueue et close doivent être sérialisées via les queues d'acteur pour éviter les courses.
  • Les actions locales au match (gameplay, scoring) n'ont pas besoin de queueing sauf si elles écrivent de nouveau vers le matchmaker.

Sécurité et anti-cheat

Commencez par cette ligne de base, puis renforcez davantage pour les environnements compétitifs ou à haut risque.

Checklist de base

  • Identité : Utilisez c.conn.id comme identité transport faisant autorité. Traitez playerId/username dans les paramètres comme entrée non fiable et liez via assignment/join tickets émis par le serveur.
  • Autorisation : Validez que l'appelant est autorisé à muter l'entité cible (adhésion au salon, propriété de tour, actions réservées à l'hôte).
  • Validation d'entrée : Limitez les tailles/longueurs, validez les énumérations et validez les noms d'utilisateur (longueur, caractères autorisés, évitez Unicode illimité).
  • Limite de débit : Limites de débit par connexion pour les actions spammy (chat, join/leave, fire, mises à jour de mouvement).
  • Intégrité d'état : Le serveur recalcule l'état dérivé (scores, conditions de victoire, placements). Ne laissez jamais les modifications d'inventaire/devise/totaux du leaderboard faire autorité au client.

Validation du mouvement

Pour n'importe quel mode avec mouvement faisant autorité au client (flux hybrides), les clients peuvent envoyer les mises à jour de position/rotation pour la fluidité, mais le serveur doit :

  • Appliquer le delta max par mise à jour (plafond de vitesse) en fonction du temps écoulé.
  • Rejeter ou limiter les téléportations.
  • Appliquer les limites du monde (et collision basique si applicable).
  • Limiter la fréquence de mise à jour (par exemple 20 Hz max).

Modèles d'architecture

Chaque type de jeu ci-dessous commence par une table récapitulative rapide, puis détaille les acteurs et le cycle de vie.

Battle Royale

Sujet Résumé
Appairage Routage immédiat vers le lobby non démarré le plus rempli (break tie le plus ancien) ; les joueurs attendent dans le lobby jusqu'à capacité, puis le match démarre.
Netcode Hybride. Le client possède le mouvement, la caméra et la prédiction locale. Le serveur possède l'état de zone, les projectiles, la résolution des coups, les éliminations, le butin et le placement final.
Fréquence de tick 10 ticks/sec (100ms) avec une boucle fixe pour progression de zone et vérifications du cycle de vie.
Physics Le client possède le mouvement avec validation anti-cheat du serveur ; projectiles, coups et dégâts sont sous autorité serveur. Utilisez @dimforge/rapier3d pour 3D ou @dimforge/rapier2d pour top-down 2D.

Acteurs

  • Clé : matchmaker["main"]

  • Responsabilité : Trouve ou crée des lobbies, suit les réservations en attente et maintient l'occupation.

  • Actions

    • findMatch
    • pendingPlayerConnected
    • updateMatch
    • closeMatch
  • Queues

    • findMatch
    • pendingPlayerConnected
    • updateMatch
    • closeMatch
  • État

    • SQLite
    • matches
    • pending_players
    • player_count inclut joueurs connectés et en attente
  • Clé : match[matchId]

  • Responsabilité : Exécute les phases lobby/live/finished, possède l'état des joueurs, progression de zone et éliminations.

  • Actions

    • connect
    • Actions de mouvement et combat
  • Queues

    • Aucune
  • État

    • JSON
    • phase
    • players
    • zone
    • eliminations
    • snapshot data

Cycle de vie

sequenceDiagram
    participant C as Client
    participant MM as matchmaker
    participant M as match

    C->>MM: findMatch()
    alt no open lobby
        MM->>M: create(matchId)
    end
    MM-->>C: {matchId, playerId}
    C->>M: connect(playerId)
    M->>MM: pendingPlayerConnected(matchId, playerId)
    MM-->>M: accepted
    Note over M: lobby countdown -> live
    M-->>C: snapshot + shoot events
    M->>MM: closeMatch(matchId)

Arena

Sujet Résumé
Appairage Files d'attente à capacité fixe basées sur mode (duo, squad, ffa) qui ne construisent que des matchs complets et pré-assignent les équipes (sauf FFA).
Netcode Hybride. Le client possède le mouvement plus prédiction et lissage. Le serveur possède l'assignment d'équipe ou FFA, les projectiles, la résolution des coups, les transitions de phase et le scoring.
Fréquence de tick 20 ticks/sec (50ms) avec une boucle plus serrée pour les snapshots d'équipe et FFA live.
Physics Intensité moyenne à haute ; mouvement client avec validation serveur et combat/entités sous autorité serveur.

Acteurs

  • Clé : matchmaker["main"]

  • Responsabilité : Exécute les files d'attente mode, construit les matchs complets, assigne les équipes et publie les assignments.

  • Actions

    • queueForMatch
    • unqueueForMatch
    • matchCompleted
  • Queues

    • queueForMatch
    • unqueueForMatch
    • matchCompleted
  • État

    • SQLite
    • player_pool
    • matches
    • assignments indexés par connexion et joueur
  • Clé : match[matchId]

  • Responsabilité : Exécute les phases de match et l'état joueur/équipe dans le match pour score et conditions de victoire.

  • Actions

    • connect
    • Actions de gameplay
  • Queues

    • Aucune
  • État

    • JSON
    • phase
    • players
    • team assignments
    • score and win state

Cycle de vie

sequenceDiagram
    participant C as Client
    participant MM as matchmaker
    participant M as match

    C->>MM: queueForMatch(mode)
    Note over MM: enqueue in player_pool
    Note over MM: fill when capacity reached
    MM->>M: create(matchId, assignments)
    Note over MM: persist assignments
    MM-->>C: assignmentReady
    C->>M: connect(playerId)
    Note over M: waiting -> live when all players connect
    M->>MM: matchCompleted(matchId)

IO Style

Sujet Résumé
Appairage Routage de lobby ouvert vers la salle la plus remplie en dessous de la capacité ; les comptages de salle sont heartbeatés et de nouveaux lobbies sont auto-créés si nécessaire.
Netcode Autorité serveur avec interpolation. Le client envoie les intents d'entrée et interpole. Le serveur possède le mouvement, les limites, l'adhésion à la salle et les snapshots canoniques.
Fréquence de tick 10 ticks/sec (100ms) avec snapshots de salle légères et périodiques.
Physics Intensité basse à moyenne ; mouvement cinématique sous autorité serveur, escaladant à un moteur physics complet seulement quand les collisions deviennent complexes.

Acteurs

  • Clé : matchmaker["main"]

  • Responsabilité : Route les joueurs dans le lobby ouvert le plus rempli et suit les réservations et l'occupation.

  • Actions

    • findLobby
    • pendingPlayerConnected
    • updateMatch
    • closeMatch
  • Queues

    • findLobby
    • pendingPlayerConnected
    • updateMatch
    • closeMatch
  • État

    • SQLite
    • matches
    • pending_players
    • L'occupation inclut les réservations en attente
  • Clé : match[matchId]

  • Responsabilité : Exécute la simulation de mouvement par match et diffuse les snapshots.

  • Actions

    • connect
    • setInput
  • Queues

    • Aucune
  • État

    • JSON
    • players
    • inputs
    • movement state
    • snapshot cache

Cycle de vie

sequenceDiagram
    participant C as Client
    participant MM as matchmaker
    participant M as match

    C->>MM: findLobby()
    alt no open lobby
        MM->>M: create(matchId)
    end
    MM-->>C: {matchId, playerId}
    C->>M: connect(playerId)
    M->>MM: pendingPlayerConnected(matchId, playerId)
    MM-->>M: accepted
    Note over M: fixed tick simulation
    M-->>C: snapshot events
    M->>MM: closeMatch(matchId)

Open World

Sujet Résumé
Appairage Routage chunk piloté par client à partir des coordonnées du monde, avec fenêtres de chunk proches préchargées via connexions de chunks adjacents.
Netcode Hybride pour sandbox (mouvement client avec validation) ou autorité serveur pour flux MMO-like. Le serveur possède le routage chunk, la persistance et l'état monde canonique.
Fréquence de tick 10 ticks/sec par acteur chunk (100ms), donc la charge s'adapte aux chunks actifs.
Physics Intensité moyenne à haute à l'échelle ; simulation locale chunk peut être sous autorité serveur (MMO-like) ou mouvement client avec validation serveur (sandbox-like).

Acteurs

  • Clé : chunk[worldId,chunkX,chunkY]
  • Responsabilité : Possède les joueurs locaux chunk, les blocs, le tick de mouvement et l'adhésion chunk.
  • Actions
    • connect
    • enterChunk
    • addPlayer
    • setInput
    • leaveChunk
    • removePlayer
  • Queues
    • Aucune
  • État
    • JSON
    • connections
    • players
    • blocks limité à une clé chunk

Cycle de vie

sequenceDiagram
    participant C as Client
    participant CH as chunk

    Note over C: resolve chunk keys from world position
    loop each visible chunk
        C->>CH: connect(worldId, chunkX, chunkY, playerId)
        Note over CH: store connection metadata
    end
    C->>CH: enterChunk/addPlayer
    loop movement updates
        C->>CH: setInput(...)
        CH-->>C: snapshot
    end
    C->>CH: leaveChunk/removePlayer or disconnect
    Note over CH: remove membership and metadata

Party

Sujet Résumé
Appairage Flux de party privée créée par l'hôte utilisant des codes de party et des joins explicites.
Netcode Autorité serveur (logique basique). Le serveur possède l'adhésion, les permissions de l'hôte et les transitions de phase.
Fréquence de tick Pas de tick continu ; les mises à jour sont event-driven (join, start, finish).
Physics Intensité basse pour les flux lobby-first ; généralement pas de physics ou indexation dédiée sauf si vous ajoutez des mini-jeux temps réel.

Acteurs

  • Clé : matchmaker["main"]

  • Responsabilité : Traite le flux de création/join de party, valide les tickets de join et suit la taille de party.

  • Actions

    • createParty
    • joinParty
    • verifyJoin
    • updatePartySize
    • closeParty
  • Queues

    • createParty
    • joinParty
    • verifyJoin
    • updatePartySize
    • closeParty
  • État

    • SQLite
    • parties
    • join_tickets pour recherche de party et validation de join
  • Clé : match[matchId]

  • Responsabilité : Possède les membres de party, rôle d'hôte, drapeaux ready et transitions de phase.

  • Actions

    • connect
    • startGame
    • finishGame
  • Queues

    • Aucune
  • État

    • JSON
    • members
    • host
    • ready state
    • phase
    • party events

Cycle de vie

Flux hôte

sequenceDiagram
    participant H as Host Client
    participant MM as matchmaker
    participant M as match

    H->>MM: createParty()
    MM-->>H: {matchId, partyCode, playerId, joinToken}
    H->>M: connect(playerId, joinToken)
    M->>MM: verifyJoin(...)
    MM-->>M: allowed
    M->>MM: updatePartySize(playerCount)
    H->>M: startGame() / finishGame()
    M->>MM: closeParty(matchId)

Flux joigneur

sequenceDiagram
    participant J as Joiner Client
    participant MM as matchmaker
    participant M as match

    J->>MM: joinParty(partyCode)
    MM-->>J: {matchId, playerId, joinToken}
    J->>M: connect(playerId, joinToken)
    M->>MM: verifyJoin(...)
    MM-->>M: allowed / denied
    M->>MM: updatePartySize(playerCount)

Ranked

Sujet Résumé
Appairage Appairage de file d'attente basée ELO avec fenêtre de recherche s'élargissant au fur et à mesure que le temps d'attente augmente.
Netcode Hybride. Le client possède le mouvement avec prédiction locale et interpolation. Le serveur possède les projectiles, la résolution des coups, les résultats du match et les mises à jour de note.
Fréquence de tick 20 ticks/sec (50ms) avec ticks live fixes pour cadence déterministe et cadence de diffusion.
Physics Intensité moyenne à haute ; mouvement client avec validation serveur et combat/résolution des coups sous autorité serveur.

Acteurs

  • Clé : matchmaker["main"]

  • Responsabilité : Exécute la file d'attente basée note, l'appairage, la persistance d'assignment et le fanout de complétion.

  • Actions

    • queueForMatch
    • unqueueForMatch
    • matchCompleted
  • Queues

    • queueForMatch
    • unqueueForMatch
    • matchCompleted
  • État

    • SQLite
    • player_pool
    • matches
    • assignments avec fenêtre de note et scoping de connexion
  • Clé : match[matchId]

  • Responsabilité : Exécute la phase du match classé, le score et le report du gagnant.

  • Actions

    • connect
    • Actions de gameplay
  • Queues

    • Aucune
  • État

    • JSON
    • phase
    • players
    • score
    • winner
    • completion payload
  • Clé : player[username]

  • Responsabilité : Stocke le MMR canonique du joueur et le profil win/loss.

  • Actions

    • initialize
    • getRating
    • applyMatchResult
  • Queues

    • Aucune
  • État

    • JSON
    • rating
    • wins
    • losses
    • match counters
  • Clé : leaderboard["main"]

  • Responsabilité : Stocke et serve les joueurs top-rankers.

  • Actions

    • updatePlayer
  • Queues

    • Aucune
  • État

    • SQLite
    • Lignes de score leaderboard
    • Tri de listes top

Cycle de vie

sequenceDiagram
    participant C as Client
    participant MM as matchmaker
    participant P as player
    participant M as match
    participant LB as leaderboard

    C->>MM: queueForMatch(username)
    MM->>P: initialize/getRating
    P-->>MM: rating
    Note over MM: store queue row + retry pairing
    MM->>M: create(matchId, assigned players)
    MM-->>C: assignmentReady
    C->>M: connect(username)
    M->>MM: matchCompleted(...)
    MM->>P: applyMatchResult(...)
    MM->>LB: updatePlayer(...)
    Note over MM: remove matches + assignments rows

Turn-Based

Sujet Résumé
Appairage Appairage asynchrone invite-privée et public-queue dans le même modèle.
Netcode Autorité serveur (logique basique). Le client peut brouillon les mouvements avant soumission. Le serveur possède la propriété de tour, le journal des mouvements validés, l'ordre des tours et l'état d'achèvement.
Fréquence de tick Pas de tick continu ; la soumission de mouvements et les transitions de tour conduisent les mises à jour.
Physics Intensité très basse ; pas de boucle physics temps réel, juste validation des règles discrètes. L'indexation est optionnelle et surtout pour commodité de plateau ou requête à l'échelle.

Acteurs

  • Clé : matchmaker["main"]

  • Responsabilité : Traite invite-privée et appairage de public-queue pour matchs asynchrones.

  • Actions

    • createGame
    • joinByCode
    • queueForMatch
    • unqueueForMatch
    • closeMatch
  • Queues

    • createGame
    • joinByCode
    • queueForMatch
    • unqueueForMatch
    • closeMatch
  • État

    • SQLite
    • matches
    • player_pool
    • assignments pour mapping invite et queue
  • Clé : match[matchId]

  • Responsabilité : Possède l'état du plateau, l'ordre des tours, la validation des mouvements et le résultat final.

  • Actions

    • connect
    • makeMove
  • Queues

    • Aucune
  • État

    • JSON
    • board
    • turns
    • players
    • connection presence
    • result

Cycle de vie

File d'attente publique

sequenceDiagram
    participant A as Client A
    participant B as Client B
    participant MM as matchmaker
    participant M as match

    A->>MM: queueForMatch()
    B->>MM: queueForMatch()
    Note over MM: pair first two queued players
    MM->>M: create(matchId) + seed X/O players
    MM-->>A: assignment/match info
    MM-->>B: assignment/match info
    A->>M: connect(playerId)
    B->>M: connect(playerId)
    A->>M: makeMove()
    B->>M: makeMove()
    opt all players disconnected for timeout
        Note over M: destroy after idle timeout
    end
    M->>MM: closeMatch(matchId)

Invite privée

sequenceDiagram
    participant A as Client A
    participant B as Client B
    participant MM as matchmaker
    participant M as match

    A->>MM: createGame()
    MM-->>A: {matchId, playerId, inviteCode}
    B->>MM: joinByCode(inviteCode)
    MM->>M: create(matchId) + seed X/O players
    MM-->>A: assignment/match info
    MM-->>B: assignment/match info
    A->>M: connect(playerId)
    B->>M: connect(playerId)
    A->>M: makeMove()
    B->>M: makeMove()
    M->>MM: closeMatch(matchId)

Idle

Sujet Résumé
Appairage Pas de matchmaker ; chaque joueur utilise un acteur direct par joueur et un acteur leaderboard partagé.
Netcode Autorité serveur (logique basique). Le client possède l'UI et l'intent de construction. Le serveur possède les ressources, les taux de production, la validation de bâtiment et les totaux du leaderboard.
Fréquence de tick Pas de tick continu ; utilisez c.schedule.after(...) pour les intervalles grossiers et calculez le rattrapage hors ligne à partir du temps écoulé.
Physics Aucune pour les boucles idle standard ; les transitions sont discrètes (build, collect, upgrade) et ne nécessitent pas d'indexation spatiale.

Acteurs

  • Clé : world[playerId]

  • Responsabilité : Possède la progression d'un joueur, les bâtiments, la planification de production et les mises à jour d'état.

  • Actions

    • initialize
    • build
    • collectProduction
  • Queues

    • Aucune
  • État

    • JSON
    • Bâtiments par joueur
    • resources
    • timers
    • progression state
  • Clé : leaderboard["main"]

  • Responsabilité : Stocke les scores globaux et serve les mises à jour leaderboard.

  • Actions

    • updateScore
  • Queues

    • updateScore
  • État

    • SQLite
    • Tableau scores indexé par joueur
    • Totaux leaderboard courants

Cycle de vie

sequenceDiagram
    participant C as Client
    participant W as world
    participant LB as leaderboard

    C->>W: getOrCreate(playerId) + initialize()
    Note over W: seed state + schedule collection
    W-->>C: stateUpdate
    loop gameplay loop
        C->>W: build() / collectProduction()
        W->>LB: updateScore(...)
    Note over LB: upsert scores
    LB-->>C: leaderboardUpdate
    W-->>C: stateUpdate
    end

Carte de référence

Acteurs

Agent Os

Clients

Connexion

Cookbook

Général

Auto-hébergement

Skills similaires