суббота, 24 сентября 2011 г.

Как работает компенсация лагов в 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 - а это типа дефолтное "рабочее" значение
• поскольку сервер не может посылать обновления клиенту при каждом изменении мира, он буферизует и посылает дельту - что изменилось для каждого клиента с момента последнего пакета отправленного только этому клиенту :)
• полные "обновления" посылаются толлько при загрузке игры, затем шлется только дельта




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

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

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

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

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

1. 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

2. input prediction (предсказание ввода)


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

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

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

• вся эта котовасия включается по дефолту (cl_predict 1)
• само сглаживание происходит на время cl_smoothtime

3. lag compensation (предсказание действий других игроков)


если вы смогли понять предыдущие, то это вообще взрыв мозга xD

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

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

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

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

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

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

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

именно за счет 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 )


вот еще видео с хантером, где даже народ не понимает что происходит и думает что это баг



аналогичное для Counter-Strike Source

Комментариев нет:

Отправить комментарий