(For new projects, you should use the new networking system introduced in 5.1. This information is for legacy projects using the old networking system.)
В этом разделе рассмотрены основные принципы сетевого взаимодействия, которые необходимо понять перед разработкой игры с использованием сетевой архитектуры Юнити.
Сетевое взаимодействие - это связь между двумя и более компьютерами. Основная идея в построении взаимоотношений между клиентом client (компьютером, запрашивающим информацию) и сервером server (компьютером, отвечающим на запросы информации). Сервером может быть как выделенный хост-компьютер, принимающий запросы от всех игроков, так и компьютер одного из игроков с запущенной на нём игрой, но также работающий как сервер для остальных игроков. Как только запускается сервер и к нему подключается клиент, эти два компьютера получают возможность обмениваться информацией в соответствии с геймплеем.
Создание сетевых игр требует особого внимания к некоторым специфическим деталям. Даже несмотря на то, что в Юнити относительно несложно проектировать и работать с сетью, сетевые взаимодействия остаются довольно сложными. В Юнити было принято основополагающее дизайнерское решение обеспечить сетевые взаимодействия максимальной надежностью и гибкостью, насколько это возможно. Это означает, что вы, как создатель игры, в ответе за некоторые вещи, которые, возможно, делаются автоматически в иных движках, но менее надёжны. Решения, которые вы принимаете, потенциально могут оказывать большой эффект на архитектуру вашей игры, поэтому лучше всего принимать их как можно раньше на этапе проектирования. Понимание принципов сетевого взаимодействия поможет вам нормально спланировать архитектуру игры и избежать проблем при реализации.
There are two common and proven approaches to structuring a network game which are known as Authoritative Server and Non-Authoritative Server. Both approaches rely on a server connecting clients and passing information between them. Both also offer privacy for end users since clients never actually connect directly with each other or have their IP addresses revealed to other clients.
Использование авторитарного сервера требует от сервера просчёта и выполнения всех действий, затрагивающих мир игры, применение правил игры и обработки ввода от игроков-клиентов. Каждый клиент высылает введенную информацию (в форме нажатия клавиш или запрашиваемых действий) на сервер и постоянно получает от сервера текущее состояние игры. Клиент не может самостоятельно вносить какие-либо изменения в состояние игры. Вместо этого, он сообщает серверу, что конкретно он хочет сделать, сервер обрабатывает этот запрос и отвечает клиенту, объясняя что получилось в результате запроса.
Принципиально важно, что существует разница между тем, что игрок хочет сделать и тем, что в действительности происходит. Это позволяет серверу принимать запросы от каждого клиента, после чего решать, как изменить состояние игры.
Преимущество такого подхода в том, что он значительно усложняет клиентам возможность использования нечестных приёмов. Например, у клиента нет возможности обмануть сервер (и, соответственно, остальных клиентов), что враг был убит, поскольку клиент не принимает таких решений. Он может только лишь сказать серверу, что оружие выстрелило и, начиная с этого момента, только сервер определяет, было ли совершено убийство или нет.
Другим примером применения авторитарного сервера может быть многопользовательская игра, основанная на физике. Если бы каждый клиент просчитывал физику самостоятельно, то незначительные отличия в просчете физики между клиентами постепенно привели бы к рассинхронизации клиентов друг с другом. Однако, если симуляция всех физических объектов управляется на центральном сервере, обновленные состояния игры могут быть высланы клиентам, гарантируя их согласованность.
Возможным недостатком системы с авторитарным сервером можно назвать время, которое требуется для пересылки сигнала через сеть. Если игрок нажал кнопку, чтобы двинуться вперёд, а ответ от сервера о возможности такого движения приходит через десятую долю секунды, то такая задержка будет ощутима для игрока. Одним из возможных решений этой проблемы будет использование так называемых прогнозов движения на стороне клиента client-side prediction. Суть этой технологии в том, чтобы позволить клиенту обновлять локальную версию состояния игры, но при этом иметь возможность получать уточняющие данные со стороны сервера по мере необходимости. Как правило, это применяется только для простых действий в игре и не должно оказывать влияние на значительные изменения логики игры. Например, было бы неразумно сообщать игроку, что враг был убит только лишь затем, чтобы сервер в дальнейшем переписал это решение.
Поскольку прогнозы на стороне клиента относятся к продвинутым техникам, мы не будем пытаться их объяснить в этом руководстве, однако вам доступны множество книг и сетевых ресурсов для дальнейшего изучения.
Авторитарный сервер обрабатывает намного больше информации чем не-авторитарный. Если от сервера не требуется управления всеми изменениями состояния игры, значительная часть нагрузки может быть распределена между клиентами.
Не-авторитарный сервер не контролирует результаты ввода каждого игрока. Клиенты самостоятельно отслеживают введенные игроком действия и игровую логику локально, после чего высылают результат определенного действия на сервер. После этого сервер синхронизирует все совершенные действия с состоянием мира. Это легче реализовать с точки зрения архитектуры, так как сервер отвечает только лишь за передачу сообщений между клиентами, не делая никаких дополнительных вычислений, которые делают клиенты.
Не требуется никаких специальных методов прогнозирования, так как клиенты сами обрабатывают всю физику и события, после чего отсылают результат на сервер. Они являются хозяивами этих объектов и единственными агентами с разрешением на пересылку по сети локальных изменений этих объектов.
Теперь, когда мы разобрали базовые архитектуры сетевых игр, рассмотрим на более низком уровне, как клиенты и серверы могут связываться друг с другом.
Существует два релевантных метода: удалённый вызов процедуры Remote Procedure Calls и синхронизация состояния State Synchronization. Не редко используются оба метода в различных точках одной и той же игры.
Удаленный вызов процедуры (Remote Procedure Call, RPC) используется для вызова на другом компьютере через сеть, хотя “сеть” может подразумевать канал для сообщений между клиентом и сервером, когда они оба запущены на одном компьютере. Клиенты могут отправлять RPC на сервер, а сервер может отправлять RPC на один или несколько клиентов. Чаще всего, они используются для действий, которые происходят нечасто. Например, если клиент нажимает на кнопку, чтобы открыть дверь, он может отправить на сервер RPC, что дверь была открыта. После этого, сервер может отправить другой RPC всем клиентам, вызывая их локальные функции, открывающие эту же дверь. Они используются для управления и выполнения отдельных событий.
State Synchronization (Синхронизация Состояний) используется для обмена данными, которые постоянно меняются. Хорошим примером будут координаты игрока в игре. Игрок постоянно движется, бегает, прыгает и т.д. Все остальные игроки в сети, даже те, кто не контролируют этого игрока, должны знать где именно он сейчас находится и что он делает. При помощи постоянной ретрансляции данных о позиции игрока, игра может точно отображать эту позицию остальным игрокам.
Этот тип данных постоянно и часто передаётся через сеть. Поскольку для этих данных важно время и требуется время для передачи сигнала по сети от одного компьютера к другому, важно снижать количество передаваемой информации, насколько это возможно. Проще говоря, State Synchronization, как правило, требует гораздо большей пропускной способности сети, поэтому вам следует стремиться по возможности минимизировать сетевой трафик.
Подключение серверов и клиентом может быть сложным процессом. Компьютеры могут иметь приватные или публичные IP адреса и могут иметь внутренние или внешние брандмауэры, блокирующие доступ. В Юнити Сетевые взаимодействия построены таким образом, чтобы урегулировать как можно больше возможных ситуаций, однако не существует универсального решения.
Приватные адреса - это IP адреса, недоступные напрямую через интернет (также называются Network Address Translation или NAT адреса, после метода их реализации). Если объяснять проще, приватные адреса проходят через локальный маршрутизатор, который преобразует их в публичные адреса. Поступая таким образом, многие компьютеры с приватными адресами могут использовать один единственный публичный IP адрес для связи с интернетом. Это допустимо лишь до тех пор, пока кто-то из другой точки интернета не захочет начать контакт с одним из приватных адресов. Подключение должно произойти через публичный адрес маршрутизатора, который в дальнейшем должен передать сообщение на приватный адрес. Технология, называемая NAT punchthrough использует общедоступный сервер, известный как посредник (fascilator), служащий как связующее звено таким способом, чтобы приватный адрес был доступен при подключении с публичного адреса. Чтобы эта технология заработала, компьютер с приватным адресом сперва связывается с посредником, который “пробивает” дыру через локальным маршрутизатор. Посредник теперь может видеть публичный IP адрес и порт, который использует приватный IP адрес. Используя эту информацию, любой компьютер, подключенный к интернету, теперь может подключиться напрямую к приватному адресу, недоступному в иных случаях (следует отметить, что реализация NAT punchthrough на практике может быть несколько сложнее).
Публичные адреса более легкодоступны. В этом случае, наиболее частой причиной блокирования соединения будет внутренний или внешний брандмауэр (внутренний брандмауэр это брандмауэр, запущенный локально на компьютере, который он защищает). В случае внутреннего брандмауэра у пользователя могут попросить снять запрет с определенного порта, чтобы таким образом сделать доступным игровой сервер. Внешний брандмауэр, напротив, не может управляться пользователями. Юнити может попытаться использовать NAT punchthrough, чтобы получить доступ через внешний брандмауэр, однако эта технология не гарантирует успех. Наши тесты показывают, что в основном это работает на практике, но никакого официального исследования, подтверждающего эти результаты, не проводилось.
Упомянутые проблемы с подключением по разному затрагивают серверов и клиентов. Запросы от клиентов включают в себя только исходящий сетевой трафик, который относительно простой для обработки. Если клиент имеет публичный адрес, практически всегда всё будет работать, поскольку исходящий трафик обычно блокируется только в корпоративных сетях, где вводится жесткое ограничение доступа. Если у клиента приватный адрес, он может подключаться ко всем серверам, за исключением серверов с приватными адресами, которые не могут использовать NAT punchthrough (подробнее об этом будет рассказано позже). Сторона сервера более сложна, так как сервер должен иметь возможность принимать входящие подключения от неизвестных источников. Сервер с публичным адресом должен иметь открытый для интернета игровой порт (т.е. не блокируемый брандмауэром), или иначе он не сможет принимать подключения от клиентов и будет бесполезен. Если у сервера приватный адрес, он должен иметь возможность использовать NAT punchthrough, чтобы разрешить подключения и клиенты также должны иметь разрешение на подключение через NAT punchthrough, чтобы подсоединиться к серверу.
Юнити предоставляет инструменты для проверки всех этих различных вариантов соединений. Когда будет установлено, что соединение возможно, существует два метода, с помощью которых его можно будет осуществить: прямое соединение (когда клиент должен знать имя DNS или IP адрес сервера) и соединение через Master Server (Главный Сервер). Master Server позволяет серверам извещать клиентов о своём присутствии, так что клиентам не понадобится что-либо заранее узнавать о деталях подключения к этим игровым серверам.
Во время работы State Synchronization с несколькими клиентами, нет необходимости синхронизировать каждую отдельную деталь, чтобы объекты выглядели синхронизированными. Например, когда синхронизируете аватар персонажа, достаточно только пересылать между клиентами его позицию и вращение. Даже если сам по себе персонаж гораздо более сложен и может содержать глубокую иерархию из Transform, нет нужды делиться данными обо всей иерархии.
Множество данных вашей игры фактически статичны, значит клиентам следует передать только их начальные значения, а не синхронизировать. Использование редких или однократных вызовов RPC может быть достаточным, чтобы заставить многое из вашего функционала заработать. Используйте данные, которые содержаться в каждой инсталляции вашей игры и позволяйте клиенту работать самостоятельно как можно больше, насколько это возможно. Например, вы знаете, что такие ассеты, как текстуры или модели существуют во всех инсталляциях и обычно не изменяются, значит никогда не потребуют синхронизации. Это простой пример, но он должен помочь вам понять, какими именно данными критически важно делиться от одного клиента к другому. Это единственные данные, которые вообще следует передавать.
Возможно, будет сложно разобраться, что именно следует передавать, а что нет, особенно если вы никогда прежде не делали сетевые игры. Держите в уме, что вам достаточно всего лишь одного вызова RPC с указанием имени уровня, чтобы все клиенты самостоятельно целиком загрузили выбранный уровень и добавили свои собственные элементы для сетевого взаимодействия. Структурируйте свою игру таким образом, чтобы каждый клиент был максимально самодостаточным, что возможно, приведет к уменьшению сетевого трафика.
Физическое местоположение и производительность сервера могут значительно влиять на “играбельность” запущенной на нём игры. Клиенты, расположенные на другом континенте относительно сервера, могут столкнуться со значительным запаздыванием (лагами). Это физическое ограничение интернета и единственным реальным решением может быть распределение серверов в точках, максимально приближенных к клиентам, которые будут их использовать, или по крайней мере, расположение их на том же континенте.
Мы собрали следующие ссылки на ресурсы о сетях:-