Sincronización de clientes de bajo tráfico con el servidor en MMO

22

Estoy implementando MMO donde el jugador vuela en el espacio en su nave estelar controlando con teclas de flecha y cooperando con otros jugadores.

Quiero implementarlo para que el jugador pueda esquivar su nave del cohete o algo más, así que estoy tratando de predecir el estado del juego completo en el lado del cliente usando el mismo algoritmo de simulación mundial que el uso del servidor. Ese mundo del juego está escrito en C # y se llamará directamente dentro del cliente (está escrito en Unity3D) y a través de CLR en el servidor C ++ (en Linux). Conexión a través de UDP.

El problema es cómo mantener, por ejemplo, 1000 jugadores en un solo mapa (excluyendo todos los demás objetos del juego, mobs ...): Digamos que lo haré:

  • sincronizar servidor con clientes 50 veces por segundo
  • enviar a cada cliente estados de los objetos del juego (y los jugadores) que puede ver (dentro de cierto radio)
  • tiene que enviar 100 objetos a cada jugador dentro de su radio de visión
  • debe enviar un promedio de 50 bytes por objeto de juego (es id, x, y coords, rotación, estado ...)

por lo tanto, deberá tener dicho ancho de banda de red: 1000 (clientes) * 50 (veces por segundo) * 100 (objetos para enviar a cada jugador) * 50 (bytes por objeto) = 250 000 000 bytes por segundo. ¡Es imposible!

¿Es posible reducir este valor de alguna manera? Por ejemplo, permita que los clientes simulen completamente sus mundos de juego (durante un largo período de tiempo) y envíenles solo entradas de otros clientes y sincronicen mundos de juego, digamos, cada varios segundos, pero causará problemas de desincronización extraños debido a cálculos de flotación. .

De todos modos, ¿cómo se programan estos juegos de manera común? Gracias.

eslavo
fuente
1
Envío información lógica sobre los objetos (posición del mundo, estado actual (que es un byte), etc.), sin gráficos.
Eslavo
1
@Slav: ¡Qué bien! Todo ese cambio me recuerda mis días de programación de ASM.
Randolf Richardson
1
¿Por qué no "los días de hoy"? :) Cuando escribo en AS3, Java, Lua, C # y me enfrento a un rendimiento tan pobre que echo de menos C ++ y recuerdo sobre ASM.
Eslavo
1
@Slav: Jeje, no he hecho mucho ASM recientemente. La mayoría de las cosas para mí están en Java y Perl (mod_perl2 en su mayoría) en estos días, pero realmente disfruto estos lenguajes también.
Randolf Richardson
2
@Slav, usted escribió: "Cuando escribo en AS3, Java, Lua, C # y enfrento un rendimiento tan pobre, echo de menos C ++ y recuerdo sobre ASM". Debería aprender a usar Lua y C # correctamente, tal vez encuentre el rendimiento menos abismal. Además, quejarse del lenguaje de secuencias de comandos (supuestamente) más rápido que existe es, en el mejor de los casos, singular ... ¿Es este un juego sobre análisis del genoma humano en tiempo real?
Raine

Respuestas:

20

Solo necesita unas 30 actualizaciones (o incluso menos, tal vez 10 o 20) por segundo. interpolar las posiciones de los objetos en movimiento del lado del cliente. En general, solo debe enviar datos cuando sea REALMENTE necesario. En WoW puede recibir más actualizaciones de los jugadores con los que está en un grupo que de los jugadores que están en la misma ubicación. Además, si otro jugador está lejos de ti, no recibes tantas actualizaciones por segundo sobre él.

Luego, solo envíe una instantánea completa a cada jugador cuando se conecte. Después de eso solo envía los cambios de los objetos del juego. Si no se produjo ningún cambio, no lo envíe.

Luego, ¡haga un uso intensivo de BitVectors o de cómo los llame para reducir la cantidad de datos innecesarios! Ejemplo: También puede intentar escribir un flotante usando solo un byte (en un rango de 0 a 1 o -1 a 1) para que solo tenga 256 o 128 valores diferentes. Pero el jugador no notará ningún movimiento brusco gracias a las interpolaciones.

Mira esto para ver un ejemplo con LidgrenLibrary sobre cómo comprimir datos: http://code.google.com/p/lidgren-network-gen3/wiki/Optimization

A continuación: intente reducir el radio de visión de los jugadores mientras se mueven, y solo transmita información importante en ese momento. Luego, cuando dejen de aumentar su radio de visión nuevamente. Puede usar un sistema de hashing espacial o un árbol bsp para reducir la sobrecarga de buscar objetos que están "dentro del rango". Esta es una buena lectura para el tema: http://en.wikipedia.org/wiki/Collision_detection

Comprima también los datos USTED MISMO, solo USTED conoce la estructura de datos y la coherencia temporal en los datos (que pueden y deben explotarse). Debe usarse un algoritmo general como Bzip2, Deflate, lo que sea, ¡pero solo como la etapa final de compresión!

Además, para obtener información que no sea crítica para el juego, también puede emplear técnicas P2P adicionales. Ejemplo: un jugador reproduce la animación "hola" (solo un efecto gráfico). El jugador envía esta información al servidor, pero el servidor no transmite la información a los otros jugadores. En cambio, este efecto no crítico es enviado por el propio jugador a los otros clientes dentro del alcance.

EDITAR (por el comentario):

Métodos adicionales para disminuir el conteo de bits promedio por segundo para cada jugador:

  1. Usted escribió que envía "El objeto no cambió". No hay razón para hacer esto. Si le preocupa la pérdida de paquetes (y la sincronización de su simulación debido a esto) considere lo siguiente: En cada paso fijo (por ejemplo, 100, 200, 300, 400 ...), controle el estado de la simulación y envíelo al servidor . el servidor confirma o envía una instantánea completa de todos los datos.

  2. Para cosas como cohetes o incluso jugadores, puede emplear no solo interpolación sino también extrapolación para hacer que la simulación sea más realista. Ejemplo 'Cohete': en lugar de actualizar con mensajes como "Ahora está en la posición x", simplemente envíe un mensaje que contenga lo siguiente: "Cohete generado: posición (vector), Tiempo (en el paso de simulación que se generó el cohete), velocidad ( vector)". Por lo tanto, ni siquiera tiene que incluir la rotación porque la punta siempre estará en la dirección de "velocidad".

  3. Combine múltiples comandos en un mensaje y nunca envíe mensajes de menos de 16-20 bytes porque el encabezado udp será más grande que el mensaje en sí. Tampoco envíe paquetes más grandes que la MTU de su protocolo porque la fragmentación reducirá la velocidad de la transmisión.

Riki
fuente
Oh, es una buena idea actualizar algunos objetos con más frecuencia que otros, usar P2P, degradar la precisión de coma flotante, enviar solo cambios (lo cual no es trivial para mí porque tenía la intención de sincronizar objetos periódicamente, pero "el objeto no cambió" es la información también). ¡Con todas estas modificaciones, la imagen completa parece más realista!
Eslavo
1
El envío de avisos de tipo "el objeto no cambió" podría ser una técnica útil para fines de prueba en los que desea ver cómo se desempeña su juego cuando los jugadores están activos durante las horas ocupadas porque tiene el potencial de exigir el procesamiento y la red, pero todavía hay mejores soluciones que esta (como crear un demonio independiente que controle un personaje real en el juego, luego ejecutar ese demonio varias veces desde diferentes máquinas).
Randolf Richardson
5

Aquí hay dos enfoques:

Primero:
cambie a física determinista, envíe comandos de jugador, acciones ai, objetos a la vista y lo que no pueda determinarse del lado del cliente a los clientes. Esto debe incluir no comandos, una confirmación de que hasta cierto punto en el tiempo solo se aplican los comandos que se han enviado y recibido.

El cliente debe ejecutar dos o tres simulaciones simultáneas.
1: se detiene cuando faltan datos para el siguiente paso.
2: Continúe usando datos de conjetura y proporcione el estado utilizado para la representación. 3: Cada vez que el 1 no se detiene, esta simulación copia el estado del no 1, se pone al día con la hora actual y toma el control del no 2, que luego se descarta.

Si la actualización es lo suficientemente rápida, puede omitir la diferencia entre no 2 y no 3 y simplemente descartar los datos antiguos de inmediato.

Segundo:
no use física determinista, haga lo mismo que antes, pero envíe "fotogramas completos" una vez cada pocos segundos. Puede omitir fácilmente la transferencia de cosas temporales como balas.

En ambos casos, es posible que desee tener cuidado con el cliente que predice que alguien morirá, es un poco tonto ver a un oponente sin explotar.

Y +1 por hacer los cálculos, demasiadas personas no logran hacer estimaciones simples de uso de recursos.

aaaaaaaaaaaa
fuente
2
¿La "física determinista" significa que no puedo usar valores de coma flotante o diferentes pasos de simulación? Me pregunto que puede ocurrir una desincronización crítica si, por ejemplo, un cohete pasa por una torreta enemiga en el cliente pero lo golpea en el servidor (debido a alguna imprecisión de coma flotante) que hará que el jugador siga luchando contra esa torreta hasta el próximo paquete de sincronización del servidor entrante (varios segundos)
Eslavo
3
Significa enteros y paso de tiempo fijo. Teóricamente, podrías simular puntos flotantes para comportarte, pero usar números enteros es mucho más simple. Tienes un punto con el ejemplo de misil perdido, si usas física no determinista, probablemente sea mejor dejar que el servidor maneje la muerte por completo y transmitir casos de muerte / destrucción rápidamente.
aaaaaaaaaaaa
5

Pocas preguntas primero.

¿Son los 'cohetes u otra cosa' inteligentes o tontos? Si son tontos, todo lo que necesita es la marca de tiempo del fuego, el origen y el vector para simular su camino. Si son inteligentes, ¿qué tan inteligentes son? ¿Puedes calcular en el momento del incendio que van a acertar o fallar? Si es así, puede simular la ruta completa en el cliente. ("En T13 el misil golpeará la nave porque la jugada perdió la tirada de esquivar / el tirador obtuvo un golpe crítico").

En general, aunque no hay prácticamente ninguna razón para: A) tener una frecuencia de reloj de 50Hz, (la mayoría de los tiradores se escapan con 15-20 y los MMO menos que eso). B) enviar el estado completo en cada cuadro. (¿Importa la rotación de un misil en el espacio? ¿O puede suponer que su 'frente' está orientado a lo largo del vector en el que viaja?)

Dedique tiempo a la predicción y la interpolación, y verá que su ancho de banda se desploma. Un proyecto en el que trabajé tenía una tasa de actualización de 10Hz, y una representación de estado de objeto de creo 14 bytes. (¡Comprima todo lo que pueda! Creo que usamos 6 bits para definir la rotación alrededor del plano xy luego otros 6 bits para una inclinación por encima / debajo de ese plano, parecía indistinguible de enviar una matriz rotacional / cuaternión real).

Otra cosa que puedes hacer es priorizar objetos. Mostrar, tal vez hay 100 objetos en el conjunto relevante, pero ¿conoces su punto de vista en el servidor? Si algo no está en su opinión, ¿puede eliminar su frecuencia de actualización en un orden de magnitud?

La idea general no es hacer una simulación perfecta en el cliente, eso es imposible, la idea es hacer un juego divertido donde los jugadores no se den cuenta de que no es una simulación perfecta.

Doug-W
fuente