Code réseau Age of Empires: 1 500 archers par modem à 28,8 kbps

image

Note du traducteur: cet article a déjà 17 ans, et il n'est intéressant que d'un point de vue historique. Il est intéressant d'apprendre comment les développeurs ont réussi à réaliser un jeu en ligne fluide à l'ère des modems 28,8k et des premiers Pentiums.

Cet article décrit l'architecture et l'implémentation, ainsi que quelques leçons tirées de la création du code multi-utilisateurs (réseau) pour les jeux Age of Empires 1 et 2 . Il décrit également les approches d'architecture de réseau actuelles et futures utilisées par Ensemble Studios dans leurs moteurs de jeu.

Age of Empires multijoueur: exigences de structure


Au début des travaux sur le code multijoueur Age of Empires en 1996, nous nous sommes fixés des objectifs très spécifiques nécessaires à la mise en place du gameplay requis.

  • Des batailles historiques à grande échelle et épiques avec de nombreuses unités militaires différentes
  • Prise en charge de jusqu'à 8 joueurs en mode multijoueur
  • Simulation de jeu fluide sur LAN, via une connexion directe par modem et sur Internet
  • Prise en charge de la plate-forme cible: Pentium 90 avec 16 Mo de RAM et un modem à 28,8 kbps
  • Le système de communication doit fonctionner avec le moteur existant (Génie)
  • Stable 15 images par seconde sur les machines avec une configuration minimale

Le moteur Genie était déjà prêt et le gameplay en mode mono-utilisateur a commencé à prendre ses formes. Le moteur Genie est un moteur de boucle de jeu à un seul filetage en deux dimensions. Les sprites sont rendus en 256 couleurs dans un monde composé de tuiles. Les cartes générées aléatoirement sont remplies de milliers d'objets: des arbres pouvant être coupés aux gazelles au galop. Répartition approximative (après optimisation) du temps d'exécution des tâches du moteur: 30% pour le rendu des graphiques, 30% pour l'IA et la recherche de chemins, 30% pour l'exécution des simulations et des tâches officielles.

Déjà à un stade assez précoce, le moteur était relativement stable et les communications multi-utilisateurs devaient fonctionner avec du code prêt à l'emploi sans qu'il soit nécessaire de modifier considérablement l'architecture (de travail) existante.

Pour compliquer la tâche, le temps nécessaire pour terminer chaque étape de simulation pouvait varier considérablement: le temps de rendu dépendait du fait que l'utilisateur regardait les unités, faisait défiler ou regardait la zone inexplorée, et les longs trajets ou la planification stratégique de l'IA affectaient considérablement le temps d'exécution du mouvement de jeu. : les oscillations étaient jusqu'à 200 ms.

De brefs calculs ont montré que le transfert d'un petit ensemble de données sur les unités et les tentatives de les mettre à jour en temps réel limitent considérablement le nombre d'unités et d'objets avec lesquels le joueur peut interagir. Si vous transférez simplement les coordonnées X et Y, l'état, l'action, la direction de la vue et les dégâts, alors dans le jeu, il ne peut y avoir plus de 250 unités mobiles.

Nous voulions que les joueurs puissent détruire les villes grecques avec des catapultes, des archers et des guerriers, tout en menant des sièges avec des trirèmes de la mer. De toute évidence, nous avions besoin d'une autre approche.

Simulations simultanées


Au lieu de transmettre l'état de chaque unité du jeu, nous avons voulu effectuer des simulations absolument identiques sur chaque machine, en passant chacune le même jeu de commandes donné par les joueurs en même temps. Les ordinateurs des joueurs, en substance, devaient synchroniser le gameplay dans les meilleures traditions des films de guerre, permettant aux joueurs d'émettre des commandes, puis de les exécuter de la même manière et en même temps, garantissant l'identité des jeux.

Initialement, une synchronisation aussi délicate était difficile à mettre en œuvre, mais en conséquence, elle apportait des avantages inattendus dans d'autres domaines.

Amélioration de base du modèle

Au niveau conceptuel le plus simple, la mise en œuvre de simulations simultanées semble très facile. Dans certains jeux qui utilisent des simulations avec une étape fixe (étape de verrouillage) et des timings constants, cela peut même être tout à fait possible.

Étant donné qu'avec cette approche, il devrait prendre la responsabilité de déplacer simultanément des centaines ou des milliers d'objets, le système doit rester viable même avec des fluctuations de retard de 20 à 1000 millisecondes et gérer les changements lors du traitement de la trame.

L'envoi des commandes des joueurs, la confirmation de tous les messages, puis leur traitement avant de passer au mouvement suivant serait un cauchemar du point de vue du processus de jeu, avec une attente constante et un échange lent des équipes. Nous avions besoin d'un schéma qui pourrait continuer à traiter le jeu en parallèle avec l'arrière-plan en attendant la fin du processus d'échange de données.

Mark [Terrano] a utilisé un système pour marquer les commandes qui devraient être exécutées à travers deux «mouvements d'échange de données» à l'avenir (les mouvements d'échange de données dans AoE étaient séparés des cadres de rendu eux-mêmes).

C'est-à-dire que les commandes données pendant le cours 1000 sont affectées pour être exécutées pendant le cours 1002 (voir figure 1). Au cours de 1001, les commandes données au cours de 0 999 sont exécutées, ce qui nous a permis de recevoir, de confirmer et de préparer des messages à traiter, tandis que le jeu a continué à dessiner des animations et à effectuer des simulations.


Figure 1. Balisage des commandes à exécuter via deux «mouvements d'échange de données».

Habituellement, les mouvements prenaient 200 ms, et les équipes étaient envoyées pendant ce tour. Après 200 ms, le mouvement s'est arrêté et un nouveau mouvement a commencé. À chaque instant de la partie, les équipes ont été traitées en un coup, reçues et enregistrées pour le coup suivant, puis envoyées pour exécution deux coups plus tard.

"Contrôle de vitesse"



Figure 2. Contrôle de vitesse.

Étant donné que les simulations doivent toujours avoir exactement la même entrée, un jeu ne peut pas fonctionner plus vite que la machine la plus lente ne parvient à traiter l'échange de données, à effectuer un déplacement et à envoyer de nouvelles commandes. Nous avons appelé le système qui modifie la durée du coup pour maintenir des animations et un gameplay fluides dans des conditions de délai d'échange de données et de vitesse de traitement variables «Speed ​​Control».

Le gameplay peut être ressenti comme un "freinage" pour deux raisons: si la fréquence d'images d'une machine chute (ou si elle est inférieure aux autres), les autres machines traitent leurs commandes, rendent tout au temps imparti et, par conséquent, elles doivent attendre le prochain mouvement. Dans ce cas, toute pause devient immédiatement perceptible. De plus, le jeu est ralenti par un retard dans l'échange de données - les joueurs doivent attendre que la machine reçoive suffisamment de données pour terminer le mouvement.

Chaque client a calculé la fréquence d'images considérée comme constamment réalisable, qui a été calculée en faisant la moyenne du temps de traitement de plusieurs images. Étant donné que cette valeur change pendant le jeu en fonction de la portée, du nombre d'unités, de la taille de la carte et d'autres facteurs, elle a été transmise dans chaque message concernant la fin du mouvement.

De plus, chaque client a également mesuré le «temps de ping» entre lui et les autres clients et vice versa. Il a également envoyé le ping moyen au client le plus long dans un message sur la fin du déplacement (au total, 2 octets ont été utilisés pour contrôler la vitesse).

À chaque déplacement, la machine désignée par l'hôte a analysé les messages d'achèvement, calculé la fréquence d'images nécessaire et la correction du retard dans la transmission des données sur Internet. L'hôte a ensuite envoyé une nouvelle fréquence d'images et la durée de l'échange de données. Les figures 3 à 5 montrent comment le flux d'échange de données a été divisé dans différentes conditions.


Figure 3. Flux d'échange de données typique.


Figure 4. Transmission de données à latence élevée sur Internet à vitesse normale de la machine.


Figure 5. Faible vitesse de la machine avec un délai de transfert de données normal.

La "progression de l'échange de données", qui était approximativement égale au temps de ping pour l'aller-retour pour le message, était divisée par le nombre de trames de simulation que la machine la plus lente pouvait effectuer en moyenne pendant cette période.

La durée de l'échange de données a été pondérée, de sorte qu'elle pourrait rapidement augmenter en fonction des changements dans la latence de la transmission de données sur Internet et diminuer lentement jusqu'à la meilleure vitesse moyenne qui peut être constamment maintenue. Habituellement, le jeu a ralenti et ralenti uniquement aux moments des pires pics - le délai de transmission des commandes a augmenté, mais est resté fluide (et n'a augmenté que de quelques millisecondes par tour), car le jeu a progressivement réduit les retards à la meilleure vitesse possible. Cela a créé la plus grande fluidité possible du gameplay, tout en offrant un ajustement aux conditions changeantes.

Livraison garantie


UDP a été utilisé dans la couche réseau et chaque client a été impliqué dans la commande des commandes, la reconnaissance des pertes et la retransmission. Chaque message utilisait une paire d'octets, indiquant le cours pour lequel l'exécution des commandes était prévue et le numéro de série du message. Si un message a été reçu après le déplacement, il a été rejeté et les messages entrants ont été enregistrés pour exécution. En raison de la nature de l'UDP, Mark a utilisé le principe suivant lors de la réception de messages: «En cas de doute, vous devriez considérer le message perdu. Si des messages sont reçus dans le désordre, le destinataire envoie immédiatement une demande de retransmission des messages perdus. Si l'accusé de réception est reçu plus tard que l'heure prévue, l'expéditeur envoie simplement à nouveau le message, sans attendre un signal de sa perte. "

Avantages cachés


Étant donné que les résultats calculés par le jeu dépendaient de tous les utilisateurs effectuant des simulations identiques, il était incroyablement difficile pour un client (ou un flux de données client) de pirater et de tricher. Toute simulation effectuée différemment a été marquée comme «désynchronisée» et le jeu s'est arrêté. Il était toujours possible de tricher localement pour la divulgation d'informations, mais ces fuites étaient relativement facilement corrigées dans les correctifs et révisions ultérieurs. La sécurité est devenue notre plus grande victoire.

Problèmes cachés


Au début, il peut sembler que la même exécution de deux instances du même code est facile à implémenter, mais ce n'est pas le cas. Aux toutes premières étapes du projet, Tim Znamenachek, chef de produit Microsoft, a déclaré à Mark: «Chaque projet a un bogue persistant qui n'abandonne pas jusqu'à la fin. Je pense que dans notre cas, ce sera désynchronisé. » Et il avait raison. Les difficultés de détection des erreurs de synchronisation se sont multipliées à chaque petit changement. Le cerf, dont la position est légèrement différente lors de la création d'une carte aléatoire, se déplacera un peu différemment, et quelques minutes plus tard, le chasseur se déplacera légèrement ou manquera une lance, à la suite du retour à la maison sans viande. Par conséquent, ce qui semblait parfois n'être qu'une différence dans les sommes de contrôle de la quantité de nourriture avait des raisons très difficiles à suivre.

Bien que nous ayons vérifié le monde, les objets, recherché des chemins, visé et tous les autres systèmes avec des sommes de contrôle, il y avait toujours quelque chose que nous ne pouvions pas prendre en compte. D'énormes volumes (50 Mo chacun) de suivi des messages et de vidages d'objets du monde ont rendu le problème encore plus compliqué. Une partie des difficultés était d'ordre conceptuel - les programmeurs n'étaient pas habitués à écrire du code utilisant le même nombre d'appels de générateur de nombres aléatoires dans une simulation (oui, des nombres aléatoires étaient également générés et synchronisés).

image

Leçons apprises


Lors du développement de la partie réseau d' Age of Empires, nous avons reçu plusieurs leçons qui peuvent être appliquées au développement de tout système multi-utilisateur de jeu.

Apprenez à votre utilisateur. L'étude de l'utilisateur est l'étape la plus importante pour comprendre ses attentes concernant la vitesse du multijoueur, les freins perçus et les retards dans la transmission des commandes. Chaque genre est individuel et vous devez comprendre ce qui convient à votre style de jeu et à votre gestion.

Dans les premières étapes du processus de développement, Mark et le concepteur principal ont retardé l'échange de données (ce prototype a été révisé plusieurs fois au cours du processus de développement). Puisqu'ils jouaient à un jeu en solo, il était très facile de simuler différents niveaux de retards de transfert d'équipe et d'obtenir des commentaires des joueurs («le contrôle semble bon / lent / tremblant / tout simplement horrible»).

Pour les jeux du genre RTS, les retards de transmission des commandes de 250 millisecondes ne sont même pas perceptibles, à 250-500 ms le gameplay est assez jouable, et les freins deviennent perceptibles à 500 ms et plus. Il est également intéressant de noter que les joueurs sont habitués au "rythme du jeu" et à l'attente mentale d'un délai entre les clics de souris et les réactions des unités. Une réponse différée constante était meilleure que des sauts dans les délais de transmission des commandes (par exemple, de 80 à 500 ms) - dans ce cas, des retards constants de 500 ms étaient perçus comme jouables, et les changements modifiables semblaient "nerveux" et compliquaient le jeu.

Cela a obligé les programmeurs à concentrer leurs efforts sur la fluidité - il vaut mieux choisir une durée de course plus longue et être sûr que tout sera fluide et constant que d'effectuer les opérations le plus rapidement possible, face à des ralentissements réguliers. Tous les changements de vitesse doivent être progressifs et le taux de croissance doit être aussi faible que possible.

Nous avons également mesuré les besoins de l'utilisateur pour le système - généralement, ils donnaient des commandes (déplacer, attaquer, couper des arbres) environ toutes les secondes et demie à deux secondes, parfois avec des pics de 3-4 équipes par seconde lors de batailles acharnées. Comme les actions actives dans notre jeu sont en constante augmentation, les exigences les plus élevées pour l'échange de données surviennent au milieu et vers la fin du jeu.

Si vous prenez le temps d'étudier le comportement des utilisateurs, vous remarquerez d'autres fonctionnalités de leur jeu, ce qui vous aidera à configurer le jeu en réseau. Dans AoE pendant les attaques, les utilisateurs ont rapidement cliqué sur la souris (cliquer-cliquer-cliquer-cliquer - avancer-avancer-avancer-avancer!), Ce qui a entraîné d'énormes pics dans le nombre de commandes émises. En outre, ils ont envoyé de grands groupes d'unités qui doivent ouvrir la voie - ainsi que d'énormes pics dans les exigences de transmission de données sur le réseau. Un simple filtre, coupant les commandes répétées à un moment donné, a considérablement réduit l'impact négatif de ce comportement.

En général, la surveillance des utilisateurs vous permettra de:

  • Découvrez les attentes des utilisateurs concernant les retards de jeu
  • Aspects multijoueurs prototypes aux premiers stades de développement
  • Découvrez les comportements préjudiciables à la vitesse du mode multi-utilisateur.

La mesure est la chose la plus importante. Si vous introduisez des mesures dans les premières étapes du travail, vous apprendrez des choses incroyables sur votre système d'échange de données. Rendez les métriques lisibles pour les testeurs et utilisez-les pour comprendre ce qui se passe à l'intérieur du moteur réseau.

Leçon: Une partie du problème avec l'échange de données dans AoE est survenue lorsque Mark a déduit les mesures trop tôt et n'a pas vérifié les niveaux de message (longueur et fréquence) après avoir préparé le code final. Des choses inattendues comme des courses aléatoires entre les IA, des chemins difficiles à calculer et des packages de commandes mal structurés peuvent causer d'énormes problèmes de performances, même lorsque le système fonctionne bien.

Faire en sorte que le système informe les testeurs et les développeurs de ce qui semble être un excès de conditions aux limites - les programmeurs et les testeurs verront dans le processus de développement quelles tâches chargent le système; cela résoudra les problèmes aux premiers stades de leur apparition.

Prenez le temps d'expliquer aux testeurs comment fonctionne le système d'échange de données, montrez-leur et expliquez-leur les mesures - vous serez peut-être surpris qu'ils remarqueront quand d'étranges défaillances se produisent inévitablement dans le code réseau.

En général, les métriques doivent avoir les propriétés suivantes:

  • Soyez lisible et compréhensible par les testeurs
  • Indiquez les goulots d'étranglement, les freins et les problèmes
  • Peu d'impact sur l'exécution et constamment lancé.

Formation des développeurs. Il est très difficile d'apprendre aux programmeurs habitués à créer des applications mono-utilisateur à réfléchir à la séparation entre donner, recevoir et traiter une commande. Il est facile d'oublier que vous pouvez demander quelque chose qui ne s'est pas produit ou ce qui pourrait arriver quelques secondes après l'émission de la commande. L'exactitude des commandes doit être vérifiée à l'envoi et à la réception.

Dans un modèle synchrone, les programmeurs doivent également tenir compte du fait qu'à l'intérieur de la simulation, le code ne devrait dépendre d'aucun facteur local (comme la disponibilité de temps libre, des équipements spéciaux ou des paramètres différents). L'exécution du code sur toutes les machines doit correspondre. Par exemple, la présence de sons aléatoires du terrain dans une simulation peut entraîner des comportements de jeu différents.

Autres leçons. Cela devrait être le bon sens habituel - mais si vous dépendez d'un réseau tiers (dans notre cas, c'est DirectPlay), alors écrivez une application de test indépendante confirmant que lorsque les propriétaires réclament une «livraison garantie», les messages obtiennent vraiment cet «ordre de paquet garanti» en fait il y en a, et que le produit n'a pas de goulots d'étranglement cachés ou de comportement étrange lors du traitement des données transmises dans votre jeu.

Préparez-vous à créer des applications de simulation et des simulateurs de tests de résistance. Au final, nous avons créé trois applications de test minimales différentes utilisées pour étudier les problèmes individuels et importants: les inondations de connexion, les problèmes de connexions simultanées lors de la sélection des opposants et les packages garantis perdus.

Testez avec des modems (et, avec un peu de chance, avec des simulateurs de modem) le plus tôt possible; Poursuivez les tests de modem (aussi douloureux que cela puisse être) tout au long du processus de développement.Après tout, les problèmes sont difficiles à isoler (quelle est la raison de la forte diminution de la vitesse - le fournisseur, le jeu, le logiciel de communication, le modem, le service de recherche rival pour une correspondance ou autre chose?), Et les utilisateurs ne veulent pas s'embêter avec des connexions à distance lentes, s'habituer à des vitesses LAN instantanées . Il est essentiel de tester les connexions par modem avec la même persistance que pour les jeux LAN multi-joueurs.

image

Améliorations pour Age of Empires 2


Dans Age of Empires 2: The Age of Kings, nous avons ajouté des fonctionnalités multi-utilisateurs telles que l'enregistrement de jeux, le transfert de fichiers et le suivi constant des statistiques sur le site Web de The Zone. Nous avons également amélioré les systèmes multijoueurs tels que l'intégration DirectPlay et le contrôle de vitesse pour faire face aux bugs et problèmes de vitesse identifiés après la sortie d' Age of Empires .

La fonction d'enregistrement de jeux était l'une de ces choses qui ont été à l'origine inventées pour le débogage, et en conséquence est devenue une «fonctionnalité» à part entière du jeu. Les jeux enregistrés sont incroyablement populaires sur les sites de fans. Ils permettent aux joueurs de partager des stratégies et de les analyser, de voir des batailles célèbres et d'apprendre les jeux auxquels ils ont participé. L'enregistrement de jeux est devenu un outil de débogage inestimable. Étant donné que notre simulation est déterministe et que les jeux enregistrés sont synchrones dans le même sens que le multijoueur, l'enregistrement de jeux nous a fourni un excellent moyen de jouer aux bugs, car à chaque fois, il était garanti de jouer de la même manière.

Notre intégration avec le service de recherche de rival (matchmaking) de The Zone a été limitée dans Age of Empires pour simplement lancer le jeu. Dans Age of Kingsnous l'avons élargi, ce qui nous a permis de contrôler les paramètres de lancement et de fournir des rapports constants sur les statistiques. Cela a permis aux joueurs de mieux trouver les jeux qui les intéressaient, car ils pouvaient voir les paramètres du niveau de matchmaking, et ne pas attendre que les paramètres du jeu s'affichent sur l'écran des paramètres du jeu. Dans le backend, nous avons mis en place des statistiques de reporting et de suivi constantes. Nous avons fourni à The Zone une structure commune qui a été remplie et transférée au serveur à la fin du jeu. Les données de cette structure ont été utilisées pour créer des évaluations d'utilisateurs et les afficher sur le site Web de The Zone.

image

Multijoueur RTS3: tâches


RTS3 est le nom de code du jeu de stratégie de nouvelle génération Ensemble (environ Per: le jeu est sorti sous le nom Age of Mythology) . La structure RTS3 est créée sur la base de la formule réussie utilisée dans la série de jeux Age of Empires, avec l'ajout de nombreuses nouvelles fonctionnalités et exigences pour le mode multi-utilisateurs.

  • Basé sur l'ensemble des fonctionnalités d' Age of Empires 1 et 2 . Exigences obligatoires telles que jouer sur Internet, des cartes grandes et variées, des milliers d'unités gérées.
  • 3D: RTS3 est un jeu entièrement en trois dimensions avec des animations interpolées et des positions et des rotations d'unités non discrètes.
  • Plus de joueurs - prise en charge de plus de huit joueurs.
  • Prise en charge TCP / IP: Notre objectif principal est une connexion Internet TCP / IP à 56 / kbps.
  • — , NAT.

RTS3 , Age of Empires 1 2 — — RTS3 . AOE/AOK DirectPlay, RTS3 , .

La transition vers un monde entièrement en trois dimensions signifie que nous devons être plus attentifs aux problèmes de fréquence d'images et de fluidité globale de la simulation en mode multi-utilisateur. Cependant, cela signifie également que le temps de mise à jour de la situation de simulation et la fréquence d'images seront encore plus sujets à la variabilité, et que nous devrons consacrer plus de temps au rendu. Dans le moteur Genie, les rotations des unités étaient discrètes et les animations étaient liées à la fréquence d'images dans BANG! une rotation d'unité arbitraire et une animation fluide sont possibles, c'est-à-dire que visuellement le jeu sera beaucoup plus sensible à l'influence des retards et des sauts dans la fréquence de mise à jour.

Finaliser Age of Kings, nous voulions nous attaquer à ces domaines critiques où une conception réfléchie et l'utilisation d'outils réduiraient considérablement le temps de débogage. Nous avons également réalisé à quel point le processus de test itératif est important dans la conception de nos jeux, une priorité élevée a donc été accordée à la conclusion la plus rapide possible du jeu en ligne.

Architecture de communication RTS3



Figure 6. Architecture réseau orientée objet stricte de RTS3.

Approche orientée objet. L'architecture réseau de RTS3 est fortement orientée objet (voir figure 6). Les exigences de prise en charge pour diverses configurations de réseau vous permettent de tirer parti de l'approche OO, abstraite des spécificités de la plate-forme, du protocole et de la topologie qui sous-tendent un ensemble d'objets et de systèmes généralisés.

Les versions spécifiques au protocole et à la topologie des objets réseau contiennent le moins de code possible. La fonctionnalité principale de ces objets est abondante dans les objets parents de haut niveau. Pour implémenter le nouveau protocole, nous avons développé uniquement les objets réseau qui avaient besoin d'un code spécifique au protocole (par exemple, pour le client et la session, qui devraient agir légèrement différemment selon le protocole). Aucun autre objet système (tel que Channels, TimeSync, etc.) n'a nécessité de modifications, car ils n'avaient une interface avec le client et la session que via leurs interfaces abstraites de haut niveau.

Topologie d'égal à égal.Le moteur Genie prend en charge une topologie de réseau d'égal à égal dans laquelle tous les clients d'une session se connectent les uns aux autres dans une configuration en étoile. Dans RTS3, nous avons continué à utiliser cette topologie, car lorsqu'elle est implémentée avec un modèle de simulation synchrone, elle présente des avantages inhérents.

La topologie d'égal à égal implique l'utilisation d'une configuration en étoile pour les clients connectés dans une session (figure 7). Autrement dit, chaque client est connecté à tous les autres clients. Le même schéma a été utilisé aux âges 1 et 2 .


Figure 7. Configuration en étoile des clients homologues dans une session.

Avantages de pair à pair:

  • Diminution de la latence due au schéma de messagerie client à client au lieu de client-serveur-client.
  • Il n'y a pas de lien faible central - si le client (même l'hôte) se déconnecte de la session, le jeu peut continuer.

Inconvénients de pair à pair:

  • Composés plus actifs dans le système (somme de n = 0 à k-1 (n)), c'est-à-dire plus de maillons faibles potentiels et des retards probables plus élevés.
  • L'incapacité à prendre en charge certaines configurations NAT dans un tel schéma.

Net.lib. Lors du développement de l'architecture d'échange de données RTS3, notre objectif était de créer un système spécialement conçu pour les jeux stratégiques, mais en même temps, nous voulions créer un système pouvant être utilisé pour nos outils internes, ainsi que de l'étendre pour prendre en charge les futurs jeux. Pour atteindre cet objectif, nous avons créé une architecture multicouche qui prend en charge les objets de niveau jeu tels que le client et la session, mais prend également en charge les objets de transport de bas niveau tels que les liens et les adresses réseau.


Figure 8. Quatre couches de services dans notre modèle de réseau.

RTS3 est basé sur notre moteur BANG! une nouvelle génération qui utilise une architecture modulaire avec des bibliothèques de composants telles que le son, le rendu et la mise en réseau. Le sous-système réseau est intégré ici en tant que composant, mais est connecté au moteur BANG! (ainsi qu'avec divers outils internes). Notre modèle de réseau est divisé en quatre couches de service, qui ne sont pas, mais pas complètement, similaires au modèle de réseau OSI utilisé dans le jeu (voir la figure 8).

Chaussettes niveau 1

Le premier niveau, Socks, fournit une API fondamentale de niveau socket en C. Elle est abstraite pour créer un ensemble générique de procédures réseau de bas niveau pour de nombreux systèmes d'exploitation. L'interface ressemble à l'interface de socket Berkeley. La couche Socks est principalement utilisée par les couches supérieures de la bibliothèque réseau et n'est pas vraiment destinée à être utilisée par le code d'application.

Link, Level 2

Level 2, Link, fournit des services de couche transport. Les objets à ce niveau, tels que Link, Listener, NetworkAddress et Packet, sont des éléments utiles nécessaires pour établir une connexion et envoyer des messages par-dessus (voir la figure 9).

  • Packet (): — , / ( ) .
  • Link (): . , . send receive , , void*.
  • Listener (): . .
  • Data stream ( ): , , , .
  • Net Address: entité d'adressage réseau indépendante du protocole.
  • Ping: Une classe de ping simple. Signale un retard de réseau présent lors de la communication avec la liaison.

  • Figure 9. Niveau de liaison.

Niveau multijoueur 3
Le niveau multijoueur est le niveau le plus élevé d'objets et de procédures présents dans l'API net.lib. Il s'agit de la couche avec laquelle RTS3 interagit lors de la collecte d'objets de niveau inférieur, tels que des liens et de leur conversion en concepts / objets plus utiles - clients, sessions, etc.

Les objets les plus intéressants de la bibliothèque du réseau BANG! sont ceux qui sont au niveau multijoueur. Ici, l'API fournit un ensemble d'objets avec lesquels le niveau de jeu peut interagir, mais fournit une implémentation indépendante de l'approche du jeu.

  • Client (): . () ( ). , .
  • Session (): , , , . . host() join(), , , . / , .
  • Channel Ordered Channel: . . TimeSync, .
  • Shared Data: . , , .
  • Time Sync: .

Game Communications, 4

RTS3. , , . , , .

image


Système de synchronisation amélioré. Aucune des équipes de développement d' Age of Empires n'a pu dire que nous n'avons pas besoin de meilleurs outils de synchronisation. Comme dans tout projet, lors de l'analyse du processus de développement dans l'autopsie, il s'avère que la plupart du temps a été consacré à certains domaines, mais cela pourrait être beaucoup moins si nous les abordions à l'avance. Au début du développement de RTS3, le débogage de la synchronisation était en tête de liste de ces domaines.

Le système de suivi de synchronisation RTS3 vise principalement à reconnaître rapidement les bogues de synchronisation. Les autres priorités étaient la simplification de l'utilisation, la capacité de traiter arbitrairement de grandes quantités de données synchronisées transmises par le système, la possibilité de compiler complètement le code de synchronisation dans la version finale, et enfin, la possibilité de changer complètement la configuration de test en changeant les variables au lieu de recompiler complètement.

La vérification de la synchronisation dans RTS3 est effectuée à l'aide de deux ensembles de macros:

#define syncRandCode(userinfo)
gSync->addCodeSync(cRandSync, userinfo, __FILE__, __LINE__)


#define syncRandData(userinfo,
v) gSync->addDataSync(cRandSync, v, userinfo, __FILE__, __LINE__)


Ces deux macros reçoivent le paramètre de chaîne userinfo, qui est le nom ou l'indication d'un élément synchronisé spécifique. Par exemple, un appel de synchronisation pourrait ressembler à ceci:

syncRandCode("syncing the random seed", seed);

Commandes de console synchrones et variables de configuration. Comme tout développeur de mod Quake peut le confirmer, les commandes de la console et les variables de configuration sont très importantes pour le processus de développement. Les commandes de la console sont de simples appels de fonction effectués à l'aide du fichier de configuration de lancement, de la console en jeu ou de l'interface utilisateur, qui invoquent des fonctionnalités de jeu arbitraires. Les variables de configuration sont des types de données nommés fournis via les fonctions simples get, set, define et toggle, que nous utilisons pour toutes sortes de tests et de définition des paramètres de configuration.

Paul a créé des versions compatibles multijoueurs de nos systèmes de commande de console et des configurations variables. Avec leur aide, nous pouvons facilement transformer une variable de configuration régulière (par exemple, enableCheating) en une variable de configuration multijoueur en ajoutant un indicateur à la définition de la variable de configuration. Si ce drapeau est activé, la variable de configuration est transférée dans le jeu multijoueur et les décisions synchronisées dans le jeu (par exemple, sur la possibilité de transfert gratuit de ressources) peuvent être basées sur sa valeur. Les commandes de console du multijoueur ont un principe similaire - les appels aux commandes de console du multijoueur sont transmis sur le réseau et sont exécutés de manière synchrone sur toutes les machines clientes.

En utilisant ces deux outils, les développeurs peuvent utiliser le système multijoueur sans écrire de code. Ils peuvent rapidement ajouter de nouveaux outils de test et de configuration et les intégrer facilement dans un environnement en réseau.

Pour résumer


La simulation synchronisée et le modèle pair à pair ont été utilisés avec succès dans la série de jeux Age of Empires. Malgré l'importance cruciale d'investir du temps dans la création d'outils et de technologies pour résoudre les principaux problèmes de cette approche (tels que la synchronisation et les métriques de réseau), la viabilité de cette architecture dans le genre de stratégies en temps réel a été prouvée par l'expérience. Les améliorations ultérieures que nous avons apportées à RTS3 ont conduit au fait que le gameplay multijoueur est presque impossible à distinguer du mode solo, même dans les conditions les plus terribles de connexions réseau.

Source: https://habr.com/ru/post/fr417703/


All Articles