Работа с предсказанием
1 Вступление
2 Подробности
2.1 Передача по сети через таблицы данных
2.2 Создание таблицы предсказаний
2.1 Консольные комманды
2.1.1 cl_predictionlist
2.1.2 cl_pdump
3 Решение проблем
Вступление
Система предсказания (prediction) Source спроектирована с целью
уменьшить влияние задержек на динамику игры. Наиболее чувтсвительны к
задержкам события когда игрок нажимает клавиши (во время чего комманда
отправляется на сервер и возвращается обратно), система предсказания
Source имитирует эффект нажатия кнопки на клиенте немедленно. Когда
после этого приходит ответ от сервера, клиент определяет корректная или
нет спекулятивная имитация.
- 99% времени, спекуляция клиента корректная. Поэтому, клиент может играть не замечая задержек в передаче по сети.
- Если спекуляция клиента не корректная, клиент возвратно повторяет
симуляцию всех комманд которые выполнялись с ошибочными данными. В связи
с этим, клиент ощущает небольшой рывок в его
позиции видимости, анимации оружия, и т.д. К счастью, если код написан
корректно, этот случай не очень часто встречается.
ПодробностиОсновные требования которые требуется выполнить для того чтоб энтитя использовала систему предсказания:
- Одинаковые части кода энтити должны выполняться на клиенте и сервере. Такой код относится к общему коду (shared code).
- Все переменные энтити которые меняются на сервере и клиенте должны передаваться при помощи таблиц данных.
- Эти переменные должны также быть добавлены в список называемый таблица предсказаний (prediction table).
Передача по сети через таблицы данныхХорошее место для начала - рассмотреть пример кода оружия. Откройте файл
src/game_shared/basecombatweapon_shared.cpp. Блоки
#ifdef CLIENT_DLL и
#ifdef GAME_DLL
являются разделением кода между клиентским и сервером (условные
директивы компилятора). Эти блоки указывают какой код компилируется для
client DLL
а какой для server DLL. Приведенный ниже код (сокращенный) соответствует
шагу 2 описанной выше последовательности (помещает переменные
измененные общим кодом в
таблицу данных).
BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon)
#if !defined( CLIENT_DLL )
SendPropInt( SENDINFO(m_iState ), 8, SPROP_UNSIGNED ),
SendPropEHandle( SENDINFO(m_hOwner) ),
#else
RecvPropInt( RECVINFO(m_iState )),
RecvPropEHandle( RECVINFO(m_hOwner ) ),
#endif
END_NETWORK_TABLE()
Создание таблицы предсказанийТаблица предсказаний описывает данные в вашей энтити которые должны быть
одинаковые на клиенте и сервере когда клиент спекулятивно имитирует
комманду. Это список переменных котрые передаются по сети и их типы.
Если значение допустимое к отклонению от серверного (как в случае с
значением с плавающе запятой которое передается с урезанным количеством
бит), то вы можите указать на сколько допустимо отклонение. В коде
приведенном ниже, это выполняется макросом
DEFINE_PRED_FIELD_TOL macro.
Примечание: таблица предсказаний только требуется к наличии в client DLL, так что ограничте код при помощи
#ifdef CLIENT_DLL.
#ifdef CLIENT_DLL
BEGIN_PREDICTION_DATA( CBaseCombatWeapon )
DEFINE_PRED_FIELD( m_nNextThinkTick, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_hOwner, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD_TOL( m_flNextPrimaryAttack, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
END_PREDICTION_DATA()
#endif
Консольные коммандыЕсли вы добавляете функциональность к оружию и забываете выполнить шаги
описанные выше, энтитя может сопровождаться рывками и страностями с
анимацией. Ниже приводятся консольные комманды которые можно
использовать для отладки в таких случаях.
cl_predictionlistЕсли ввести
cl_predictionlist 1 в консоли, вы увидите графическое
окно в верхнем правом углу. Оно отображает все энтити которые в данный
момент используются системой предсказания Source
(то есть: выполняющиеся одновременно на клиенте и сервере). левая
колонка отображает индекс кажой энтити, средняя колонка отображает имя
классов энтитей.
Как только будет определен индекс энтити, которую требуется отладить, используется
cl_pdump.
cl_pdumpЕсли установить значение
cl_pdump к индексу предсказываемой энтити (из левой колонки в выводе окна
cl_predictionlist),
развернется обширный список всех предсказываемых переменных энтити.
Затем в процессе игры можно увидеть какие из этих переменных не
попадают в предсказание. Переменные отмечаются красным цветом когда
клиент не предсказывает ее значение.
Решение проблемПредположим мы видим переменную красным цветом в панели
cl_pdump
время от вермени. Теперь, мы знаем что иногда клиент производит
отличающеся значение от того что на сервереs. Обычно это можно отнести к
следующим проблемам:
- Клиент не выполняет тот же код ч товыполняет сервер. Это может быть случай, если участок кода помещен в секцию ограниченную #ifdef GAME_DLL или #ifndef CLIENT_DLL вокруг кода который влияет на переменную отмеченную красным цветом.
- Другая переменная которая влияет на данное значение становящееся
красным не передается через таблицу данных. В таком случае на клиенте,
значение этой переменной всегда неверное (так как сервер никогда не
передает его).
- Также возможно не было добавлено соответствующее отклонение при помощи макроса DEFINE_PRED_FIELD_TOL.
Например, если передается значение с плавающей запятой в диапазоне от
0.0 до 255.0, и было задано только 4 бита точности, тогда требуется
отклонение около 17.0, иначе система предсказания считает значение
переменной неверным изза того что значение сжимается до 4
бит перед отпарвкой клиенту.
Отслеживание проблем предсказаний обычно предмет рассмотрения различного
кода который влияет на переменные которые отображаются красным, и
проверки других переменных которые влияют на их значение. Вначале это
может показаться утомительным, но проверив это на собственном опыте
проблемы с системой предсказания быстро исчезают.
Перевод: DarkLight
Источник:
www.developer.valvesoftware.com