«Двоичный XML» для игровых данных?

17

Я работаю над инструментом редактирования уровней, который сохраняет свои данные в формате XML.

Это идеально во время разработки, поскольку безболезненно вносить небольшие изменения в формат данных, и оно прекрасно работает с древовидными данными.

Недостатком, однако, является то, что файлы XML довольно раздуты, в основном из-за дублирования имен тегов и атрибутов. Также из-за того, что числовые данные занимают значительно больше места, чем при использовании собственных типов данных. Небольшой уровень может легко закончиться как 1Mb +. Я хочу значительно уменьшить эти размеры, особенно если система будет использоваться для игр на iPhone или других устройствах с относительно ограниченной памятью.

Оптимальным решением для памяти и производительности было бы преобразование XML в двоичный формат. Но я не хочу этого делать. Я хочу сохранить формат достаточно гибким. XML позволяет очень легко добавлять новые атрибуты к объектам и присваивать им значение по умолчанию, если загружена старая версия данных. Поэтому я хочу придерживаться иерархии узлов с атрибутами в качестве пар имя-значение.

Но мне нужно хранить это в более компактном формате - чтобы убрать массовое дублирование имен тегов / атрибутов. Может также дать атрибуты нативные типы, так что, например, данные с плавающей точкой хранятся в виде 4 байтов на число с плавающей запятой, а не в виде текстовой строки.

Google / Wikipedia показывают, что «двоичный XML» вряд ли является новой проблемой - он уже решался несколько раз. Кто-нибудь здесь получил опыт работы с какой-либо из существующих систем / стандартов? - Есть ли какой-нибудь идеал для использования в играх - с бесплатной, легкой и кроссплатформенной библиотекой парсера / загрузчика (C / C ++)?

Или мне самому изобретать это колесо?

Или мне лучше забыть об идеале и просто сжать мои сырые .xml данные (они должны хорошо упаковываться с zip-подобным сжатием), и просто взять нагрузку памяти / производительности на нагрузку?

bluescrn
источник
1
XML можно очень хорошо сжать, используя gzip et al .
ThiefMaster

Ответы:

18

Мы использовали бинарный XML для Возвращений Супермена: Видеоигра . Мы говорим тысячи и тысячи файлов. Это работало хорошо, но, честно говоря, не стоило усилий. Это израсходовало заметную часть нашего времени загрузки, и «гибкость» XML не увеличилась. Через некоторое время в наших файлах данных появилось слишком много странных идентификаторов, внешних ссылок, которые необходимо было синхронизировать, и других странных требований, чтобы их можно было реально редактировать.

Кроме того, XML - это действительно формат разметки, а не формат данных. Он оптимизирован для большого количества текста со случайными тегами. Это не очень хорошо для полностью структурированных данных. Это был не мой звонок, но если бы это было так, и я знал тогда то, что знаю сейчас, я бы, наверное, сделал JSON или YAML. Они оба достаточно кратки, чтобы не требовать сжатия, и оптимизированы для представления данных , а не текста .

необычайно щедрый
источник
1
Существует двоичная версия JSON, которая называется BSON .
Филипп
12

Сохраняйте и редактируйте свои уровни как обычный XML, но ваш игровой движок лениво запекает его в двоичный XML во время загрузки и сохраняет двоичный XML обратно на диск, чтобы он мог загрузить его в следующий раз (если необработанный XML не изменился) ,

Что-то вроде этого:

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

Таким образом, вы получаете лучшее из обоих миров. При выпуске вам просто нужно убедиться, что все бинарные файлы есть.

Петр Александр
источник
5

Буферы протокола Google кажутся подходящими, но я сам ими не пользовался.
http://code.google.com/p/protobuf/

Вы определяете файл .proto, который описывает формат файла:

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

Затем он компилируется с помощью инструмента командной строки, который генерирует классы C / C ++ для записи и анализа двоичных файлов данных в ранее определенном формате данных. Есть также несколько расширений для разных языков программирования.

Недостатком ProtocolBuffer является то, что они не являются открытым текстом. Вам понадобится инструмент для их генерации, чтения и редактирования. Но это не должно быть проблемой, если вы используете их только для обмена данными между вашим игровым редактором и вашей игрой. Я бы не использовал его для определения конфигурационных файлов;)

Сжатие сырых XML-файлов также должно работать. Какой тип игры вы делаете? Если это основано на уровне, тогда вы должны загрузить все необходимые ресурсы только один раз, когда уровень загружен.

обновление: есть несколько проектов для других языков, таких как C #, для работы с ProtocolBuffers:
http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns

Стивен
источник
Разве сериализатор не приспособлен к такой проблеме? Наверное, нет, но я не вижу четкой разницы. Но мне этот ответ кажется уместным. Но также tar / gzip xml-файлы значительно уменьшат их размер (так как это текст, но я думаю, что это также будет работать для xml), так что это может быть «более простым» решением. В любом случае XML - простой язык, но он очень дорогой с точки зрения анализа / использования памяти: когда вы используете XML, вы должны читать / писать как можно меньше раз.
Jokoon
Это интересный вариант, но он больше похож на полную альтернативу использованию XML в любом месте конвейера. Честно говоря, я не буду с энтузиазмом относиться к сгенерированному коду - и еще одна сложность заключается в том, что я использую C # для инструментальной стороны (я рад, что инструменты продолжают работать с большими файлами .XML ). Конвертер XML-> PB может быть вариантом, хотя я думаю, что я все еще ищу что-то, что является более «бинарным XML общего назначения», а не способами запекания конкретных «данных двоичного уровня» (даже если это будет немного больше эффективный)
Bluescrn
«Я использую C # для инструментов», есть несколько проектов для C #. обновил мой ответ.
Стивен
@bluescrn, я не слишком беспокоюсь о сгенерированном коде. Google предоставляет поддержку первого класса C ++, Java и Python. Они широко используют его внутри себя; сгенерированный код довольно устойчив. Одно из больших преимуществ PB - это ваша программа для работы с .protoфайлами, которая почти исключает проблемы недопонимания. Прото намного проще для чтения / обслуживания, чем XML-схемы, если у вас даже есть дисциплина (и время) для использования XML-схем.
deft_code
4

А как насчет JSON-формата?

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

Sven
источник
Он выглядит немного более компактным, чем XML, но по-прежнему имеет основную проблему с дублированными именами атрибутов. Если файл содержит список игровых объектов с атрибутами «XPosition», «YPosition» и «Scale», строки «XPosition» / «YPosition» / «Scale» будут продублированы для каждого игрового объекта. Это главное, что я сейчас хочу «сжать»
bluescrn
1
@bluescrn: Нет, это не проблема. Объекты - это одна структура; Вы также можете использовать массивы [которые, просто, смотрите, вот так]. Это означает, что вы можете получить что-то подобное для хранения имен и свойств автомобилей: "cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}вы даже можете опустить идентификатор «cars» и просто перейти прямо в массив, если вы знаете, где будет находиться поле cars. Вы можете даже опустить «брод» и «Холден» имена , если вам не нужно , чтобы сохранить эти данные, оставляя вам: [...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]. Это становится более компактным?
doppelgreener
1
@Axidos: Если вы собираетесь сделать разметку нечитаемой и неструктурированной, вы можете просто сделать ее двоичной. Кроме того, это ложная экономия, если вы не анализируете несжатые данные во время выполнения (в этом случае вы, вероятно, все равно испорчены) или каким-то образом ограничены несколькими сотнями байтов памяти строк во время синтаксического анализа (если вы не используете микроволновка, а ты нет).
@Joe: bluescrn, кажется, ищет читаемый формат, который не имеет дублированных имен. Я иллюстрировал способность JSON предложить именно это. Я полностью согласен с тем, что в определенный момент вы можете просто задаться вопросом, почему вы вообще беспокоитесь о разметке, подобной этой.
двойник
4

Используйте JSON.

(Основываясь на ответе Манипулина, и в значительной степени в ответ на ваши опасения, высказанные в другом месте)

Вы упомянули обеспокоенность тем, что в JSON существует проблема потери пространства имен элементов, таких как XML. Это не так.

JSON построен на двух структурах: пары имя / значение ( объекты ) и упорядоченные списки значений ( массивы ). XML построен только на парах имя / значение.

Если вы думаете, что JSON опирается на объекты, которые вы читали, JSON создан для самоописания и восприятия человеком, например, так (используя пары восьмеричных цифр для представления отдельных байтов):

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

Однако у вас также есть возможность написать это так, если вы знаете, где все будет (и поэтому можете искать индекс 4, а не объект «автомобили», чтобы получить свой список автомобилей):

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

Имеет ли получить более кратким , чем просто [, ], ,и ваши ценности?

Что ж, это так, если вы просто хотите приблизиться к чисто двоичному потоку.

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

Только не стреляйте себе в ногу, оптимизируя слишком много.

doppelgreener
источник
2

Я знаю, что вы приняли ответ, но Google и "Fast Infoset" (двоичный XML) и vtd-xml.

Хотя последний (VTD) может не разрешить аспект сжатия использования вами XML, он может значительно ускорить доступ к узлам для больших файлов (он использует двоичный словарь смещений для перехода к узлам и не создает объекты для каждого узла). вместо работы с исходной XML-строкой). Следовательно, поиск в XML, как говорят, быстрее и не требует большого количества оперативной памяти для доступа к документу XML и манипулирования им.

Оба вышеперечисленных имеют привязки в популярных языках (включая C #).

ура

Богатый

Большой Богатый
источник
1

Вы можете попробовать Карвоните . Это должно быть проворным. Это постоянная среда, которая достаточно хорошо адаптируется к изменениям в ваших данных (что приятно по сравнению с обработкой двоичных данных самостоятельно). Я не совсем уверен, как структурированы данные, но файлы намного меньше, чем раздутые файлы XML. (Я предполагаю, что он сохраняет данные в двоичном формате вместо текста, такого как XML)

Единственный минус, о котором я могу подумать, это то, что если ваши данные испорчены или каким-то образом испорчены таким образом, что Karvonite это не нравится, то ваш вид зависит от его создателей, если вы не выясните, как устроена структура данные работают.

Чтобы указать, как сохранять / загружать данные, вы просто открываете их редактор постоянства, импортируете свою сборку со всеми объектами данных и устанавливаете флажки, чтобы показать, какие объекты вы хотите поддерживать и какие поля / свойства сохранить.

Возможно, стоит попробовать. Поскольку вы используете C #, это соответствует вашему языку, поскольку он работает с XNA (Windows, Xbox360 и Windows Phone 7, которые, я думаю, вас интересуют, поскольку вы упомянули iPhone?).

Редактировать: только что заметил, что вы используете только C # для инструментов. Это, вероятно, не очень хорошо вписывается в ваш рабочий процесс. По какой-то причине у меня была XNA в голове.

Майкл Коулман
источник