Автар dex35
dex35
Разработка, 3d печать, игры

FiveWars - как мой перфекционизм погубил интересный проект в GTA V

В 2018 году я познакомился с RAGE MP и, недолго думая, взялся за очередной GTA-проект.

Реализовав классический TDM режим, вспомнил про фичу реализованную для SVO Clan в 2018 году - тогда ребята активно участвовали в ClanWars турнирах и было не всегда удобно мониторить статистику матчей вне дома.

Я реализовал простенький PHP-скрипт, который запускался по cron заданию, запрашивал информацию о сервере из мастер-листа SA:MP, генерировал изображение и публиковал в обложку группы ВК - это была крутая фича в те времена.

Обложка публикации

Из этого воспоминания вытекло несколько мыслей и немного додумав я определился со списком ключевых фич:

  • Удобная возможность конфигурировать матч
  • Возможность отслеживать процесс матча
  • Сбор статистики игроков и кланов
  • Матчмейкинг
  • Турниры

Стек выбрал тот, на котором работал в тот момент: Vue.js, Node.js, PHP, Redis, MySQL, дополнительно вооружился Electron для desktop клиента.

Определившись с ключевыми фичами, я решил стартовать разработку.

Игровой сервер

В TDM версии проекта, конфигурация матча хранилась в json файле, рядом с бинарником сервера - она читалась при запуске и настраивала игровой процесс.

Распределение по командам было на совести самих игроков.

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

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

Если команды не собирались, по истечении КД сервер посылал запрос об отмене матча и выключался в штатном режиме.

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

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

Что забавно: при подключении к игровому серверу достаточно было указать в RAGE MP клиенте никнейм, который игрок вводил при регистрации на сайте. Если в лобби такой игрок был, сервер пропускал его в игру.

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

Бэкенд

бэкенд был реализован в виде монолитного API-сервиса на Laravel с разделением на отдельные точки входа и RBAC моделью для пользователей состоящей из 5 ролей:

  • Администратор
  • Модератор
  • Тестировщик
  • Редактор карт
  • Пользователь

Игровые серверы

Серверы передавали информацию в ручки server/v1/*, например старт/завершение раунда, вход/выход игрока и т.д., используя персонализированные ключи для авторизации.

Клиент

Пользователи аутентифицировались по паре почта + пароль, получая JWT токен, в дальнейшем передавая его в ручки client/v1/* для авторизации, а доступ к функционалу определялся RBAC моделью. Дополнительно, существовала ABAC модель в рамках кланов - была возможность создать роль и назначить ей определенные скоупы (привилегии), например: кикнуть или пригласить игрока в клан.

Редактор карт

Редактор авторизовывался по персональному ключу и обращался к ручкам editor/v1/*, а при подключении игрока к редактору, проверялись роли игрока на наличие "редактор карт".

Менеджер серверов

Маленький сервис на nodejs, стоявший на той же VPS машинке, где запускались игровые серверы.

Выполнял несколько задач:

  1. Обновлял бинарники игрового сервера и игрового режима по запросу
  2. Запрашивал у основного бэкенда перечень лобби готовых к запуску
  3. Клонировал игровой сервер создавая конфигурацию лобби
  4. Запускал новые инстансы игрового сервера используя pm2

Клиент

Клиент перерабатывался несколько раз и это была настоящая проблема проекта. Первая версия была приложением на Electron + Vue.js. К сожалению скриншотов первой версии я не нашел, поэтому показываю одну из последних Electron версий.

Клиент покрывал следующие задачи:

  • Аутентификация/регистрация игрока
  • Просмотр статистики игрока
  • Создание и управление кланом
  • Управление игроками клана, ранговая система
  • Просмотр статистики клана и игроков
  • Просмотр истории матчей клана и игрока
  • Создание матчей, просмотр матчей

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

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

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

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

Панель администратора

Админка была реализована частью бэкенд-сервиса используя Sleeping Owl над Laravel. В первую очередь использовалась для управления контентом, разбора жалоб от игроков, управления картами, паками карт, оружием и т.д.

Выдать бан, назначить роль игроку и прочее, описывать не буду - стандартные фичи.

Из действительно интересного было управления картами, с возможностью посмотреть карту на 2d схеме, посмотреть версии и по необходимости откатить до нужной.

Панель администратора

Редактор карт

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

  • /arena [name] - создать карту
  • /larena [name] - загрузить карту
  • /spawn [attack/defence] - установить точку спауна команды
  • etc. Карты хранились в файлах формата json, прямо в директории сервера.

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

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

  • Создать/отредактировать/удалить карту
  • Изменить название, описание
  • Разметить границы
  • Разметить спауны команд атаки и защиты
  • Расставить камеры, которые проигрываются на старте раунда
  • Сделать скриншот-превью с одной из камер
  • Выбрать погоду и время

Интересный факт - редактор карт до сих пор используется на благо Epsilon Play.

Финальная архитектура проекта

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

Архитектура проекта

Итог

Проект был закрыт в сентябре 2023, потому что мой перфекционизм сыграл злую шутку: лучшее - враг хорошего.

Я несколько раз переписывал клиент, сначала он был на Electron + Vue.js, затем на Nuxt, затем Nuxt + PWA, несколько раз менял его дизайн и часть ключевых фич.

Игровой TDM режим так же бесконечно дорабатывался, а финальным аккордом стала идея запустить игровой режим в формате Counter Strike а затем еще и перевезти на alt:V, все это тянулось довольно долго из-за непостоянной занятости проектом и желанием все сделать идеально, а в итоге проект закрылся.

Закончился ли мой путь в GTA? Нет - сейчас по мере возможностей пилю фичи для Epsilon Play, который недавно перевез с alt:V на FiveM, но это отдельная история.

P.S.

Полноценный матчмейкинг и систему турниров я так и не реализовал, а жаль, это интересные фичи.

Помимо Team DeathMatch режима, я планировал и другие игровые режимы, например Capture The Flag. И даже была мысль реализовать sdk для сторонних разработчиков с возможностью интеграции игровых режимов от коммьюнити в проект.

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