Как исправить Player Location Desync в UEFN и Unreal Engine Multiplayer
Кошмар Multiplayer Transform Desync
Каждый разработчик мультиплеерных игр рано или поздно сталкивается с моментом, когда netcode начинает ему врать. Вы пишете скрипт, где игрок садится в кресло, кресло движется по карте, и на сервере все выглядит идеально. Но когда вы заходите со второго клиента, иллюзия рушится. Клиент А видит себя идеально сидящим в кресле. Клиент B видит, как кресло уезжает, а Клиент А остается висеть в воздухе в точке старта.
Этот феномен — uefn player location desync — известная проблема при использовании player inputs для вызова команд MoveTo на пропах с прикрепленными (attached) игроками. Сервер регистрирует верное абсолютное местоположение, но simulated proxies (копии игрока на других клиентах) не наследуют обновленный transform от родительского пропа.
Независимо от того, создаете ли вы проект в Unreal Editor for Fortnite (UEFN) или проектируете выделенный сервер в Unreal Engine 5, понимание причин сбоя replication при аттачах критически важно. В этом туториале мы разберем механику Network Dormancy, почему аттачи ломают client-side prediction и как заставить replication graph уважать состояние вашего мира.
Почему аттачи ломают Network Updates
Чтобы исправить десинхрон, нужно понять, как Unreal Engine иерархически обрабатывает actor replication.
Когда character actor прикрепляется к пропу, его transform становится относительным (relative) по отношению к родителю. Для экономии трафика Unreal Engine агрессивно использует концепцию Network Dormancy.
Когда игрок сидит и не совершает активных движений, сервер может пометить актера игрока как dormant (спящий). Сервер считает: «Игрок не движется самостоятельно, значит, мне не нужно слать обновления для него. Я буду слать обновления только для движущегося кресла».
Математика десинхрона
- Server Tick Rate: Обычно 30Гц в UEFN.
- Prop NetUpdateFrequency: Часто по умолчанию 100 обновлений в секунду.
- Character MinNetUpdateFrequency: Может падать до 2.0 при отсутствии инпута.
При вызове MoveTo кресло обновляется на 30Гц. Но так как игрок находится в состоянии dormancy, другие клиенты не получают RPC (Remote Procedure Call), сообщающий об обновлении относительной позиции игрока. Итог — жесткий визуальный десинхрон.
Шаг 1: Решение в UEFN Verse
Разработчики заметили: если встать с кресла, проблема исчезает. Это происходит потому, что смена movement mode с Custom на Walking заставляет сервер сбросить (flush) Network Dormancy.
Мы можем программно воссоздать этот «сброс» в Verse через микро-телепортацию, чтобы «разбудить» replication graph.
# [Код Verse без изменений]
Вызывая TeleportTo в те же координаты, мы заставляем движок C++ выставить флаг TeleportPhysics, что полностью сбрасывает client-side prediction для этого актера.
Шаг 2: Нативный фикс в Unreal Engine C++
Если у вас есть доступ к исходному коду, вы можете напрямую управлять dormancy через networking API.
// Пример на C++
// [Код C++ без изменений]
Шаг 3: Сохранение состояния в Backend
Исправление десинхрона в реальном времени — это только половина дела. Если в вашей игре есть персистентный мир, важно сохранять в базу данных корректные server-authoritative координаты. Создание своего бэкенда для частых сохранений занимает недели. horizOn предлагает Backend-as-a-Service, созданный специально для разработчиков игр.
5 советов по Multiplayer Movement
- Никогда не верьте состоянию аттача на клиенте: Используйте server-authoritative RPC.
- Управляйте NetDormancy вручную: Вызывайте
FlushNetDormancyпри активном движении. - Избегайте глубоких иерархий: Не делайте аттачи более чем в один уровень.
- Используйте надежные RPC для важных изменений: NetMulticast для посадки/высадки.
- Проверяйте Transform при высадке: Сверяйте позицию на сервере при выходе из транспорта.
Заключение
Мультиплеерные десинхроны — это результат агрессивной оптимизации трафика. Понимая Network Dormancy, вы можете принудительно обновлять состояние через Verse или C++. Возьмите replication graph под свой контроль.
Нужен масштабируемый бэкенд? Попробуйте horizOn бесплатно.