Samuel García
samgh96
@SamRadioFloyd
- 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)
- 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.
En esta charla nos ceñiremos al protocolo de transporte y de aplicación
- 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 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.
- 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...
- 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.
- Los equipos se comunican entre ellos sin un líder.
- En videojuegos esto se traduce en que cada equipo mantiene su propio game state.
- 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.
- 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.
- 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.
- 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)
- 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.
- ¿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?
- 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).
- 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!).
- 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)
- 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.
- 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.
- 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.
- 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.
- 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.
https://gafferongames.com/post/what_every_programmer_needs_to_know_about_game_networking/
http://www.gamasutra.com/view/feature/3094/1500_archers_on_a_288_network_.php
https://gafferongames.com/post/udp_vs_tcp/
https://web.archive.org/web/20160103125117/https://www.isoc.org/inet97/proceedings/F3/F3_1.HTM
http://mrelusive.com/publications/papers/The-DOOM-III-Network-Architecture.pdf
https://fabiensanglard.net/quake3/The%20Quake3%20Networking%20Mode.html
https://gafferongames.com/post/introduction_to_networked_physics/
https://www.forrestthewoods.com/blog/synchronous_rts_engines_and_a_tale_of_desyncs/
https://gamedevelopment.tutsplus.com/tutorials/building-a-peer-to-peer-multiplayer-networked-game--gamedev-10074
https://www.reddit.com/r/gamedev/comments/ahy5rl/a_curated_list_of_game_network_programming/
https://parasol.tamu.edu/people/jack/fromCS/cpsc619/qnp.html