Ru/Prediction

From Valve Developer Community
Jump to navigation Jump to search

Вступление

Система предсказания (prediction) Source спроектирована с целью уменьшить влияние задержек на динамику игры. Наиболее чувствительны к задержкам события, когда игрок нажимает клавиши (во время чего команда отправляется на сервер и возвращается обратно), система предсказания Source имитирует эффект нажатия кнопки на клиенте немедленно. Когда после этого приходит ответ от сервера, клиент определяет корректная или нет предполагаемая имитация.

  • 99% времени, предположения клиента корректны. Поэтому, клиент может играть, не замечая задержек в передаче по сети.
  • Если предположение клиента некорректно, клиент идет назад и повторяет имитацию всех комманд которые выполнялись с ошибочными данными. В связи с этим, клиент ощущает небольшой рывок в его поле зрения, анимации оружия, и т.д. К счастью, если код написан корректно, этот случай не очень часто встречается.

Для более подробной информации можно прочитать Lag Compensation.

Подробности

Основные требования которые требуется выполнить для того чтоб энтитя использовала систему предсказания:

  1. Одинаковые части кода энтити должны выполняться на клиенте и сервере. Такой код относится к общему коду.
  2. Все переменные энтити которые меняются на сервере и клиенте должны передаваться при помощи таблиц данных.
  3. Эти переменные должны также быть добавлены в список называемый таблица предсказаний (prediction table).

Передача по сети через таблицы данных

Хорошее место для начала рассмотреть код оружия. Если у вас есть установленный исходный код, вы можете посмотреть файл src\game_shared\basecombatweapon_shared.cpp. Там, вы можете увидеть блоки #ifdef CLIENT_DLL и #ifdef GAME_DLL. Это для разделения какой код компилируется в клиентской DLL и какой в компилируется в серверной DLL. Приведенный ниже (сокращенный) код соответствует шагу 2 описанной выше последовательности (помещает переменные измененные общим кодом в таблицу данных).

BEGIN_NETWORK_TABLE(CBaseCombatWeapon, DT_BaseCombatWeapon)
#ifndef 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.

Template:Note:ru

#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_pdump для отладки этого.

Подавление сетевых данных

Большинство оружий имеют общий код, одинаковый код для клиента и сервера. Это позволяет клиенту предсказывать вещи. Не требовательные вещи такие как эффекты оружия могут быть полностью выполняться клиентом, без отправки серверу данных эффекта всем клиентам. В этом случае подавление данных хорошая идея, которая даст меньшую загрузку сети.

Интерфейс IPredictionSystem предназначен для этого. Когда IPredictionSystem::SuppressHostEvents( pPlayer ); вызван, все сетевые данные к этому пользователю останавливаются. Отправка NULL повторно остановит подавление. Для примера:

if ( pPlayer->IsPredictingWeapons() )
IPredictionSystem::SuppressHostEvents( pPlayer );

pWeapon->CreateEffects();

IPredictionSystem::SuppressHostEvents( NULL );


Решение проблем

Предположим мы видим переменную становлящаяся время от времени красным цветом в панели cl_pdump. Теперь, мы знаем что иногда клиент производит отличающеся значение от того что на сервере. Обычно это можно отнести к следующим проблемам:

  1. Клиент не выполняет тот же код что выполняет сервер. Это может быть случай, если участок кода помещен в секцию ограниченную #ifdef GAME_DLL или #ifndef CLIENT_DLL вокруг кода который влияет на переменную отмеченную красным цветом.
  2. Другая переменная которая влияет на данное значение становящееся красным не передается через таблицу данных. В таком случае на клиенте, значение этой переменной всегда неверное (так как сервер никогда не передает его).
  3. Также возможно не было добавлено соответствующее отклонение при помощи макроса DEFINE_PRED_FIELD_TOL. Например, если передается значение с плавающей запятой в диапазоне от 0.0 до 255.0, и было задано только 4 бита точности, тогда требуется отклонение около 17.0, иначе система предсказания считает значение переменной неверным изза того что значение сжимается до 4 бит перед отправкой клиенту.

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

Template:Otherlang:ru Template:Otherlang:ru:en