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

Made with Slides.com