Netcode
# Netcode

Netcode se trata de un hiperónimo utilizado en la comunidad gamer para denominar cualquier cosa que se relacione a la gestión de redes (networking en inglés) de los juegos en línea, a menudo refiriéndose a problemas de sincronización entre clientes y servidores. Los jugadores habitualmente hacen afirmaciones sobre "netcodes malos" cuando se encuentran problemas de conexión en un juego, a pesar de que las causas de estos problemas podrían estar completamente fuera del control de su motor (algunas causas habituales: latencia alta entre el servidor y el cliente, pérdida de paquetes, congestión de la red, etc.). Incluso podrían ser causados por factores externos que no tienen nada que ver con la calidad de la red como el tiempo de renderización de los fotogramas o velocidades inconsistentes de fotogramas. Netcode como término tiende a ser utilizado solamente en el mundo de los videojuegos, y no es reconocido por la comunidad científica de las ciencias de la computación.

## Tipos de netcode

A diferencia de una partida local donde las entradas de todos los jugadores se ejecutan al instante en una misma simulación o instancia del juego, en una partida en línea hay varias simulaciones paralelas (una para cada jugador) donde las entradas de sus jugadores respectivos se reciben instantáneamente, mientras que las entradas para el mismo fotograma de los otros jugadores llegan con un cierto retraso (mayor o menor dependiendo de la distancia física entre los jugadores, la calidad y rapidez de las conexiones a la red de los jugadores, etc.). Durante una partida en línea, los juegos tienen que recibir y procesar la entrada (input en inglés) de los jugadores en un tiempo determinado para cada fotograma (por ejemplo, 16 ms a 60 FPS), y si la entrada de un jugador remoto de un fotograma concreto (por ejemplo, del fotograma número 10) llega en el momento en el que ya se está ejecutando otro (por ejemplo, en el fotograma número 20, 160 ms más tarde) se produce una desincronización entre las simulaciones de los jugadores. Para resolver este conflicto y conseguir que el juego funcione con fluidez hay dos soluciones principales:

### Basado en retraso

La solución clásica a esta problemática se trata de la utilización de un netcode basado en retraso (delay-based netcode en inglés). Cuando las entradas de un jugador remoto llegan tarde lo que hace el juego es retrasar las entradas del jugador local el mismo tiempo para sincronizar las dos entradas y ejecutarlas vez. El hecho de que las entradas del jugador local no se ejecuten instantáneamente puede ser molesto para los jugadores (sobre todo cuando hay una latencia alta entre ellos), pero en general el cambio no es muy notable. El verdadero problema de este sistema se trata de su inconsistencia, ya que el retraso de las entradas de los jugadores remotos puede variar adecuándose a la latencia del momento, la cual puede fluctuar inesperadamente. Cuando la latencia entre jugadores es tan alta que no se puede enviar la entrada del jugador remoto dentro de una memoria intermedia (buffer en inglés) de, por ejemplo, 3 fotogramas (48 ms), el juego debe esperar, causando que se "congelen" las pantallas (un netcode basado en retraso no permite continuar con la simulación hasta que no reciba las entradas de todos los jugadores del fotograma en cuestión). Como este retraso puede ser variable, la experiencia de los jugadores en partidas en línea resulta ser menos agradable y responsiva que con partidas offline (o en una red LAN), y puede llegar a afectar negativamente el rendimiento de los jugadores en juegos altamente sensitivos y de acción rápida como los juegos de lucha.

### Retrospectivo

Un sistema alternativo al netcode anterior es el netcode retrospectivo (rollback en inglés). Este sistema ejecuta inmediatamente las entradas del jugador local (de forma que no se retrasan como con el netcode basado en retraso), como si se tratara de una partida offline, y predice las entradas del jugador o jugadores remotos en lugar de esperarlos (suponiendo que harán la misma entrada que la del tick anterior). Una vez llegan estas entradas remotas (suponemos, por ejemplo, 45 ms después), el juego puede actuar de dos maneras: si la predicción es correcta, el juego continúa tal cual, de manera totalmente fluida; si la predicción era incorrecta, el estado del juego se revierte y el juego continúa desde el estado corregido, por lo que el otro u otros jugadores verán el cambio de estado en forma de un pequeño salto temporal (equivalente a 45 ms, siguiendo el ejemplo). Algunos juegos utilizan una solución híbrida para disimular estos "saltos" (los cuales pueden llegar a ser problemáticos a medida que la latencia entre los jugadores crece, ya que cada vez hay menos tiempo para reaccionar a las acciones de los otros jugadores) mediante un retraso de entrada fijo y luego aplicando el sistema de networking retrospectivo. El netcode retrospectivo resulta bastante efectivo al momento de disimular subidas breves de la latencia de los jugadores u otros problemas relacionados con inconsistencias de las conexiones de los clientes, ya que las predicciones son a menudo correctas y los jugadores ni se dan cuenta. No obstante, cuando este sistema se encuentra con la situación de que el juego de un cliente se ralentiza (normalmente por sobrecalentamiento), se pueden causar problemas de rift que lleven a un intercambio de entradas entre máquinas a ritmos desiguales. Esto genera errores visuales (glitches en inglés) que dificultan el juego a los jugadores que reciben las entradas a un ritmo más lento, mientras el jugador cuyo juego está ralentizado tendrá una ventaja sobre el resto recibiendo a un ritmo normal las entradas de los otros (esto se conoce como rollback unilateral). Para solucionar este desequilibrio desigual de entradas (y en consecuencia, de fotogramas), hay soluciones lógicas como la espera de todas las máquinas para sincronizar las entradas que llegan tarde (similar al modelo de netcode basado en retraso) o soluciones más ingeniosas como el empleado actualmente en el juego Skullgirls, la cual consiste en la omisión sistemática de un fotograma cada siete para que cuando el juego se encuentre con el problema en cuestión este pueda recuperar los fotogramas omitidos para así poco a poco sincronizar las instancias de los juegos en las diversas máquinas.

El netcode retrospectivo requiere que el motor del juego pueda retroceder su estado, lo que exige modificaciones en muchos motores existentes y, por tanto, la implementación de este sistema puede ser problemática y cara en títulos del tipo AAA (los cuales suelen tener un motor sólido y una red con mucho tráfico), como ha comentado el productor de Dragon Ball FighterZ Tomoko Hiroki, entre otros.

Aunque este sistema sea a menudo asociado al modelo de igual a igual (peer-to-peer en inglés) y a los juegos de lucha, hay formas de networkings retrospectivos que también se utilizan habitualmente en arquitecturas cliente-servidor (como los planificadores agresivos que encontramos en los sistemas de gestión de bases de datos, los cuales incluyen una funcionalidad retrospectiva) y en otros géneros de videojuegos.

Hay una librería popular con licencia MIT llamada GGPO diseñada para facilitar la implementación del networking retrospectivo a un juego (principalmente los de lucha).

## Causas potenciales de problemas de netcode

### Latencia

La latencia es inevitable en los juegos en línea, y la calidad de la experiencia de los jugadores está estrictamente ligada a esta (cuanta más latencia hay entre los jugadores, mayor es el sentimiento de que el juego no es responsivo a sus entradas). Hay que tener en cuenta el hecho de que la latencia de la red de los jugadores (la cual está en gran parte fuera del control de los juegos) no es el único factor en cuestión, sino también la latencia inherente a la manera en que las simulaciones de los juegos se ejecutan. Para disfrazar o disimular la latencia y para corregir problemas causados por valores altos de esta se han desarrollado varios métodos de compensación de lag.

### Tickrate

La medida temporal mínima de una reiteración de acciones en un juego se conoce como tick. La tasa a la cual la simulación es ejecutada en un servidor es referido a menudo como el tickrate (o tasa de actualización) de un servidor; esto es esencialmente el equivalente de los fotogramas por segundo del cliente. El tickrate es limitado por el periodo de tiempo que la simulación necesita para ejecutarse, y es a menudo intencionadamente limitado todavía más para reducir la inestabilidad introducida por una tasa fluctuante (y también para reducir los costes de la CPU y de transmisión de datos). Un tickrate bajo incrementa la latencia de la sincronización entre la simulación del servidor y las de los clientes. El tickrate en juegos de acción rápida como los shooters en primera persona a menudo se encuentra entre los 120 ticks por segundo (cómo es el caso de Valorant), los 60 ticks por segundo (en juegos como Counter-Strike: Global Offensive u Overwatch), los 30 ticks por segundo (como en Fortnite y en la versión de consola de Battlefield V) y los 20 ticks por segundo (cómo con los polémicos casos de Call of Duty: Modern Warfare, Call of Duty: Warzone y Apex Legends). Un tickrate bajo, naturalmente, también reduce la precisión de la simulación, de manera que podría llegar a causar problemas si se lleva a extremos, o si las simulaciones del cliente y del servidor se encuentran ejecutándose a tasas significativamente diferentes.

Debido a limitaciones en la cantidad de la anchura de banda disponible y el tiempo de la CPU dedicado a la comunicación de la red, algunos juegos priorizan ciertas comunicaciones vitales mientras se limita la frecuencia y prioridad de otros tipos de información menos importantes. Igual que con el tickrate, esto aumenta la latencia de la sincronización. Los motores de juego pueden limitar las veces por segundo que las actualizaciones (de la simulación) son enviadas a un cliente determinado y/o a objetos determinados en el mundo del juego además de reducir la precisión de algunos valores enviados a través de la red para ayudar con el uso de la anchura de banda. Esta carencia de precisión puede llegar a ser notable.

### Errores de software

Hay varios errores de sincronización de una simulación entre máquinas que suelen ser considerados como "problemas de netcode". Por ejemplo, podemos encontrar varios bugs que causen que la simulación avance y se desarrolle de manera diferente entre una máquina y otra, o que algunos objetos o elementos no se comuniquen entre ellos aunque el usuario perciba que deberían hacerlo. Tradicionalmente, los juegos de estrategia en tiempo real (por ejemplo, Age of Empires) utilizaron modelos de gestión de redes peer-to-peer del tipo lock-step donde se asume que las simulaciones se ejecutan de manera exactamente igual para todos los clientes; aun así, si un cliente perdiera el paso por cualquier razón, la desincronización puede ser grave y volverse irrecuperable.

### Protocolos de capa de transporte y código de comunicación: PCT y PDU

El tipo de protocolo de capa de transporte (y su gestión y programación) escogido para un juego también puede causar problemas de networking.

Si un juego utiliza un protocolo de control de transmisión (PCT, TCP en inglés), habrá una latencia añadida entre los jugadores. Este protocolo se basa en la conexión entre dos máquinas, en la cual estas pueden intercambiar datos y leerlas. Este tipo de conexiones son muy fiables, estables, ordenadas y fáciles de implementar, y se utilizan en prácticamente cualquier operación que hacemos por internet (tanto en la navegación de la web como en los correos electrónicos o los IRC). Estas conexiones, sin embargo, no se adecuan correctamente a las velocidades de red que los juegos de acción rápida necesitan, ya que este tipo de protocolo (los protocolos de transmisión en tiempo real) agrupa los datos automáticamente en paquetes (los cuales no se enviarán hasta alcanzar un volumen de información determinado) que se enviarán a través de la conexión establecida entre las máquinas, en vez de manera directa (sacrificando la velocidad por seguridad). Este tipo de protocolo también tiende a responder muy lentamente cuando se encuentra con la situación de que ha perdido un paquete, o que han llegado en un orden incorrecto o duplicados, lo que puede ser muy perjudicial para un juego en línea en tiempo real (hay recordar que este protocolo no se diseñó para este tipo de software).

Si el juego en cambio utiliza un protocolo de datagramas de usuario (PDU, UDP en inglés), la conexión entre las máquinas será muy rápida, ya que en vez de establecer una conexión entre ellas se enviarán y recibirán los datos directamente. Este protocolo es mucho más sencillo que el anterior, pero no goza de su fiabilidad y estabilidad y requiere la implementación de código propio para encargarse de las funciones indispensables para la comunicación entre máquinas que el PCT incluye (tales como la división de datos en paquetes, la detección automática de la pérdida de paquetes, la suma de verificación, etc.); esto aumenta la complejidad del motor, por lo que se podrían provocar problemas.

