Ru/Prediction

==Вступление==
Система предсказания (prediction) движка Source спроектирована с целью уменьшить влияние задержек на динамику игры. Наиболее чувствительны к задержкам события, вызываемые нажатиями клавиш (во время чего команда отправляется на сервер и возвращается обратно), система предсказания Source имитирует эффект нажатия кнопки на клиенте немедленно. После этого, когда приходит ответ от сервера, клиент определяет, была ли корректной предполагаемая имитация. 
* 99% времени, предположения клиента корректны. Поэтому, клиент может играть, не замечая задержек в передаче по сети. 
* Если предположение клиента некорректно, клиент возвращается назад и повторяет имитацию всех команд, которые выполнялись с использованием ошибочных данных. В связи с этим, клиент ощущает небольшой рывок в его поле зрения, анимации оружия, и т.д. К счастью, если код написан корректно, этот случай не очень часто встречается.
Для более подробной информации можно прочитать .
==Подробности==
Основные требования, которые требуется выполнить, чтобы энтити использовала систему предсказания:
# Одинаковые части кода энтити должны выполняться и на клиенте, и на сервере. Такой код относится к общему коду.
# Все переменные энтити которые меняются на сервере и клиенте должны передаваться при помощи .
# Эти переменные должны также быть добавлены в список называемый таблица предсказаний (prediction table).
===Передача по сети через таблицы данных===
Хорошим примером будет рассмотреть код оружия. Если у вас есть установленный исходный код, вы можете посмотреть файл src\game_shared\basecombatweapon_shared.cpp. Там, вы можете увидеть блоки #ifdef CLIENT_DLL и #ifdef GAME_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.
#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
==Консольные комманды==
Если вы добавляете функциональность к оружию и забываете выполнить шаги описанные выше, работа энтити может сопровождаться рывками и странностями с анимацией. Вы можете использовать и , чтобы устранить эти проблемы.
== Подавление сетевых данных ==
Большая часть оружия имеет общий код, одинаковый для клиента и для сервера. Это позволяет клиенту предсказывать события. Не требовательные к точности предсказания события, такие, как эффекты оружия, могут быть полностью выполняться клиентом, без отправки серверу данных эффекта для передачи всем клиентам. В этом случае подавление данных хорошая идея, которая даст меньшую загрузку сети.
Интерфейс IPredictionSystem предназначен для этого.
Когда IPredictionSystem::SuppressHostEvents( pPlayer ); вызван, все сетевые данные к этому пользователю останавливаются. Отправка NULL повторно остановит подавление. Для примера:
if ( pPlayer->IsPredictingWeapons() )
IPredictionSystem::SuppressHostEvents( pPlayer );
pWeapon->CreateEffects();
IPredictionSystem::SuppressHostEvents( NULL );
==Решение проблем==
Предположим мы видим переменную, становящуюся время от времени красной в консоли cl_pdump. Теперь, мы знаем что иногда клиент производит значения отличающиеся от тех, что на сервере. Обычно это можно отнести к следующим проблемам:
# Клиент не выполняет тот же код что выполняет сервер. Это может быть случай, если участок кода помещен в секцию ограниченную #ifdef GAME_DLL или #ifndef CLIENT_DLL вокруг кода который влияет на переменную отмеченную красным цветом.
# Другая переменная которая влияет на данное значение становящееся красным не передается через таблицу данных. В таком случае на клиенте, значение этой переменной всегда неверное (так как сервер никогда не передает его).
# Также возможно не было добавлено соответствующее отклонение при помощи макроса DEFINE_PRED_FIELD_TOL. Например, если передается значение с плавающей запятой в диапазоне от 0.0 до 255.0, и было задано только 4 бита точности, тогда требуется отклонение около 17.0, иначе система предсказания считает значение переменной неверным из-за того что значение сжимается до 4 бит перед отправкой клиенту.
Отслеживание проблем предсказаний обычно предмет рассмотрения различного кода который влияет на переменные которые отображаются красным, и проверки других переменных которые влияют на их значение. Вначале это может показаться утомительным, но проверив это на собственном опыте проблемы с системой предсказания быстро исчезают.