Какие технологии, процессы и решения мы используем при разработке на Unreal Engine 4 — опыт Allods Team

Время на прочтение

Всем привет, меня зовут Виктор Щепкин, я руководитель проекта в Allods Team. В этом тексте я расскажу, как мы искали рабочий мессенджер и в итоге остановились на Discord. Также опишу, как устроен наш сервер, и поделюсь подробным описанием функций, которые мы используем.

Всем привет, меня зовут Алексей Капустин, я старший программист в Allods Team. В этой статье я расскажу о серверной архитектуре Warface — как она устроена изнутри, как мы пришли к кроссплатформенному мультиплееру, про метагейм, масштабирование и многое другое.

Warface — онлайн f2p-шутер, который доступен на основных игровых платформах

Оглавление

Общие особенности

Realm обладает высокой отказоустойчивостью. Если начнут падать сервера метагейм-логики, то игроков будет переключать на другие сервисы. Если откажут некоторые другие сервисы, то игрок скорее всего этого не заметит.

Также у Realm достаточно высокая нагрузкоустойчивость. То есть мы можем запускать много серверов нашей метагейм-логики, не испытывая трудностей. Однако есть несколько точек отказа — если падает Jabber и база, то у нас ничего не работает.

У проекта большая кодовая база. Только серверная часть занимает более 400 тысяч строчек кода. Проекты для всех платформ мы собираем из одного большого монорепозитория.

Всем привет, меня зовут Виктор Щепкин, я работаю Team Lead’ом в Allods Team, которая входит в состав MY.GAMES и уже насчитывает целых 14 студий. В этом тексте я расскажу про особенности работы с Unreal Engine, а также подробно опишу, какие решения и процессы мы используем при разработке проектов:

Отдельно хочу отметить cross-sharing технических решений. Сейчас в Allods Team ведется активная разработка нескольких проектов на Unreal Engine, поэтому мы всегда заинтересованы в том, чтобы не только обмениваться опытом, но и делиться конкретными техническими решениями, которые появились в ходе работы над проектами. Это значительно упрощает процесс самой разработки и экономит ресурсы.

Все, что я расскажу ниже — это исключительно наш личный опыт, а когда речь идет о личном опыте, то всегда можно найти, что можно улучшить или с чем-то поспорить. Поэтому не стесняйтесь писать свои мысли и предложения в комментариях, я с радостью почитаю про вашу практику, а также отвечу на ваши вопросы.

Запреты и отмены сразу сказываются на игровом рынке. После того, как российским игрокам воздвигли препоны, в частности, в покупке игр в Steam и оплате подписки World of Warcraft, рекордно выросла посещаемость в доступных играх.

Создатели «Аллодов Онлайн» на днях сообщили, что онлайн на единственном подписочном сервере «Нить Судьбы» побил рекорд за всё время с момента его запуска в 2013 году. Компания не назвала точные цифры, но объявила, что посещаемость выросла в 80 раз. На сервере даже начали появляться очереди.

Чтобы справиться с резким ростом спроса, Allods Team открыла премиум-сервер «Звезда Удачи», а за ним — ещё один платный сервер, «Приют». Но этого оказалось мало, очереди начинают собираться уже на них. И сегодня разработчики объявили о запуске четвёртого подписочного сервера, «Звёздная Тропа».

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

Чтобы попасть на платный сервер, придётся оплатить подписку в размере 390 рублей в месяц. Новички могут воспользоваться пробным периодом в 14 дней.

Больше на Игромании

Команда Allods Team Arcade (входит в состав студии Allods Team) представила игру Blast Brigade vs. the Evil Legion of Dr. Cread. Это двухмерный сайд-скроллер с четырьмя героями и элементами платформера. Об этом сообщила пресс-служба компании MY.GAMES (входит в Mail.Ru Group), которой принадлежит студия Allods Team.

Сюжет Blast Brigade vs. the Evil Legion of Dr. Cread разработан в духе шпионских триллеров про Джеймса Бонда. Злодей доктор Кред, одержимый идеей мирового господства, захватывает остров и порабощает местное население, чтобы то трудилось на его заводе по созданию огромного боевого робота. Против Креда и предстоит выступить четырем героям с уникальными способностями.

https://youtube.com/watch?v=ruqc-bLTatU%3Ffeature%3Doembed

Так, американский спецназовец Джефф Дж. Джефферсон обладает способностью взрывать все подряд. Российская шпионка Александра Ворон избавляет от врагов с помощью снайперской винтовки. Шотландец Гэвин Генри Гейл пережил опыты Креда и наполовину стал роботом. А представительница коренного населения острова Вартаксаклахун Пакарнуста вооружена шакрамами.

Blast Brigade vs. the Evil Legion of Dr. Cread выйдет на PC, PS4, PS5, Xbox One, Xbox Series S/X и Switch. Дату релиза Allods Team Arcade назовёт позже.

Почему Discord

Наша команда присоединилась к Allods Team в начале 2021 года, а до этого мы были петербургской инди-студией OctoBox Interactive. В процессе становления нас как команды мы в том числе прошли через этап поиска командного мессенджера. Когда мы выбирали его, у нас было несколько требований.

В тот момент большинство команд использовали: Skype, Telegram, Slack.

Со Skype многие из нас уже были знакомы и в тот момент у него было очень много проблем — он мог подтормаживать, зависать и долго включаться. Что касается звонков — в нем достаточно сложно организовать групповой стихийный звонок: нужно добавить всех участников в контакты, организовать группу, потом менеджерить эти чаты и так далее.

У Telegram не было проблем с вылетами и тормозами, но у него были все те же трудности с групповыми звонками и многие использовали его в личных целях.

Slack вроде бы подходил по функциям, но мы были небольшой инди-командой, поэтому не могли позволить себе оплачивать платную версию. И там тоже были трудности с организацией групповых звонков. Поэтому от этого варианта мы тоже отказались.

Когда мы отмели эти варианты, то вспомнили про Discord. Некоторые из нас были с ним знакомы, но использовали его только для игр. Вот что привлекло нас в Discord.

Рассмотрим матчмейкинг

Мы используем один сервер под каждую уровневую группу — аналогично мастер-серверам. Но в отличие от них мы не умеем горизонтально масштабировать матчмейкинг — у нас по одному сервису на каждую уровневую группу.

Ранее матчмейкинг был написан на Python. Но это создавало проблемы с производительностью, особенно в часы пик, поэтому мы переписали на C#. Это ускорило матчмейкинг, уменьшило кодовую базу, а именно путем образования общей кодовой базы с мастер-серверами.

Также мы научились определять твинков игроков — пользователи иногда создают новые аккаунты и играют с новичками, что негативно сказывается на их опыте. Мы таких игроков распознаем, и если позволяет онлайн, ссылаем их в отдельную очередь. Если же условия не позволяют это сделать (например, ночью, когда игроков меньше), то мы отправляем их к новичкам. Мы поступаем так, потому что стараемся соблюдать баланс между временем сбора матча и качеством опыта игры. Никто не будет ждать 10-15 минут, пока матч соберется.

Также мы масштабируем матчмейкинг путем гейм-дизайна. Недавно Warface праздновал 10 лет, в честь этого мы запустили внутриигровой ивент: новый режим, карту, подарки и так далее. Под этот ивент мы сделали отдельный матчмейкинг — отдельную очередь, куда идут игроки. Это снижает нагрузку основных сервисов. Также мы используем отдельные инстансы матчмейкинга под различные сезонные режимы игры, например, под ранкед. Это дешевле, чем переписывать архитектуру, и незаметно для игроков.

Git

Как я ранее уже написал, мы используем Git Hook’и, и помимо клиентского хука для валидации данных, у нас множество различных серверных хуков. Вот описание некоторых из них:

Конечно же, в работе с Git мы активно используем ветки — любой разработчик может при необходимости создавать отдельные ветки и работать в них. Это особенно важно, когда речь идет о больших фичах, реализация которых изначально делается только в отдельных ветках — в них же периодически подмердживается основная ветка. А ветка под фичу попадает в основную только после проверки отделом QA.

Но есть еще один нюанс при работе команды над одним проектом в Unreal Engine: все файлы, которые мы видим в Content Browser (они являются частью проекта) — это, как правило, бинарные файлы. Что это значит для нас: если два разработчика будут одновременно работать над одним файлом, то у того, кто будет заливать свои изменения последним, обязательно произойдет конфликт. А поскольку файлы бинарные, то ему придется переделывать свою работу.

Ранее, года три-четыре назад, при работе с Git нам приходилось писать в специальный чатик, что ты забрал такой-то файл в работу и его лучше не трогать. И это было не очень удобно. Но прогресс не стоит на месте. Поскольку поверх Git у нас стоит Git LFS — мы активно используем систему локов (да-да-да, в Git LFS есть система локов файлов, которая очень похожа на таковую в Perforce.

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

При этом сама процедура лока и его снятия может быть выполнена через Git Bash или любой Git Client, поддерживающий эту функцию, а также через сам Unreal Engine при помощи Source Control Plugin.

Если хотите попробовать, то вот достаточно хорошее решение для работы в движке.

Самое главное в этом процессе — научить людей снимать локи, когда они заканчивают работу. Чтобы справиться с этим, мы применили автоматизацию: после коммита происходит автоматическое снятие лока.

Роли в Discord

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

Все начиналось с трех ролей: GD, Code, Art. А сейчас у их уже 17! Этот рост в первую очередь связан с увеличением количества людей в команде — в начале нас было 15 человек, а теперь на сервере в Discord 84 человека. Тут без грамотного распределения ролей не обойтись.

Мы разделяем роли пользователей на три категории.

Зачем под каждый отдел разработки иметь отдельную роль? Чтобы тэгать сразу всех, кто связан с определенным направлением работы в чатах. Также для разграничения по ролям мы используем иконки — это помогает быстро определить, чем занимается человек. Это особенно полезно при онбординге новых сотрудников, когда они еще не понимают, кто чем занимается.

CI/CD

Тут не будет каких-то открытий или ноу-хау, просто раз уж я говорю обо всем по чуть-чуть, то надо и по CI/CD немного пройтись. На самом деле я сконцентрируюсь преимущественно на CI. Для начала давайте освежим, что такое CI.

Continuous Integration подразумевает частые автоматизированные сборки проекта с целью быстрого выявления интеграционных проблем. У вас всегда будет актуальная и готовая к тестам версия продукта.

Для всего этого мы используем Jenkins. Сам процесс настройки Jenkins описывать не буду, но вот несколько вещей, которые советуем сделать первым делом.

1) Система нотификаций. Не важно, каким мессенджером вы пользуетесь, нотификации сильно облегчат вам жизнь! Сборка не собралась? Надо чинить. И чем быстрее мы это сделаем, тем лучше.

2) Использование Сommandlets как Build Step. Это набор дополнительных шагов-инструкций для сборок. Например: запекание света, расчет навигационного меша для AI.

Зачем нам нужны Сommandlets, если все это можно сделать в редакторе? Во-первых, не у всех есть мощное железо, чтобы посчитать что-то быстро. Во-вторых, ошибки иногда все же случаются, например, кто-то может забыть сохранить карту вместе с рассчитанным Nav Mesh.

Coding Standard

Прежде чем говорить о стандартизации кода, следует подчеркнуть, что у нас внутри работают независимые друг от друга команды, у каждой из которых есть своя история, свой опыт и набитые шишки, а соответственно, и свои стандарты. Но в основе этих подходов лежит общая стандартизация кода от Epic Games.

Выбор основного стандарта кода от Epic Games обусловлен тем, что мы не стали изобретать велосипед, а применили существующий стандарт, с которым каждый день встречаются разработчики на Unreal Engine. За счет этого при найме новых сотрудников у нас нет необходимости переучивать их на наш уникальный стандарт. Но если кто-то не знает стандартизации кода от Epic Games, то он быстро этому обучится, потому что будет встречать его 90% времени (стоит учитывать, что Epic Games в исходниках движка не везде соблюдает свои же стандарты — все же они такие же разработчики, как и мы с вами, и им тоже не всегда хватает времени на вычитку).

Кроме того, если вы пишете собственный стандарт кода, то, скорее всего, его будет сложно использовать, потому что он далеко не всегда будет устраивать всех разработчиков в разных командах. Лучше брать что-то более обобщенное, что уже было придумано до вас.

Что касается документации самого стандарта, то в качестве основы мы используем документацию от Epic Games, но в разных командах есть незначительные отличия в виде расширений или улучшений. Я крайне не советую все это переносить в свою документацию по следующим причинам:

Вместо этого в качестве документации мы используем код, хранящийся в отдельном плагине, который содержит в себе Unreal Engine Module и ассеты. Ассеты содержатся в виде блюпринтов, в которых также находится описание стандартизации кода — это важно, потому что стандартизация кода блюпринтов никак не должна отличаться от обычных стандартов, которые используются при разработке на C++ в Unreal Engine.

Такой подход лучше всего проявил себя при код-ревью, потому что у нас больше нет необходимости кидать ссылку на документацию и заставлять сотрудника что-то там искать — нам достаточно указать на строчку кода в CodingStandard.h или CodingStandard.cpp.

У разных команд есть отличия в стандартах, но они не слишком сильные:

Data Standard

Мы считаем, что если есть стандартизация кода, то должна быть и стандартизация данных (ассетов). Но речь идет не о блюпринтах — для них у нас есть Coding Standard. В стандартизацию данных входят следующие вещи:

В случае со стандартизацией данных у Epic Games нет конкретного стандарта, а есть лишь набор рекомендаций, да и те разбросы по множеству статей в документации. И здесь на помощь приходит комьюнити, которое по большей части решило проблему.

Но вот в отличие от Coding Standard, Data Standard у нас задокументирован в Сonfluence — по этой причине Data Standard сильно зависит от проекта и может меняться под него. Да, есть некоторые общие вещи, которые всегда будут похожи у разных проектов, но все-таки большая часть стандартов всегда будет отличаться. Вот некоторые примеры:

Устройство нашей архитектуры

Вот как устроена наша архитектура. Есть клиент игры, запущенный на одной из платформ. После запуска он идет к сервису выбора Realm, тот отдает ему список Ejabberd кластеров. После этого пользователь выбирает, к какому кластеру подключиться. Сейчас на проде мы отключили эту возможность, так как все свели в один Realm. Но для целей разработки удобно использовать список Realms, так как после запуска клиента мы можем выбрать, к какому стенду подключиться. На Xbox все устроено чуть сложнее, но об этом расскажу ближе к концу.

Мы используем Jabber для общения с нашим метагейм бэкендом, для статусов, для чатов — в целом для всего, в чем он хорош. Но у Jabber есть проблемы с безопасностью, особенно в неактуальных версиях. В частности, он не слишком устойчив к атакам Man-in-the-Middle. Поэтому мы используем запатченный Jabber. Jabber написан на Erlang — найти на рынке шарписта со знанием этого языка достаточно сложно.

Но не все общение с серверами происходит через Jabber — это было бы слишком медленно. В игровой сессии происходит общение с Dedicated сервером (он же дедик). Дедики запускаются по всему миру, чтобы расстояние между ними и игроками было меньше — для уменьшения пинга, для создания приятного игрового опыта.

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

Предположим, у игрока пинг около 100 миллисекунд — это стандартное значение. Запрос уходит на дедик, возвращается, и в результате проходит 200 миллисекунд (время на просчет опустим). Спустя 200 миллисекунд можно отобразить информацию о совершенном действии. Это долго — игра будет выглядеть лагающей, игроки будут ругаться. Поэтому мы используем механизмы компенсации задержки.

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

Мы используем один дедик на одну игровую сессию. Пробовали переиспользовать на много сессий, но столкнулись с проблемами, что игровой мир после завершения сессии не до конца очищает свой стейт и частично сохраняет его между сессиями. А это нам не нужно. И несмотря на оверхед на запуск и завершение работы сервера, мы решили запускать один дедик на одну игру.

Но вернемся к метагейму. После того, как сообщение пришло на Jabber, оно уходит на наш Realm, где считается метагейм-логика, логика обсчета.

Рассмотрим архитектуру Realm. У нас есть сервера метагейм-логики, матчмейкинга, набор web-сервисов и специфических консольных сервисов. Сервисы между собой общаются через Rabbit, база данных — mysql, с кэшем Memcached.

Особенность геймдева в том, что количество запросов на чтение и запись зачастую сравнимо. Использование кэша в таких условиях вызывает вопросы, поэтому стараемся использовать кэш только на запросы с очевидным преобладанием чтений. Например, для чтения игровых ресурсов, параметров из базы данных. Для управления сервисами используем самописную систему, которая умеет запускать, поднимать, деплоить, мониторить сервисы и так далее.

Наши сервера метагейм-логики написаны на C#, .NET 5. Сервера матчмейкинга — аналогично. Для более мелких сервисов используем Python и Go.

Для разработки новых сервисов используем следующую идеологию. Если знаем, что сервис получится большим, с большим количеством логики (более 1-1,5 тысяч строчек кода), то мы используем C#. Если знаем, что сервис будет маленький (на несколько сотен строчек кода), используем Golang.

На изображении выше зеленым выделены блоки, которые мы умеем масштабировать. Рассказывать про масштабирование Jabber не так интересно, потому что он умеет масштабироваться из коробки. Поэтому сфокусируюсь на масштабировании серверов метагейм-логики и матчмейкинга.

Мы распределяем игроков между серверами на основании режима игры, уровня, загруженности серверов. Игрок приходит на наш Jabber, он смотрит на список серверов, подходящих этому пользователю, определяет наименее загруженный и отправляет его туда. Игрок при этом может находиться в состоянии подключения только к одному такому серверу.

Сейчас есть три основные уровневые группы игроков: новички, средние и профессионалы. И пользователи с разных уровневых групп не могут играть между собой. Иногда это создает неприятные казусы. Например, игроки 25 и 26 уровня не могут играть вместе, а игроки 26 и 27 уровня могут без проблем. То есть мы запускаем много инстансов таких серверов.

В целом для игрока характерна регулярная смена сервера. При разработке важно это учитывать, чтобы избегать багов и неприятных «гонок». Например, сервер выполняет тяжелую нетранзакционную операцию, состоящую из нескольких этапов. В середине операции игрок переключается на другой сервер. В результате операция продолжает выполняться на старом сервере, а игрок уже находится на другом.

Из этого можно сделать вывод, что по возможности не надо совершать нетранзакционные операции. Но если это необходимо, не жалейте оверхеда на дополнительную валидацию. Это позволит избежать неприятных, редких и трудноотлавливаемых багов.

Data Validation

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

1) Соответствие данных актуальным стандартам:

2) Данные, хранящиеся в репозитории, должны быть валидными — то есть не содержать ошибок или предупреждений.

3) «Эффект бабочки» — это явление, при котором мельчайшие изменения в одном файле могут повлечь проблемы в других связанных файлах.

Для валидации данных у Epic Games уже есть готовое решение (даже несколько) в виде Data Validation Plugin. Подробнее об этом и о том, что мы валидируем, вы сможете прочитать в нашей следующей статье, которая выйдет в ближайшее время, а пока пройдемся только по ключевым местам.

Прежде всего мы валидируем:

Сам процесс валидации данных запускается при помощи клиентского Git Hook — он запускает сommandlet, который проверяет каждый файл, указанный в коммите.

Source Code/Data Management

Все проектные данные хранятся в двух различных репозиториях:

Почему мы в Allods Team используем Git, а не Perforce? К сожалению, у меня нет конкретного ответа — так исторически сложилось что ли. Но я успел поработать с Perforce в рамках разработки проекта на Unreal Engine и вот мое личное мнение: что Git не очень справляется со всеми возложенными на него задачами (речь идет именно о работе в связке с Unreal Engine), что Perforce не огонек. К сожалению, серебряную пулю никто так и не сделал (ну или я не в курсе), везде есть свои плюсы и минусы. Единственное, чем Perforce подкупает — это готовые технические решения от Epic Games. Но даже сейчас все это легко перекрывается отличными Open Source решениями.

Интересное наблюдение: все чаще и чаще слышу о том, что часть разработчиков перебирается на Plastic SCM. Я с ним не работал, поэтому если у вас есть опыт взаимодействия, делитесь им в комментариях, очень интересно почитать.

Теперь про SVN — художникам с ним проще работать (да и большинство художников только с ним и работали). Но на этот счет у нас в команде есть правило: любой художник, работающий над проектом, должен знать хотя бы основы Git — pull/push/branch и кого звать, когда происходит конфликт.

Зачем художникам все это? Художники (тут речь больше о 3D Artist’ах, художниках по текстурам, иногда о UI Artist’ах и так далее) отвечают за свой контент от самого начала разработки до полной интеграции контента в проект, поэтому им нужно знать Git. Конечно, у нас есть технический художник, который занимается интеграцией и автоматизацией этих процессов, но дело не в этом — художникам нужно понимать и видеть, как их работа выглядит в самом проекте после того, как применяются постпроцессы и шейдинг. Поэтому достаточно важно, чтобы художники самостоятельно умели интегрировать в проект свои наработки, в том числе и заливать их (порой даже в свои экспериментальные ветки).

Ну и вторым плюсом является более простой sparse checkout: когда нужна конкретная папка, можно достать только ее (ну и контент в ней), а не выкачивать весь репозиторий разом. У нас даже есть пример того, когда это может пригодиться. Допустим, у кого-то из Allods Team появилась задача посмотреть старые артовые наработки Skyforge, а все они весят 4 Тб. Если бы они были в Git, то пришлось бы качать все 4 Тб, что заняло бы примерно неделю. Откуда я знаю, сколько времени на это уйдет? Как-то раз пришлось скачивать полностью все исходники.

По этой причине арт у нас в SVN, а проект — в Git.

Автотесты

Это самая грустная часть моего текста, потому что автотесты у нас есть, но далеко не на все. Основная трудность в том, что при разработке фичи, написание качественного автотеста с хорошим покрытием всех сценариев занимает 60-70% времени от создания самой фичи. И как правило, автотесты пишут сами программисты, потому что QA, знающие Gauntlet или просто Unreal Engine в контексте разработки автотестов, очень редки. А бизнес суров, порой сложно объяснить ценность автотестов в сравнении с какой-нибудь новой игровой механикой.

Но у каждого проекта есть две части, которые обязательно нужно покрыть автотестированием — это backend и все, что связано с экономикой (в том числе и монетизация)! Без автотестов backend’a и экономики вы сильно рискуете в один прекрасный день увидеть свой сервис на сервере просто мертвым и с испорченными данными. Это в лучшем случае, а в худшем — понесете финансовые потери.

Поэтому собирайте отдельную команду из QA, которая будет писать автотесты для backend’a, потому что там слишком много кейсов, которые обычным ручным тестированием покрыть невозможно!

Как и говорилось ранее, прогресс не стоит на месте, а вместе с ним и мы! Мы продолжаем дальше набираться опыта и совершенствоваться, в наших планах разработка и интеграция следующих интересных вещей, о которых я расскажу в будущем:

И это лишь малая часть того, что мы разрабатываем для работы с проектами. Еще осталось много того, о чем хотелось бы рассказать, но что не уместилось в рамках этой статьи. Вот некоторые из тем:

Если что-то из этого вам интересно, то пишите в комментариях — наиболее востребованная тема отправится в печать первой. Ну а в остальном, спасибо всем за внимание, до новых встреч!

Дополнительные функции, которые мы используем

Треды работают примерно как в Slack — если нужно обсудить вопрос, мы создаем тред под изначальным сообщением, а не пишем в канал.

Ивенты

Это отличная функция, с помощью которой можно создавать события прямо в Discord, а не в календаре. Если участник нажмет кнопку «Заинтересован», то ему автоматически придет уведомление в Discord, когда событие начнется.

Боты

Сейчас мы пользуемся одним, а еще один в стадии активной разработки.

Jenkins — бот для работы с билдером.

Вот так выглядят сообщения, которые присылает бот

Второй бот, который находится в разработке — это статус-бот. Он должен заменить чаты, в которых сотрудники отчитываются о собственном состоянии. Если сотрудник собирается, например, отойти на обед, то ему достаточно нажать на одну кнопку в этом боте, а тот автоматически задаст статус.

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

На мой взгляд, Discord — это самый оптимальный вариант мессенджера: он не только стабильно работает, но и предоставляет все необходимые функции. Кроме того, его можно подстраивать под свои нужды, добавляя ботов и расширяя функциональность.

Unreal Engine Modules и Plugins

Мы считаем, что при работе с Unreal Engine можно и нужно придерживаться модульности: вместо того, чтобы проект состоял только лишь из одного основного модуля, мы стремимся использовать множество независимых системных модулей — это позволяет формировать наши проекты по принципу конструктора, состоящего из системных модулей, что помогает нам легко переносить целые фичи из проекта в проект.

Чтобы достичь модульности, мы используем возможности, которые нам предоставляет Unreal Engine:

Unreal Engine Modules мы используем в случаях, когда вся логика может храниться в одном модуле. Например, наш Character Stats System Module представляет собой базовый набор атрибутов GAS’a, компонентов для работы с ними, а также набор вспомогательных функций, который мы используем при реализации базового представления персонажа, его характеристик и боевой системы.

Важно учитывать, что Unreal Engine Modules, которые мы разрабатываем и которые находятся в проекте, могут зависеть только от движка и от плагинов, но ни в коем случае не друг от друга! Такие зависимые вещи должны находиться в Unreal Engine Module самого проекта.

А вот плагины мы используем в случаях, когда речь идет о разработке более комплексных фичей, которые сложно уместить в один Unreal Engine Module. Или же когда фича, помимо самого Unreal Engine Module, содержит в себе какой-либо контент. Например, наш Compass Plugin — это плагин, состоящий из Compass Module, в котором находится реализация поведения игрового компаса, а также из Widget, который является базовым UI-представлением компаса. Этот Widget можно использовать на этапе прототипирования как готовое решение из коробки, а в последующем как шаблон для реализации своего уникального UI-представления.

Модульный подход лежит в корне cross-sharing’a технических решений между проектами, поскольку мы можем использовать готовую фичу на другом проекте. И при необходимости мы улучшаем и расширяем наши наработки. Таким образом, мы существенно экономим время и ресурсы при разработке и прототипировании проектов.

Каналы

Для начала важно сказать, что категории каналов — это не внутреннее разделение, как это было с ролями, а полноценная фича Discord, при помощи которой можно группировать текстовые и голосовые каналы вместе. При этом права доступа можно настроить сразу для всей категории, что помогает в работе с большим количеством каналов — достаточно выделить сразу целую категорию и внести какое-то изменение, а не выбирать все по одному.

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

Что же касается наших каналов.

Первое, что встречает нового пользователя — это 🤝 welcome канал.

После получения первого набора прав, он может зайти на наш сервер.

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

Следующая категория каналов — Report.

В них отделы отчитываются, что сделали за определенный промежуток времени. Одно сообщение — один отчет (за день, период, неделю), а все вопросы по конкретному отчету можно обсудить в ветках.

Эти каналы нужны для прозрачности — они помогают людям из разных отделов понимать, что происходит в других командах, и как двигается разработка проекта.

Третья категория — DEV, которая полностью посвящена разработке проекта.

С аудио-каналами все устроено подобным образом:

Разговоры на нерабочие темы мы ведем в Off-Dev категории.

Также у нас есть отдельные категории под каждую нашу студию-партнера, которые находится на нашем проектном сервере Discord.

Особенности работы с консолями

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

Например, у метода получения баланса на различных платформах будет разная имплементация — на ПК одна, на PlayStation вторая, на Xbox третья. Но сама идея и возвращаемый результат будет одинаковым. Поэтому на старте сервера мы определяем набор запускаемых сервисов и подставляем конкретную имплементацию. В этом помогает библиотека Ninject — удобный Dependency Injector.

Но так было до 2021 года — после мы решили объединить все консольные сервера в один большой, чтобы у игроков был кроссплатформенный мультиплеер. При разработке консольного сервиса руководствовались аналогичными принципами.

Еще у нас есть несколько консольных сервисов, которые не слишком вписываются в логику общего метагейма. Поэтому они сделаны отдельно. Рассмотрим парочку из них.

Microsoft в требованиях сертификации игр указывает, что для общения с нашим сервером должна использоваться исключительно их имплементация web-сокетов. А для других платформ мы используем TCP. Но все это было для нас неудобно — мы не хотели переписывать сервер, делать костыли, поэтому разработали отдельный сервис, к которому подключаются игроки с Xbox. Этот сервис перекладывает данные с web-сокет коннекшена в обычный TCP-коннекшен. И данные с TCP-коннекшена текут на Ejabberd, а дальше все происходит как на других платформах.

Для клиентской библиотеки мы используем Gloox. Из коробки он не умеет работать с Microsoft-сокетами. Нам пришлось его пропатчить, чтобы он мог это делать.

Такие специфические платформенные сервисы встречаются редко. Обычно мы стараемся делать универсальный сервис под все платформы, даже несмотря на их особенности. К примеру, у нас есть сервис «Кошелек» — он отвечает за взаимодействие с консольными сторами. То есть он получает список паков, умеет их продавать, отвечает за рефанды. Кстати, рефанды есть на всех платформах, даже несмотря на то, что платформодержатели и документация заявляют обратное — например, возвраты зачастую оформляет служба поддержки.

С API сторов иногда возникают проблемы, несмотря на то, что ими занимаются крупные компании (Microsoft, Sony, Nintendo). Не так давно была история, когда API одной из платформ сломалась — после определенной последовательности действий у игроков возникали безлимитные деньги. Пользователи обнаружили это и накупили предметов на много миллиардов внутриигровой валюты. Все это происходило глубокой ночью, поэтому мы не сразу заметили. Потом мы с трудом искали этих игроков и отнимали купленное. Но это стало для нас уроком. И теперь мы не так слепо верим таким API — если подобное повторится, то мы будем готовы.

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

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

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

Понравилась статья? Поделиться с друзьями:
ТВОЙ ВК
Добавить комментарий