L'angolo del programmatore: ricreare i preparativi per la guerra di Ahn'Qiraj
La guerra è alle porte. All'inizio di questo mese, uno degli eventi di World of Warcraft Classic più attesi è cominciato, ovvero quello dei preparativi per la guerra di Ahn'Qiraj. Interi reami di Classic si sono riuniti, con la forza di Orda e Alleanza combinata, per contribuire alla raccolta delle risorse per aprire i cancelli e sbloccare le incursioni di Ahn'Qiraj. Quando la War of the Shifting Sands è cominciata per la prima (e unica) volta nel 2006, migliaia di giocatori di ogni reame si sono diretti a Silithus per prendere parte all'evento o essere testimoni del caos portato da esso. L'afflusso di giocatori ha superato le più rosee aspettative degli sviluppatori e, per dirla in modo semplice, non eravamo pronti a una mole simile di giocatori. I server si sono sovraccaricati in breve tempo e molti giocatori sono entrati in un ciclo continuo di riconnessione e disconnessione nel tentativo di prendere parte all'evento in queste 12 ore mentre i nostri programmatori erano al lavoro per cercare di risolvere rapidamente il problema e fare in modo che i giocatori potessero riconnettersi. Alla fine siamo riusciti a sistemare i server durante l'evento, ma abbiamo anche appreso qualche lezione e capito come fare meglio in futuro. Quindici anni dopo, eravamo pronti a ricreare uno dei momenti più epici della storia di WoW in WoW Classic, concentrandoci sull'ottimizzazione dei server per combattere la latenza ed eliminare i crash dei server, il tutto ospitando più del doppio dei giocatori presenti a Silithus durante il debutto dell'evento nel 2006.
In questo articolo, ti spiegheremo come abbiamo ricreato questo evento tanto atteso basandoci su personaggi automatizzati e stress test per determinare i punti di rottura e ideare soluzioni ottimali, come abbiamo implementato queste soluzioni tramite software per porre rimedio ai problemi che l'hardware non poteva risolvere, e come abbiamo gestito un evento globale con crash dei server limitati, il tutto preservando l'esperienza di gioco di WoW Classic.
Ricreare la War of the Shifting Sands
Avevamo tre obiettivi specifici in mente quando abbiamo pensato a come approcciare questo evento dal punto di vista della progettazione: prevenire le disconnessioni continue, aumentare il limite massimo di giocatori nella zona dell'evento e determinare il livello di latenza tollerabile oltre il quale sarebbe stato necessario teletrasportare i giocatori via da Silithus. Prima di entrare nei dettagli di come abbiamo massimizzato le prestazioni dei server, è importante capire quali sono i limiti entro i quali potevamo muoverci, ovvero le limitazioni imposte dal codice di WoW Classic, il funzionamento della soluzione al problema di gestione del numero di giocatori e come questo avrebbe influito sul gameplay.
Oltre i limiti
La versione moderna di World of Warcraft è stata costruita sulle fondamenta del codice originale creato 15 anni fa. In seguito alla pubblicazione del gioco, abbiamo sviluppato dei metodi più moderni per gestire un alto numero di personaggi in Battle for Azeroth, in particolar modo con lo "sharding". Questo sistema permette ai server di WoW di ospitare molti più giocatori rispetto a quanto accadeva nel 2006. In Battle for Azeroth, abbiamo usato lo sharding per gestire il carico di giocatori su un server facendo una copia di una zona (per esempio Zuldazar) una volta che il numero di giocatori raggiunge una certa soglia. In questo modo i problemi di latenza vengono neutralizzati dividendo i giocatori in diverse versioni della zona, dal momento che le interazioni sono tra le azioni più dispendiose a livello di CPU, a causa dei pacchetti che inviano costantemente al server per garantire una precisione ottimale nei movimenti e nel lancio di incantesimi. Inoltre, lo sharding mitiga potenziali problemi di latenza che possono verificarsi durante la transizione in un'altra zona quando il numero di giocatori supera una determinata soglia. Il concetto sembra abbastanza semplice, ma c'è un piccolo problema: WoW Classic è stato progettato per essere una fedele ricreazione dei dati di gioco originali della patch 1.12 e questo vuol dire preservare anche le peculiarità del gioco. In rari casi, le shard faranno sì che il vostro bersaglio, sia esso un personaggio nemico o un PNG, scompaia durante il passaggio in una nuova zona. Mantenere lo sharding avrebbe significato perdere una parte di quel gameplay nostalgico del quale facevano parte anche la caccia a personaggi della fazione avversaria o PNG fino oltre ai limiti di una regione. Per questo motivo, ora avevamo bisogno di trovare una soluzione che non interferisse con il gameplay del gioco originale e ci permettesse allo stesso tempo di avere più personaggi sul server senza che questi dovessero affrontare una latenza esagerata.
Per risolvere questo problema, abbiamo deciso di utilizzare i layer, copie di intere regioni (come le Eastern Kingdoms), per gestire il numero di giocatori e i problemi di latenza mantenendo intatto il fascino memorabile del gioco originale, in modo che i personaggi potessero nuovamente portare i boss esterni da una zona all'altra e inseguire personaggi nemici passando di regione in regione senza il rischio di essere assegnati a una shard diversa. Ad ogni modo, i layer erano stati ideati come soluzione temporanea. Siccome nella patch 1.12 del gioco originale non esistevano né lo sharding né il layering, avevamo promesso ai giocatori che avremmo usato i layer alla pubblicazione di WoW Classic per poi rimuoverli nel corso del tempo. Ci sono alcuni casi per i quali stiamo ancora utilizzando i layer a causa dell'altissimo livello di personaggi attivi (come nel server Faerlina in Nord America), ma abbiamo notevolmente ridotto il numero di layer attivi su questi reami rispetto alla pubblicazione. Con 15 anni alle spalle, la guerra di AQ era uno degli eventi più attesi di WoW Classic e volevamo avere il maggior numero di personaggi possibili in una zona, eccezion fatta per le aree di partenza alla pubblicazione del gioco, senza l'aiuto dei layer. Senza le tecnologie del layering o dello sharding, dovevamo obbligatoriamente essere creativi... e in fretta.
Soluzioni manuali e un'esperienza indimenticabile
Abbiamo cominciato la ricerca di una soluzione che non includesse il layering o lo sharding creando dei client automatici che replicavano le azioni che avrebbero compiuto i personaggi veri, come lanciare incantesimi, combattere contro PNG e muoversi all'interno dell'area. Questo ci ha permesso di ottenere un quadro della situazione e avere delle informazioni su quali avrebbero potuto essere le prestazioni con migliaia di giocatori che interagivano in una singola zona. Dopo aver eseguito delle simulazioni, abbiamo organizzato degli stress test con dei volontari in modo da carpire quali sarebbero stati i reali comportamenti dei personaggi. Questo ci ha dato importanti indicazioni riguardo ad alcuni punti di rottura e a quali parti del codice del nostro server stavano riscontrando il maggior numero di problemi. I server sono stati analizzati minuziosamente per determinare quanto fossero vicini a causare un problema non rispondendo agli input, ovvero quanto fossero vicini al cosiddetto "deadlocking".
Il passo successivo era analizzare cosa stesse intaccando le prestazioni del server in modo da cominciare a suddividere quest'immenso compito in vari obiettivi. Quello che dovevamo affrontare era un problema polinomiale, che non potevamo fronteggiare utilizzando dell'hardware migliore, perché la sua qualità non cresce esponenzialmente. Ciò che dovevamo fare era invece calibrare manualmente l'ottimizzazione scegliendo deliberatamente quali dati dovevano essere comunicati ai personaggi e quanto spesso. Per meglio illustrare questo dilemma, facciamo finta che ci siano 20 personaggi che saltano in cerchio. Il server trasmette le azioni degli altri 19 personaggi attraverso i pacchetti (dati trasferibili). In questo gruppo di 20, il server processa 380 pacchetti (20 personaggi totali moltiplicati per 19 riceventi = 380 pacchetti). Questo problema si aggrava quando più giocatori compiono la stessa azione nella zona. Se aumentiamo il numero di personaggi a 500, vengono inviati 249.500 pacchetti al server. Se aumentiamo ancora il numero a 1.500, verranno inviati 2.248.500 pacchetti al server. A seconda delle azioni dei giocatori, vengono inviati ancora più pacchetti ogni secondo: tieni a mente che gli esempi qui sopra prendono in considerazione una sola azione. Un maggior numero di pacchetti inviati al server aumenta il tempo di elaborazione che il server impiega per un singolo giocatore per poi passare a tutte le azioni degli altri giocatori. Quando il problema si aggrava, i server cominciano ad avvicinarsi al deadlocking. In WoW Classic, abbiamo un numero notevolmente maggiore di giocatori per reame rispetto al 2006, per cui ci si aspetta che riusciamo a gestire un numero ben maggiore di personaggi intorno ai cancelli rispetto a prima.
Ottimizzare le prestazioni dei server
I nostri server sono progettati per andare in crash e ripartire se si verifica un deadlock, per cui sapevamo di dover fare qualunque cosa in nostro potere per cercare di minimizzare il tempo di elaborazione. Dopo alcuni test, ci è stato subito chiaro che il movimento era ciò che richiedeva il maggior carico di elaborazione e che di conseguenza pesava molto sui server. Così abbiamo cominciato a ridurre gli aggiornamenti direzionali (che mostrano la direzione in cui il modello di un personaggio è rivolto) e a inviare aggiornamenti solo quando un personaggio si muove, si ferma o usa movimenti dettati dalla tastiera. Dal momento che la latenza con un numero eccessivo di giocatori era già compromessa, utilizzare la CPU per inviare meno aggiornamenti direzionali non aveva migliorato le cose. A questo punto, era meglio smettere di inviarli. Abbiamo preso la decisione di inviare aggiornamenti legati al movimento molto meno spesso in modo da poter avere più personaggi all'interno della zona. Ricorda che siamo ancora alla ricerca del punto di rottura che ci permetta di ospitare il maggior numero di personaggi possibile a Silithus prima che il server ceda. Dopotutto, è meglio perdere qualche aggiornamento dei movimenti rispetto a non potersi connettere col proprio personaggio. Abbiamo anche iniziato a ridurre i dati considerati come di bassa priorità. Un'azione classificata come meno importante non dovrebbe essere inviata con la stessa frequenza di una più importante. Abbiamo infine visto che molti messaggi venivano inviati assieme, indipendentemente dalla loro importanza, e abbiamo ottimizzato il codice in modo da inviare quelli meno importanti in gruppo e meno frequentemente.
I benefici e le penalità erano un'altra delle cose che intaccavano maggiormente le prestazioni dei server. In giro per il mondo, specialmente quando si combatte contro i mostri, i benefici e le penalità vengono applicati molto spesso. Anche se non sembra un grosso problema, con una grande concentrazione di personaggi, tutti vicini, queste informazioni devono essere condivise tra tutti. Proprio come abbiamo fatto con i dati a bassa priorità, ora inviamo i dati di benefici e penalità in blocchi per evitare di inviare pacchetti multipli in successione ai giocatori.
Gestire il numero di giocatori
Oltre all'ottimizzazione dei server per gestire più personaggi in ogni zona, non ci era di certo sfuggito il fatto che sarebbe stato impossibile far entrare l'intera popolazione di un reame (più del doppio di quella che potevano gestire i reami del WoW originale con la patch 1.12) a Silithus. Dovevamo prendere una decisione molto difficile per limitare l'accesso alla zona, controllando quanti personaggi ci fossero all'interno e quanti potevamo ancora farne entrare. Abbiamo deciso di far entrare solo i personaggi di livello 60 a Silithus e di bloccare l'entrata una volta raggiunto il numero massimo. Creare questa restrizione è stata la scelta giusta dal momento che l'evento di Silithus è considerato contenuto di alto livello e i personaggi di livello basso possono comunque partecipare ai preparativi per la guerra nelle altre zone, uccidendo gli Anubisath che vagano nelle Barrens, pensati apposta per i personaggi di livello compreso tra 20 e 30. Pur sapendo quale fosse il limite massimo di personaggi che potevamo far entrare nell'area senza che il server collassasse, la vera domanda, che ci porta al secondo punto critico, era a quale numero saremmo dovuti arrivare per garantire le migliori prestazioni possibili ai giocatori. Nel corso dei test, abbiamo scoperto che il numero ideale si aggirava intorno ai 1.500 personaggi, qualora questi fossero ammassati. A ogni modo, siccome l'evento ha luogo in tutta la zona e i giocatori sarebbero stati piuttosto sparsi, non abbiamo individuato grossi problemi di prestazioni.
L'evento era stato programmato per avvenire in tutte le regioni, per cui dovevamo essere certi che tutto funzionasse su più layer. Questo significa che chi aveva uno scettro e suonava il gong su un layer avrebbe dato il via all'evento su tutti gli altri layer connessi a quel reame. Dal momento che l'attivazione dell'evento era basata sull'interazione di un personaggio, volevamo assicurarci che chi era in possesso di uno scettro fosse visibile attraverso più layer, in modo che i personaggi dello stesso reame potessero vederli. Questo aveva creato un interessante problema, dal momento che ora i server dovevano comunicare quest'informazione, cosa che di norma non avrebbero fatto. Questo poteva creare molte complicazioni durante l'invio degli aggiornamenti al server, in quanto dovevamo mandare gli stessi dati a più layer, potenzialmente a migliaia di giocatori.
Abbiamo iniziato a sviluppare questa tecnologia dall'introduzione dello Stranglethorn Fishing Tournament e poco dopo l'abbiamo applicata anche ai benefici nel mondo di gioco dati da Onyxia, Nefarian, Zul'gurub e Rend. Quando abbiamo capito che funzionava a dovere, eravamo pronti a fare qualche test con questa tecnologia e con le altre adottate per l'evento della guerra di AQ.
Sperimentazione delle soluzioni
Ora che avevamo risolto i maggiori problemi tecnologici e implementato diversi modi per ottimizzare le prestazioni dei server, era giunto il momento di testare ogni cosa alla quale avevamo lavorato. Abbiamo quindi creato una versione più corta della 10-hour war, destinata a durare solamente un'ora.
Durante il primo stress test, abbiamo lasciato che quasi tutti i personaggi entrassero nella zona per vedere cosa sarebbe successo. A un certo punto, abbiamo raggiunto quasi il 150% della capacità di un reame della patch 1.12 ed è qui che si sono verificati i primi crash. Sapevamo di aver impostato un numero massimo di persone molto alto e abbiamo osservato dei numeri ben superiori. Abbiamo indagato sul problema e capito che il codice che permetteva ai personaggi di entrare in un'area e uscire da essa era una sorta di coda che non era in grado di gestire diversi personaggi per volta. Questa era la ragione per la quale i personaggi non venivano teletrasportati all'esterno e rimanevano bloccati durante lo spostamento coi percorsi aerei per tempi insolitamente lunghi. Abbiamo rimesso a posto i server e continuato lo stress test, modificando alcune variabili nel corso di quest'ultimo. Abbiamo lentamente abbassato il numero fino a raggiungere una situazione in cui la latenza era presente ma si poteva comunque giocare e allo stesso tempo abbiamo raggiunto un numero di personaggi mai visto in nessun'altra zona prima d'ora. L'evento doveva durare solamente un'ora e mezza, ma alla fine ci sono volute quattro ore per giungere al termine a causa dei crash.
Il secondo stress test ha avuto luogo una settimana dopo. Questo ci ha permesso di vedere all'opera le nostre ottimizzazioni. Abbiamo subito notato dei miglioramenti, in quanto i personaggi non rimanevano più bloccati durante lo spostamento con percorsi aerei verso Silithus! Siamo quindi riusciti a ottenere dati a sufficienza da determinare il numero di giocatori che potevamo ospitare a Silithus. Al termine di entrambi i test, abbiamo deciso di procedere con i numeri che credevamo migliori per ottenere un buon bilanciamento tra latenza non eccessiva e stabilità del server. Questi test ci hanno permesso di vedere se le nostre ottimizzazioni funzionassero ed entrambi si sono rivelati un successo, dal momento che ci hanno permesso di identificare il massimo numero di personaggi nella zona.
Soluzioni applicate a tutta Azeroth
Originariamente, queste ottimizzazioni dovevano essere applicate solo a Silithus durante la War of the Sands. Dopo aver determinato che queste potevano essere applicate senza problemi globalmente, le abbiamo applicate all'intero mondo di gioco nella patch 1.13.5. Una volta cominciati i preparativi per la guerra, i personaggi hanno cominciato a consegnare risorse e depredare cadaveri di scarafaggi in massa. Abbiamo così notato un picco di personaggi non solo a Silithus, ma anche nelle capitali e nelle zone al di fuori di esse. Queste ottimizzazioni ci hanno aiutato a migliorare le prestazioni generali dell'esperienza di gioco, permettendo a battaglie PvP su larga scala di avere luogo su tutta Azeroth. Alcuni personaggi hanno addirittura evocato il boss esterno Thunderaan per cercare di eliminare i membri della fazione avversaria in modo da avere accesso all'alveare.
Anche se l'apertura dei cancelli non aveva ancora avuto luogo, su alcuni server si stavano verificando strani problemi riguardo al progresso dei preparativi per la guerra. La velocità con la quale alcuni server stavano completando i preparativi era talmente alta che aveva intaccato la logica di ogni consegna di risorse e in questo modo il timer dei cinque giorni prima dell'inizio della guerra non cominciava. Si trattava comunque di un caso limite e la probabilità che si verificasse era molto bassa, per cui siamo riusciti a risolvere manualmente il problema sui server nei quali si era verificato e abbiamo impedito che si verificasse in futuro nei reami che dovevano ancora portare a termine i preparativi.
Una volta completati i preparativi e passati i cinque giorni necessari antecedenti all'apertura di cancelli, abbiamo cominciato a monitorare i reami cinesi, che sono stati i primi a suonare il gong. Il primo server cinese in assoluto ad aprire i cancelli è stato Ouro. In quel momento stavamo tenendo d'occhio il numero di personaggi in ogni layer e abbiamo osservato che la maggior parte dei personaggi di ogni layer si trovava a Silithus. Un evento nel quale erano presenti diversi layer, nei quali si era raggiunto il numero massimo di personaggi, raggiungendo un numero totale di migliaia di personaggi, era qualcosa di incredibile e mai visto prima. Anche se era presente un po' di latenza, sui nostri server non si è verificato alcun crash durante la prima tornata di apertura dei cancelli in Cina.
Via al gong!
Il 4 agosto abbiamo notato che ci sarebbero stati diversi reami del Nord America pronti a suonare il gong poco dopo il reset dei server. Abbiamo monitorato questi reami attivamente, uno per uno, grazie agli account Game Master e ai nostri strumenti di osservazione, e abbiamo risolto tutti i problemi che potevano essere riscontrati. Su ogni reame l'evento è cominciato senza alcun tipo di problema. I detentori dello scettro hanno ricevuto la prestigiosa cavalcatura Black Qiraji Battle Tank, i personaggi hanno affrontato insetti dalle dimensioni incredibili e siamo rimasti molto soddisfatti della stabilità. Mentre aspettavamo il primo reset del server in seguito al periodo d'attesa di cinque giorni, abbiamo notato un problema considerevole: gli eventi non proseguivano dopo il riavvio dei reami. Questo significa che se si fosse verificato un crash del server o se questo fosse stato riavviato, si sarebbe perso tutto il progresso dell'evento. Nonostante questo problema esistesse sin dall'inizio dello sviluppo di WoW Classic, non ci sono stati molti casi di eventi che persistevano dopo il riavvio dei server. Il nostro team è riuscito a risolvere il problema rapidamente, ma dovevamo assicurarci che nessun altro riavvio si verificasse prima di implementare la risoluzione del problema e catalogare propriamente nel nostro database tutti i progressi dei preparativi per la guerra senza interrompere i giocatori.
Alcuni potrebbero dire che il crash dei server è ciò che ha contraddistinto il caos della guerra di AQ, ciò che l'ha resa memorabile. Noi invece abbiamo lavorato duramente per riprodurre lo stesso fervore portando ai giocatori un'esperienza molto più stabile, da condividere assieme a circa 1.500 personaggi a Silithus sullo stesso server. Volevamo che questa guerra di AQ in WoW Classic venisse ricordata per il maggior numero di personaggi possibili in gioco e per l'assenza di interruzioni durante l'evento, della durata di 10 ore. Sebbene si siano verificati alcuni crash dei reami, siamo riusciti a fare in modo che tornassero online velocemente. Questi reami sono stati ripristinati e sono tornati online nel giro di qualche minuto e in seguito non ha avuto luogo nessun altro crash.
Oltre 4.000 personaggi in tutto il mondo hanno ottenuto il titolo di Scarab Lord e quel numero continua a crescere man mano che i preparativi per la guerra vengono portati al termine sui vari server. L'entusiasmo e il coinvolgimento su Classic sin dall'inizio dei preparativi per la guerra di AQ è stato incredibile e siamo davvero grati a tutti coloro che si sono uniti a noi per la seconda War of the Shifting Sands!