Вся наша жизнь спираль: сеть
И снова здравствуйте. Год назад я выкладывал пост, под названием «Вся наша жизнь спираль», в котором немножко рассказал об игре, над которой работаю. Вот он: https://pikabu.ru/story/vsya_nasha_zhizn_spiral_5831544 Этот пост можно считать его продолжением.
Не писал достаточно долго по нескольким причинам. Основная, я опять подзабил на проект и занимался основной работой, также появились некоторые трудности, которые заставили меня снова залезть в дебри Unreal Engine 4 и смотреть, что Эпики там понакрутили. Но я снова в седле, и т.к. очередной этап разработки завершен, то можно и написать статью об этом.
Начну, пожалуй, с новостей. Их всего две:
1) Мы относительно недавно обзавелись сервером в дискорде: https://discordapp.com/invite/aNfW5FQ , т.ч. милости просим.
2) Мы приняли решение часть неигровых модулей выложить в Open Source под BSD лицензий.
Вот об одном (единственном доступном широкой публике на данный момент) open Source модуле, под названием Client Authority Network (CANet) мы и поговорим.
Данный модуль был написан с одной единственной целью: решить проблему синхронизации игроков в сетевом режиме игры. Казалось бы, в чем проблема? Объясняю, в стандартной сетевая модель UE4 постулирует следующие законы.
• Все игроки должны находится на одной локации в рамках одного сервера.
• Все игроки должны считать логику на сервере, на клиенты транслируется только результаты обработки.
• Все игроки должны иметь на сервере координаты в глобальной сетке карты.
Что из этого следует: в нашем проекте, чтобы игроки были синхронизированы с картой, нужно будет постоянно держать загруженной всю галактику, со всеми планетами, станциями, итд, а также сохранять глобальные координаты игроков (а это, на минуточку числа, которые современные компьютеры не умеют считать. Для знающих: int256 и выше). И кроме того, невозможно применить стандартные «хаки» (динамическое масштабирование, World Shifting, и прочее) для поджатия мира, т.к. в этом случае будет нарушаться третий закон.
Решение, казалось бы, напрашивается само собой: написать свою сетевую модель, которая не будет столь категорична к позициям игроков. Примерно это, CANEt и делает. Однако, чтобы написать свою сеть в UE4, это нужно переписать туеву кучу кода, и не факт, что после очередного обновления движка все будет работать так, как было задумано. Посему я решили схитрить. Я не стали переделывать всю сеть, а заместо этого перевернул работу оригинального, получив заместо стандартной модели сервер-клиент, модель клиент-роутер-клиент (почти честная PTP). В результате, все три закона стандартной модели стали недействительными. И проблема частично была решена. Почему частично? Осталась проблема синхронизации игроков в отдельно взятых локациях. Эту проблему модуль не решает, но, зато ее способна решить фича, которая перекочевала в UE4 прямо из Фортнайта, а именно Replication Graph, но сегодня речь не о нем.
Итак, как же работает CANet. CANet, как я уже говорил, переворачивает принцип работы сети в UE4 с ног на голову. Начинается все так-же, как и в оригинале. На сервер создаётся Game Mode, которая ждет подключения игрока. Как только игрок подключился, создается Player Controller и Player State, которые реплицируется на клиенты (Player Controller только владельцу подключения), а вот дальше начинаются отличия.
В оригинале, следующим этапом было бы создать на сервере чарактер игрока (ACharacter/APawn) и среплицировать его на клиенты. В случае CANet это происходит немножко иначе:
• На сервере создается специальный класс UClientChannel, который привязан к APlayerState в качестве компонента и реплицируется вместе с ним.
• При первой репликации UClientChannel создается карта всех реплицируемых свойств чарактера игрока, считаются их контрольные суммы и записываются в буфер.
• Если APlayerState привязан к APlayerController, то UClientChannel начинает считаться авторитетным и начинается покадровая проверка свойств из буфера.
• При проверке, если контрольная сумма свойства в буфере не сошлась с суммой свойства чарактера, то свойство помечается как изменившееся и записывается во второй буфер.
• В конце кадра, если буфер имеет не нулевую длину, то отправляем его на сервер.
• Сервер сохраняет себе свойства в свой буфер и перенаправляет его остальным клиентам.
• Клиенты в свою очередь опять сверяют контрольные суммы, и если они не сошлись, то записывают свойство в чарактер.
Иными словами, обязанности сервера плавно переходят на клиенты, а на самом сервере, чарактеров и прочих актеров просто не существует.
Существует и ряд проблем: в частности, нужно понимать, что, отдав права на изменение переменных на клиенты мы, по сути, открываем особо одаренным товарищам целый плацдарм для читерства. Для противоборства этому, как раз и существует отдельный буфер на сервере. Этот буфер в будущем будет передаваться подсистеме чит-детектора, который по определенным правилам будет выискивать читеров, и отключать их от игровой сессии.
Написание такого детектора, одна из причин, выкладки модуля в Open Source. Нужна действительно большая команда, чтобы предусмотреть все возможные варианты и подводные камни, а так-как разработка держится исключительно на моем энтузиазме, то самым простым решением было выложить его в Open Source, иными словами, разработчики помогут довести модуль до ума, а взамен смогут свободно его использовать в своих проектах.
На этой ноте, наверно можно и заканчивать. Сам модуль можно найти по адресу: https://github.com/TehnoMag/UE4-Module-CANet , а в следующий раз мы поговорим либо о Replication Graph либо о Wave Function Collapse (WFC) генерации в UE4 и его роли в L.I.M.A. strace_.