Questo sito usa i cookie per migliorare la tua esperienza di navigazione. Continuando a navigare su questo sito acconsenti a usare i nostri cookie. Ottieni maggiori informazioni Ignora
Stai usando un browser non supportato. Alcune caratteristiche potrebbero non funzionare correttamente. Per favore controlla il nostro elenco di browser supportati per una migliore esperienza. Ignora

Torchlight 3

Aggiornamento di sviluppo: Storie di guerra sulla correzione dei dati

Di Fero | ven 18 dic 2020 10:00:00 PST

Consultate i nostri canali DiscordFacebookTwitter e Twitch per avere le ultime notizie di sviluppo e gli aggiornamenti.

 

 

L’Aggiornamento di sviluppo di questo mese è di Guy Somberg, Programmatore capo di Echtra. A volte il miglior modo per guardare al futuro di un progetto è capirne il passato. Anche se il prossimo Aggiornamento di sviluppo approfondirà gli aggiornamenti futuri, problemi ricorrenti e altri feedback della community, questo blog è per coloro che apprezzano una buona lettura tecnica e vogliono uno sguardo approfondito alle nostre “storie di guerra” di sviluppo.

 

Introduzione

Nello sviluppo di un gioco, non tutti i problemi che si risolvono sono prestazioni, contenuti o funzionalità che i giocatori vedono. A volte si ha qualcosa di ingarbugliato da sistemare e bisogna scavare a fondo per sbrogliarlo.

C’è una frase che usiamo per questo tipo di lavoro: “tosatura di yak”. Il termine ha origine nel programma TV “Ren and Stimpy” e ora si riferisce a un lavoro che apparentemente non c’entra con l’obiettivo finale ma che devi compiere per raggiungerlo. Per esempio: “Voglio costruire un ponte di pietra su questo torrente. Sto tosando questo yak per scambiare il pelo con un filatore, per farmi prestare il suo carretto e andare alla cava e prendere un po’ di rocce”. Tosare lo yak non è necessariamente una parte importante del costruire un ponte, ma non si può compiere nessun progresso finché lo yak ha il suo pelo!

Questa è una raccolta di alcune storia di problemi da tosatura di yak che dovevano essere “semplicemente sistemati”.

 

0D0D0A

I sistemi di controllo delle sorgenti sono uno degli strumenti più importanti che gli sviluppatori dei videogiochi (ma anche tutti gli altri sviluppatori) usano. È un database che contiene uno storico di tutti i file che compongono il nostro gioco: codici sorgente, risorse, suoni e altro.

Circa tre anni fa, passammo dal nostro sistema di controllo delle sorgenti a un altro. Non importa da quale a quale. Il sistema che stavamo usando si stava rompendo sotto il nostro carico, perciò avevamo bisogno di uno nuovo. Abbiamo fatto i compiti, esaminato le alternative ed effettuato una scelta.

Quando si devono cambiare i sistemi di controllo delle sorgenti, ci sono, diciamo, due modi per farlo. Il modo più semplice è scollegare tutti dal controllo, prendere un’istantanea delle ultime cose, importarle nel nuovo sistema, ritoccarle per renderle conformi all’idea di funzionamento dell’universo del nuovo sistema ed attivare il nuovo sistema per tutti. Questo metodo ha il vantaggio che “funziona”, ma si perde tutto lo storico precedente al cambiamento. In questi ambienti ci sta spesso solo una voce nello storico che dice “Importato tutto. Se volete lo storico precedente controllate nell’altro sistema di controllo”. Questo va bene finché l’altro sistema rimane disponibile, ma spesso gli impegni precedenti sono persi per sempre.

Il metodo più complesso è di importare lo storico dal vecchio sistema a quello nuovo. La maggior parte dei sistemi di controllo delle sorgenti vi permette di farlo, ma richiede tempo, è soggetto a errori e richiede comunque degli interventi manuali per conformarlo alle idiosincrasie del nuovo sistema. Anche se richiede più lavoro preventivo, è estremamente utile avere l’intero storico delle sorgenti disponibile.

Abbiamo scelto l’importazione dello storico che, almeno in superficie, sembrava funzionare perfettamente.  Vedevamo lo storico, vedevamo i file ed eravamo in grado di controllare e verificare che tutto sembrasse a posto. Alcuni file aveva uno strano problema di spaziamento, ma non sembrava niente di che.

Ma poi abbiamo provato a compilarlo ed è crollato tutto. Il compilatore di Visual studio si è lamentato riguardo le “chiusure di linea Mac” e si è rifiutato di compilare qualunque cosa.

Cosa!? E perché mai?

Una piccola nota: quando un computer vuole rappresentare un carattere, deve selezionare una codifica. La codifica più comune in uso oggi è chiamata UTF-8 che è in grado di codificare qualunque carattere della lingua inglese, segni di interpunzione comuni e diversi codici di controllo in un singolo byte di dati. Usando più byte si può codificare dati in qualunque lingua, ma questo è un altro discorso.

Due di questi codici di controllo sono i caratteri Carriage return (CR) e  Line feed (LF), che si rifanno ai giorni in cui i computer erano attaccati alle macchine da scrivere automatiche e non agli schermi. In quei giorni si diceva al carrello stampatore di tornare alla colonna iniziale con il codice CR e si faceva scorrere il foglio alla riga successiva con il codice LF. Perciò, per iniziare a digitare all’inizio di una nuova linea si doveva mandare la sequenza CR LF

Quando è avvenuto il passaggio ai monitor, la convenzione CR LF è rimasta per compatibilità con i dispositivi precedenti. Tuttavia, gli sviluppatori di nuovi sistemi, come il nuovissimo computer Macintosh della Apple e il sistema Unix di Bell Labs, non erano intralciati dalla compatibilità con i sistemi precedenti ed erano liberi di compiere scelte diverse.

È saltato fuori che i tre sistemi oggi più comuni al mondo hanno compiuto tutti scelte diverse: DOS ha usato CR LF, Macintosh ha usato CR e Unix ha usato LF. Windows ha ereditato i codici da DOS e MacOS ora usa LF (come Unix).

Con il tempo le differenze si sono risolte da sole. I software sono in grado di funzionare in “modalità testo” e fornire all’utente qualunque codice di chiusura linea che serva al suo sistema per farlo funzionare correttamente. I dettagli di queste differenze ogni tanto emergono, ma in genere non sono un problema.

Tutta questa storia ci è balenata davanti agli occhi appena abbiamo visto l’errore “chiusure di linea Mac”. Di cosa stava parlando? Noi sviluppiamo su Windows, quindi tutte le chiusure di linea dovrebbero essere di Windows (CR LF) o quantomeno una combinazione di Windows e Unix (LF). Da dove erano usciti questi CR solitari?

E ci siamo ricordati di tutto quello strano spaziamento: tutto il nostro codice aveva uno spaziamento doppio. Da dove uscivano quegli spazi extra?

A questo punto, qualcuno ha avuto l’idea di guardare il file in un editor esadecimale, uno strumento che permette di vedere la rappresentazione binaria di un file di testo mostrando il valore di ciascun byte in esadecimale. Normalmente su un file con le chiusure di linea di Windows ci si aspetterebbe una linea di testo, poi un CR (13 o 0D nella rappresentazione esadecimale) e un LF (10 o 0A). Per qualche ragione nelle linee rotte c’erano un CR (0D), un altro CR (0D) e poi un LF (0A) dandoci un 0D0D0A.

In qualche modo, durante il processo di conversione da un programma di controllo sorgenti all’altro, il programma di conversione ha deciso che il file aveva chiusure di linea Unix e ha quindi sostituito ogni LF con CR LF anche se c’era già un CR! Ciò spiegava tutto. Il nostro editor era felicissimo di rendere il CR come una linea vuota e sapeva come convertire il CRLF in una linea vuota, ragione per cui il nostro codice era tutto separato da un doppio spazio. Visual Studio, d’altro canto, non interpretava la combinazione CR LF come una nuova linea ma dava errore sul CR che precedeva.

Ho corretto ciò scrivendo un piccolo programma in C++. Avrebbe passato in rassegna la nostra directory di codici sorgente, aperto ogni file, trovato ogni 0D0D0A e l’avrebbe sostituito con 0D0A.  Non ci aspettavamo di cambiare il sistema di controllo delle sorgenti di nuovo, perciò il codice di questo tool è perso nelle sabbie del tempo... (O così credevamo! Abbiamo scoperto un drive che conteneva questo programma dopo aver scritto questo articolo, perciò abbiamo caricato il codice nei nostri archivi per i posteri.)

Solo due o tre di noi hanno lavorato su questo problema specifico, ma potete far venire qualche tic a chiunque di noi dicendo semplicemente “oh doh doa”.

 

Correttore Octothorpe

Un paio d’anni fa, il nostro ingegnere del suono e il nostro compositore hanno fatto un viaggio a Bratislava, in Slovacchia, per registrare parte della nostra musica con un’orchestra. È Stato un viaggio fantastico (o così mi hanno detto) e hanno portato a termine molte cose nei pochi giorni che sono stati lì.

Uno dei risultati di questo viaggio è una suite del contenuto che chiamiamo “vzory”, parola che in slovacco significa “schema”. Sono piccoli spezzoni di musica orchestrale che possono essere combinati in una miriade di modi per creare nuova musica, e sono registrati in varie tonalità. Il risultato finale è che abbiamo un dato schema in sol, sol#, fa, fa#, ecc.

Il nostro compositore ha fatto la cosa più naturale: ha passato del tempo a tagliare e riorganizzare tutti questi contenuti, distribuiti in cartelle e file corrispondenti alle tonalità della registrazione e importato l’intera suite nel tool audio che usiamo: FMOD Studio. FMOD è agganciato al nostro sistema di controllo delle sorgenti che ha felicemente controllato e aggiunto tutti i nuovi file.

Finora tutto bene. Finché la gente non ha iniziato a ricevere avvisi misteriosi riguardo nomi di file che erano nell’ultimo codice del nostro sistema di controllo delle sorgenti. Erano solo avvisi, non impedivano a nessuno di lavorare, ma era qualcosa che non volevamo continuasse a comparire.

Queste tracce vzory erano le colpevoli. È saltato fuori che al sistema di controllo delle sorgenti non piace se inserisci file con un octothorpe (“#”, a volte chiamato simbolo della libbra, cancelletto, hash tag, simbolo dei numeri e altre cose) nel nome del file. Li accetta, ma si lamenta insistentemente. Il nostro compositore aveva nominato la directory e i relativi file delle tracce vzory di tonalità la diesis con il nome “la#”, come è ovvio che sia! (Anche gli altri diesis erano scritti in questo modo.)

Il sistema di controllo delle sorgenti era davvero contrariato da questa scelta.

Rinominare questi file non era sufficiente perché FMOD traccia i metadata di file e directory in file XML, ciascuno con un GUID (una sequenza di lettere, numeri e trattini) come nome del file.

Di nuovo i codici sono venuti in nostro soccorso. Questa volta è stato un programma scritto, ironicamente, in C# che avrebbe passato in rassegna tutti i file e sub-directory nel percorso indicato, per trovare tutti quelli con un octothorpe nel nome e sostituire il “#” con la parola “diesis”. Quindi “la#” divenne “ladiesis”. Dopodiché sarebbe passato ai file XML in quel percorso alla ricerca di tutti gli octothorpe nei file (che erano quindi metadata dei file o directory rinominati) e avrebbe sostituito il “#” in quella linea con la parola “diesis”.

A parte direi ai nostri ragazzi “non fatelo,” non c’era molto che potevamo fare per prevenire che accadesse di nuovo. Questa volta abbiamo tenuto il codice sorgente, così se avessimo compiuto di nuovo lo stesso errore avevamo pronto un tool per correggerlo.

 

Correttore PO

La localizzazione e l’internazionalizzazione sono parti importanti di qualunque progetto di giochi. Usiamo l’Unreal engine che ha tool di localizzazione incorporati. Usando una particolare struttura di dati per i nostri file, Unreal può trovare tutte le linee localizzate nel gioco. Possiamo quindi esportarle nel formato standard “portable object” (.po) file, usato dal tool GNU, oltre ad altri.

Questo è un formato su cui i nostri traduttori possono lavorare. Prendono i file, traducono le righe e poi ce li rimandano. Poi possiamo importarli in un particolare formato in modo che Unreal possa sistemare il testo. Tutto molto bello, finché rimani dentro i confini e segui la strada che si aspetta Unreal.

Ovviamente, abbiamo costruito delle cose nostre che risiedono nel sistema di Unreal e vivono in pace con lui, ma che sono abbastanza “sul bordo” da risultare invisibili ad altri sistemi di Unreal. Una di queste parti è il sistema delle righe localizzate che non vedeva nessuno dei nostri bellissimi strumenti.

Abbiamo scritto un tool per renderli visibili e ci siamo ritenuti soddisfatti. Il nostro primo grande blocco di localizzazione  è stato mandato ai traduttori. Stavamo per importarlo quando abbiamo scoperto che nessuna delle righe era stata importata!

Cos’era successo?

Unreal permette di identificare ogni riga localizzata con un paio di linee di testo: una categoria e una voce di quella categoria. Se non si fornisce una qualunque di quelle voci, le genera lui per te. Ma il tool che avevamo scritto per rendere visibili le nostre risorse ai traduttori ha generato una nuova categoria e voce per ogni riga di testo localizzata ogni volta che è stato usato, e ciò ha fatto sì che ogni riga di testo ricevesse un codice diverso ogni volta che importavamo ed esportavamo.

Oh, cielo. Abbiamo corretto il problema alla base e fatto in modo che la coppia di categoria/voce non variasse a ogni procedura, ma avevamo questa colossale sfilza di righe in tutte le lingue che non era compatibile con i dati aggiustati! Dovevamo trovare un modo per correggere queste righe e farle combaciare.

Fortunatamente, ogni riga aveva molti dati sul suo contesto e sulla sua origine. Molti di questi dati non erano cambiati, o almeno lo avevano fatto in una maniera prevedibile. Questi dati sono stati sufficienti per paragonare una riga importata con una riga esportata in maniera corretta e abbinarle.

Come prima, scrivere un codice è stata la soluzione. Abbiamo scritto un programma (C++ di nuovo) per leggere il file tradotto (contenente le vecchie ed errate coppie categoria/voce) e un nuovo file  esportato in inglese (contenente le nuove e corrette coppie categoria/voce), abbinare i dati e scrivere una versione corretta del file con il testo tradotto con le corrette coppie categoria/voce.

Questa era una situazione in cui semplicemente correggere i dati era insufficiente. Dovevamo prima risolvere il problema alla base per poter scrivere un tool per correggere i dati.

 

Conclusione

Questi problemi hanno avuto un tema comune: tramite una sequenza di eventi (errori umani o delle macchine) una serie di file importanti sembravano essere rotti in qualche modo. Alla fine, per le persone che lavorano con i dati non è molto importante perché queste cose sono successe. Vogliono solo correggere i file che non funzionano. Vale sempre la pena individuare la causa del problema per evitare che esso si ripresenti, ma alle volte devi solo metterti a lavorare. Tutte le analisi retrospettive e il lavoro preventivo del mondo non aiutano le persone a fare il loro lavoro con i file rotti che già hanno.

Gli esempi di cui ho parlato qui sono tutti lavori importanti che vanno fatti, ma tutti e tre quei tool sono stati usati una sola volta. Molti dei sistemi che abbiamo costruito sono complessi e problemi del genere fanno parte del normale processo di sviluppo man mano che scopriamo i casi limite.

Alle volte devi scrivere dei tool che usi solo una volta e non è un problema: devi solo stringere i denti e tosare lo yak.

- Guy Somberg

 

 

tl3-news, tl3-general, tl3-frontpage, tl3-featured, tl3-dev,

Più recenti Altro

Un'introduzione del lupo di mare, il Pirata maledetto.
Leggi altro
Date un'occhiata alle Patch notes del nostro nuovissimo aggiornamento di Torchlight 3!
Leggi altro
La classe del Capitano maledetto arriverà con il prossimo aggiornamento di Torchlight III...
Leggi altro

hover media query supported