Задержка и производительность сети
Задержка и производительность сети
Если вы играли онлайн, то наверняка замечали, как задержка ухудшает впечатление от игры. Недостаточная пропускная способность и нестабильное соединение приводят к рывкам персонажей, неравномерной частоте кадров и заметной задержке ввода. Теперь, понимая обмен между клиентами и сервером, легко увидеть причину. При передаче через интернет многое может пойти не так. Даже с механизмами надёжности Unity Transport UDP-пакеты способны потеряться, прийти в неверном порядке или повредиться по пути. Всё это вызывает задержку, которую игрок воспринимает как лаг.
Имитация задержки Чтобы изучить и смягчить влияние задержки во время разработки, в Unity Editor можно имитировать разные сетевые условия с помощью Debug Simulator компонента UnityTransport или Network Simulator.
Debug Simulator в Unity Transport Настройте Debug Simulator в компоненте UnityTransport, чтобы добавить искусственную задержку, джиттер и потерю пакетов. Эти параметры находятся в Inspector объекта NetworkTransport сцены. Задайте несколько значений, имитирующих перегрузку сети:
Latency: добавляет задержку в миллисекундах для имитации медленного соединения. Например, значение 100 мс воспроизводит умеренную сетевую задержку.
Jitter: добавляет колебания задержки, имитируя нестабильные сетевые условия. Например, задайте 50 мс и посмотрите, как нестабильное соединение влияет на игру. Packet Loss: задаёт процент отбрасываемых пакетов для имитации плохого качества связи. Попробуйте установить потерю пакетов 5 %, чтобы оценить её влияние на игровой процесс. Снова запустите игру и посмотрите, как смоделированные условия влияют на игровой процесс.
Настройте Debug Simulator в Unity Transport.
Network Simulator Network Simulator из пакета Multiplayer Tools позволяет тестировать неблагоприятные сетевые условия и находить проблемы до выпуска игры. Он имитирует сетевые события: разрывы соединения, всплески задержки и потерю пакетов.
Установите Network Simulator из пакета Multiplayer Tools.
Проверьте влияние задержки с помощью Network Simulator.
Другие инструменты эмуляции сетевых условий Debug Simulator и Network Simulator работают только в редакторе. Для сборок приложения задержку можно имитировать с помощью других инструментов эмуляции сетевых условий. Например, clumsy для Windows и Network Link Conditioner для macOS/iOS позволяют воспроизводить различные сетевые условия и тщательно тестировать игру. Подробнее см. в разделе «Тестирование и отладка» далее в этом руководстве. Учет влияния задержки на производительность приложения - одна из главных задач при разработке многопользовательских игр. К счастью, существует ряд подходов, позволяющих ослабить ее последствия. Рассмотрим некоторые из них.
Интерполяция на стороне клиента Один из способов уменьшить влияние задержки - интерполяция на стороне клиента. При таком подходе клиент не отображает состояние сразу, а намеренно откладывает отрисовку на небольшой интервал интерполяции. В клиент-серверной топологии клиент обычно отображает состояние, отстающее от серверного примерно на половину времени кругового прохождения сигнала (RTT). Интерполяция на стороне клиента добавляет к этому еще одну намеренную задержку.
Работая с небольшим отставанием, клиент может буферизовать поступающие с сервера обновления состояния. Когда приходит время отобразить следующее обновление, клиент вычисляет интерполированное состояние по двум последним серверным тикам.
Буфер позволяет клиенту выводить обновления равномерно, даже если серверные тики поступают нерегулярно из-за джиттера. Интерполированные состояния скрывают небольшую задержку и дрожание времени доставки.
Буферизованный тик
Тики сервера поступают неравномерно, с джиттером, из-за различий в задержке
Тик сервера СЕРВЕР Тик сервера 1
Тик сервера 2
Тик сервера 3
Тик сервера 4
Тик сервера 5
Тик сервера 6
Кадр клиента 1
Кадр клиента 2
Кадр клиента 3
Тик сервера 7 Тик сервера 8
Тик сервера 9
Тик сервера 10
Тик сервера 11
Буфер клиента КЛИЕНТ
Кадр клиента 4
Кадр клиента 5
Кадр клиента 6
Кадр клиента 7
Кадр клиента 8
Обновление кадра на клиенте КЛИЕНТ
Буферизация тиков позволяет выдавать их на клиенте с равномерной частотой
Клиент отображает интерполированные состояния из буфера.
В Netcode for GameObjects интерполяция на стороне клиента включается параметром компонента NetworkTransform. Параметр Interpolation интерполирует положение, поворот и масштаб соответствующего GameObject.
Интерполяция на стороне клиента включена в NetworkTransform.
Учтите, что интерполяция на стороне клиента неизбежно добавляет небольшую задержку отрисовки.
Прогнозирование и упреждение на стороне клиента В предыдущем примере ClientNetworkTransform передает клиенту непосредственное управление перемещением игрока, поэтому игра ощущается более отзывчивой. Однако во многих играх клиентская авторитетность недопустима из-за требований игрового дизайна, честности и безопасности.
Зачем нужен авторитетный сервер В соревновательных играх, где особенно важна честность, клиентская авторитетность позволяет игрокам жульничать и использовать уязвимости, изменяя клиентский код или данные. Играм со сложным взаимодействием игроков и общим игровым миром часто нужен авторитетный сервер: он обеспечивает целостность данных, препятствует вмешательству и поддерживает единообразный игровой процесс для всех участников. Такой подход сохраняет равные условия и целостность игры. Поэтому вместо ClientNetworkTransform, где объектом управляет владелец, используется стандартный компонент NetworkTransform. В этом случае ввод клиента не управляет игроком напрямую - управление остается только у сервера.
Объект на сервере
Сервер
Смоделировать новое движение
СЕРВЕР
Отправить ввод
NetworkTransform синхронизирует позицию
Объект на клиенте
Клиент
Объект на клиенте
КЛИЕНТ
Перемещение NetworkTransform под управлением авторитетного сервера.
Однако авторитетность сервера может усиливать влияние задержки. Клиент не управляет персонажем на экране напрямую, а отправляет ввод на сервер. Сервер обрабатывает его, выполняет симуляцию и вычисляет состояние игры. Клиент может показать следующий кадр только после получения результатов этой симуляции.
При использовании авторитетного сервера игрок замечает задержку, пока данные идут от клиента к серверу и обратно. Поэтому клиент обычно отстает от сервера, особенно когда UDP-пакеты передаются через интернет.
Для многих элементов игры такое отставание приемлемо, но в случае персонажа игрока оно может испортить ощущение от управления и затруднить игру.
Как работает прогнозирование на стороне клиента Прогнозирование на стороне клиента помогает компенсировать задержку, возникающую при серверной авторитетности. Не дожидаясь ответа сервера, клиент прогнозирует состояние игры на долю секунды вперед и сразу обновляет изображение. Подход называется прогнозированием, потому что клиент еще не знает фактическое состояние, рассчитанное сервером. Благодаря этому действия игрока немедленно получают визуальный отклик, и управление ощущается отзывчивым.
Объект на сервере
Сервер СЕРВЕР
Объект на клиенте
Клиент
Объект на клиенте
Клиент прогнозирует новое движение для мгновенного отклика
КЛИЕНТ
Клиент прогнозирует состояние игры.
Одновременно клиент отправляет действия игрока на сервер в пакете. Сервер получает пакет с вводом, обрабатывает данные и выполняет симуляцию, формируя эталонное авторитетное состояние игры. Затем сервер отправляет это состояние клиенту.
Объект на сервере
Сервер
Обработать перемещени е
СЕРВЕР
NetworkTransform синхронизирует позицию
Одновременно отправить ввод на сервер
Объект на клиенте
Клиент КЛИЕНТ
Объект на клиенте Клиент прогнозирует новое движение для мгновенного отклика
Клиент подтверждает авторитетное состояние
Время кругового обхода (RTT)
Сервер возвращает авторитетное состояние.
Согласование и откат Затем клиент сравнивает авторитетное состояние с упрежденным и ищет различия. Если состояния достаточно близки, ничего исправлять не нужно и игра продолжается.
При существенном расхождении, которое также называют рассинхронизацией, клиент должен скорректировать свое состояние в соответствии с авторитетным состоянием сервера. Этот процесс называется согласованием.
Сервер
Обработка движения
Обработка движения
Объект на сервере
Объект на сервере
Задержка вызывает запаздывание
Задержка вызывает запаздывание
СЕРВЕР
Ввод 1 отправлен на сервер
Объект на клиенте
Клиент КЛИЕНТ
Клиент прогнозирует движение по вводу 1
Позиция 0
Ввод 2 отправлен на сервер
Объект на клиенте
Клиент прогнозирует движение по вводу 2
Синхр.
Объект на клиенте
Позиция 1
Интервал кадров клиента
Синхр.
Позиция 2
Интервал кадров клиента
Объект на клиенте
Объект на клиенте
Сервер синхронизирует авторитетную позицию 1
Сервер синхронизирует авторитетную позицию 2
РАССИНХРОНИЗАЦИЯ: авторитетное значение не совпадает с прогнозом
Клиент получает несовпадающее состояние - происходит рассинхронизация.
Чтобы компенсировать задержку, клиент хранит историю ввода и прогнозируемых состояний за определенное число кадров. При рассинхронизации он откатывается к последнему корректному состоянию, полученному от сервера, а затем повторно выполняет симуляцию с правильными входными данными. Так состояние клиента снова синхронизируется с сервером.
Сервер
Обработка движения
Обработка движения
Объект на сервере
Объект на сервере
Задержка вызывает запаздывание
Задержка вызывает запаздывание
СЕРВЕР
Ввод 1 отправлен на сервер
Объект на клиенте
Клиент КЛИЕНТ
Клиент прогнозирует движение по вводу 1
Позиция 0
Ввод 2 отправлен на сервер
Объект на клиенте
Клиент прогнозирует движение по вводу 2
Синхр.
Объект на клиенте
Позиция 1
Интервал кадров клиента
Позиция 2
Интервал кадров клиента
Синхр.
Объект на клиенте
Объект на клиенте
Сервер синхронизирует авторитетную позицию 1
Сервер синхронизирует авторитетную позицию 2
Согласование на стороне клиента: Принять значение сервера и повторить симуляцию с ввода 1; скорректировать движение до позиции 2
Подтвердить авторитетное значение позиции 2
Клиент устраняет рассинхронизацию путем согласования.
В одном кадре клиенту иногда приходится повторно просчитывать сразу несколько кадров, поэтому сетевое приложение требует больше вычислительных ресурсов. Однако согласование и откат позволяют сохранить плавность и целостность игрового процесса даже при сетевой задержке.
Упреждение на стороне клиента в Netcode for GameObjects Netcode for GameObjects поддерживает клиентское упреждение - упрощенный способ работы с задержкой без полноценного прогнозирования и согласования на стороне клиента. Для этого используются следующие компоненты:
- AnticipatedNetworkVariable<T> - обобщенный компонент для скалярных и простых типов данных: целых чисел, чисел с плавающей запятой, цветов и т. п. Он подходит для свойств, не относящихся к Transform, например здоровья, счета или состояния предмета.
- AnticipatedNetworkTransform работает аналогично AnticipatedNetworkVariable, но предназначен для данных Transform: положения, поворота и масштаба. Клиентское упреждение дает игроку немедленный визуальный отклик, пока клиент ожидает авторитетное обновление от сервера. Благодаря этому игра ощущается более отзывчивой. Например, в простом примере ColorTrigger клиент может сразу показать изменение цвета объекта с белого на синий, не дожидаясь подтверждения сервера.
Взаимодействие клиента и сервера при упреждении выглядит примерно так:
Исходный цвет объекта - белый
Клиент
Клиент отправляет запрос на синий цвет. Локально цвет становится синим.
Объект предугадывает синий цвет и ждёт ответа сервера
Клиент получает команду установить синий цвет. Цвет остаётся синим.
Цвет синий
КЛИЕНТ
Сервер получает сообщение и устанавливает синий цвет
Сервер СЕРВЕР
Клиент упреждает состояние игры.
AnticipatedNetworkVariable<T> и AnticipatedNetworkTransform разделяют значения на упрежденное (визуальное) и авторитетное состояния. Упреждение - это прогнозируемое клиентом состояние, которое обеспечивает игроку немедленный локальный отклик. Авторитетное состояние определяет сервер. Получив обновление сервера, клиент сравнивает оба состояния. Если они заметно расходятся, клиент корректирует свое состояние по серверному, сохраняя согласованность между всеми клиентами.
Исходный цвет Клиент задаёт синий цвет. объекта - белый Локально он уже синий.
Клиент
Объект ожидает синий цвет и ответ сервера
Клиент получает синий цвет. Цвет остаётся синим.
Цвет объекта синий
Клиент получает красный цвет. Цвет становится красным.
Теперь цвет объекта красный
КЛИЕНТ
Сервер получает сообщение и задаёт синий цвет
Сервер
Сервер получает сообщение и задаёт красный цвет
СЕРВЕР
Исходный цвет объекта - белый
Клиент
Клиент задаёт красный цвет. Локально он уже красный.
Объект ожидает красный цвет и ответ сервера
Клиент получает синий цвет. Устаревшие данные игнорируются.
Цвет объекта красный
Клиент получает красный цвет. Цвет становится красным.
Цвет объекта остаётся красным
КЛИЕНТ
По времени отправки сообщение устарело.
Клиентское упреждение может игнорировать устаревшие данные.
При клиентском упреждении необходимо учитывать «устаревшие данные» - обновления сервера, отражающие действия, которые произошли до последнего запроса клиента. В Netcode for GameObjects свойство StaleDataHandling предлагает два варианта обработки:
- StaleDataHandling.Ignore игнорирует устаревшие данные и сохраняет упрежденное значение. Это полезно, если состояние меняется быстро и изображение начинает мерцать.
- StaleDataHandling.Reanticipate обрабатывает устаревшие данные как обычное обновление сервера: выполняет откат и повторное упреждение, воспроизводя ввод игрока для сохранения согласованности. Чтобы избежать резких визуальных скачков при расхождении серверных и упрежденных значений, используйте доступный обоим компонентам метод Smooth. Метод Smooth принимает начальное и конечное значения, а также длительность сглаживания. Это помогает сохранить плавный и отзывчивый визуальный отклик при сетевой задержке.
Клиентское упреждение повышает отзывчивость игры, однако этот упрощенный подход охватывает не все случаи задержки и сетевых неполадок. Обратите внимание: для полноценного отката и согласования нужна детерминированная физическая система, в которой одинаковые входные данные всегда дают одинаковый результат (см. ниже). Только так можно точно откатывать и повторно просчитывать состояния игры. Без детерминизма симуляции клиента и сервера могут расходиться. Netcode for GameObjects не поддерживает детерминированную физику, необходимую для полноценного клиентского прогнозирования и компенсации задержки. Вместо этого пакет предлагает более простое решение на основе клиентского упреждения и сглаживания, которое повышает отзывчивость без полной системы отката.
Детерминированная физика Детерминированная физическая система гарантирует, что при одинаковых начальных условиях и входных данных симуляция всегда даст одинаковый результат. Netcode for GameObjects использует встроенный физический движок Unity, который не является детерминированным: повторный запуск симуляции с теми же входными данными не гарантирует идентичного результата.
Netcode for Entities, напротив, поддерживает Unity Physics и Havok Physics с возможностью детерминированной симуляции. Благодаря этому пакет обеспечивает полноценное прогнозирование на стороне клиента.
Прогнозирование на стороне клиента в Netcode for Entities Netcode for Entities предоставляет развитые средства клиентского прогнозирования и компенсации задержки. Для каждой сущности на клиенте и сервере выполняется один и тот же код симуляции. Поэтому клиент может прогнозировать состояние игры по вводу игрока и давать немедленный отклик, не ожидая ответа сервера.
Получив от сервера последний снимок, клиент обновляет им все прогнозируемые сущности. Затем он запускает PredictedSimulationSystemGroup. Эта группа систем выполняет симуляцию от самого старого сохраненного тика до текущего целевого времени: откатывает и заново просчитывает состояние игры. Такой процесс исправляет расхождения и поддерживает синхронизацию с авторитетным состоянием сервера.
На сервере цикл прогнозирования выполняется один раз за кадр. Сервер обновляет авторитетное состояние игры и отправляет его клиенту. Клиент хранит историю ввода и прогнозируемых состояний. При рассинхронизации он откатывается к последнему корректному состоянию сервера и повторно просчитывает игру с правильными входными данными. Так клиент остается синхронизированным с эталонным состоянием сервера.
Netcode for Entities также поддерживает расширенные возможности физики: - Несколько физических миров: локальные физические симуляции, которые не нужно реплицировать по сети. - Пользовательские физические прокси: позволяют ghost-сущностям взаимодействовать с физическими объектами, существующими только на клиенте, например с обломками.
- Детерминированная физическая симуляция: при одинаковых входных данных клиент и сервер получают одинаковый результат, поэтому их состояния остаются согласованными. GhostPredictionSmoothingSystem сглаживает ошибки прогнозирования при переходе между прогнозируемым и авторитетным состояниями и поддерживает пользовательские алгоритмы сглаживания.
Сочетание прогнозирования, отката, компенсации задержки и сглаживания сводит к минимуму влияние сети, помогая сохранить целостность и отзывчивость игры. Сравним подходы Netcode for GameObjects и Netcode for Entities к клиентскому прогнозированию:
Характеристика
Netcode for GameObjects
Netcode for Entities
Прогнозирование
Ожидание на клиенте: клиент предугадывает ответ сервера.
Снижение задержки
Предугадывает результат Использует откат и повторную симуляцию сервера и сглаживает переходы. для исправления рассинхронизации.
Снимки
Явно не используются.
Представляют состояние игры в конкретные моменты.
Компенсация задержки
Упрощённая модель с параметрами StaleDataHandling.
Полная компенсация задержки с обращением к мирам столкновений.
Полное прогнозирование: клиент выполняет тот же код симуляции, что и сервер.
Физические Ограничено клиентским взаимодействия прогнозированием с упреждением преобразований.
Взаимодействие прогнозируемых и только клиентских физических миров.
Сглаживание
Метод Smooth для ожидаемых значений.
GhostPredictionSmoothingSystem сглаживает переходы между прогнозируемым и авторитетным состоянием.
Применение
Простые игры с мгновенной визуальной обратной связью.
Сложные игры, требующие точной синхронизации состояния.
И Netcode for GameObjects, и Netcode for Entities предоставляют механизмы клиентского прогнозирования и компенсации сетевой задержки. Netcode for GameObjects предлагает упрощенную модель клиентского упреждения, а Netcode for Entities - более развитую систему с полноценным прогнозированием, откатом и компенсацией задержки.
Термины Netcode for Entities
Netcode for Entities использует Entity Component System (ECS) и Data-Oriented Technology Stack (DOTS). Этот подход отличается от рабочего процесса MonoBehaviour в Netcode for GameObjects. Ниже перечислены термины, которые могут быть вам незнакомы: Entity (сущность): в ECS это базовая единица данных, представляющая отдельный игровой объект или компонент. Сущности легковесны и содержат только данные, но не поведение.
Game world (игровой мир): вся среда, в которой происходит игра. В нее входят все сущности, их состояния и правила взаимодействия. Collision world (мир столкновений): состояние всех физических объектов игрового мира, включая их положение, скорость и взаимодействия. Используется для обнаружения столкновений и физической симуляции. Snapshot (снимок, или ghost snapshot): набор данных о состоянии игры в определенный момент времени. Клиент и сервер периодически синхронизируют состояние игры с помощью снимков. Ghost: сетевая сущность, реплицируемая между сервером и клиентами. В каждом кадре сервер отправляет клиенту снимок текущего состояния всех ghost-сущностей. Они синхронизируют сущности, чтобы все игроки видели согласованное состояние игрового мира.
Predicted ghost (прогнозируемая ghost-сущность): клиентская сущность, которую локально симулируют для немедленного визуального отклика на действия игрока и снижения воспринимаемой задержки. Используйте такие сущности для объектов под непосредственным управлением игрока и других интерактивных объектов, требующих мгновенного отклика. Interpolated ghost (интерполированная ghost-сущность): представление серверной сущности на клиенте. Клиент отображает ее состояние по полученным от сервера снимкам, плавно смешивая их для уменьшения вызванного задержкой джиттера. Такой вариант подходит для объектов, которыми игрок не управляет напрямую и которым не нужен немедленный отклик: персонажей других игроков, NPC и управляемых сервером сущностей.
Network latency and performance
If you’ve ever played an online game, you likely have firsthand experience with how latency can detract from the experience. Poor bandwidth and unstable networking connections lead to jerky player movement, inconsistent frame rates, and noticeable input lag. Now that you understand how clients and servers communicate, you can appreciate why this happens. With the internet filling the gap between your devices, a lot can go wrong. Even with the extra reliability of Unity Transport, UDP packets can get lost, arrive out of order, or get damaged on the way to their destination. These are potential sources of latency, also perceived as lag.
Simulating latency To understand and mitigate the effects of latency during development, you can simulate various network conditions in the Unity Editor using either the Debug Simulator in the UnityTransport or Network Simulator.
Unity Transport Debug Simulator Adjust the Debug Simulator in the UnityTransport component to introduce artificial latency, jitter, and packet loss. You can find these settings in the Inspector when selecting the NetworkTransport object in your scene. Set a few values to recreate network congestion: Latency: Add a delay in milliseconds to simulate slower network connections. For example, set latency to 100ms to mimic moderate network delay.
Jitter: Introduce variability in latency to simulate fluctuating network conditions. For instance, set jitter to 50ms to see how unstable connections affect gameplay. Packet Loss: Specify a percentage of packets to drop, mimicking poor connection quality. Try setting packet loss to 5% to understand its impact on gameplay. Play the game application again to observe how these simulated conditions affect gameplay.
Adjust the Debug Simulator of the Unity Transport.
Network Simulator The Network Simulator from the Multiplayer Tools package lets you test less-than-ideal network conditions. This can help you discover and fix issues before they surface in production. It facilitates simulating network events, such as network disconnects, lag spikes, and packet loss.
Install the Network Simulator from the Multiplayer Tools package.
Test latency in the Network Simulator.
Other network conditioners The Debug Simulator or the Network Simulator only work in the Editor, however. For runtime builds, alternative network conditioners can be used to simulate latency. Tools such as clumsy for Windows and Network Link Conditioner for macOS/iOS can recreate various network conditions for thorough testing. For more information see the Testing and Debugging section further on in this guide. Dealing with the impact of latency on application performance is one of the biggest challenges in multiplayer development. Fortunately there are some strategies to help mitigate the effects of latency. Let’s explore a few of them here.
Client-side interpolation One way to reduce the effects of latency is client-side interpolation. In this method, each client intentionally delays rendering by a short interpolation period, rather than rendering it right away. In client-server topology, clients generally render a state that is about half the round-trip time (RTT) behind the server. Client-side interpolation adds an extra intentional delay on top of that. By running slightly behind, clients can buffer incoming state updates from the server. When it’s time to render the next update, the client calculates an interpolated state from the two most recent server ticks. The buffer allows the client to render regular client updates, even if ticks from the server arrive at a jittered, irregular rate. The interpolated states conceal minor latency or jitter.
The client renders interpolated states from a buffer.
Client-side interpolation is available in Netcode for GameObjects as a flag on the NetworkTransform component. Enabling Interpolation interpolates position, rotation, and scale for the associated GameObject.
Client-side interpolation enabled on the NetworkTransform.
Just bear in mind that client-side interpolation introduces a slight delay in rendering, which is necessary for the interpolation.
Client-side prediction and anticipation In our earlier example, the ClientNetworkTransform gives the client direct control over player movement, making the game feel more responsive and instant. However, it’s important to note that client authority is not possible in many games due to a number of factors, such as game design, fairness, and security.
Why server authority In competitive games where fair competition is crucial, client authority can give players the ability to cheat or exploit the game by manipulating the client-side code or data. Games with complex player interaction and shared game worlds often require server authority to ensure data integrity, prevent tampering, and maintain a consistent experience for all players. Here, server authority is required to ensure a level playing field and maintain the integrity of the game. This means using the standard NetworkTransform component instead of the ownerauthoritative ClientNetworkTransform. This ensures that client input does not control the player; instead, only the server will have control.
Moving a NetworkTransform using server authority.
Server authority, however, can exacerbate latency. Instead of manipulating an onscreen player directly, each client must send its inputs to the server. The server then processes those inputs to simulate the game and calculates the game state. Only when the client receives the results of that simulation can it display the next frame. When using an authoritative server, players perceive latency because of the time it takes for data to travel from the client to the server and back again. In this scenario, clients tend to lag behind the server, especially as your UDP packets need to traverse the internet.
For many elements in a game, this lag might be acceptable, but for others, like the player’s character, such lag can ruin the feel of the game and make it difficult to play.
How client-side prediction works Client-side prediction offers one solution to the lag introduced by server authority. Instead of waiting for the server’s response, the client predicts the game state a fraction of a second into the future and updates the game visually. This is called “prediction” because the client predicts the game state without knowing the true state from the server. By doing this, the client can provide instant visual feedback to the player’s actions, making the game feel responsive.
Client predicts the game state.
Simultaneously, the client sends the player’s actions to the server in a packet. The server receives the client’s input packet and simulates the game state using those inputs. The server processes these inputs to simulate the game state, establishing the authoritative game state as the ground truth. The server sends that authoritative state back to the client.
The server sends back the authoritative state.
Reconciliation and rollback The client then compares the authoritative state with the anticipated state and looks for any differences. If the two states are close enough, then nothing happens and the client continues playing. If there is a significant mismatch – also called a “desync” – then, the client must decide how to correct its state to match the server’s authoritative state. This process is called reconciliation.
The client receives a mismatched state, or “desync.”
To handle latency and compensate for it, the client stores a history of its inputs and predicted state for a certain number of frames. When a desync occurs, the client can roll back its state to the last known correct state from the server. Then, it re-simulates the game from that point using the correct inputs. This brings the client state back in sync with the server.
The client reconciles the desync.
On any given frame, the client may need to re-simulate several frames, which is why a networked application can be more computationally expensive. This reconciliation and rollback, however, is what helps maintain a smooth and consistent experience for the player even with the presence of network latency.
Client-side anticipation in Netcode for GameObjects Netcode for GameObjects supports client anticipation, a simplified model for handling latency without full client-side prediction and reconciliation. It uses these components: —
AnticipatedNetworkVariable<T> is a generic component used for scalar or simple data types like integers, floats, and colors. It’s suitable for non-transform properties such as health, score, or item states.
AnticipatedNetworkTransform works similarly to AnticipatedNetworkVariable but is designed for Transform data, including position, rotation, and scale.
Client anticipation allows the client to provide immediate visual feedback to the user while waiting for the server’s authoritative update. This helps make the game feel more responsive. In our simple ColorTrigger example, when a player changes the color of an object from white to blue, the client can visually update the color immediately while waiting for the server to confirm the change. Between the client and server, anticipation would look something like this:
The client anticipates the game state.
AnticipatedNetworkVariable<T> and AnticipatedNetworkTransform both work by separating values into anticipated (visual) and authoritative states. Anticipation refers to the client’s predicted state, which provides immediate visual feedback to the player locally. The authoritative state is determined by the server. When the server’s update arrives, the client compares its anticipated state with the authoritative state. If they differ significantly, the client adjusts its state to match the server’s, ensuring consistency across all clients.
Client anticipation can ignore stale data.
Client anticipation also needs to account for “stale data” – updates from the server that reflect actions occurring before the client’s last request. Netcode for GameObjects provides two ways to handle this through the StaleDataHandling property: —
StaleDataHandling.Ignore ignores stale data and keeps the anticipated value. This can be useful if the state is changing rapidly and causing visual flickering.
StaleDataHandling.Reanticipate treats stale data like any other server update, triggering rollback and re-anticipation, which replays player inputs to maintain consistency.
To prevent choppy visual updates when server values differ from anticipated values, use the Smooth method available to both components. Smooth requires a starting value, a final value, and a duration for the smoothing process. This helps maintain a smooth and responsive visual experience despite network latency. While client anticipation improves gameplay responsiveness, this simplified approach may not cover all cases of latency and network issues. Note that true rollback and reconciliation require a deterministic physics system, which ensures that the same inputs will always produce the same results (below). This is essential for accurately rolling back and resimulating game states. Without determinism, discrepancies can arise between the server and client simulations. Netcode for GameObjects does not support deterministic physics, which is necessary for true client prediction and lag compensation. Instead, Netcode for GameObjects provides a simpler solution that focuses on client anticipation and smoothing. This can improve responsiveness without a full rollback system.
Deterministic physics A deterministic physics system ensures that given the same initial conditions and inputs, the physics simulation will always produce the same results. Note that Netcode for GameObjects uses Unity’s built-in physics engine, which is not deterministic. When re-running the simulation with the same inputs, the physics system does not guarantee identical results. Netcode for Entities, however, supports Unity Physics and Havok Physics, both of which offer deterministic simulation capabilities. This allows Netcode for Entities to support true client-side prediction.
Client-side prediction in Netcode for Entities Netcode for Entities offers advanced tools for handling client-side prediction and lag compensation. The same simulation code runs on both the client and the server for each entity. This allows the client to predict the state of the game based on player inputs, giving immediate feedback without waiting for the server’s response. When the client receives the latest snapshot from the server, it updates all the predicted entities with this data. After applying this snapshot, the client runs a simulation called the PredictedSimulationSystemGroup. This simulation processes from the oldest saved tick to the current target time, rolling back and re-simulating the game state to ensure that the client accurately simulates the game state. This rollback and re-simulation process helps the client correct any discrepancies and maintain synchronization with the server’s authoritative state. On the server side, the prediction loop runs once per frame. The server updates the authoritative game state and sends this updated state back to the client. The client stores a history of inputs and predicted states. When a desync occurs, the client rolls back to the last correct state from the server and re-simulates the game using the correct inputs. This keeps the client in sync with the server’s “ground truth.” Netcode for Entities also supports advanced physics features like: —
Multiple physics worlds: This allows for local-only physics simulations that don’t need to be replicated across the network.
Custom physics proxies: These enable interactions when you would like to make the ghosts interact with physics objects that are present only on the client (ex: debris).
Deterministic physics simulation: This ensures that the client and server simulations produce the same results given the same inputs, maintaining consistency between the client and server states.
The GhostPredictionSmoothingSystem helps smooth out prediction errors by transitioning between predicted and authoritative states, with options for custom smoothing.
This combination of prediction, rollback, lag compensation, and smoothing techniques minimizes the impact of latency and helps maintain game integrity and responsiveness. Compare how Netcode for GameObjects and Netcode for Entities handle client prediction:
Feature
Netcode for GameObjects
Netcode for Entities
Prediction Method
Client anticipation: The client anticipates server responses.
Full client prediction: The client runs the same simulation code as the server.
Latency Mitigation
Anticipates server results and smooths transitions
Uses rollback and re-simulation to correct desyncs
Snapshots
Not explicitly used
Uses snapshots to represent game state at specific moments in time
Lag Compensation
Simplified model with StaleDataHandling options
Comprehensive lag compensation with a reference to collision worlds
Physics Interaction
Limited to client-side prediction with anticipated transforms
Supports interaction between predicted and client-only physics worlds
Smoothing
Uses the Smooth method for anticipated values
GhostPredictionSmoothingSystem for smoothing transitions between predicted and authoritative states
Use Case
Suitable for simpler games requiring immediate visual feedback
Suitable for complex games requiring accurate state synchronization
Both Netcode for GameObjects and Netcode for Entities provide mechanisms to handle client prediction and mitigate latency issues encountered during multiplayer networking. While Netcode for GameObjects offers a simplified model using client anticipation, Netcode for Entities provides a more advanced system with full prediction, rollback, and lag compensation.
Netcode for Entities terms Netcode for Entities uses the Entity Component System (ECS) and Data-Oriented Technology Stack (DOTS), which differ from the MonoBehaviour workflow used in Netcode for GameObjects. Here are some terms that may be new: Entity: In ECS, an entity is a basic unit of data representing individual GameObjects or components within the game. Entities are lightweight and contain no behavior, only data. Game world: The game world refers to the entire environment in which the game takes place. It includes all the entities, their states, and the rules governing their interactions. Collision world: The collision world is the state of all physical objects in the game world, including their positions, velocities, and interactions. It is used for collision detection and physics simulations. Snapshot: A snapshot (also called “ghost snapshot”) is a set of data representing the game state at a specific moment in time. Clients and servers periodically stay in sync by updating the game state via snapshots. Ghost: A ghost is a networked entity that is replicated across clients and the server. Every frame, the server sends a snapshot of the current state of all ghosts to the client. Ghosts are used to synchronize the state of entities between the server and clients, ensuring that all players have a consistent view of the game world. Predicted ghost: A predicted ghost is a client-side entity simulated locally to provide instant visual feedback for player actions, reducing perceived latency. Use these for entities that are directly controlled by the player or other interactive entities that need immediate feedback. Interpolated ghost: An interpolated ghost is a representation of a server-side entity on a client. The client displays its state based on snapshots received from the server, blending them to minimize jitter caused by latency. Use these for entities not controlled directly by the player that don’t require immediate feedback, like other players’ characters, NPCs, or server-controlled entities.