World of Warcraft

Taller de ingeniería: la recreación del esfuerzo de guerra de Ahn'Qiraj

Blizzard Entertainment

La guerra se cierne sobre nosotros. A principios de este mes se lanzó uno de los eventos más esperados de World of Warcraft: Classic: el esfuerzo de guerra de Ahn'Qiraj. Reinos de Classic al completo (con todo el poder de la Horda y de la Alianza) se unieron y aportaron recursos para abrir las puertas y desbloquear las bandas de Ahn'Qiraj. Cuando se produjo la guerra del Mar de Dunas por primera (y única) vez, en 2006, miles de jugadores de todos los reinos volaron o cabalgaron hacia Silithus para participar o ser testigos de la contienda. La participación superó las expectativas más descabelladas del equipo de desarrollo y, en pocas palabras, nos cogió desprevenidos. Los servidores se sobrecargaron rápidamente y, durante 12 horas, muchos jugadores se estancaron en un bucle en el que iniciaban sesión, se desconectaban e intentaban volver a conectarse mientras nuestros ingenieros se dejaban la piel para solucionar los problemas en tiempo real. Aunque logramos estabilizar los servidores durante el evento y tomamos buena nota de lo ocurrido, también aprendimos cómo mejorar. Quince años después, nos preparamos para recrear uno de los momentos centrales de la historia del juego en WoW Classic: nos centramos en la optimización de los servidores, en el retardo de los combates y en evitar los bloqueos inesperados. Además, en Silithus se reunió el doble de jugadores que durante el estreno del evento en 2006.

En este artículo os vamos a contar cómo recreamos este evento tan esperado y repasaremos nuestros procesos: el uso de jugadores automatizados y pruebas de estrés para detectar posibles problemas y soluciones de optimización manual, la implementación de alternativas en el software cuando el hardware no era capaz de resolver los problemas y la reproducción de un evento global con unos pocos cierres inesperados; sin olvidarnos de que debíamos conseguirlo conservando en todo momento la experiencia de juego WoW Classic.

Recrear la segunda guerra del Mar de Dunas

Teníamos tres objetivos concretos en mente a la hora de abordar la organización de este evento: evitar cierres inesperados en cadena, aumentar el límite previsto de jugadores en la zona y determinar cuál era el retardo tolerable antes de tener que teletransportar a los jugadores fuera de Silithus. Antes de que entremos en materia sobre lo que hicimos para mejorar el rendimiento de los servidores, es importante que tengáis en cuenta las limitaciones con las que hemos trabajado: las restricciones del sistema de programación de WoW Classic o el funcionamiento de las soluciones para la gestión de la población y su efecto sobre la jugabilidad.

Los Anubisath invaden Azeroth

Más allá de los límites

La versión moderna de World of Warcraft se diseñó usando como base el sistema de programación original, que se lanzó hace 15 años. Desde el lanzamiento del juego, hemos desarrollado alternativas más modernas para gestionar un número elevado de jugadores en Battle for Azeroth, sobre todo mediante la fragmentación. Este sistema permite que los servidores de WoW alberguen muchos más jugadores que en 2006. En Battle for Azeroth usamos la fragmentación para gestionar el volumen de jugadores de los servidores al realizar una copia de una zona (por ejemplo, Zuldazar) cuando el recuento de jugadores alcanza cierto umbral. Esta acción evita los problemas de retardo al distribuir los jugadores por diferentes versiones de la zona, ya que sus interacciones se encuentran entre las más exigentes en términos de CPU debido a la cantidad de paquetes que se envían constantemente al servidor para obtener una precisión milimétrica en el movimiento y hechizos. Además, la fragmentación mitiga los posibles problemas de retardo al realizar la transición a una nueva zona en la que el volumen de jugadores supera el máximo. Parece algo sencillo, pero la cosa tiene truco: WoW Classic se ha diseñado para ser una recreación fidedigna de los datos del juego de la versión 1.12, lo que incluye conservar las particularidades de la jugabilidad. En algunos casos poco frecuentes, la fragmentación provoca que un jugador enemigo o un PNJ desaparezcan al entrar en una zona distinta. Si hubiésemos mantenido la fragmentación, se habrían perdido esos momentos tan entrañables de perseguir a jugadores y PNJ a través de los límites de las zonas. Por lo tanto, tuvimos que dar con una solución que no interfiriese con la jugabilidad original y que, a la vez, nos permitiese mantener más jugadores en el servidor sin un retardo insoportable.

Para solucionar este problema, nos decantamos por usar capas: realizamos copias de regiones enteras (como los Reinos del Este) para gestionar la población de jugadores y los retardos mientras conservamos el encanto de la versión original para que los jugadores pudiesen atraer a los jefes de mundo de zona en zona y perseguir a los jugadores enemigos por las fronteras de una región sin correr el riesgo de verse afectados por la fragmentación. No obstante, las capas se diseñaron para ofrecer una solución temporal. Dado que la versión 1.12 original no disponía de tecnologías de fragmentación o de capas, prometimos a los jugadores que solo usaríamos las capas durante el lanzamiento de WoW Classic y que las iríamos eliminando paulatinamente a medida que se distribuyesen por el mundo de forma más equilibrada. Existen casos aislados en los que seguimos usando el sistema de capas debido a poblaciones extremadamente altas de jugadores activos (como en el reino Faerlina, de Norteamérica), pero las hemos reducido en este tipo de reinos desde el lanzamiento del juego. Con 15 años de mejoras a nuestras espaldas, la guerra de AQ era uno de los eventos más esperados de WoW Classic, y esperábamos que reuniese a la mayor cantidad de jugadores en una misma zona que se hubiera visto nunca (sin contar las zonas de inicio cuando lanzamos el juego) y encima sin capas. Como veis, al no disponer de capas ni tecnología de fragmentación de población, debíamos dar con soluciones alternativas cuanto antes.

Jugadores alrededor del gong

La creación de una experiencia inolvidable

Comenzamos la tarea de encontrar una solución que no pasase por las capas ni la fragmentación de la población generando clientes sin mente (jugadores automatizados), programados para imitar las acciones de los jugadores reales, como lanzar hechizos, luchar contra PNJ y desplazarse por la zona. Esto nos permitió hacernos una idea del estado del rendimiento con miles de jugadores interactuando en una única zona. Tras llevar a cabo estas simulaciones, organizamos pruebas de estrés con voluntarios para comparar el rendimiento con comportamientos realistas de los jugadores. El resultado nos permitió encontrar algunos puntos de conflicto y constatar qué partes del sistema de los servidores experimentaban el mayor número de problemas al contar con un número elevado de jugadores. Las lecturas de fotogramas por segundo del servidor se analizaron exhaustivamente para comprobar lo cerca que estaban de provocar que el servidor dejase de responder (es decir, que se diese un cierre inesperado).

El siguiente paso fue analizar los factores que afectaban al rendimiento del servidor para dividir esta hercúlea tarea en objetivos más digeribles. Nos enfrentamos a un problema de polinomios, lo que significa que no se podía resolver utilizando un hardware más rápido (dado que el hardware no es superior de forma exponencial). Por ello, tuvimos que configurar la optimización para elegir exactamente qué datos se comunicaban a los jugadores y con qué frecuencia. Para ejemplificar este galimatías, pongamos que tenemos 20 jugadores saltando en círculo. El servidor transmite las acciones de cada jugador a los otros 19 a través de paquetes (entregas de datos). En este grupo de 20 jugadores, el servidor procesa 380 paquetes (20 jugadores multiplicados por 19 destinatarios = 380 paquetes). El problema se agrava cuando más jugadores realizan la misma acción en esa ubicación. Si aumentamos nuestro ejemplo a 500 jugadores, entonces se envían 249 500 paquetes desde el servidor. Si volvemos a aumentar la muestra a 1500 jugadores, se envían 2 248 500 paquetes al servidor. En función de las acciones que lleven a cabo, se envían varios paquetes por segundo; hay que tener en cuenta que los ejemplos anteriores representan una única acción. Cuantos más paquetes se envían al servidor, más aumenta el tiempo de procesamiento del servidor para un único jugador (sin olvidar que, a la vez, se encarga de las acciones de los demás jugadores). Cuando esta circunstancia se agrava, los servidores pueden sufrir cierres inesperados. En WoW Classic tenemos muchos más jugadores en cada reino que en 2006, así que la previsión era alojar una cantidad nunca vista en torno a las puertas.

Optimizar el rendimiento de los servidores

Nuestros servidores están diseñados para cerrarse y reiniciarse cuando llegan a un punto de bloqueo, así que sabíamos que era fundamental hacer todo lo posible para reducir el tiempo de procesado. Tras realizar algunas pruebas, quedó claro que el movimiento era el primer factor de procesado que sometía a los servidores a mucha presión. En primer lugar implementamos actualizaciones relativas a la orientación (las que muestran la dirección a la que está encarado el modelo del personaje) y solo enviamos actualizaciones de jugador cuando estos iniciaban, detenían o usaban el movimiento con el teclado. Dado que la latencia con una cantidad excesiva de jugadores ya se veía afectada, al invertir tiempo de la CPU para enviar actualizaciones menores relativas a la dirección la fidelidad empeoraba. Por ese motivo, lo mejor era dejar de enviarlas, y tomamos la decisión de descartar la frecuencia con la que se enviaban actualizaciones de movimiento a cambio de contar con más jugadores en una misma zona. Tened en cuenta que estábamos intentando encontrar el punto de inflexión previo al cierre de los servidores con la mayor cantidad posible de jugadores en Silithus. Al fin y al cabo, es mejor perderse algunas actualizaciones de movimiento que no poder iniciar sesión con el personaje. Además, comenzamos a limitar los datos considerados de menor prioridad. Las acciones «menos importantes» no debían enviarse con la misma frecuencia que las «más importantes». Nos percatamos de que se enviaban muchos mensajes a la vez con independencia de su importancia, así que optimizamos el sistema para que enviase la información de menor importancia en bloque y con menor frecuencia.

Los beneficios y perjuicios también afectaban en gran medida al rendimiento. Por todo el mundo, sobre todo al luchar contra criaturas, se aplican beneficios y perjuicios constantemente a todas las unidades. Aunque puede parecer que esto no es muy importante, esta información debía transmitirse con una gran concentración de jugadores en un mismo lugar. Al igual que en el caso de la limitación de los datos de baja prioridad, agrupamos los beneficios y perjuicios en bloques para evitar el envío de muchos paquetes seguidos a los jugadores.

Gestionar la población de jugadores

Aparte de optimizar los servidores para que cada zona pudiese contener más jugadores, sabíamos que no cabía en Silithus toda la población de un reino (más del doble de lo que era capaz de gestionar un reino de la versión 1.12 de WoW original). Tuvimos que tomar algunas decisiones complicadas para limitar el acceso a la zona y controlar a quiénes dejábamos entrar en ella. Acordamos que solo permitiríamos la entrada en Silithus a personajes de nivel 60 y, una vez alcanzada su capacidad máxima, si siquiera a estos. Fue una decisión acertada, ya que el evento de Silithus es contenido avanzado y los personajes de nivel más bajo podían participar en el esfuerzo de guerra de todos modos en otras zonas como, por ejemplo, Los Baldíos (una zona para jugadores de nivel 20 al 30), matando a los Anubisaths deambulantes. El segundo escollo estaba relacionado con el hecho de que sabíamos dónde estaba el umbral de jugadores que podía contener una zona sin que el servidor se cerrase inesperadamente. Por tanto, ¿hasta dónde debíamos reducir esa cantidad para obtener la relación óptima entre rendimiento y cantidad de jugadores? Durante las pruebas, establecimos esta cifra en 1500 jugadores apiñados. Sin embargo, dado que el evento tuvo lugar por toda la zona, registramos muy pocos problemas de rendimiento en cuanto los jugadores comenzaron a repartirse por el mapa.

El evento estaba pensado para que tuviese lugar en todas las regiones, así que tuvimos que asegurarnos de que funcionaba a través de varias capas. Esto implicaba que un portador del cetro que golpease el gong en una capa debía desencadenar el evento en el resto de capas conectadas a ese reino. Como el desencadenante del evento era la interacción de un jugador, consideramos necesario que el portador del cetro fuese visible en varias capas para que todos los jugadores del mismo reino pudiesen verlo. Esto nos planteó un problema interesante, ya que ahora los servidores debían transmitir una información que normalmente no transmiten. Esta acción podía generar un montón de complicaciones, ya que se trataba de agrupar y enviar actualizaciones a través de los servidores para replicar los datos en varias capas a, probablemente, miles de jugadores.

Empezamos a desarrollar esta tecnología con la presentación del Torneo de Pesca de Tuercespina y, con el tiempo, la aplicamos a los beneficios de mundo que se obtienen de Onyxia, Nefarian, Zul'gurub y Rend. Una vez constatado que funcionaba según lo previsto, estábamos en disposición de probar esta solución junto al resto de tecnologías en el evento de guerra de AQ.

Jugadores de la Horda en Silithus

Experimentos con soluciones

Una vez resueltos los principales obstáculos tecnológicos e implementadas varias formas de optimizar el rendimiento de los servidores, llegó el momento de poner a prueba todo el trabajo. Generamos una versión más breve de la guerra de 10 horas para que durase solo una.

Durante la primera prueba de estrés permitimos que casi todos los jugadores entraran en la zona para ver qué ocurría. En un momento dado, estuvimos casi al 150 % de la capacidad de un reino de la versión 1.12. Llegado ese punto, el reino de prueba se cerró inesperadamente. Éramos conscientes de que habíamos elevado mucho el tope de jugadores y registramos cifras que excedían en gran medida ese umbral. Investigamos el problema y descubrimos que el código que permitía que los jugadores se desplazasen entre zonas consistía en una cola incapaz de procesar a muchos jugadores a la vez. Este fue el motivo por el que se sacaba a los jugadores de la zona y por qué se quedaban atascados en rutas de vuelo durante periodos de tiempo demasiado largos. Reiniciamos el servidor y continuamos con la prueba de estrés adaptándonos a la situación. Fuimos reduciendo poco a poco el número de jugadores hasta llegar a un punto en que nos pareció que se podía jugar (con un poco de retardo) y con más jugadores que nunca. Estaba previsto que el evento durase una hora, pero la mitad de los participantes tardaron cuatro horas en completarlo debido a los cierres del servidor.

La segunda prueba de estrés tuvo lugar una semana después y nos sirvió para comprobar si las optimizaciones daban resultado. Nada más comenzar la prueba, se hicieron patentes las mejoras: ¡los jugadores ya no se quedaban estancados en las rutas de vuelo hacia Silithus! Además, recabamos datos suficientes para determinar cuántos podía haber en Silithus de forma fluida. Tras realizar ambas pruebas, decidimos aprobar unas cifras que consideramos representativas del equilibrio entre la gestión del retardo y la estabilidad del servidor. Gracias a las pruebas, que fueron todo un éxito, verificamos la viabilidad de las optimizaciones, ya que nos permitieron identificar unos límites de la zona con los que trabajar.

Repartir soluciones de servidor por todo Azeroth

En principio, las optimizaciones estaban pensadas para que solo estuviesen activas en Silithus durante la guerra del Mar de Dunas. Cuando nos aseguramos de que se podían lanzar a nivel global, las aplicamos a todo el mundo en la versión 1.13.5. Al comenzar el esfuerzo de guerra, los jugadores comenzaron a entregar suministros y a saquear cadáveres de insectos de forma masiva. Registramos un aumento enorme del número de jugadores no solo en Silithus, sino también en las capitales y en las zonas circundantes. Las optimizaciones contribuyeron a que estas experiencias fuesen más fluidas, lo que permitió que se llevaran a cabo batallas JcJ a gran escala por todo Azeroth. De hecho, algunos jugadores invocaron al jefe de mundo Thunderaan para que los ayudase a eliminar a la facción contraria de una colmena.

Aunque aún no se había llevado a cabo el evento de apertura de las puertas, algunos servidores estaban experimentado unos errores extraños que impedían que avanzase el esfuerzo de guerra: completaban el esfuerzo de guerra tan rápido que podía provocar una circunstancia poco común en la lógica la entrega de recursos que evitaría que se iniciase la cuenta atrás de cinco días. La probabilidad de que se diese este caso tan extremo era muy reducida, así que pudimos estabilizar estos servidores de forma manual y atajar el mismo problema en otros reinos que estuviesen completando el esfuerzo de guerra en el futuro.

Una vez completados los esfuerzos de guerra y transcurridos cinco días para poder abrir las puertas, comenzamos a seguir de cerca los reinos de China, que fueron los primeros que en estar disponibles. El primero en contar con un gong activo fue el de Ouro. Al realizar el seguimiento de las poblaciones en cada capa, vimos que la mayor parte de los jugadores de cada una de ellas estaban en Silithus. Nunca habíamos desarrollado el evento a través de varias capas adaptadas para contener a varios miles de jugadores a la vez. A pesar del retardo, nuestros servidores no sufrieron cierres durante la primera tanda de reinos chinos disponibles.

¡A golpear el gong!

El 4 de agosto, varios reinos de Norteamérica estaban preparados para golpear el gong al poco tiempo del restablecimiento de los servidores. Realizamos un seguimiento activo de cada uno de estos reinos en cuentas de maestros de juego y mediante nuestras herramientas de observación para detectar y corregir posibles errores. Se abrieron todos los reinos y el evento comenzó sin problemas. Los portadores de cetros recibieron los prestigiosos tanque de batalla qiraji y los jugadores lucharon contra insectos aún más grandes, y todo ello con un nivel de estabilidad satisfactorio. Mientras esperábamos a que el primer servidor reestablecido completase el periodo de cinco días, descubrimos un problema importante: los eventos no seguían activos tras el reinicio, lo que implicaba que, si un servidor se cerraba inesperadamente o se reiniciaba, se perdería toda la progresión del evento. Aunque este problema había existido desde el comienzo del desarrollo de WoW Classic, no se habían celebrado demasiados eventos que tuviesen que seguir activos tras el reinicio del servidor. Nuestro equipo pudo resolver el problema rápidamente, pero tuvimos que ir con ojo para que no tuviesen lugar más reinicios hasta implementar una solución y catalogar adecuadamente todos los esfuerzos de guerra existentes en nuestra base de datos sin interrumpir a los jugadores.


Es posible que algunos opinen que el cierre inesperado de los servidores fue parte de lo que provocó que la guerra original de AQ fuese caótica y memorable. Pero nos hemos esforzado para generar esa sensación reproduciendo una experiencia mucho más estable y que se pudiese compartir con unos 1500 jugadores en Silithus en cada servidor. Nuestra intención fue contar con la mayor cantidad de jugadores posible en la guerra de AQ de que se hubieran visto en Classic y hacerlo durante 10 horas y sin interrupciones. Aunque algunos reinos sufrieron cierres inesperados, pudimos reestablecerlos rápidamente: se recuperaron por completo y volvieron a estar operativos en cuestión de minutos sin incidentes posteriores.

Más de 4000 jugadores de todo el mundo se han convertido en Señores Escarabajo, un número que va en aumento a medida que los reinos avanzan en sus respectivos esfuerzos de guerra. Ha sido increíble ser testigos del entusiasmo y la participación de los que ha gozado Classic desde que comenzó el esfuerzo de guerra de AQ, ¡y estamos muy agradecidos a todos los que nos han acompañado en la segunda guerra del Mar de Dunas!