Как работает компенсация лагов в Left 4 Dead (Source engine)

Введение

Итак, игра у нас типичная и клиент-серверная, где сервер занимается следующими вещами:

• симуляция мира вокруг

• отработка движка игры

• обработка командочек пользователя

• игровой мир рассчитывается каждые N ms (эта штука называется внутренний tickrate сервера, для l4d1 и l4d2 = 30)

Клиент посылает серверу команды по UDP

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

UDP это пакеты по 10-200байт, без установления соединения (в отличие от TCP), оверхед примерно 20 байт служебной инфы + данные

• посылается примерно 20-30 пакетов в секунду, это и есть серверный cmd_rate — он может быть от 20 до 30.

• клиент может пожаловаться серверу что он имеет плохой канал итп.. и запросить «худшие» значения по качеству вот этими параметрами

sv_minrate\sv_maxrate — мин и макс значение в байтах сколько он готов принимать

sv_minupdaterate\sv_maxupdaterate — то же самое в командах

cl_updaterate — а это типа дефолтное «рабочее» значение

• поскольку сервер не может посылать обновления клиенту при каждом изменении мира, он буферизует и посылает дельту — что изменилось для каждого клиента с момента последнего пакета отправленного только этому клиенту :)

• полные «обновления» посылаются толлько при загрузке игры, затем шлется только дельта

Net_graph

итак, от чего зависит качество вашей игры

• загрузка цп клиента

• канал клиента

• загрузка цп сервера

• канал сервера

• потери пакетов

• среднее время на прием и предачу ответа от сервера (ping или round trip time)

[ если вы дочитали до сюда, и что-то поняли уже хорошо :) ]

чтобы игра была интересной важно чтобы доли секунды реально что-то значили.

итак чтобы бороться со всей этой фигней, в движке source встроено аж 3 механизма

Entity interpolation

Это предсказание поведения физики\объектов карты на клиенте, работает следующим образом:

• берется n последних пакетов (cl_extrapolate_amount), берется ваш текущий FPS (cl_showfps 1) и рассчитывается следующий кадр и местоположение объектов для которых физика и считается (полет ящика, бросок канистры, танк пнул машинку)

• если пакеты доходят с потерями — то буфер старых пакетов пуст и делать интерполяцию особо не по чему — тут вступает в игру экстраполяция (cl_extrapolate 1) — движок на клиенте пытается округлить вперед (уже довольно грубо) что же творится на карте.

• эффект экстраполяции ограничен по времени — 0.25s после последнего пакета с сервера — чтобы не внести сильные искажения

• итак вот мы пришли к cl_interp

cl_interp = ну это каждый задрот знает ;) = cl_interp_ratio / cl_updaterate

где

cl_interp_ratio = сколько последних пакетов использовать для «округления» вашей картины мира (чем больше = тем дальше от реальности на сервере, но тем плавнее)

cl_updaterate = кол-во команд с сервера, в общем то это константа равная 20..30

Input prediction

допустим у нас пинг 150ms и мы нажали w — сервер узнает об этом только чз 150ms; еще через некоторое время он рассчитает куда же мы переместились; потом он разошлет это всем другим клиентам; и нам придет назад пакет с информацией; и тут мы уже «реально» переместились вперед на метр… как-то так

чтобы не было таких дерганий — движок на клиенте САМ двигает нас вперед не дожидаясь подтверждения от сервера (замечу — реальность на сервере — САМАЯ правильная, т.е. то что на клиенте — неважно)

поэтому так бывает — мы куда-то забежали — клиент это показал — сервер подумал и исправил неправильное округление клиента — вернув назад нас же резким рывком :\

• вся эта котовасия включается по дефолту (cl_predict 1)

• само сглаживание происходит на время cl_smoothtime

Lag compensation

Это предсказание действий других игроков, если вы смогли понять предыдущие, то это вообще взрыв мозга :)

кейс такой:

мы видим врага бегущего мимо и стреляем ему в голову

• мы жмем ЛКМ 8)

• X ms пакет с инф о выстреле пакуется

• Y ms он едет на сервер

• Zms сервер его переваривает, и через время Z+Y+X ваш враг уже убежал..

что же делает движок?

• он помнит все события на сервере за последнюю секунду… при этом он отматывает НАЗАД!!! время и проверяет где тогда был ваш враг — если он был на линии выстрела — засчитывается хит.. бабац. попали.. и во время очередного тика на сервере всем клиентам рассылается информация что вы попали..

именно за счет lag compensation появляются вот такие перлы

Lag_compensation

(игроки часто думают что это баг игры.. лол)

на пальцах — эта известная картинка показывает модельку (то что в текстурах) которую видит клиент и реальные серверные хит-боксы (белым) которые отстают — и показывают то что видит сервер.

• всё это side-effect от lag compensation.

итого имеем lag compensation + entity interpolation + client prediction,

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

P.S.

основной фокус этого текста — объяснить как оно работать внутри,

как настроить cl_interp получше уже давно описано много где.. например тут (http://www.deadzone.ru/forum/showthread.php?t=3536 )

Другие записи...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

* Please Enter the Output

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>