Як працює прогнозування на стороні клієнта?


33

Я читав Valve + Gafferon і сотні сторінок від Google, але з будь-якої причини я не можу осягнути передбачення клієнта.

Наскільки я розумію, основна проблема:

  • Клієнт А надсилає вхід на адресу T0
  • Сервер отримує вхід на адресу T1
  • Усі клієнти отримують зміну за адресою T2

При T2однак, використовуючи пророкування клієнта, клієнт А тепер в положенні доречно T4.

Як Ви гарантуєте, що Клієнт А, передбачивши, що сервер прийме запит на переміщення, не випередить його? Очевидно, що весь час вони випереджають, це призводить до того, що вони повертаються туди, де сервер їх бачив востаннє. З усіма виправленими вами виправленнями, це все ще помітно, коли ви зупиняєтесь, оскільки сервер зупиняється за вами

Відповіді:


35

Про це я написав низку статей . Він базується на тих самих ідеях, які ви читали деінде, але пояснив дуже детально і (сподіваюся) доступним способом.

Зокрема, стаття про передбачення клієнта саме ця .


Відмінні статті :-) Я хотів би побачити четверту частину серії. Як невелика пропозиція, посилання на наступну частину в кінці кожної статті безумовно покращить навігацію.
АБО Mapper

5
@ORMapper - я нарешті написав 4-ю статтю! gabrielgambetta.com/fpm4.html
ggambett

Kudos для вашої серії статей :-) Дуже корисно, дякую :-)
АБО Mapper

Усі статті (я можу знайти), які розповідають про відновлення минулого за допомогою збережених знімків, беруть за приклад зйомку. Це стосується і руху? Я можу собі уявити, що відновлення руху може призвести до великих відмінностей для інших гравців, якщо вони можуть зіткнутися один з одним. Скажімо, два гравці рухаються один проти одного, і один з них перестає рухатися на кілька «кроків» від точки зору зіткнення. Ця команда зупинки надходить із запізненням через відставання, тож якщо ми будемо перебудовувати світ, то два гравці опиняться на дуже різних позиціях
Лопе

Це цікаве питання. На жаль, я не маю остаточної відповіді. Я думаю, це залежить від того, наскільки критичні рухи для гри; ти просто натикаєшся на когось іншого і нічого не відбувається? У такому випадку сервер, мабуть, не хвилює, це сприймається як помилка передбачення (ми всі бачили, що це відбувається в точках задушення, правда?). Ти вбиваєш іншого гравця при контакті? У цьому випадку правильне значення має набагато важливіше значення і, можливо, варто його реімулювати. Зверніть увагу, що в якийсь момент вам потрібно буде відкинути деякі пакети як "занадто старі", інакше в будь-який момент ви потенційно зможете змінити значення t = 0.
ggambett

4

Я насправді цього не реалізував (тому можуть виникнути проблеми, яких я не відразу бачу), але я подумав, що спробую допомогти.

Ось що ви сказали, що відбувається:

Клієнт А надсилає вхід на T0

Сервер отримує вхід на T1

Усі клієнти отримують зміну на T2

Однак у T2, використовуючи передбачення клієнта, Клієнт А зараз знаходиться на позиції, відповідної T4.

Напевно, було б корисно продумати час сервера. Це (ймовірно) дуже схоже на те, як працює інтерполяція .

Кожна команда надсилається з сервером часу. Цей час сервера з'ясовується на початку матчу шляхом запиту на галочку сервера, компенсуючи час пінгу. У клієнта у вас є власний локальний підрахунок галочок, і кожна команда, яку ви надсилаєте, перетворюється на тикові сервера (це проста операція віднімання)

Також клієнт завжди рендерує "в минулому". Отже, ви припускаєте, що світ, який бачить клієнт, на 100 м відстає від часу сервера.

Тож давайте перефразовуємо ваш приклад із часом сервера (позначеним S).

Клієнт надсилає вхід на T0 із часом сервера S0 (який, мабуть, насправді є "клієнтським представленням часу сервера мінус час інтерполяції"). Клієнт не чекає відповіді від сервера і рухається негайно.

Сервер отримує вхід на T1. Сервер визначає авторитетну позицію клієнта в час сервера S0, заданий клієнтом. Надсилає це клієнту.

Клієнт отримує авторитетну позицію на T2 (все ще з позначенням часу сервера S0). Клієнт відслідковує деякий час, що варто попередніх подій (можливо, це лише черга всіх непідтверджених прогнозів).

Якщо передбачувана позиція / швидкість / те, що сервер надсилає назад у S0, відрізняється від того, що клієнт зберігав у S0, клієнт це якось обробляє. Або відкинувши програвач на попередню позицію, або змінивши попередній вхід, або, можливо, щось інше я не думав.


3
Це все правильно, за винятком того, що стосується надання клієнта в минулому. Відносно сервера клієнт насправді рендерує в майбутньому! Сервер знає, що інформація, яку вона має у кожного клієнта, є давньою і що з цього часу кожен клієнт вже змінився.
Kylotan

2

Насправді в github є реалізація з відкритим кодом, яка показує, як це робиться. Перевірте Lance.gg

github repo: https://github.com/lance-gg/lance

Код передбачення клієнта реалізований у модулі, що називається src/syncStrategies/ExtrapolateStrategy.js

Крім екстраполяції, є два поняття, про які я не бачив згаданих вище:

  1. Поступовий згин. В основному замість того, щоб застосовувати корекцію сервера всі відразу, ви дозволяєте дельті застосовувати невеликими кроками. Таким чином віддалені об'єкти будуть поступово коригувати свої позиції відповідно до позицій сервера. Існує вигин положення, згинання швидкості, кутове згинання та кутове згинання швидкості. Також вам можуть знадобитися різні коефіцієнти вигину для різних об'єктів.
  2. Крок Повторне введення в дію. Той факт, що дані є в минулому, означає, що ви можете відкинути час на час даних сервера та перезапустити з цього моменту. Звичайно, вам все одно потрібно буде нахилитися до нового знайденого положення, а не стрибати на нього.

1

Клієнт А завжди випереджає сервер - але це не має значення. Клієнту потрібно просто відкинути назад, якщо сервер каже, що виникла проблема з повідомленою позицією, і тоді клієнт повторно запускає всі зміни, які він зробив після помилки з виправленими значеннями, щоб привести його до стану, сумісного з сервером.

Для цього клієнту потрібно запам’ятати деякі його попередні стани та оновлені оновлення. Це може бути лише кілька простих значень, таких як положення, швидкість, орієнтація, така річ. Сервер періодично надсилає підтвердження того, що різні оновлення клієнта були законними, тобто тепер їх можна забути від клієнта. Якщо сервер повідомляє, що оновлення було недійсним, стан клієнта відкочується до цього моменту і майбутні зміни застосовуються до цього зміненого стану.

У нижній частині статті Valve є кілька додаткових посилань, які варто прочитати - ось одне з них: https://developer.valvesoftware.com/wiki/Prediction


Отже, я прав, думаючи , що клієнт (в t=4) отримує інформацію про t=2, так він скидає стан на t=2те повторно пробігів поновлення , щоб принести об'єкти з t=2до t=4?
Джордж Дакетт

Я досі чомусь не розумію цього. Сервер не повідомляється про позицію програвача, лише входи. Таким чином, гравець рухається з останньої позиції, на якій сервер сказав, що знаходиться. Введення застосовується. Повідомлено сервер. Сервер підтверджує вхід для всіх. Якщо припустити, що всі команди прийняті, сервер все ще буде відставати від клієнта A - тому, коли клієнт A зупиняється, його характер негайно зупиняється, а потім повертається назад на місце серверів, коли отримує підтвердження зупинки.
Кріс Еванс

@GeorgeDuckett: так (хоча це не повинно бути t = 4, це може бути кожного разу, коли буде виявлено розбіжність, і може бути будь-яка кількість повторно застосованих оновлень.)
Kylotan

@ChrisEvans: відомий стан + зміни, засновані на введенні, еквівалентні стану надсилання. Що стосується зупиняючого прикладу, то він сам по собі є входом, і сервер все ще імітує рух, поки не отримає цей вхід. Припускаючи постійну затримку, сервер зупинить програвач, рухаючись у точно тій самій позиції, яку бачив клієнт, коли він перестав рухатися, оскільки клієнт випереджав сервер. (У реальному світі затримка змінюється, тому ви трохи інтерполюєте, щоб згладити її.)
Kylotan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.