'XML binario' para los datos del juego?

17

Estoy trabajando en una herramienta de edición de nivel que guarda sus datos como XML.

Esto es ideal durante el desarrollo, ya que es sencillo realizar pequeños cambios en el formato de datos y funciona muy bien con datos en forma de árbol.

Sin embargo, la desventaja es que los archivos XML están bastante hinchados, principalmente debido a la duplicación de nombres de etiquetas y atributos. También debido a que los datos numéricos ocupan mucho más espacio que el uso de tipos de datos nativos. Un nivel pequeño podría terminar fácilmente como 1Mb +. Quiero reducir significativamente estos tamaños, especialmente si el sistema se va a usar para un juego en el iPhone u otros dispositivos con memoria relativamente limitada.

La solución óptima, para memoria y rendimiento, sería convertir el XML a un formato de nivel binario. Pero no quiero hacer esto. Quiero mantener el formato bastante flexible. XML hace que sea muy fácil agregar nuevos atributos a los objetos y darles un valor predeterminado si se carga una versión anterior de los datos. Entonces quiero mantener la jerarquía de nodos, con atributos como pares de nombre-valor.

Pero necesito almacenar esto en un formato más compacto, para eliminar la duplicación masiva de nombres de etiquetas / atributos. Quizás también para dar atributos a los tipos nativos, por ejemplo, los datos de punto flotante se almacenan como 4 bytes por flotante, no como una cadena de texto.

Google / Wikipedia revelan que 'XML binario' no es un problema nuevo, ya se ha resuelto varias veces. ¿Alguien aquí tiene experiencia con alguno de los sistemas / estándares existentes? ¿Son ideales para el uso de juegos? ¿Con una biblioteca de analizador / cargador (C / C ++) gratuita, liviana y multiplataforma disponible?

¿O debería reinventar esta rueda yo mismo?

¿O es mejor olvidar el ideal y simplemente comprimir mis datos .xml sin procesar (debería empaquetarse bien con una compresión similar a la de un archivo zip), y simplemente tomar la carga de memoria / rendimiento bajo carga?

bluescrn
fuente
1
XML se puede comprimir usando gzip et al muy bien.
ThiefMaster

Respuestas:

18

Utilizamos mucho XML binario para Superman Returns: The Videogame . Estamos hablando de miles y miles de archivos. Funcionó bien, pero sinceramente no parecía que valiera la pena el esfuerzo. Consumió una fracción notable de nuestro tiempo de carga, y la "flexibilidad" de XML no aumentó. Después de un tiempo, nuestros archivos de datos tenían demasiados identificadores extraños, referencias externas que debían mantenerse sincronizadas y otros requisitos extraños para que realmente pudieran ser editados por humanos.

Además, XML es realmente un formato de marcado, y no un formato de datos. Está optimizado para una gran cantidad de texto con etiquetas ocasionales. No es genial para datos completamente estructurados. No era mi decisión, pero si lo hubiera sido y supiera lo que sé ahora, probablemente habría hecho JSON o YAML. Ambos son lo suficientemente concisos como para no requerir compactación y están optimizados para representar datos , no texto .

munificente
fuente
1
Hay una versión binaria de JSON llamada BSON .
Philipp
12

Almacene y edite sus niveles como XML normal, pero haga que su motor de juego lo convierta perezosamente en XML binario durante la carga, y guarde el XML binario nuevamente en el disco para que pueda cargarlo la próxima vez (si el XML sin procesar no ha cambiado) .

Algo como esto:

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

De esa manera, obtienes lo mejor de ambos mundos. En el lanzamiento, solo necesita asegurarse de que todos los archivos binarios estén allí.

Peter Alexander
fuente
5

Los Buffers de protocolo de Google parecen ser el camino a seguir, pero yo no los he usado.
http://code.google.com/p/protobuf/

Define un archivo .proto que describe el formato del archivo:

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

Luego se compila con una herramienta de línea de comandos que genera clases C / C ++ para escribir y analizar archivos de datos binarios en el formato de datos previamente definido. También hay un par de extensiones para diferentes lenguajes de programación.

La desventaja de ProtocolBuffer es que no son un formato de texto sin formato. Necesitaría una herramienta para generarlos, leerlos y editarlos. Pero esto no debería ser un problema si los usa solo para intercambiar datos entre su editor de juegos y su juego. No lo usaría para definir archivos de configuración;)

La compresión de los archivos xml sin procesar también debería funcionar. ¿Qué tipo de juego estás haciendo? Si está basado en niveles, debe cargar todos los recursos necesarios solo una vez cuando se carga el nivel.

actualización: Hay varios proyectos para que otros lenguajes, como C #, funcionen con ProtocolBuffers:
http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns

Stephen
fuente
¿No está un serializador adaptado a ese tipo de problema? Supongo que no, pero no veo una diferencia clara. Pero para mí esta respuesta me parece apropiada. Pero también tar / gzip los archivos xml reducirán en gran medida su tamaño (ya que es texto, pero supongo que también funcionará para xml), por lo que podría ser la solución "más fácil". De todos modos, XML es un lenguaje fácil, pero es muy costoso en términos de análisis / uso de memoria: cuando usa XML, debe leer / escribir lo menos posible.
jokoon
Es una opción interesante, pero se parece más a una alternativa completa al uso de XML en cualquier parte de la tubería. Para ser honesto, no estaría muy entusiasmado con el código generado, y otra complicación es que estoy usando C # para el lado de las herramientas (estoy feliz de que las herramientas continúen trabajando con los grandes archivos .XML ) Un convertidor XML-> PB puede ser una opción, aunque creo que todavía estoy buscando algo que sea más 'XML binario de propósito general', en lugar de formas de hornear 'datos de nivel binario' específicos (incluso si eso fuera un poco más eficiente)
bluescrn
"Estoy usando C # para el lado de las herramientas" hay varios proyectos para C #. Actualicé mi respuesta.
Stephen
@bluescrn, no estaría demasiado preocupado por el código generado. Google ofrece soporte de primera clase para C ++, Java y Python. Lo usan ampliamente internamente; El código generado es bastante robusto. Una gran ventaja con PB es su programa de herramientas contra un .protoarchivo, que casi elimina los problemas de falta de comunicación. Los prototipos son mucho más fáciles de leer / mantener que un esquema xml, incluso si tiene la disciplina (y el tiempo) para usar esquemas xml.
deft_code
4

¿Qué pasa con el formato JSON?

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

Sven
fuente
Parece un poco más compacto que XML, pero aún tiene el problema principal de los nombres de atributos duplicados. Si el archivo contiene una lista de objetos del juego con los atributos 'XPosition', 'YPosition' y 'Scale', las cadenas 'XPosition' / 'YPosition' / 'Scale' se duplicarán para cada objeto del juego. Esto es lo principal que estoy tratando de 'comprimir' en este momento
bluescrn
1
@bluescrn: No, no tiene ese problema. Los objetos son una estructura; también podría usar matrices [que, simplemente, se parecen a esto]. Eso significa que puede terminar con algo como esto para almacenar los nombres y propiedades de los automóviles: "cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}incluso puede omitir el identificador de "automóviles" y simplemente ir directamente a una matriz si sabe dónde estará el campo de automóviles. Incluso se puede omitir el "Ford" y nombres "Holden" si no es necesario guardar los datos, dejándole con: [...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]. ¿Se vuelve más compacto?
doppelgreener
1
@Axidos: Si va a hacer que el marcado sea ilegible y desestructurado, también podría hacerlo binario. Aparte de eso, es un ahorro falso, a menos que esté analizando datos sin comprimir durante el tiempo de ejecución (en cuyo caso, probablemente esté atornillado de todos modos), o de alguna manera limitado por unos cientos de bytes de memoria de cadena durante el análisis (a menos que esté en un microondas, no lo eres).
@ Joe: bluescrn parece estar buscando un formato legible que no tenga nombres duplicados. Estaba ilustrando la capacidad de JSON para ofrecer precisamente eso. Sin embargo, estoy totalmente de acuerdo en que, en cierto punto, es muy posible que te preguntes por qué te molestas con un marcado como este.
doppelgreener
4

Usa JSON.

(Basándose en la respuesta de Munificent, y en gran medida en respuesta a sus preocupaciones expresadas en otro lugar)

Has mencionado la preocupación de que JSON tiene el problema de desperdiciar elementos de nombres de espacio, como XML. No lo hace.

JSON se basa en dos estructuras: pares de nombre / valor ( objetos ) y listas ordenadas de valores ( matrices ). XML solo se construye en pares de nombre / valor.

Si cree que JSON se basa en objetos que ha estado leyendo, JSON está diseñado para ser autodescriptivo y legible para humanos, de esta manera (usando pares de dígitos octales para representar bytes individuales):

{
    "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}
    ]
}

Sin embargo, también tiene la opción de escribirlo así, siempre que sepa dónde estará todo (y así puede buscar el índice 4, en lugar de objetar "autos", para obtener su lista de autos):

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

¿Puede haber algo más conciso que sólo tener [, ], ,y sus valores?

Bueno, lo hace si estás dispuesto a acercarte cada vez más a una secuencia binaria pura.

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

Simplemente no te dispares en la pierna optimizando demasiado.

doppelgreener
fuente
2

Sé que ha aceptado una respuesta, pero Google tanto "Fast Infoset" (XML binario) como vtd-xml.

Aunque este último (VTD) podría no resolver el aspecto de compresión del uso de XML, puede acelerar el acceso a los nodos a través de archivos grandes, considerablemente (utiliza un 'diccionario' de compensaciones binarias para saltar a los nodos y no crea objetos para cada nodo , en su lugar, trabaje en la cadena XML original). Por lo tanto, su búsqueda XML se dice que es más rápida y no requiere tanta memoria en proceso para acceder / manipular el documento XML.

Ambos de los anteriores tienen enlaces en los lenguajes populares (que incluyen C #).

Salud

Rico

Grande rico
fuente
1

Podrías probar Karvonite . Se supone que es ágil. Es un marco de persistencia que se adaptará bastante bien a los cambios en sus datos (lo cual es bueno en comparación con el manejo de binarios). No estoy realmente seguro de cómo se estructuran los datos, pero los archivos son mucho más pequeños que los archivos xml hinchados. (Supongo que guarda los datos en formato binario en lugar de texto como xml)

La única desventaja que se me ocurre con esto es que si sus datos se corrompen o están tan desordenados de una manera que a Karvonite no le gusta, está a merced de sus creadores a menos que descubra cómo la estructura del los datos funcionan

La forma en que especifica cómo guardar / cargar sus datos es simplemente abrir su editor de persistencia, importar su ensamblaje con todos los objetos de datos y marcar algunas casillas de verificación para mostrar qué objetos desea admitir y qué campos / propiedades guardar.

Puede valer la pena intentarlo. Dado que usa C #, esto encaja perfectamente con su idioma, ya que funciona con XNA (Windows, Xbox360 y Windows Phone 7, que creo que le interesa desde que mencionó el iPhone).

Editar: Acabo de notar que solo usa C # para las herramientas. Esto probablemente no encajaría muy bien en su flujo de trabajo. Por alguna razón, tenía XNA en mi cabeza.

Michael Coleman
fuente