¿Cómo sincronizar relojes a través de redes para el desarrollo de juegos?

10

Estoy escribiendo un juego que tiene muchos aspectos basados ​​en el tiempo. Utilizo el tiempo para ayudar a estimar las posiciones de los jugadores cuando la red se detiene y los paquetes no están pasando (y el tiempo entre la recepción y la recepción de los paquetes). Es un juego de tipo pacman en el sentido de que un jugador elige una dirección y no puede dejar de moverse, por lo que el sistema tiene sentido (o al menos eso creo).

Entonces tengo dos preguntas: 1) ¿Cómo sincronizo los relojes de los juegos al principio ya que hay un retraso en la red? 2) ¿Está bien NO sincronizarlos y simplemente asumir que son iguales (mi código es independiente de la zona horaria)? No es un juego súper competitivo en el que las personas cambien sus relojes para hacer trampa, pero aún así.

El juego se está programando en Java y Python (desarrollo paralelo como proyecto)

sinθ
fuente
77
buscar ntp
monstruo de trinquete
55
Estoy seguro de que esta pregunta ya está cubierta en gamedev.stackexchange.com, o al menos pertenece allí.
congusbongus
1
@CongXu: No estoy tan seguro. Si bien esta es una tarea que generalmente se realiza para juegos, no es inherentemente específica para el desarrollo del juego. Muchos otros sistemas distribuidos necesitan reloj sincronizado.
Jan Hudec
2
¿Ya intentó usar la opción TIMESTAMP de IPv4? Más información está en linux.die.net/man/7/socket desde allí a linux.die.net/man/3/cmsg y luego un pequeño programa de ejemplo en pdbuchan.com/rawsock/rawsock.html el último antes del Sección IPv6.
ott--
2
Los juegos (aplicaciones) no deben tocar el reloj del sistema.
Restablecer a Monica - M. Schröder

Respuestas:

9

Creo que definitivamente no está bien sincronizar el reloj en el sistema . El usuario no espera que toque la configuración del sistema y muchos sistemas ni siquiera lo dejan.

Todo lo que necesita es tener una correlación para convertir la marca de tiempo del reloj de un lado al reloj del otro lado. Por otro lado, necesita que esta correlación sea bastante precisa, digamos al menos una centésima de segundo, si desea usarla para predecir las posiciones de los jugadores. El reloj del sistema nunca estará tan bien correlacionado entre máquinas aleatorias. Por lo tanto, debe establecer la correlación usted mismo, utilizando alguna variación en el tema NTP , probablemente incrustado en sus otros mensajes para conservar el ancho de banda de la red.

La idea básica podría ser que con cada paquete que envió la marca de tiempo lo envió y el número de secuencia y la marca de tiempo cuando recibió el último paquete del otro lado. A partir de esto, calcula el viaje de ida y vuelta: por ejemplo, si el paquete Q dice que se envió a 1000 y el paquete P se recibió a 500, luego de que usted envió el paquete P a 0 y está recibiendo Q a 800, el viaje de ida y vuelta es (800 - 0 ) - (1000 - 500) = 300. No hay forma de conocer la asimetría, por lo que simplemente asume que el paquete toma la mitad (150) de ticks en cualquier dirección. Y esa marca de tiempo remota está por delante de la local en 1000 - (800 - 150) = 350 ticks. El viaje de ida y vuelta variará. Si asume que el reloj es razonablemente preciso, debe usar un promedio a largo plazo de la correlación.

Tenga en cuenta que tampoco desea utilizar el reloj del sistema para el reloj. Es posible que se vuelvan a sincronizar a mitad de camino, lo que lo desviará del camino. Debería usarlo clock(CLOCK_MONOTONIC)en Unix o GetTickCounten Windows (no estoy seguro de cómo esas API están envueltas en Java o Python en este momento).


Nota: La SO_TIMESTAMPopción de socket (ver socket (7) mencionado por ott-- en el comentario sobre la pregunta) sería útil para separar el efecto de latencia del bucle de eventos que recibe los paquetes. Si vale la pena el esfuerzo depende de cuán buena precisión necesite.

Jan Hudec
fuente
1

¿Cómo sabes qué reloj de jugador es correcto? No, así que usa un reloj de referencia .

NTP es excesivo aquí: solo necesita una precisión de ~ 1 segundo, así que use rdate o elija algo de uno de los muchos algoritmos de sincronización de reloj.

Una vez que haya elegido un método, haga que la máquina de cada jugador recoja el tiempo por ese método (sin cambiar el reloj de su sistema). Cualquier diferencia que haya entre la hora UTC de referencia y la hora UTC del reloj del sistema de los jugadores es su compensación efectiva. Cada vez que realice cálculos relacionados con el tiempo para, por ejemplo, extrapolar movimientos de bot o viñetas de trazado de rayos, tendrá en cuenta este desplazamiento después de obtener la hora del sistema. El uso de UTC eliminará los factores de zona horaria.

JBRWilkinson
fuente
1

En segundo lugar, declaro que no debe usar NTP ni acercarse al reloj del sistema para esto. Si realmente examina este requisito, encontrará que tiene las siguientes necesidades:

  • Cuánto tiempo ha transcurrido desde el fotograma anterior para que pueda avanzar cualquier cosa basada en el tiempo. Esto puede ser diferente en el cliente y el servidor si ambos marcan a diferentes velocidades (por ejemplo, a veces puede ver servidores que se ejecutan a una velocidad fija de 20Hz (o lo que sea), pero clientes que pueden ejecutar tan rápido como lo deseen).
  • Cuánto tiempo ha transcurrido desde que comenzó el mapa actual. Este es un temporizador basado en cero (simplemente inicie a 0 en el cliente y el servidor cuando se inician) y la hora del servidor se considera el "maestro", por lo que el servidor envía su vista actual de esta hora al cliente para cada trama que se ejecuta en el servidor Esto se puede obtener tomando la hora actual del servidor y restando la hora en que se inició el servidor, o acumulando los tiempos por cuadro anteriores. El tiempo anterior por cuadro del lado del cliente también se puede utilizar para generar puntos de interpolación entre dos cuadros de servidor consecutivos.
  • Una referencia "tiempo base" desde el cual avanza el resto del tiempo; Esto puede ser (pero no es necesario que sea para todos los tipos de juego) lo mismo tanto en el cliente como en el servidor y se inicializa al comienzo del juego (o mapa actual) pero nunca cambia después (a menos que sea un juego nuevo o un mapa nuevo) - Está empezado).

Este es un esquema simplificado: no intento abordar problemas como la latencia / paquetes descartados / etc., pero es el marco básico en el que se debe basar todo.

Nada de esto debe acercarse al reloj del sistema o preocuparse por asuntos tales como diferentes zonas horarias, aunque el último elemento puede usar una zona horaria si lo desea. Lo importante es que los tiempos transcurridos reales se miden utilizando un temporizador de alta resolución basado en cero, por lo que son completamente independientes de las diferencias de zona horaria. ¿Quieres encontrar la hora actual en el servidor? Simplemente agregue el tiempo transcurrido al tiempo base de referencia y ya lo tiene. Igualmente para el cliente.

Maximus Minimus
fuente