Comment nous avons créé le moteur et le jeu pendant un an et demi. Deuxième partie L'infrastructure

Tout d'abord, quelques commentaires sur les traces de l'article précédent. Nous travaillions vraiment à Wargaming , où nous avons développé un moteur connu sous le nom de dava.framework ou dava.engine . C'est pourquoi de nombreux anciens collègues avec lesquels nous sommes toujours en bonnes relations participent activement à la discussion.

Un certain nombre de personnes ont des doutes: s'agit-il de la même technologie ou d'une autre? Réponse: il s'agit d'une nouvelle technologie écrite à partir de zéro.

Comment avons-nous réussi en seulement un an? Notre équipe possède une vaste expérience. Beaucoup développent des moteurs et des jeux depuis plus de 15 ans.

Pourquoi à partir de zéro, si vous pouviez prendre notre ancien moteur, qui réside également en open-source? Il a environ 10 ans et la plupart du code est obsolète. Même les meilleures parties du moteur, dont nous sommes fiers, contenaient parfois des morceaux de code et des rudiments de 5, 7 et parfois même 10 ans. De nombreuses solutions architecturales ont été conçues pour les appareils de l'époque - à commencer par un iPhone 3G. Maintenant, nous nous concentrons au moins sur l'iPad Air 1 et les appareils Android de puissance similaire. En conséquence, les approches ont quelque peu changé.

Et la question la plus courante: pourquoi posséder son moteur? Dans le dernier article, il y avait plusieurs arguments de divers degrés de persuasion. Je veux me concentrer sur l'essentiel: seule notre propre technologie peut vous permettre de tirer le meilleur parti du fer, de faire le maximum d'optimisations spécifiquement pour votre gameplay, votre style visuel. Nous nous positionnons, notamment en tant qu'entreprise technologique, non seulement en tant que développeur de jeux. Nous pensons qu'avec notre niveau d'ingénieurs et notre expérience, nous pouvons sérieusement rivaliser sur le marché des produits mobiles de haute technologie.

Et maintenant au point: quels outils et techniques nous ont aidés à accomplir cette tâche plutôt ambitieuse en peu de temps?

L'infrastructure


Nous avons choisi Atlassian Bitbucket Server + Jenkins. Dans le Bitbucket se trouve le référentiel principal (maître), auquel Jenkins est connecté. Chaque développeur a sa propre fourchette. Pour chaque tâche, une nouvelle fourche est créée dans la fourche, qui est intégrée à nouveau via la demande de tirage. En général, le schéma est assez standard. Chaque demande de traction est soumise à un examen obligatoire et à des tests automatiques. Et, en cas de succès, il fusionne automatiquement dans le maître.

Jenkins


Jenkins a plusieurs défauts: il est un ancien museau du Web, pas très rapide, gourmand, qui ressemble à un portail Internet des années 90. Cependant, sa flexibilité, un grand nombre de modules et sa gratuité en font un bon choix même en 2019. Après avoir joué avec les modules et les paramètres, vous pouvez obtenir une apparence digestible, une description déclarative des pipelines (se trouvant dans le référentiel). Soit dit en passant, il y a maintenant environ 40 pipelines: tests, éditeurs, un jeu pour toutes les plateformes; travailler avec l'infrastructure du serveur et le méta-jeu. Collectionnez les 20 buildagentov.

À l'avenir, bien sûr, je veux essayer des solutions hipster modernes, par exemple GitLab ou TravisCI auto-hébergé. Nous ne considérons pas complètement les solutions cloud (Nevercode, Bitrise, CircleCI, etc.) en raison de la grande taille de notre référentiel, de nos actifs et, par conséquent, du temps de construction et de la taille des artefacts.

Système de construction


La principale exigence du système était la suivante: génération de projet pour iOS, MacOS, Android, Windows, Linux dans un seul script. Nous avons réussi à essayer Premake, SCons, Bazel et CMake. Pour diverses raisons, nous nous sommes arrêtés au CMake éprouvé.

Ces dernières années, CMake est devenu presque la norme pour les bibliothèques C ++. Presque tout, du rappel à SDL, peut être connecté à votre projet CMake en quelques lignes. Il y a bien sûr des exceptions, comme OpenSSL ou V8, avec lesquelles j'ai dû transpirer un peu. En plus du Zmeik nu, nous avons développé un petit cadre (environ 3 000 lignes au total). Caractéristiques clés:
Modularité. Les différentes parties du moteur sont conçues comme des modules. Par exemple, le son, l'interface utilisateur, la physique, le réseau, etc. Chaque module peut avoir ses propres actifs (par exemple, des shaders) et peut avoir des dépendances sur d'autres modules.

L'application finale sur le moteur (jeu, éditeur, utilitaires) connecte uniquement les modules dont il a besoin. Un peu à part est le module de base, qui est une dépendance pour la plupart des autres modules. Le noyau implémente le point d'entrée, le cycle d'application principal, l'interaction avec le système d'exploitation et d'autres entités de base.
Modules tiers. Notre framework vous permet de télécharger un dépôt ou une archive git en plusieurs lignes, de décompresser, de compiler, de copier des bibliothèques et / ou des sources. Aujourd'hui, nous avons 66 de ces modules tiers: analytique, formats de fichiers tiers, middleware comme la physique, une bibliothèque de sons, etc.

Processus de développement


Sur la base de l'expérience précédente, nous avons décidé d'ajouter à la fois le moteur et le jeu dans un référentiel. Cela vous permet de modifier sans difficulté l'API du moteur et d'adapter le jeu de manière synchrone. Le résultat a été le soi-disant monorepositaire avec ses avantages et ses inconvénients. Mais, comme nous avions immédiatement prévu de maintenir un rythme de développement très élevé, la possibilité d'un refactoring synchrone du moteur et du jeu l'emportait sur tous les autres inconvénients de cette solution.

En moyenne, nous ajoutons plus de 20 demandes de tirage par jour. Cela signifie que le maître peut potentiellement être brisé 20 fois par jour. Heureusement, en 1991, ils ont mis au point la technique d'intégration continue. Où en sommes-nous?

Intégration continue


Comme mentionné ci-dessus, un brunch est créé pour chaque tâche dans la fourchette du développeur. Ensuite, une demande d'extraction est créée à partir de ce brunch vers le référentiel principal. Cette demande de traction réussit une série de tests automatisés chez Jenkins:

  1. Tests unitaires pour toutes les plateformes (windows, linux, macos, ios, android). Googletest est utilisé comme base et OpenCppCoverage, dont le rapport est vérifié par un script python supplémentaire, est utilisé pour vérifier le pourcentage de couverture. Si le pourcentage de couverture pour un fichier particulier est inférieur à 75%, le test est considéré comme ayant échoué. Ainsi, nous avons couvert la plupart des classes de moteurs de bas niveau avec des tests.
  2. Codeformatter Pour le code C ++, nous utilisons le format clang. Le formatage du code modifié se produit d'abord automatiquement lors de la validation sur la machine du développeur, puis il est vérifié dans le test. Pour javascript, qui est utilisé comme langage de script, npm linter est utilisé.
  3. Tests d'actifs. Un groupe de tests assez important: de la validation des formats de fichiers à la vérification des dépendances (par exemple, vérification de l'existence de la texture utilisée dans le niveau de jeu).
  4. Tests unitaires et fonctionnels de l'éditeur. Une partie intégrante du moteur est l'éditeur, où les niveaux de jeu et autres actifs sont créés et modifiés. En plus des tests unitaires, froglogic Squish pour Qt est utilisé pour tester l'éditeur - un utilitaire pour les tests GUI automatiques. Tout cela nous permet de nous passer de tests manuels de l'éditeur. De plus, selon les critiques d'artistes et de level designers, le niveau de sa qualité et de sa stabilité est plus élevé que dans l'entreprise précédente, lorsque nous avions une équipe de cinq testeurs. Dans le même temps, les versions se produisent quotidiennement et, avec des tests manuels, les versions se produisent toutes les 2 semaines.
  5. Tests fonctionnels du jeu. Il est clair que je souhaite utiliser des tests fonctionnels automatiques pour le jeu. Par conséquent, nous avons commencé à développer le système suivant:

  • l'application de test (en particulier - un script python) lance un serveur de jeu et un client avec certains paramètres
  • le serveur et le client en cours d'exécution ouvrent le port réseau,
  • L'application de test s'y connecte et envoie des commandes: téléchargez une carte, sélectionnez un personnage et des armes, déplacez-vous vers un point, visez, tirez, etc.
  • la syntaxe de test elle-même est python pytest. Ce système est actuellement en développement actif.

La plupart des projets de tests sont collectés avec le drapeau «traiter les avertissements comme des erreurs» activé, et sur la plate-forme MacOS avec le clang AddressSanitizer également activé, ce qui vous permet de détecter encore plus d'erreurs au stade de la préparation de la demande d'extraction.

En plus des tests, chaque demande d'extraction est examinée par au moins deux autres développeurs et, si nécessaire, est envoyée pour révision. Lorsque tous les tests sont terminés et que les examinateurs n'ont aucun commentaire, la demande de retrait se bloque automatiquement.
Étant donné que certains tests peuvent prendre un temps considérable (par exemple, un test complet de l'éditeur d'interface graphique dure plus d'une heure), un script raccourci est utilisé dans les demandes d'extraction. L'ensemble complet de tests est lancé dans l'assistant toutes les 4 heures.

À ce jour, 6 600 pull-quêtes ont été créées et organisées de cette manière.



Livraison continue


Nous utilisons le concept de versions automatiques quotidiennes (ou plutôt quotidiennes). Comment cela se produit-il exactement:

  1. la balise git est créée,
  2. il exécute des versions complètes de tous les tests,
  3. en cas de succès, des artefacts sont collectés:

  • éditeurs pour MacOS et Windows. Ainsi, chaque matin, tout le monde a une nouvelle version des outils. Et, grâce aux tests automatiques, nous avons confiance en leur qualité et leur stabilité.
  • client et serveur de jeu pour toutes les plateformes. Le client pour iOS est téléchargé sur TestFlight, pour Android - sur Google Play, d'autres plates-formes - sur JFrog Artifactory, des serveurs de jeux et d'autres services - sur le cloud. Autrement dit, chaque matin, nous avons une nouvelle version du jeu, prête à être testée et testée.

Bien sûr, toutes les versions nocturnes ne se terminent pas avec succès. Certains tests peuvent échouer ou une erreur critique se produira au démarrage de l'application. Dans ce cas, les problèmes détectés sont réparés par le développeur en service pendant la journée et le processus de libération est redémarré.
Il y en a plusieurs en service tous les jours:

  1. Préposé de 1er niveau. Surveille la stabilité des tests dans le référentiel principal.
  2. Préposé de 2e niveau sur le jeu. Réparer les bugs du jeu.
  3. Préposé de 2e niveau aux éditeurs. Corrige des bugs éditoriaux, conseille les utilisateurs (artistes, level designers, game designers).

Le jour même de votre devoir, vous pouvez vous engager sur une dette technique: ajoutez les tests manquants pour l'ancienne fonctionnalité, complétez la documentation ou effectuez une refactorisation, ce qui ne prend pas le temps avec la planification habituelle des versions.



Dans le prochain article, nous examinerons de plus près l'architecture logicielle du moteur lui-même, ainsi que les principaux modules et sous-systèmes.

À suivre ...

La première partie: habr.com/en/post/461623

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


All Articles