Wie wir anderthalb Jahre lang die Engine und das Spiel darauf gemacht haben. Teil Zwei Die Infrastruktur

Zunächst einige Kommentare zu den Spuren des vorherigen Artikels. Wir haben wirklich bei Wargaming gearbeitet , wo wir eine Engine namens dava.framework oder dava.engine entwickelt haben . Daher beteiligen sich viele alte Kollegen, mit denen wir noch gute Beziehungen haben, aktiv an der Diskussion.

Einige Leute haben Zweifel: Ist das die gleiche Technologie oder eine andere? Antwort: Dies ist eine neue Technologie, die von Grund auf neu geschrieben wurde.

Wie haben wir es in nur einem Jahr geschafft? Unser Team verfügt über umfangreiche Erfahrungen. Viele entwickeln seit über 15 Jahren Engines und Spiele.

Warum von Grund auf neu, wenn Sie unseren alten Motor nehmen könnten, der auch in Open Source liegt? Er ist ungefähr 10 Jahre alt und der größte Teil des Codes ist veraltet. Sogar die besten Teile des Motors, auf die wir stolz sind, enthielten manchmal Code-Teile und einige Grundlagen von 5, 7 und manchmal sogar 10 Jahren. Viele Architekturlösungen wurden für Geräte dieser Zeit entwickelt - beginnend mit einem 3G iPhone. Jetzt konzentrieren wir uns zumindest auf das iPad Air 1 und ähnliche Android-Geräte. Dementsprechend haben sich die Ansätze etwas geändert.

Und die häufigste Frage: Warum eigener Motor? Im letzten Artikel gab es mehrere Argumente mit unterschiedlichem Maß an Überzeugungskraft. Ich möchte mich auf die Hauptsache konzentrieren: Nur unsere eigene Technologie kann es Ihnen ermöglichen, das Beste aus Eisen herauszuholen und die maximale Anzahl von Optimierungen speziell für Ihr Gameplay und Ihren visuellen Stil vorzunehmen. Wir positionieren uns, auch als Technologieunternehmen, nicht nur als Spieleentwickler. Wir glauben, dass wir mit unserem Niveau an Ingenieuren und unserer Erfahrung ernsthaft auf dem Markt für mobile High-Tech-Produkte konkurrieren können.

Und jetzt zum Punkt: Welche Werkzeuge und Techniken haben uns geholfen, diese ziemlich ehrgeizige Aufgabe in kurzer Zeit zu erfüllen?

Die Infrastruktur


Wir haben uns für Atlassian Bitbucket Server + Jenkins entschieden. Im Bitbucket liegt das Haupt-Repository (Master), mit dem Jenkins verbunden ist. Jeder Entwickler hat seine eigene Gabel. Für jede Aufgabe wird eine neue Gabel in der Gabel erstellt, die über die Pull-Anforderung wieder integriert wird. Im Allgemeinen ist das Schema ziemlich Standard. Jede Pull-Anfrage wird einer obligatorischen Überprüfung und automatischen Tests unterzogen. Bei Erfolg wird es automatisch in den Master integriert.

Jenkins


Jenkins hat mehrere Mängel: Er ist ein alter, nicht sehr schneller, gefräßiger Web-Maulkorb, der aussieht wie ein Internetportal aus den 90er Jahren. Aufgrund seiner Flexibilität, einer Vielzahl von Modulen und seiner kostenlosen Nutzung ist es jedoch auch 2019 eine gute Wahl. Nachdem Sie mit den Modulen und Einstellungen gespielt haben, können Sie ein verdauliches Erscheinungsbild erzielen, eine deklarative Beschreibung der Pipelines (die im Repository liegen). Übrigens gibt es derzeit etwa 40 Pipelines: Tests, Editoren, ein Spiel für alle Plattformen; Arbeit mit Serverinfrastruktur und Metaspiel. Sammle alles 20 buildagentov.

In Zukunft möchte ich natürlich moderne Hipster-Lösungen ausprobieren, zum Beispiel GitLab oder selbst gehostete TravisCI. Wir berücksichtigen Cloud-Lösungen (Nevercode, Bitrise, CircleCI usw.) aufgrund der Größe unseres Repositorys, unserer Assets und dementsprechend der Erstellungszeit und der Größe von Artefakten nicht vollständig.

System erstellen


Die Hauptanforderung für das System war wie folgt: Projektgenerierung für iOS, MacOS, Android, Windows, Linux in einem Skript. Wir haben es geschafft, Premake, SCons, Bazel und CMake auszuprobieren. Aus verschiedenen Gründen haben wir beim bewährten CMake angehalten.

In den letzten Jahren ist CMake fast zum Standard für C ++ - Bibliotheken geworden. Fast alles von Abseilen bis SDL kann in nur wenigen Zeilen mit Ihrem CMake-Projekt verbunden werden. Es gibt natürlich Ausnahmen wie OpenSSL oder V8, mit denen ich etwas schwitzen musste. Auf dem nackten Zmeik haben wir ein kleines Framework entwickelt (insgesamt ca. 3.000 Zeilen). Hauptmerkmale:
Modularität. Die einzelnen Teile des Motors sind als Module ausgeführt. Zum Beispiel Sound, Benutzeroberfläche, Physik, Netzwerk usw. Jedes Modul kann über eigene Assets (z. B. Shader) und Abhängigkeiten von anderen Modulen verfügen.

Die endgültige Anwendung auf der Engine (Spiel, Editor, Dienstprogramme) verbindet nur die Module, die sie benötigt. Ein wenig auseinander liegt das Kernmodul, das für die meisten anderen Module eine Abhängigkeit darstellt. Core implementiert den Einstiegspunkt, den Hauptanwendungszyklus, die Interaktion mit dem Betriebssystem und anderen grundlegenden Entitäten.
Module von Drittanbietern. Mit unserem Framework können Sie ein Git-Repository oder -Archiv in mehreren Zeilen herunterladen, Bibliotheken und / oder Quellen entpacken, kompilieren, kopieren. Heute haben wir 66 solcher Module von Drittanbietern: Analytics, Dateiformate von Drittanbietern, Middleware wie Physik, eine Soundbibliothek usw.

Entwicklungsprozess


Aufgrund früherer Erfahrungen haben wir beschlossen, sowohl die Engine als auch das Spiel in einem Repository hinzuzufügen. Auf diese Weise können Sie problemlos Änderungen an der Engine-API vornehmen und das Spiel synchron anpassen. Das Ergebnis war das sogenannte Monorepository mit seinen Vor- und Nachteilen. Da wir jedoch sofort vorhatten, ein sehr hohes Entwicklungstempo beizubehalten, überwog die Möglichkeit eines synchronen Refactorings der Engine und des Spiels alle anderen Nachteile dieser Lösung.

Im Durchschnitt fügen wir mehr als 20 Pull-Anfragen pro Tag hinzu. Dies bedeutet, dass der Master möglicherweise 20 Mal am Tag unterbrochen werden kann. Glücklicherweise haben sie 1991 die Continuous Integration-Technik entwickelt. Zu was sind wir gekommen?

Kontinuierliche Integration


Wie oben erwähnt, wird für jede Aufgabe in der Gabel des Entwicklers ein Brunch erstellt. Als Nächstes wird aus diesem Brunch eine Pull-Anforderung an das Haupt-Repository erstellt. Diese Pull-Anfrage besteht eine Reihe automatisierter Tests bei Jenkins:

  1. Unit-Tests für alle Plattformen (Windows, Linux, Macos, iOS, Android). Googletest wird als Basis verwendet, und OpenCppCoverage, dessen Bericht von einem zusätzlichen Python-Skript überprüft wird, wird verwendet, um den Prozentsatz der Abdeckung zu überprüfen. Wenn der Prozentsatz der Abdeckung für eine bestimmte Datei weniger als 75% beträgt, wird der Test als fehlgeschlagen betrachtet. Daher haben wir die meisten Low-Level-Motorklassen mit Tests abgedeckt.
  2. Codeformatierer Für C ++ - Code verwenden wir das Clang-Format. Die Formatierung des geänderten Codes erfolgt zuerst automatisch beim Festschreiben auf dem Computer des Entwicklers und wird dann im Test überprüft. Für Javascript, das als Skriptsprache verwendet wird, wird npm linter verwendet.
  3. Asset-Tests. Eine ziemlich große Gruppe von Tests: von der Validierung von Dateiformaten bis zur Überprüfung von Abhängigkeiten (z. B. Überprüfung, ob die in der Spielebene verwendete Textur vorhanden ist).
  4. Unit- und Funktionstests des Editors. Ein wesentlicher Bestandteil der Engine ist der Editor, in dem Spielebenen und andere Elemente erstellt und bearbeitet werden. Zusätzlich zu Unit-Tests wird froglogic Squish for Qt zum Testen des Editors verwendet - ein Dienstprogramm für automatische GUI-Tests. All dies ermöglicht es uns, auf manuelle Tests des Editors zu verzichten. Darüber hinaus ist nach den Bewertungen von Künstlern und Leveldesignern das Niveau der Qualität und Stabilität höher als im vorherigen Unternehmen, als wir ein Team von fünf Testern hatten. Zur gleichen Zeit treten Freisetzungen täglich auf, und bei manuellen Tests erfolgten Freisetzungen alle 2 Wochen.
  5. Funktionstests des Spiels. Es ist klar, dass ich automatische Funktionstests für das Spiel verwenden möchte. Aus diesem Grund haben wir mit der Entwicklung des folgenden Systems begonnen:

  • Die Testanwendung (speziell ein Python-Skript) startet einen Spieleserver und einen Client mit bestimmten Parametern
  • Laufender Server und Client öffnen den Netzwerkport.
  • Die Testanwendung stellt eine Verbindung zu ihnen her und sendet Befehle: Laden Sie eine Karte herunter, wählen Sie einen Charakter und Waffen aus, bewegen Sie sich zu einem Punkt, zielen Sie, schießen Sie usw.
  • Die Testsyntax selbst ist Python Pytest. Dieses System befindet sich derzeit in der aktiven Entwicklung.

Die meisten Testprojekte werden mit aktiviertem Flag "Warnungen als Fehler behandeln" und auf der MacOS-Plattform mit zusätzlich aktiviertem clang AddressSanitizer erfasst, sodass Sie in der Phase der Vorbereitung der Pull-Anforderung noch mehr Fehler abfangen können.

Zusätzlich zu den Tests wird jede Pull-Anforderung von mindestens zwei anderen Entwicklern überprüft und bei Bedarf zur Überarbeitung gesendet. Wenn alle Tests abgeschlossen sind und die Prüfer keine Kommentare haben, friert die Pull-Anfrage automatisch ein.
Da einige Tests viel Zeit in Anspruch nehmen können (z. B. dauert ein vollständiger GUI-Editor-Test mehr als eine Stunde), wird bei Pull-Anforderungen ein kurzes Skript verwendet. Der vollständige Testsatz wird alle 4 Stunden im Assistenten gestartet.

Bisher wurden 6.600 Pull-Quests erstellt und so durchgeführt.



Kontinuierliche Lieferung


Wir verwenden das Konzept der automatischen täglichen (oder eher täglichen) Veröffentlichung. Wie genau passiert das:

  1. Git-Tag wird erstellt,
  2. Es werden Vollversionen aller Tests ausgeführt.
  3. Bei Erfolg werden Artefakte gesammelt:

  • Editoren für MacOS und Windows. Somit hat jeder Morgen eine neue Version der Werkzeuge. Und dank automatischer Tests sind wir von ihrer Qualität und Stabilität überzeugt.
  • Game Client und Server für alle Plattformen. Der Client für iOS wird auf TestFlight, für Android - auf Google Play, andere Plattformen - auf JFrog Artifactory, Spieleserver und andere Dienste - in die Cloud hochgeladen. Das heißt, wir haben jeden Morgen eine neue Version des Spiels, die zum Testen und Testen bereit ist.

Natürlich endet nicht jede nächtliche Veröffentlichung erfolgreich. Einige Tests schlagen möglicherweise fehl oder beim Start der Anwendung tritt ein kritischer Fehler auf. In diesem Fall werden die gefundenen Probleme tagsüber vom diensthabenden Entwickler behoben und der Freigabeprozess neu gestartet.
Jeden Tag sind mehrere im Dienst:

  1. 1st Level Attendant. Überwacht die Stabilität von Tests im Haupt-Repository.
  2. 2. Level Begleiter im Spiel. Spielfehler beheben.
  3. 2nd Level Attendant für Redakteure. Behebt redaktionelle Fehler und berät Benutzer (Künstler, Leveldesigner, Spieledesigner).

Auch am Tag des Dienstes können Sie technische Schulden machen: Fügen Sie die fehlenden Tests für die alte Funktionalität hinzu, ergänzen Sie die Dokumentation oder führen Sie ein Refactoring durch, was bei der üblichen Release-Planung nicht die Zeit in Anspruch nimmt.



Im nächsten Artikel werden wir uns die Softwarearchitektur der Engine selbst sowie die Hauptmodule und Subsysteme genauer ansehen.

Fortsetzung folgt…

Der erste Teil: habr.com/de/post/461623

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


All Articles