Хабрахабр

Как мы сделали движок и игру на нем за полтора года. Часть вторая. Инфраструктура

Для начала несколько комментариев по следам предыдущей статьи. Мы действительно раньше работали в компании Wargaming, где разрабатывали движок, известный как dava.framework или dava.engine. Поэтому многие старые коллеги, с которыми мы по-прежнему в хороших отношениях, активно участвуют в обсуждении.

Ответ: это новая технология, написанная с нуля. У ряда людей возникли сомнения: это та же технология или другая?

Наша команда имеет огромный опыт. Как же мы справились всего за год? Многие занимаются разработкой движков и игр более 15-и лет.

Ему около 10 лет, и большая часть кода устарела. Почему с нуля, если можно было взять наш старый движок, который к тому же лежит в open-source? Многие архитектурные решения были рассчитаны на устройства того времени — начиная с айфона 3G. Даже самые лучшие части движка, которыми мы гордимся, местами содержали куски кода и какие-то рудименты 5-и, 7-и и иногда даже 10-ти летней давности. Соответственно и подходы несколько поменялись.
И самый часто встречающийся вопрос: почему собственный движок? Сейчас же мы ориентируемся минимум на iPad Air 1 и аналогичные ему по мощности Android-устройства. Хочу сконцентрироваться на главном: только собственная технология может позволить вам получить максимум из железа, сделать максимальное количество оптимизаций именно для вашего геймплея, визуального стиля. В прошлой статье было несколько доводов разной степени убедительности. Мы считаем, что с нашим уровнем инженеров и нашим опытом можем составить серьезную конкуренцию на рынке высокотехнологичных мобильных продуктов. Мы позиционируем себя в том числе как технологическую компанию, не только разработчика игр.

А теперь к делу: какие инструменты и техники помогли осуществить нам эту довольно амбициозную задачу в сжатые сроки?

Инфраструктура

Мы выбрали Atlassian Bitbucket Server+Jenkins. В Битбакете лежит главный репозиторий (мастер), к которому подключен Дженкинс. У каждого разработчика есть свой форк. Под каждую задачу создается новый бранч в форке, который назад интегрируется через пулл-реквест. В общем, схема довольно стандартная. Каждый пуллреквест проходит обязательное ревью и автоматические тесты. И, в случае успеха, автоматически вливается в мастер.

Дженкинс

Дженкинс обладает рядом недостатков: он древний, не очень быстрый, прожорливый, веб-морда выглядит как интернет портал из 90-х. Однако его гибкость, огромное количество модулей и бесплатность делают его неплохим выбором даже в 2019м. Пошаманив с модулями и настройкой можно добиться удобоваримого внешнего вида, декларативного описания пайплайнов (лежащих в репозитарии). К слову, пайплайнов сейчас около 40: тесты, редакторы, игра под все платформы; работа с серверной инфраструктурой и метагеймом. Собирают все это 20 билдагентов.

Полностью облачные решения (Nevercode, Bitrise, CircleCI и т.п.) мы не рассматриваем ввиду большого размера нашего репозитария, ассетов, и, соответственно времени сборки и размера артефактов. В перспективе, конечно, хочется попробовать и современные хипстерские решения, к примеру GitLab или self-hosted TravisCI.

Система сборки

Основное требование к системе было следующим: генерация проекта для iOS, MacOS, Android, Windows, Linux одним скриптом. Мы успели попробовать Premake, SCons, Bazel и CMake. По разным причинам остановились на проверенном временем CMake.

Практически все, начиная от abseil и заканчивая SDL, можно подключить к своему CMake проекту буквально в несколько строк. В последние годы CMake стал практически стандартом для C++ библиотек. Поверх голого Цмейка мы разработали небольшой фреймворк (всего порядка 3000 строк). Есть конечно и исключения, как OpenSSL или V8, с которыми пришлось немного попотеть. Отдельные части движка оформлены в виде модулей. Основные возможности:
Модульность. Каждый модуль может иметь собственные ассеты (например, шейдеры) и может иметь зависимости от других модулей. Например, звук, UI, физика, сеть и т.п.

Немного особняком стоит модуль core, который является зависимостью для большинства других модулей. Конечное приложение на движке (игра, редактор, утилиты) подключает только те модули, которые ей необходимы. Наш фреймворк позволяет в несколько строк скачать git репозитарий или архив, распаковать, собрать, скопировать библиотеки и/или исходники. Core имплементирует точку входа, главный цикл приложения, взаимодействие с операционной системой и другие базовые сущности.
Thirdparty модули. На сегодняшний день у нас 66 таких thirdparty модулей: аналитика, сторонние файловые форматы, middleware вроде физики, звуковой библиотеки и т.п.

Процесс разработки

Учитывая предыдущий опыт, мы решили сложить и движок, и игру в один репозитарий. Это позволяет безболезненно вносить изменения в API движка и синхронно адаптировать под него игру. Получился так называемый монорепозитарий с его достоинствами и недостатками. Но, поскольку мы сразу планировали поддержать очень высокий темп разработки, возможность синхронного рефакторинга движка и игры перевесила все остальные недостатки данного решения.

Это означает, что мастер может быть потенциально сломан 20 раз в день. В среднем у нас добавляется более 20 пулл-реквестов в день. К чему же мы пришли? К счастью, еще в 1991-м году придумали технику Непрерывной интеграции (Continuous Integration).

Continuous Integration

Как сказано выше, для каждой задачи в форке разработчика создается бранч. Далее создается пулл-реквест из этого бранча в в основной репозитарий. Этот пулл-реквест проходит ряд автоматических тестов на Дженкинсе:

  1. Юнит-тесты под все платформы (windows, linux, macos, ios, android). В качестве основы используется googletest, а для проверки процента покрытия — OpenCppCoverage, отчет которого проверяется дополнительным питон-скриптом. Если процент покрытия конкретного файла меньше 75%, тест считается проваленным. Таким образом у нас покрыта тестами большая часть низкоуровневых классов движка.
  2. Codeformatter. Для C++ кода используем clang-format. Форматирование измененного кода сначала автоматически происходит при коммите на машине разработчика, а потом проверяется в тесте. Для джаваскрипта, который используется у нас в качестве скриптового языка, используется npm linter.
  3. Тесты ассетов. Довольно большая группа тестов: от валидации форматов файлов до проверки зависимостей (например, проверка, что текстура, используемая в игровом уровне, действительно существует).
  4. Юнит- и функциональные тесты редактора. Неотъемлемой частью движка является редактор, где создаются и редактируются игровые уровни и прочие ассеты. Кроме юнит-тестов, для тестирования редактора используется froglogic Squish for Qt — утилита для автоматического GUI тестирования. Все это позволяет нам обходиться вообще без ручного тестирования редактора. При этом, по отзывам художников и левелдизайнеров, уровень его качества и стабильности выше, чем в прошлой компании, когда у нас была команда из пяти тестеров. При этом релизы происходят ежедневно, а при ручном тестировании релизы происходили раз в 2 недели.
  5. Функциональные тесты игры. Понятно, что автоматическое функциональные тесты хочется использовать и для игры. Поэтому мы начали разработку следующей системы:

  • тестовое приложение (конкретно — скрипт на питоне) запускает игровые сервер и клиент с определенными параметрами
  • запущенные сервер и клиент открывают сетевой порт,
  • тестовое приложение подключается к ним и посылает команды: загрузить карту, выбрать персонажа и оружие, переместиться в точку, прицелиться, выстрелить и т.п.
  • сам синтаксис тестов — питоновский pytest. Эта система сейчас находится в активной разработке.

Большинство проектов для тестов собираются с включенным флагом «treat warnings as errors», а на платформе MacOS с дополнительно включенным clang AddressSanitizer, что позволяет отлавливать еще больше ошибок на этапе подготовки пулл-реквеста.

Когда все тесты пройдены и у ревьюверов нет замечаний, пуллреквест автоматически вмерживается.
Поскольку некоторые тесты могут занимать значительное время (например, полный GUI тест редактора длится более часа), в пулл-реквестах используется сокращенный сценарий. Кроме тестов, каждый пулл-реквест проходит ревью как минимум двумя другими разработчиками и, в случае необходимости, отправляется на доработку. Полный же набор тестов запускается в мастере каждые 4 часа.

На сегодняшний день так создано и вмержено уже 6600 пуллреквестов.

Continuous Delivery

Мы используем концепцию автоматических ежедневных (а точнее еженочных) релизов. Как именно это происходит:

  1. создается git tag,
  2. в нем запускаются полные версии всех тестов,
  3. в случае успеха собираются артефакты:

  • редакторы для MacOS и Windows. Таким образом, каждое утро у всех есть свежая версия инструментов. И, благодаря автоматическим тестам, мы уверены в их определенном качестве и стабильности.
  • игровые клиент и сервер для всех платформ. Клиент для iOS заливается в TestFlight, для Android — в Google Play, остальные платформы — в JFrog Artifactory, игровые сервера и прочие сервисы — в облако. То есть каждое утро у нас есть свежая версия игры, готовая для тестирования и плейтестов.

Конечно, не каждый ночной релиз заканчивается успешно. Какие-то тесты могут не пройти, или на запуске приложения возникнет критическая ошибка. В этом случае найденные проблемы чинятся дежурным разработчиком в течение дня и процесс релиза запускается заново.
Дежурных каждый день несколько:

  1. Дежурный 1го уровня. Следит за стабильностью тестов в главном репозитарии.
  2. Дежурный 2го уровня по игре. Чинит игровые баги.
  3. Дежурный 2го уровня по редакторам. Чинит редакторные баги, консультирует пользователей (художников, левелдизайнеров, геймдизайнеров).

Также в день дежурства можно заниматься техническим долгом: дописать недостающие тесты на старую функциональность, дополнить документацию, или сделать рефакторинг, на который не находится времени при обычном планировании релизов.

В следующей статье мы подробнее рассмотрим программную архитектуру самого движка, а также основные модули и подсистемы.

Продолжение следует…

Первая часть: habr.com/ru/post/461623
Сайт игры

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть