"Бінарний XML" для ігрових даних?


17

Я працюю над інструментом редагування рівня, який зберігає свої дані як XML.

Це ідеально під час розробки, оскільки безболісно вносити невеликі зміни у формат даних, і це прекрасно працює з деревоподібними даними.

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

Оптимальним рішенням для пам’яті та продуктивності було б перетворення XML у формат бінарного рівня. Але я не хочу цього робити. Я хочу зберегти формат досить гнучким. XML дозволяє легко додавати нові атрибути до об'єктів і надавати їм значення за замовчуванням, якщо завантажується стара версія даних. Тому я хочу дотримуватися ієрархії вузлів, з атрибутами як парами іменних значень.

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

Google / Вікіпедія виявляють, що "бінарний XML" навряд чи є новою проблемою - це вже було вирішено вже кілька разів. Хтось тут мав досвід роботи з будь-якою з існуючих систем / стандартів? - чи є ідеал для використання в іграх - доступна безкоштовна, легка та кросплатформна бібліотека парсера / завантажувача (C / C ++)?

Або я повинен сам винаходити це колесо?

Або мені краще забути ідеал, і просто стиснути свої сирі дані .xml (він повинен добре упаковуватися при стисненні на блискавці) і просто брати в пам'ять хіт / продуктивність?


1
XML можна дуже добре стиснути, використовуючи gzip et al .
ThiefMaster

Відповіді:


18

Ми використовували двійкові XML для повернення Superman: The Videogame . Ми говоримо про тисячі та тисячі файлів. Це спрацювало нормально, але, чесно кажучи, не здавалося, варто докладати зусиль. Він з'їв помітну частину нашого часу завантаження, і "гнучкість" 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


Він виглядає дещо компактніше, ніж XML, але все ж має головну проблему дублюваних імен атрибутів. Якщо файл містив перелік ігрових об'єктів з атрибутами 'XPosition', 'YPosition' та 'Scale', рядки 'XPosition' / 'YPosition' / 'Scale' будуть дублюватися для кожного об'єкта гри. Це головне, що я маю на меті "стиснути" на даний момент
bluescrn

1
@bluescrn: Ні, це не проблема. Об’єкти - це одна структура; ви також можете використовувати масиви [що, просто, виглядайте, як, це]. Це означає, що ви можете щось подібне зберегти назви та властивості автомобілів: "cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}Ви навіть можете пропустити ідентифікатор "машини" і просто перейти прямо до масиву, якщо знаєте, де буде поле для автомобілів. Ви можете навіть опустити «брід» і «Холден» імена , якщо вам не потрібно , щоб зберегти ці дані, залишаючи вам: [...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]. Це стає більш компактним?
doppelgreener

1
@Axidos: Якщо ви збираєтеся зробити розмітку такою, що не читається і не структурується, ви можете просто зробити її двійковою. Окрім цього, це помилкова економія, якщо ви не аналізуєте нестиснені дані під час виконання (у цьому випадку ви, ймовірно, все одно накрутили), або якимось чином обмежений на кілька сотень байт рядкової пам'яті під час розбору (якщо ви не перебуваєте на мікрохвильова піч, ти ні).

@Joe: схоже, що bluescrn шукає читабельний формат, який не має дублюваних імен. Я ілюстрував можливість JSON запропонувати саме це. Я повністю погоджуюся, що в певний момент ви можете також просто задатися питанням, чому ви навіть турбуєтесь з такою розміткою.
doppelgreener

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]

Просто не стріляйте собі в ногу, надто оптимізуючи.


2

Я знаю, що ви прийняли відповідь, але Google і "Fast Infoset" (бінарний XML), і vtd-xml.

Хоча останній (VTD) може не вирішити аспект стиснення вашого використання XML, він може значно пришвидшити доступ до вузлів до великих файлів (він використовує «словник» двійкових зсувів для переходу до вузлів і не створює об'єктів для кожного вузла , замість цього працюйте над оригінальним рядком XML). Тому його пошук у XML є [сказано, що] і швидше, і для отримання доступу / маніпулювання документом XML не потрібно стільки оперативної пам'яті.

У обох вищезазначених є прив’язки на популярних мовах (до яких належить C #).

Ура

Багатий


1

Ви можете спробувати Karvonite . Це повинно бути спритним. Це система стійкості, яка досить добре адаптуватиметься до змін ваших даних (що приємно порівняно з обробкою двійкових даних). Я насправді не впевнений у тому, як структуруються дані, але файли набагато менші, ніж розширені файли xml. (Я припускаю, що це зберігає дані у двійковому форматі замість тексту, як xml)

Єдине, про що я можу подумати, це те, що якщо ваші дані будуть пошкоджені або дещо переплутано таким чином, що Карвоніту це не подобається, ваш вид на милість його творців, якщо ви не з'ясуєте, як структура структури дані працюють.

Спосіб, який ви визначаєте, як зберегти / завантажити свої дані, - це просто відкрити їх редактор збереження, імпортувати збірку з усіма об'єктами даних і встановити прапорці, щоб показати, які об’єкти ви хочете підтримувати та які поля / властивості зберігати.

Можливо, варто спробувати. Оскільки ви користуєтесь C #, це повністю відповідає вашій мові, оскільки він працює з XNA (Windows, Xbox360 та Windows Phone 7, що, на мою думку, вас зацікавило, оскільки ви згадали про iPhone?).

Редагувати: Щойно помітив, що ви використовуєте лише C # для інструментів. Це, ймовірно, не дуже добре вписується у ваш робочий процес. Я чомусь мав XNA в голові.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.