¿Cómo funciona la predicción del lado del cliente?

33

He leído Valve + Gafferon y cientos de páginas de Google, pero por alguna razón no puedo entender las predicciones de los clientes.

A mi entender, el problema básico es:

  • El cliente A envía información a T0
  • El servidor recibe entrada en T1
  • Todos los clientes reciben el cambio en T2

En T2sin embargo, utilizando predicción cliente, el cliente A se encuentra ahora en una posición apropiada para T4.

¿Cómo se asegura de que el Cliente A, al predecir que el servidor aceptará la solicitud de movimiento, no se adelantará al servidor? Obviamente todo el tiempo están adelante, esto resulta en regresar a donde el servidor los vio por última vez. Con todas las correcciones que he probado, esto todavía se nota cuando se detiene, porque el servidor se detiene detrás de usted

Chris Evans
fuente

Respuestas:

35

Escribí una serie de artículos sobre esto. Se basa en las mismas ideas que ha leído en otros lugares, pero se explica de manera muy detallada y (espero) accesible.

En particular, el artículo sobre la predicción del lado del cliente es este .

ggambett
fuente
Excelentes artículos :-) Me encantaría ver la cuarta parte de la serie. Como pequeña sugerencia, un enlace a la siguiente parte al final de cada uno de los artículos ciertamente mejoraría la navegación.
O Mapper
55
@ORMapper: ¡finalmente escribí el cuarto artículo! gabrielgambetta.com/fpm4.html
ggambett
Felicitaciones por su serie de artículos :-) Muy útil, gracias :-)
O Mapper
Todos los artículos (que pude encontrar) que hablan sobre la reconstrucción del pasado usando instantáneas almacenadas toman como ejemplo el rodaje. ¿Esto también se aplica al movimiento? Me imagino que la resimulación de movimiento puede generar grandes diferencias para otros jugadores si pueden chocar entre sí. Digamos que dos jugadores se mueven uno contra el otro y uno de ellos deja de moverse a unos pocos "pasos" de distancia sería un punto de colisión. Este comando de detención llega tarde debido al retraso, por lo que si resimulamos el mundo, los dos jugadores estarían en posiciones muy diferentes
Lope el
Esa es una pregunta interesante. Lamentablemente, no tengo una respuesta definitiva. Supongo que depende de cuán críticos sean los movimientos para el juego; ¿te topas con alguien más y no pasa nada? En ese caso, al servidor probablemente no le importa, se ve como un error de predicción (todos lo hemos visto suceder en los puntos de estrangulamiento, ¿verdad?). ¿Matas al otro jugador por contacto? En ese caso, hacer las cosas bien es mucho más importante y puede valer la pena volver a simular. Tenga en cuenta que en algún momento debe descartar algunos paquetes como "demasiado viejos", de lo contrario estaría resimulando potencialmente desde t = 0 en cualquier momento.
ggambett
4

Realmente no he implementado esto (por lo que puede haber algunos problemas que no estoy viendo de inmediato), pero pensé que intentaría ayudar.

Esto es lo que dijiste que está sucediendo:

El cliente A envía una entrada en T0

El servidor recibe la entrada en T1

Todos los clientes reciben el cambio en T2

Sin embargo, en T2, utilizando la predicción del cliente, el Cliente A está ahora en una posición apropiada para T4.

Probablemente sería útil pensar en términos de tiempo de servidor. Es (probablemente) muy similar a cómo funciona la interpolación .

Cada comando se envía con un tiempo de servidor. Este tiempo del servidor se calcula al comienzo de una coincidencia al consultar la marca del servidor, compensando el tiempo de ping. En el cliente, tiene su propio recuento de tics local, y cada comando que envía se convierte en ticks del servidor (es una operación de resta simple)

Además, el cliente siempre representa "en el pasado". Entonces, asume que el mundo que ve el cliente está, digamos, 100 ms atrás de lo que realmente es el tiempo del servidor.

Así que reformulemos su ejemplo con la hora del servidor (designada por S).

El cliente envía la entrada en T0 con el tiempo del servidor S0 (que supongo que es realmente "representación del cliente del tiempo del servidor menos el tiempo de interpolación"). El cliente no espera la respuesta del servidor y se mueve de inmediato.

El servidor recibe la entrada en T1. El servidor calcula la posición autorizada del cliente en el momento del servidor S0 proporcionado por el cliente. Envía eso al cliente.

El cliente recibe el puesto de autoridad en T2 (aún con la designación del tiempo del servidor S0). El cliente realiza un seguimiento de una cantidad de tiempo anterior de eventos anteriores (probablemente solo una cola de todas las predicciones no confirmadas).

Si la posición / velocidad predicha / lo que sea que el servidor envíe de vuelta en S0 es diferente de lo que el cliente ha almacenado en S0, el cliente maneja esto de alguna manera. Ya sea volviendo a colocar al jugador en su posición anterior o volviendo a simular la entrada anterior, o tal vez algo más en lo que no he pensado.

Tétrada
fuente
3
Eso es todo correcto, excepto el bit sobre la representación del cliente en el pasado. En relación con el servidor, ¡el cliente está renderizando en el futuro! El servidor sabe que la información que tiene de cada cliente es antigua y que cada cliente ya habrá cambiado desde entonces.
Kylotan
2

En realidad, hay una implementación de código abierto en github que muestra cómo se hace esto. Mira Lance.gg

repositorio de github: https://github.com/lance-gg/lance

El código de predicción del cliente se implementa en el módulo llamado src/syncStrategies/ExtrapolateStrategy.js

Además de la extrapolación, hay dos conceptos que no vi mencionados anteriormente:

  1. Flexión incremental. Básicamente, en lugar de aplicar la corrección del servidor de una vez, deja que el delta se aplique en pequeños incrementos. De esta forma, los objetos remotos ajustarán gradualmente sus posiciones para que coincidan con las posiciones del servidor. Hay flexión de posición, flexión de velocidad, flexión angular y flexión de velocidad angular. También es posible que desee diferentes factores de flexión para diferentes objetos.
  2. Re-promulgación de pasos. El hecho de que los datos estén en el pasado significa que puede revertir el tiempo al tiempo de datos del servidor y reiniciar desde ese punto. Por supuesto, aún tendrá que inclinarse hacia la posición recién encontrada, en lugar de saltar a ella.
Gary Weiss
fuente
1

El cliente A siempre está por delante del servidor, pero no importa. Solo tiene que volver a ajustar el cliente si el servidor dice que hubo un problema con la posición informada, momento en el cual el cliente vuelve a ejecutar todos los cambios realizados desde el error con los valores corregidos, para llevarlo a un estado compatible con el servidor

Para hacer esto, el cliente necesita recordar algunas de sus actualizaciones pasadas y de estado. Esto puede ser solo unos pocos valores simples como posición, velocidad, orientación, ese tipo de cosas. El servidor enviará periódicamente un reconocimiento de que varias actualizaciones de clientes eran legítimas, lo que significa que ahora pueden olvidarse del cliente. Sin embargo, si el servidor informa que una actualización no es válida, el estado del cliente vuelve a ese punto y los cambios futuros se aplican a ese estado modificado.

Hay algunos enlaces adicionales en la parte inferior del artículo de Valve que vale la pena leer; este es uno de ellos: https://developer.valvesoftware.com/wiki/Prediction

Kylotan
fuente
Entonces, ¿estoy en lo cierto al pensar que el cliente (at t=4) recibe información t=2, por lo que restablece el estado para t=2luego volver a ejecutar las actualizaciones para llevar los objetos t=2a t=4?
George Duckett
Todavía no lo entiendo por alguna razón. No se le dice al servidor la posición del jugador, solo las entradas. Entonces, el jugador se está moviendo desde la última posición en la que el servidor dijo que estaba. Se aplica la entrada. El servidor está informado. El servidor confirma la entrada a todos. Suponiendo que se aceptan todos los comandos, el servidor seguirá estando detrás del Cliente A, por lo que cuando el Cliente A se detenga, su personaje se detendrá inmediatamente y luego volverá a la ubicación del servidor cuando reciba la confirmación de detención.
Chris Evans
@GeorgeDuckett: sí (aunque no tiene que ser t = 4, podría ser cada vez que se detecte una discrepancia, y podría haber cualquier cantidad de actualizaciones
reaplicadas
@ChrisEvans: el estado conocido + los cambios basados ​​en la entrada son equivalentes al estado de envío de todos modos. En cuanto al ejemplo de detención, eso en sí mismo es una entrada, y el servidor sigue simulando movimiento hasta que recibe esa entrada. Suponiendo una latencia constante, el servidor detendrá al jugador que se mueve exactamente en la misma posición que el cliente vio cuando dejó de moverse, porque el cliente estaba delante del servidor. (En el mundo real, la latencia varía, por lo que interpola un poco para suavizarla.)
Kylotan