Серия «Автостопом по мультиплееру»

4

Автостопом по мультиплееру. Часть 3: Клиент и Сервер

Дословно про Server

Дословно про Server

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

Сервер

В сильно общем смысле:

Сервер – это вычислительная единица, которая выполняет определенные сервисные функции.

Какие могут быть функции:
- хранение данных;
- обработка запросов;
- управление сетевыми ресурсами;
- и пр.

В зависимости от своих функций серверы могут быть разных типов:
- файловые серверы;
- веб-серверы;
- DNS-серверы;
- почтовые серверы;
- и пр.

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

"Агрегатные состояния" сервера:
- отдельный компьютер, настроенный на выполнение своих функций;
- виртуальная машина, эмулирующая отдельный компьютер;
- контейнер, выполняющий серверные функции;
- серверное приложение, запущенное на настроенном для этого компьютере.

Схема первых трёх "агрегатных состояний"

Схема первых трёх "агрегатных состояний"

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

В геймдеве есть и набор наиболее часто используемых типов серверов.

Мета-сервер

Самый распространённый вид сервера. Многие игры вовсе ограничиваются только им. А какие-то и не используют совсем.

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

Упрощённая схема взаимодействия с мета-сервером

Упрощённая схема взаимодействия с мета-сервером

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

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

Профиль-сервер

Профиль-сервер предназначен для хранения и управления данными игроков.

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

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

Варианты реализации:
- отдельный сервер или сервис, с которым общаются через мета-сервер;
- отдельный сервер или сервис, с которым общаются клиенты напрямую (если нет мета-сервера);
- ответственность мета-сервера непосредственно.

Упрощённая схема взаимодействия с профиль-сервером без мета-сервера

Упрощённая схема взаимодействия с профиль-сервером без мета-сервера

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

Игровой сервер предназначен для обеспечения мультиплеерного взаимодействия.

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

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

Функции игрового сервера:
- обработка данных, полученных от клиентов;
- передача полученных данных другим игрокам;
- обеспечение синхронизации игрового процесса;
- управление логикой игрового процесса;
- обеспечение защиты от мошенничества;
- управления правами доступа игроков;
- хранение состояния игры;
- ведение статистики;
- и пр.

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

Когда MMO-игры предлагают выбрать сервер, они предлагают выбрать именно игровой сервер, на котором поддерживается долгая игровая сессия, рассчитанная на большое кол-во игроков.

Выбор сервера в World of Warcraft

Выбор сервера в World of Warcraft

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

Игровая сессия в Counter Strike

Игровая сессия в Counter Strike

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

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

Мастер-сервер

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

Функции мастер-сервера:
- получение от активных игровых серверов специальных сигналов с информацией — heartbeat;
- формирование и хранение списков активных серверов по различным параметрам: режимы, карты, модификации и пр;
- мониторинг игровых серверов, отслеживание их заполненности и доступности;
- выдача списка доступных серверов по запросу клиентам или мета-серверу;
- создание и запуск новых игровых серверов.

Варианты реализации:
- отдельный сервер или сервис, с которым общаются через мета-сервер;
- отдельный сервер или сервис, с которым общаются клиенты напрямую (если нет мета-сервера);
- ответственность мета-сервера непосредственно.

Упрощённая схема взаимодействия с мастер-сервером без мета-сервера

Упрощённая схема взаимодействия с мастер-сервером без мета-сервера

Клиент

Клиент – это сама игра на устройстве пользователя.

Основные функции клиента (в контексте мультиплеера):
- получение ввода от пользователя;
- обработка полученных данных;
- передача данных серверу и/или другим клиентам;
- получение и обработка ответов от сервера и/или других клиентов;
- рендеринг игрового процесса на основе актуальных игровых данных.

В некотором общем смысле, если использовать термины MVP:

  • Сервер: это Model (владеет данными игры и реализует бизнес-логику).

  • Клиент: это View (получает инпут и рендерит игру) и Presenter (обрабатывает инпут, взаимодействует с моделью и обновляет представление).

В синглплеерных режимах/играх вся тройка MVP находится на одном узле – на клиенте.

Схема клиент-серверного взаимодействия в терминах MVP

Схема клиент-серверного взаимодействия в терминах MVP

Почему именно модель уходит на сервер:

  • На сервере нет необходимости что-то рендерить.

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

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

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

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

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

Синхронизация данных на клиенте

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

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

Упрощённая схема подключения клиентов к серверу

Упрощённая схема подключения клиентов к серверу

Для компенсации задержек используется масса всяких приёмов (подробнее – в следующих статьях). Из-за этого в реальности описанные выше MVP-границы разделения ответственностей часто размываются:

  • Где-то клиенты имеют копию серверной бизнес-логики для локальной симуляции и быстрой реакции на инпут игрока.

  • Где-то сервер пытается действовать наперёд, заранее предсказывая и имитируя инпут игрока.

  • Где-то только наиболее важная определённая для геймплея часть данных считается достоверной и управляется сервером, а оставшиеся данные обрабатывают в своих локальных моделях сами клиенты.
    (это про авторитет над данными, об этом – позже)

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

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

Если какой-то элемент игры не влияет на геймплей, то не страшно, если у каких-то игроков его состояние не синхронизируется вовремя и корректно.

Пример: какое-нибудь падающее от взрыва дерево, которое не создаёт коллизий с игроками, может упасть позже или раньше, правее или левее – на геймплей это не повлияет, только на визуальный опыт.

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

Реализация Клиента и Сервера

Образно, что из себя представляет сервер, а что клиент, обсудили. Теперь обсудим, что они из себя представляют в плане реализации. Я знаком с двумя вариантами.

Клиент и Сервер – отдельные проекты

Достоинства:
✅ Можно выбрать любую любимую технологию с набором любимых библиотек, не зависимо от того, в каком движке разрабатывается игра. Подойдут любые языки программирования, предоставляющие возможность писать серверные приложения: Python, Java, .NET, Node.js, PHP и др.
✅ Это легковесное решение, т.к. серверное приложение будет содержать только необходимые зависимости, заложенные разработчиком и самой технологией.
✅ Можно использовать готовый шаблон, готовый фреймворк или реализовать сервер полностью своими силами, что позволит контролировать максимум аспектов работы приложения.
✅ Есть возможность реализовать специфичные сценарии работы. Например, реализацию поддержки нескольких игровых сессий параллельно.

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

Проблему общих зависимостей и их дублирования в контексте Unity решают следующим образом:
- Клиентская кодовая база в Unity написана на C#.
- Для реализации сервера используют .NET Core на C#.
- Общие зависимости выделяют в отдельную сборку или отдельный C#-проект.
- Клиентский и серверный проект подключают к себе модуль с общими зависимостями или используют собранные dll с ними.

Схема клиента и сервера, реализованных как отдельные проекты

Схема клиента и сервера, реализованных как отдельные проекты

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

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

Если нужен игровой сервер для синхронной игры, то удобнее будет использовать другой способ реализации сервера.

Клиент и Сервер – один проект

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

Достоинства:
✅ Вместо двух-трёх проектов — один, что в каком-то смысле упрощает разработку.
✅ Проблема дублирования логики и общих зависимостей решается сама собой, т.к. всё необходимое всем сторонам исполнения уже находится в одном проекте.
✅ От сервера достаточно просто отказаться. Серверная логика уже написана на нужном языке и находится в целевом проекте – достаточно адаптировать её и включить в клиентские сценарии.

Недостатки:
❌ Сервер – полноценная игра на клиентском движке. Т.е. помимо серверного кода от CoreGame туда уйдёт, как минимум, сам движок с его зависимостями и, как максимум, вся остальная игра с MetaGame и прочим.
❌ Чтобы лишние зависимости не уходили на сервер, нужно постоянно заниматься их контролем и организовывать проект так, чтобы на этапе сборки всё лишнее имело возможность не попадать в билд.
❌ Клиент и сервер обычно имеют разные конфигурации для итоговой сборки, особенно в контексте CI/CD, поэтому нужно реализовывать и поддерживать разные сценарии сборки.
❌ Если используется готовая Netcode-библиотека, то один сервер будет обслуживать только одну игровую сессию. Чем больше параллельных сессий, тем больше серверов нужно включать.

Схема клиента и сервера, реализованных как один проект

Схема клиента и сервера, реализованных как один проект

Чем чревато утекание лишних зависимостей на сервер:

  • На сервере будет крутиться лишняя логика, которая будет создавать избыточную нагрузку: от еле заметной до весьма значительной.

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

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

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

Аналогично серверные зависимости также могут "протекать" на клиент и вызывать схожие проблемы.

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

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

Заключение

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

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

Впереди ещё множество нераскрытых тем. Следить за выходом новых статей по мультиплееру и не только можно в моём блоге на VK / Telegram / Dtf / Dzen, где я делюсь своими находками, мыслями, инсайтами. анонсами и новостями.

Контент

Полезные ресурсы по теме:
- Bare Metal vs Virtual Machines vs Containers: dev.to
- MasterServer: How it works: 333Networks
- What is a Game Server and How Does it Work: ServerMania
- Архитектура мета-сервера у Tacticool: Habr.Pixonic
- Инфраструктура серверов War Robots: Habr.Pixonic
- Fast paced шутер: технологии и подходы: Habr.Pixonic
- Вторые полгода разработки нового мобильного PvP: Habr.Pixonic

Показать полностью 10
1

Автостопом по мультиплееру. Часть 2: Синглплеер и Мультиплеер

Lineage II

Lineage II

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

1. Введение

2. -> Синглплеер и Мультиплеер

3. ...

Что считать мультиплеером

Для начала нужно определить, что далее будет пониматься под словом "мультиплеер". Зафиксируем:

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

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

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

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

Где отличия от синглплеера

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

Схема игрового проекта

Схема игрового проекта

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

  • MetaGame: более широкий контекст, который вносит новые возможности и механики, не направленные напрямую на достижение основной цели игры в рамках CoreGame. Обычно они направлены на увеличение степени вовлечения игрока, разнообразие взаимодействия и мотивацию продолжать играть и возвращаться в игру.
    Примеры: тюнинг авто, прокачка, дополнительные задания, внутриигровая экономика, мини-игры, социальные механики и пр.

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

  • Runtime: общая архитектура проекта, "клей" для всех блоков.

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

Ключевое отличие мультиплеерного проекта от синглплеерного, как правило, кроется в области CoreGame.
Здесь чаще всего игроки и получают возможность для непосредственного воздействия друг на друга. Многие мультиплеерные игры, когда не могут найти достаточное кол-во игроков для новой игровой сессии, превращаются в этом месте в синглплеерные: игрок в одиночестве или в сопровождении ботов болтается в основном игровом цикле.
Здесь проявляются знаковые отличия в реализация для обеспечения многопользовательского режима. Если потребуется синглплеерный проект превратить в мультиплеерный (и наоборот), то править придётся преимущественно CoreGame.

Другие блоки тоже могут быть задеты. Например, в MetaGame могут потребоваться лобби, поиск игроков или выбор сервера. А в Infrastructure может появиться больше сервисов, систем и удалённых вычислительных узлов, которые будут требовать координации. Но об этом позже.

Классификации мультиплеера

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

По взаимодействию:

  1. Соревновательные / PvP / Players versus Players: игроки соревнуются друг с другом, командами или поодиночке.

  2. Кооперативные / PvE / Players versus Environment: игроки объединяют усилия для борьбы с врагами, управляемыми компьютером.

PvP: CS 2. PvE: Alien Swarm

PvP: CS 2. PvE: Alien Swarm

По балансу:

  1. Симметричные: все участники имеют примерно равные возможности и цели.

  2. Асимметричные: предлагаются разные возможности и цели для разных сторон.

Симметричные: Unreal Tournament III. Ассиметричные: Left 2 Dead 2

Симметричные: Unreal Tournament III. Ассиметричные: Left 2 Dead 2

По времени жизни мира:

  1. Массовые многопользовательские онлайн-игры / MMO / Massively Multiplayer Online Games: тысячи игроков взаимодействуют одновременно в одном постоянно существующем виртуальном мире.

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

MMO: World of Warcraft. Сессионные: World of Tanks

MMO: World of Warcraft. Сессионные: World of Tanks

По процессу:

  1. Синхронные / Realtime: все игроки единовременно вовлечены в единый игровой процесс и взаимодействуют друг с другом в одном и том же виртуальном мире.

  2. Асинхронные: игроки взаимодействуют друг с другом не в реальном времени, а по очереди.

Синхронные: Fortnite. Асинхронные: Worms W.M.D

Синхронные: Fortnite. Асинхронные: Worms W.M.D

По технической реализации:

  1. Локальные.

  2. Сетевые.

Локальные: Mortal Kombat 11. Сетевые: Team Fortress 2

Локальные: Mortal Kombat 11. Сетевые: Team Fortress 2

Локальный и сетевой мультиплеер

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

Hotseat: Heroes of Might and Magic 3. Splitscreen: Blur. Общий экран: LEGO Star Wars

Hotseat: Heroes of Might and Magic 3. Splitscreen: Blur. Общий экран: LEGO Star Wars

При таком режиме отличий от синглплеера в техническом плане практически нет. Есть несколько источников ввода: они или обрабатываются одновременно, или поочерёдно. Аналогично есть несколько режимов вывода. Грубо говоря, локальный мультиплеер вносит лишь незначительные корректировки в слой представления приложения.

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

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

Упрощённая схема локального взаимодействия

Упрощённая схема локального взаимодействия

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

Упрощённая схема сетевого взаимодействия

Упрощённая схема сетевого взаимодействия

Для решения подобных проблем требуется применение определённых подходов при проектировании игрового приложения. Перенос практик из синглплеерной разработки будет иметь успех в редких случаях: пожалуй только в проектах с очень медленным или вовсе асинхронным геймплеем. Чем быстрее геймплей, тем больше "наворотов" и усложнений требуется вносить в программный код для учитывания и компенсации возникающих задержек.

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

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

Статьи также доступны на площадках: VK, Dzen, Habr, Dtf.

Контент

  • Полгода разработки мобильного PvP: Habr

  • Multiplayer resource roundup: Unity

  • Unity Multiplayer in 3 minutes: YouTube

  • Как устроен мультиплеер: YouTube.Cyberstars

Показать полностью 9
1

Автостопом по мультиплееру. Часть 1: Введение

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

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

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

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

——————————————————

Наблюдение №1: Сложность

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

Поиск – пусть не главный этап, но очень важный. Нельзя изучить то, что не удалось найти, и о существовании чего ты даже не знаешь :)

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

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

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

**Вывод:** если однажды удосужиться попасть на мультиплеерный проект, не имея какого-то опыта, не стоит надеяться, что удастся разобраться со всем за недельку и начать успешно перформить — вряд ли из такой затеи получится что-то удачное (но вероятность всё же есть — ситуации бывают разные). И нужно быть готовым к тому, что здесь, как и в IT в целом, придётся постоянно учиться и совершенствовать свои навыки, чтобы иметь компетенции заниматься более качественными и масштабными проектами.

——————————————————

Наблюдение №2: Неизбежность

По мере развития игровой индустрии мультиплеер захватывает всё новые и новые "территории". Раньше мультиплеер был сродни отдельной касте развлечений: с конкретными жанрами, на конкретных платформах, с конкретными правилами.

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

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

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

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

Вывод: чем дальше, тем больше в нашей жизни мультиплеера становится. С каждым днём шансы столкнуться с этой технологией возрастают. Рано или поздно, как бы мы ни избегали (если такие попытки есть), мы там окажемся. И лучше к этому быть готовым. Потому что <см Наблюдение №1>.

——————————————————

Наблюдение №3: Недооценённость

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

В ситуациях "безрыбья" приходилось прибегать к "грязному трюку", а именно предлагать кандидатам без нужного опыта выполнять ТЗ на разработку мультиплеерного прототипа.

Оффтоп: Почему я считаю этот трюк "грязным":

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

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

Оффтоп: Почему это – всё же "трюк":

1. Даже если у кандидата не было опыта работы с сетевыми кодом, он появится при подготовке ТЗ, что снимает с команды необходимость обучать нового коллегу с полного "нуля".

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

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

4. Если кандидат ушёл не в ту сторону и его "душа" к этому ну совсем "не лежит", то это вскроется сразу и не станет отложенным сюрпризом.

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

Оффтоп: Фидбэк на ТЗ

Какое бы ни было решение по ТЗ, оставить конструктивный фидбэк, который поможет кандидату шагнуть на следующую ступеньку — на мой взгляд, для компании тоже полезный "трюк" (и, к сожалению, не общепринятый стандарт). А для самого кандидата это – отличная лазейка и точка роста.

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

Вывод: для разработки мультиплеера все хотят сотрудников "на опыте", но таких катастрофически мало. И сами разработчики почему-то не придают значения такой вехе в своём портфолио навыков. Поэтому даже небольшой скромный мультиплеерный пет поможет тебе выделиться среди других кандидатов и успешнее выполнить ТЗ, если оно вообще потребуется и ты уже не находишься в числе тех, кого "отрывают с руками". А команды всё чаще обращаются к мультиплееру. Потому что <см Наблюдение №2>.

——————————————————

Выводы

Мультиплеер – это сложно, объемно, актуально, перспективно и с каждым днём всё более востребовано. И, вероятно в недалёком будущем, почти обязательно. Но среди разработчиков это на данный момент не очень популярно. И как нанимающая сторона, я подмечаю некоторый "кадровый голод" в этой области.

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

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

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

До следующих встреч!

Эту и следующие статьи можно читать на площадках: Пикабу, VK, Dzen, Habr, Dtf.

——————————————————

Контент

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

1. Joshua Glazer, Sanjay Madhav. Multiplayer Game Programming: Architecting Networked Games (есть в переводе)

2. Alan R. Stagner. Unity Multiplayer Games

3. Marco Secchi. Multiplayer Game Development with Unreal Engine 5

Показать полностью 4
Отличная работа, все прочитано!