Я прочитал Valve + Gafferon и сотни страниц из Google, но по какой-то причине я не могу понять, как прогнозируют клиенты.
Насколько я понимаю, основная проблема заключается в:
- Клиент А отправляет информацию на
T0
- Сервер получает вход в
T1
- Все клиенты получают изменения по адресу
T2
При T2
однако, используя предсказание клиента, клиент А теперь в положении уместно T4
.
Как вы гарантируете, что Клиент А, когда он предсказывает, что сервер примет запрос на перемещение, не будет опережать сервер? Очевидно, что все время, пока они впереди, это приводит к возврату туда, где сервер их видел в последний раз. Со всеми исправлениями, которые я пробовал, это все еще заметно, когда вы останавливаетесь, потому что сервер останавливается позади вас
источник
Я на самом деле не реализовал это (поэтому могут быть некоторые проблемы, которые я не сразу вижу), но я подумал, что постараюсь помочь.
Вот что вы сказали, что происходит:
Вероятно, было бы полезно подумать о времени сервера. Это (вероятно) очень похоже на то, как работает интерполяция .
Каждая команда отправляется с серверным временем. Это серверное время вычисляется в начале матча, запрашивая тик сервера, компенсируя время пинга. На клиенте у вас есть свой локальный счетчик тиков, и каждая отправляемая вами команда преобразуется в тики сервера (это простая операция вычитания)
Также клиент всегда рендерит «в прошлое». Итак, вы предполагаете, что мир, который видит клиент, скажем, на 100 мс отстает от времени сервера.
Итак, давайте перефразируем ваш пример с временем сервера (обозначено S).
Клиент отправляет входные данные в момент времени T0 со временем сервера S0 (что, я полагаю, на самом деле является «клиентским представлением времени сервера минус время интерполяции»). Клиент не ждет ответа от сервера и немедленно перемещается.
Сервер получает вход в T1. Сервер определяет авторитетную позицию клиента в момент времени сервера S0, данный клиентом. Отправляет это клиенту.
Клиент получает официальную позицию в T2 (все еще с обозначением времени сервера S0). Клиент следит за прошлым количеством времени предыдущих событий (вероятно, просто очередью всех неподтвержденных предсказаний).
Если прогнозируемая позиция / скорость / независимо от того, что сервер отправляет обратно на S0, отличается от того, что клиент сохранил на S0, клиент каким-то образом это обрабатывает. Либо вернув игрока обратно в его предыдущую позицию, либо изменив имитацию предыдущего ввода, либо, может быть, что-то еще, о чем я не думал.
источник
На самом деле в github есть реализация с открытым исходным кодом, которая показывает, как это делается. Проверьте Lance.gg
репозиторий github: https://github.com/lance-gg/lance
Код предсказания клиента реализован в модуле под названием
src/syncStrategies/ExtrapolateStrategy.js
Помимо экстраполяции, есть две концепции, которые я не видел вышеупомянутыми:
источник
Клиент А всегда впереди сервера - но это не важно. Отключить клиента нужно только в том случае, если сервер сообщает, что возникла проблема с сообщенной позицией, после чего клиент повторно запускает все изменения, внесенные с момента ошибки с исправленными значениями, чтобы привести его в совместимое состояние. с сервером.
Чтобы сделать это, клиент должен запомнить некоторые из своих прошлых состояний и прошлых обновлений. Это могут быть только несколько простых значений, таких как положение, скорость, ориентация и тому подобное. Сервер будет периодически отправлять подтверждение того, что различные клиентские обновления были законными, то есть они теперь могут быть забыты от клиента. Однако если сервер сообщает, что обновление было недействительным, состояние клиента откатывается до этой точки, и будущие изменения применяются к этому измененному состоянию.
В нижней части статьи Valve есть несколько дополнительных ссылок, которые стоит прочитать - это одна из них: https://developer.valvesoftware.com/wiki/Prediction
источник
t=4
) получает информацию оt=2
, так он сбрасывает состояние наt=2
то повторно пробегов обновления , чтобы принести объекты изt=2
кt=4
?