Arquitecturas de red en videojuegos: ¿Has visto mi paquete?

Samuel García

samgh96

@SamRadioFloyd

Introducción

Juego en red

- Compartición del estado del juego (Game State) entre jugadores a través de Internet.

 

- Game State: Conjunto de elementos en el juego en un momento concreto

 

- El concepto tiene ya mucho rodaje (el primer juego online, Empire, data de 1973)

Juego en red

- Tenemos infinidad de géneros en videojuegos, cada uno con sus atributos y necesidades.

 

- Implementar un multijugador puede diferir mucho entre géneros y tenemos que entender cuáles son nuestras cotas.

Crash Course de Redes

Network Stacks

En esta charla nos ceñiremos al protocolo de transporte y de aplicación

Nivel de transporte

- Es el nivel dedicado a ofrecer comunicación host-to-host en red.

 

- Para lo que nos concierne tenemos dos protocolos: TCP y UDP

TCP vs UDP

- TCP está orientado a conexión, asegura el correcto orden de los paquetes, es fiable.

- UDP es más rápido pero no asegura nada de lo anterior.

Nivel de aplicación

- Se encarga de la sesión, presentación y aplicación del modelo OSI

 

- Define interfaces, comunicación entre aplicaciones.

 

- Montamos los protocolos de nivel de aplicación sobre protocolos de transporte.

 

- Ejemplos: HTTP, SSH...

Arquitecturas de red

- Modelos de distribución de datos en red. (Sistemas Distribuidos)

 

- Aquí nos ocuparemos principalmente de los dos más usados en videojuegos: P2P y Cliente-Servidor.

 

- Para MMOs probablemente haya más modelos útiles.

P2P

- Los equipos se comunican entre ellos sin un líder.

- En videojuegos esto se traduce en que cada equipo mantiene su propio game state.

P2P

- En redes grandes (o con latencias altas) mantener la consistencia es duro.

 

- Pequeños cambios en un estado concreto pueden producir errores de sincronización entre los peers.

 

- Fácil de implementar (comparativamente hablando).

 

- Existe una extensión a medio camino entre P2P y cliente-servidor llamada Packet Server.

 - No todos los equipos requieren de conexión entre sí, pero hace falta un servidor "maestro" (packet server) que sí tiene conectividad completa.

- Los mensajes se mandan al PS y éste los redirige al resto.

Cliente-Servidor

- Es actualmente la arquitectura más usada en videojuegos.

 

- Requiere de separar la lógica del juego con la parte visual ("dummy terminals").

 

- Un equipo actúa de servidor y gestiona la lógica mientras que los clientes se conectan a él.

 

- El servidor es la autoridad final, por lo que se rompe la necesidad de sincronía entre clientes.

- El servidor puede (o no) ser un jugador.

Netcode

- Término paraguas para describir factores que influyen en la calidad de la implementación del multijugador.

 

- Engloba conceptos como el ping (tiempo de ida-vuelta de un paquete), tickrate (cuántas veces por segundo se generan datos a propagar/procesar por la red),  o el update rate (cuántas veces por segundo se envían/reciben datos)

 

- Se produce un tira y afloja entre cuánto podemos procesar y cómo afecta a nuestra experiencia de juego.

Netcode

- Otros factores importantes son la latencia (varianza de pings entre clientes), la ausencia de de-sync (especialmente acuciante en P2P), la seguridad (los paquetes de cada cliente deben estar identificados y ser fiables), el jitter (fluctuación de retardo entre paquetes)

Consideraciones y decisiones de diseño

Decisiones de diseño

- Necesitamos tener en cuenta el multijugador desde el principio del diseño de nuestro juego.

 

- No es tarea fácil, puede repercutir profundamente en las horas invertidas.

 

- Tenemos un gran número de factores a tener en cuenta antes de decidirnos por una arquitectura u otra.

Decisiones de diseño

- ¿Cuál es nuestro número de jugadores?

- ¿Es un juego rápido?
- ¿Es por turnos?

- ¿Disponemos de infraestructura para tener servidores?

- ¿De qué género es nuestro juego?

- ¿Contamos con tecnologías third-party? (SteamWorks/Unity)

- ¿Nuestro juego online se limita al LAN?

Decisiones de diseño

- Tenemos recomendaciones generales, por ejemplo:


   - P2P funciona mejor para juegos 1 vs 1, para lo demás es recomendable usar cliente-servidor.

   - El coste es nuestro mayor problema cuando tenemos que darle de comer a nuestros desarrolladores.

   - Debemos darle feedback a nuestros jugadores cuando las cosas van mal en la red.

   - La responsividad es clave.

   - Hay que tener cuidado con el modelo de listen server (puede dar ventajas).

Decisiones de diseño

   - Debemos darle un formato óptimo a nuestros paquetes (tanto al elegir protocolo de transporte como en aplicación).

   - TCP es lento, UDP no da confianzas.

   - Construir un protocolo sobre UDP con características de TCP es generalmente mejor que usar TCP tal cual.
   - Mucho cuidado con juntar TCP y UDP, contraintuitivamente es mucho peor de cara a performance (una conexión TCP viva provoca mayor pérdida de paquetes en UDP!).

Implementaciones típicas

P2P: Deterministic Lockstep

 - En P2P el estado debe estar sincronizado entre los clientes, y podemos hacerlo compartiendo el game state o compartiendo la entrada.

 

- Enviando la entrada en vez del estado nos evita ocupar la banda ancha (los paquetes con solo input son muchísimo más ligeros).

 

- Asegurar determinismo es duro (distintos SO, distintos compiladores pueden dar resultados ligeramente distintos)

P2P: Deterministic Lockstep

 - Determinista: Cada entrada debe generar la misma salida (y por ende todo el estado debe ser idéntico).

 

- Para esto tenemos que asegurar el orden de llegada de los paquetes.

 

-  No es recomendable tratar las llegadas y simular en tiempo real, por eso se implementa un "playout delay buffer", donde se encolan los paquetes.

 

- Tampoco es recomendable mandar todo el input sino hacer una delta con ello.

Implementando protocolos de aplicación

 - Debemos pensar en nuestras necesidades de transporte antes de pasar al nivel de aplicación (si hace falta sesión, cuánta banda ancha estamos dispuestos a llenar...)

 

 - Como ya hemos dicho antes procesar TCP es costoso y no nos suele satisfacer completamente (existen contraejemplos).

 

- Por tanto nos toca orientar UDP a conexión y luego construir sobre ello.

Implementando protocolos de aplicación

 - Es buena idea no mandar los mensajes en claro pero el cifrado/descifrado puede ser costoso computacionalmente.

 

 - Tenemos que asegurar el relacionar a los clientes con sus entidades en el juego.

 

 - También debemos asegurar robustez suficiente como para que hackers no se aprovechen de nuestra implementación.

Implementando protocolos de aplicación

  - Con el diseño del juego en mente, tenemos opciones que facilitan compartir información entre clientes basada en la implementación de los controles/mecánicas del juego.

 

- Por ejemplo la inclusión de "game commands" o la simplificación por turnos.

Snapshotting

 - Para mantener consistencia y simplificar la transmisión podemos dividir nuestro game state (o nuestro input) en snapshots.

 

 - Con esto podemos superar la pérdida de paquetes interpolando snapshots e incluso reducir el impacto del jitter implementando predicción de cliente, además de resultar más cómodo el uso de deltas.

Snapshotting

"DEMO"

¿Preguntas?

Referencias

Arquitecturas de red en videojuegos

By samgh96

Arquitecturas de red en videojuegos

  • 61