
Plongée approfondie dans le backend de jeu – Mortal Kombat X et Injustice 2

De la latence dynamique à la latence fixe : Passer d'une latence d'entrée variable de 5 à 20 images à un délai fixe de 3 images a été le principal « gain » d'expérience du joueur. Cela a aidé à garantir que la prévisibilité est tout aussi importante que la réactivité brute dans un jeu de combat.
La performance de rollback est multiplicative : Chaque optimisation appliquée aux cadres simulés rapporte jusqu'à 8 fois par rapport juste au cadre de rendu, exigeant une révision complète du budget de performance.
Le déterminisme permet tout : Le déterminisme bit à bit n'est pas seulement une exigence de correction. C'est, selon Stallone, ce qui rend le débogage hors ligne des desyncs, la relecture des matchs et l'ensemble du modèle de rollback possible.
Comparer à la réalité, pas au pire des cas : NetherRealm a passé des mois à optimiser pour un scénario qui se produit presque jamais en pratique ; la télémétrie bêta réelle et une compréhension du rythme d'entrée humain ont complètement corrigé la cible.
Les particules et desyncs nécessitent des systèmes dédiés : La re-simulation naïve des effets de particules non déterministes produit des visuels défaillants à grande échelle, et les desyncs induits par rollback nécessitent des outils de première classe pour être détectés et corrigés rapidement.
Michael Stallone, désormais directeur de la technologie chez NetherRealm Studios et ancien ingénieur logiciel principal de l'équipe moteur, a donné une présentation GDC 2017 détaillant comment NetherRealm a changé le modèle réseau de Mortal Kombat X et Injustice 2 de lockstep à rollback dans un correctif en direct (explication de chaque technique ici), sur environ sept à huit années-homme d'efforts d'ingénierie.
Indirectement, cela met en évidence les meilleures pratiques que tout studio de jeu, grand ou petit, peut appliquer à son mode multijoueur pour améliorer son architecture en ligne et l'expérience du joueur. Revenons au début.
De l'imprévisible au fixe : le cas de l'expérience joueur pour le rollback
La raison pour laquelle NetherRealm a changé n'était pas purement technique. C'est parce que les joueurs n'étaient pas satisfaits.
Sous lockstep, la latence d'entrée était dynamique. Elle fluctuait entre 5 et 20 images selon les conditions du réseau à tout moment donné. Pour un jeu de combat comme Mortal Kombat, c'est un problème sérieux. Les joueurs exécutent des combos avec un certain rythme de boutons et s'attendent à ce que ça fonctionne de la même manière à chaque fois. Lorsque le délai change en plein combat, la mémoire musculaire cesse de fonctionner. Le rythme se brise.
Critiquement, ce qui impacte la boucle de rétroaction pour les développeurs de jeux, les joueurs ne décrivaient pas cela comme "une latence élevée", ils le décrivaient simplement comme le jeu se sentant mal.
Le passage au rollback a permis d'obtenir trois images fixes de latence d'entrée, prenant en charge jusqu'à dix images totales de latence réseau (333 millisecondes de temps aller-retour) avant que le jeu ne se mette en pause.
La prévisibilité, pas seulement la faible latence, est ce dont ont besoin les joueurs de jeux de combat. Un délai fixe de 5 images est toujours meilleur qu'un délai dynamique de 3 à 15 images.
Le coût réel du rollback est multiplicatif
Avant le rollback, NetherRealm était à l'arrêt à 9 à 10 millisecondes par image. Après la mise en œuvre initiale du rollback, ce chiffre a grimpé à 30 millisecondes. Pratiquement le double de leur budget de 16,66 ms. Le saut de génération de consoles leur avait donné beaucoup de marge pour être imprudents avec les ressources CPU, et ils ont dû en payer le prix.
La raison pour laquelle le coût est si élevé est structurelle. Dans un système de rollback, chaque image simulée exécute la même logique de jeu que l'image de rendu, mais avec moins de systèmes actifs.
Optimisez quelque chose qui fonctionne sur les huit images simulées et vous obtenez jusqu'à 8 fois les économies. Optimisez uniquement l'image de rendu et vous obtenez une image d'économies. L'ensemble de la mentalité de performance doit se déplacer vers le tick simulé.
Cette pression multiplicative vaut également la peine d'être considérée dans le contexte plus large du taux de tick. Passer de 20 Hz à 60 Hz, par exemple, réduit la latence d'entrée mais multiplie également les cycles de simulation par seconde, ce qui augmente directement l'utilisation CPU du serveur et les coûts d'egrége réseau.
Il y a probablement un juste milieu entre le taux de tick idéal et le coût-efficace, et la bonne réponse dépendra de la sensibilité à la latence de votre jeu et de la taille de votre budget d'infrastructure. L'équipe de NetherRealm a commencé à 30 ms et a atteint une valeur expédiable de 13 ms à l'arrêt grâce à une optimisation disciplinée et en couches…. Et cela a pris la meilleure part de plusieurs années-homme.
Le déterminisme comme fondation
Tout dans le modèle de rollback de NetherRealm dépend d'une chose : le jeu se déroule de manière identique sur les deux machines, chaque fois.
La grande majorité de Mortal Kombat X est déterministe à l'identique. Chaque opération à virgule flottante s'exécute dans le même ordre sur chaque machine. Des milliers de contrôles de plan de clôture valident que les deux clients sont synchronisés à différents points du tick.
Toute divergence est une désynchronisation, et c'est voulu. Car si vous pouvez garantir le déterminisme, beaucoup de choses deviennent possibles : vous pouvez revenir en arrière, vous pouvez rejouer des matchs hors ligne pour le débogage, vous pouvez reproduire des désynchronisations avec un seul kit de développement, et vous pouvez détecter des problèmes avant qu'ils n'atteignent les joueurs.
Le déterminisme n'est pas glamour. Mais c'est la fondation sur laquelle tout le reste de l'expérience du jeu est construit.
La sérialisation est la pierre angulaire
"La sérialisation est la pierre angulaire de cela," a déclaré Stallone au début de la discussion, et toute l'implémentation l'a confirmé.
Le cadre de rollback est un tampon circulaire dimensionné selon la fenêtre de rollback : une entrée par image, sept entrées pour sept images de rollback.
Chaque objet contenant un état mutable doit être sauvegardé et restauré.
La création et la destruction d'objets à travers les frontières du rollback est particulièrement délicate (faites-le naïvement, vous finissez par créer et détruire constamment des objets).
NetherRealm a résolu cela avec un système appelé "Recréables" : il s'agit essentiellement de hacher l'objet et le contexte qui l'entoure, et si le hachage correspond lors du retour au bord de création, réutilisez l'objet existant. Pas de recréation, pas de re-simulation. Particulièrement précieux pour les sons et les particules, qui sont non déterministes et produiront des résultats différents si vous les détruisez, recréez et re-simulez.
Du côté de la restauration, la parallélisation du travail a réduit le coût de 2,7 millisecondes en mode mono-thread à 1,3 millisecondes pour deux fois plus de données.
Les leçons pratiques : éviter la propriété partagée des ressources mutables, préférer les pointeurs uniques pour la sérialisation, et s'appuyer sur memcopy et les échanges de tampons plutôt que sur la réparation de pointeurs dynamiques.
L'investissement dans l'infrastructure de sérialisation à lui seul était d'environ une à deux années-homme.
Les systèmes de particules nécessitent une stratégie dédiée
Les systèmes de particules étaient la source unique la plus importante des pics de performance. L'approche naïve (c'est-à-dire la re-simulation de chaque particule à chaque image simulée) était beaucoup trop coûteuse. Et cela ne produisait souvent pas de résultats corrects non plus, car de nombreuses simulations de particules sont non déterministes : si vous les re-simulez huit fois, vous obtenez huit résultats différents.
Pour résoudre cela, NetherRealm a construit un système de re-simulation en quatre modes.
La plupart des particules fonctionnaient en mode prédictif : simuler une fois sur l'image confirmée et une fois sur l'image de rendu. Cela produisait une lecture prévisible sans fonctionner sur chaque image intermédiaire. Par exemple, un cache d'exécution de 100 Mo signifie que les particules n'avaient jamais besoin d'apparaître au moment de l'exécution.
La solution “plus profonde” était le “Système de Re-simulation de Particules Prédictives (PPRS)”, qui hachait l'état des particules avec des contraintes délibérément lâches. En gros, demandant continuellement ‘Le joueur est-il à peu près au même endroit ? A-t-il fait à peu près la même chose dans le script de jeu ? Si c'est le cas, réutilisez l'objet de particule mis en cache entièrement. Ne le simulez pas, ne le sérialisez pas.”
Comme l'a noté Stallone, "Ce truc PPRS a vraiment sauvé notre peau."
Le PPRS est un modèle utile au-delà des simples particules. Tout système qui n'a pas besoin d'être parfaitement correct est un candidat : le hachage lâche plus la sérialisation légère peuvent vous amener à
Écrit par
l'équipe Edgegap









