"XML binario" per i dati di gioco?


17

Sto lavorando a uno strumento di modifica di livello che salva i suoi dati come XML.

Questo è l'ideale durante lo sviluppo, poiché è indolore apportare piccole modifiche al formato dei dati e funziona bene con i dati ad albero.

Il rovescio della medaglia, tuttavia, è che i file XML sono piuttosto gonfiati, principalmente a causa della duplicazione dei nomi dei tag e degli attributi. Anche a causa dei dati numerici che occupano molto più spazio rispetto all'utilizzo di tipi di dati nativi. Un piccolo livello potrebbe facilmente finire con 1Mb +. Voglio ridurre significativamente queste dimensioni, soprattutto se il sistema deve essere utilizzato per un gioco su iPhone o altri dispositivi con memoria relativamente limitata.

La soluzione ottimale, per memoria e prestazioni, sarebbe convertire l'XML in un formato di livello binario. Ma non voglio farlo. Voglio mantenere il formato abbastanza flessibile. XML semplifica l'aggiunta di nuovi attributi agli oggetti e fornisce loro un valore predefinito se viene caricata una versione precedente dei dati. Quindi voglio mantenere la gerarchia dei nodi, con attributi come coppie nome-valore.

Ma ho bisogno di archiviarlo in un formato più compatto - per rimuovere la massiccia duplicazione dei nomi di tag / attributi. Forse anche per fornire attributi tipi nativi, quindi, ad esempio, i dati in virgola mobile vengono archiviati come 4 byte per float, non come una stringa di testo.

Google / Wikipedia rivelano che l '"XML binario" non è certo un nuovo problema: è già stato risolto diverse volte. Qualcuno qui ha esperienza con qualcuno dei sistemi / standard esistenti? - sono ideali per l'uso dei giochi - con una libreria di parser / loader gratuita, leggera e multipiattaforma (C / C ++) disponibile?

O dovrei reinventare questa ruota da solo?

O sto meglio dimenticando l'ideale e comprimendo i miei dati .xml non elaborati (dovrebbe comprimersi bene con la compressione simile a zip) e solo caricando l'hit di memoria / prestazioni sul caricamento?


1
XML può essere compresso molto bene usando gzip et al .
ThiefMaster il

Risposte:


18

Abbiamo usato pesantemente XML binario per Superman Returns: The Videogame . Stiamo parlando di migliaia e migliaia di file. Funzionava bene, ma onestamente non sembrava valesse la pena. Ha consumato una notevole frazione del nostro tempo di caricamento e la "flessibilità" dell'XML non è aumentata. Dopo un po ', i nostri file di dati avevano troppi identificatori strani, riferimenti esterni che dovevano essere mantenuti sincronizzati e altri strani requisiti per poter essere realmente fattibili dall'uomo.

Inoltre, XML è davvero un formato di markup e non un formato di dati. È ottimizzato per un sacco di testo con tag occasionali. Non è eccezionale per i dati completamente strutturati. Non era la mia chiamata, ma se fosse stato e sapessi allora quello che so ora, probabilmente avrei fatto JSON o YAML. Sono entrambi abbastanza concisi da non richiedere compattazione e sono ottimizzati per rappresentare i dati , non il testo .


1
Esiste una versione binaria di JSON chiamata BSON .
Philipp,

12

Archivia e modifica i tuoi livelli come normale XML, ma fai in modo che il tuo motore di gioco lo installi pigramente in XML binario durante il caricamento e salva l'XML binario sul disco in modo che possa caricarlo la prossima volta (se l'XML grezzo non è cambiato) .

Qualcosa come questo:

data loadXml(xmlFile)
{
    if (xmlFile has changed OR binFile doesn't exist)
    {
        binFile = convertToBinary(xmlFile)
        save(binFile)
    }
    return loadBinaryXml(binFile)
}

In questo modo ottieni il meglio da entrambi i mondi. Al rilascio, devi solo assicurarti che tutti i file binari siano presenti.


5

I buffer di protocollo di Google sembrano la strada da percorrere, ma non li ho usati da solo.
http://code.google.com/p/protobuf/

Si definisce un file .proto che descrive il formato del file:

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}

Questo viene quindi compilato con uno strumento da riga di comando che genera classi C / C ++ per scrivere e analizzare file di dati binari nel formato dati precedentemente definito. Ci sono anche un paio di estensioni per diversi linguaggi di programmazione.

L'aspetto negativo di ProtocolBuffer è che non sono in formato testo normale. Avresti bisogno di uno strumento per generarli, leggerli e modificarli. Ma questo non dovrebbe essere un problema se li stai usando solo per scambiare dati tra il tuo editor di giochi e il tuo gioco. Non lo userei per definire i file di configurazione;)

Anche la compressione dei file XML non elaborati dovrebbe funzionare. Che tipo di gioco stai realizzando? Se è basato sul livello, è necessario caricare tutte le risorse necessarie una sola volta quando viene caricato il livello.

aggiornamento: ci sono diversi progetti per altre lingue come C # per lavorare con ProtocolBuffers:
http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns


Un serializzatore non è adattato a quel tipo di problema? Immagino di no ma non vedo una chiara differenza. Ma per me questa risposta sembra appropriata. Ma anche tar / gzip i file xml ridurranno notevolmente le loro dimensioni (dato che si tratta di testo, ma suppongo che funzionerà anche per xml), quindi potrebbe essere la soluzione "più semplice". Comunque XML è un linguaggio semplice, ma è molto costoso in termini di analisi / memoria usando: quando usi XML dovresti leggere / scrivere il minor numero di volte possibile.
jokoon

È un'opzione interessante, ma sembra più un'alternativa completa all'utilizzo di XML ovunque nella pipeline. Ad essere onesti, non sarei molto entusiasta del codice generato, tuttavia, e un'altra complicazione è che sto usando C # per il lato degli strumenti (sono felice che gli strumenti continuino a lavorare con i file .XML di grandi dimensioni ). Un convertitore XML-> PB può essere un'opzione, anche se penso che sto ancora cercando qualcosa che sia più "XML binario per scopi generici", piuttosto che modi per creare specifici "dati a livello binario" (anche se sarebbe un po 'più efficiente)
bluescrn

"Sto usando C # per il lato strumenti" ci sono diversi progetti per c #. aggiornata la mia risposta.
Stephen

@bluescrn, non sarei troppo preoccupato per il codice generato. Google offre supporto di 1a classe a C ++, Java e Python. Lo usano ampiamente internamente; il codice generato è abbastanza robusto. Un grande vantaggio con PB, è il tuo programma di strumenti rispetto a un .protofile, che elimina quasi i problemi di cattiva comunicazione. I protos sono molto più facili da leggere / mantenere rispetto a uno schema xml, se hai anche la disciplina (e il tempo) di usare gli schemi xml.
deft_code

4

Che dire del formato JSON?

http://www.json.org/xml.html


Sembra leggermente più compatto di XML, ma presenta ancora il problema principale dei nomi di attributi duplicati. Se il file contenesse un elenco di oggetti di gioco con gli attributi 'XPosition', 'YPosition' e 'Scale', le stringhe 'XPosition' / 'YPosition' / 'Scale' verrebbero duplicate per ogni singolo oggetto di gioco. Questa è la cosa principale che sto puntando a "comprimere" al momento
bluescrn

1
@bluescrn: No, non ha questo problema. Gli oggetti sono una struttura; potresti anche usare array [che, proprio, sembrano, come, questo]. Ciò significa che puoi finire con qualcosa del genere per memorizzare i nomi e le proprietà delle auto: "cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}puoi persino omettere l'identificatore "auto" e andare direttamente in un array se sai dove sarà il campo delle auto. È anche possibile omettere il "guado" e nomi "Holden", se non è necessario per salvare i dati, lasciando con: [...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]. Diventa più compatto?
doppelgreener,

1
@Axidos: se hai intenzione di rendere il markup illeggibile e non strutturato, potresti anche renderlo binario. A parte questo, è un falso risparmio, a meno che tu non stia analizzando i dati non compressi durante il runtime (nel qual caso, probabilmente sei fregato comunque), o in qualche modo vincolato per alcune centinaia di byte di memoria stringa durante l'analisi (a meno che tu non sia su un forno a microonde, non lo sei).

@Joe: bluescrn sembra essere alla ricerca di un formato leggibile che non abbia nomi duplicati. Stavo illustrando la capacità di JSON di offrire proprio questo. Concordo pienamente sul fatto che ad un certo punto potresti anche chiederti perché ti stai addirittura preoccupando di markup come questo.
doppelgreener,

4

Usa JSON.

(Basandosi sulla risposta di Munificent, e in gran parte in risposta alle tue preoccupazioni espresse altrove)

Hai menzionato la preoccupazione che JSON abbia il problema di sprecare elementi di denominazione dello spazio, come XML. Non

JSON è basato su due strutture: coppie nome / valore ( oggetti ) e liste ordinate di valori ( matrici ). XML è costruito solo su coppie nome / valore.

Se pensi che JSON si basi su oggetti che stai leggendo JSON che è costruito per essere auto-descrittivo e leggibile dall'uomo, in questo modo (usando coppie di cifre ottali per rappresentare singoli byte):

{
    "some": ...,
    "data": ...,
    "fields": ...,
    "cars": [
        {"name":"greg","cost":8C,"speed":FA,"age":04,"driverID":384FFFFF},
        {"name":"ole rustbucket","cost":00,"speed":00,"age":2A,"driverID":04FF54A9}
    ]
}

Tuttavia hai anche la possibilità di scriverlo in questo modo, a patto che tu sappia dove sarà tutto (e quindi puoi cercare l'indice 4, piuttosto che l'oggetto "auto", per ottenere il tuo elenco di auto):

{
    [
        ...,
        ..., 
        ...,
        [["greg",8C,FA,04,384FFFFF],["ole rustbucket",00,00,2A,04FF54A9]],
        ...,
    ]
}

Non potrebbe essere più concisa che avere [, ], ,ei tuoi valori?

Bene, se sei disposto ad avvicinarti sempre di più a un flusso binario puro.

"cars":{"names":["greg","ole rustbucket"],"stream":8CFA04384FFFFF00002A04FF54A9}
or
[["greg","ole rustbucket"],8CFA04384FFFFF00002A04FF54A9]

Basta non spararti alla gamba ottimizzando troppo.


2

So che hai accettato una risposta, ma Google sia "Fast Infoset" (XML binario) che vtd-xml.

Sebbene quest'ultimo (VTD) potrebbe non risolvere l'aspetto di compressione dell'utilizzo di XML, potrebbe accelerare l'accesso ai nodi su file di grandi dimensioni, considerevolmente (utilizza un "dizionario" di offset binari per passare ai nodi e non crea oggetti per ciascun nodo , invece lavora sulla stringa XML originale). Pertanto, la sua ricerca XML è [si dice sia] più veloce e non richiede tanta memoria in-process per accedere / manipolare il documento XML.

Entrambi i precedenti hanno associazioni nelle lingue popolari (che includono C #).

Saluti

Ricco


1

Potresti provare Karvonite . Dovrebbe essere agile. È un framework di persistenza che si adatterà abbastanza bene alle modifiche nei tuoi dati (il che è carino rispetto alla gestione del tuo binario). In realtà non sono sicuro di come siano strutturati i dati, ma i file sono molto più piccoli dei file con estensione xml. (Suppongo che salvi i dati in un formato binario anziché testo come xml)

L'unico svantaggio a cui riesco a pensare è che se i tuoi dati vengono danneggiati o in qualche modo incasinati in un modo che Karvonite non gli piace, il tuo tipo in balia dei suoi creatori a meno che tu non capisca come la struttura del i dati funzionano.

Il modo in cui specifichi come salvare / caricare i tuoi dati è semplicemente aprire il loro editor di persistenza, importare il tuo assieme con tutti gli oggetti dati e selezionare alcune caselle di controllo per mostrare quali oggetti vuoi supportare e quali campi / proprietà salvare.

Potrebbe valere la pena provare. Dal momento che usi C #, questo si adatta perfettamente alla tua lingua poiché funziona con XNA (Windows, Xbox360 e Windows Phone 7 a cui penso tu sia interessato da quando hai menzionato l'iPhone?).

Modifica: ho appena notato che stai usando C # per gli strumenti. Questo probabilmente non si adatterebbe molto bene al tuo flusso di lavoro. Per qualche ragione avevo XNA nella mia testa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.