„Binarny XML” dla danych gry?


17

Pracuję nad narzędziem do edycji poziomu, które zapisuje dane w formacie XML.

Jest to idealne rozwiązanie podczas programowania, ponieważ wprowadzanie drobnych zmian w formacie danych jest bezbolesne i działa dobrze z danymi drzewiastymi.

Minusem jest jednak to, że pliki XML są raczej rozdęte, głównie z powodu powielania nazw znaczników i atrybutów. Również z powodu danych numerycznych zajmujących znacznie więcej miejsca niż przy użyciu rodzimych typów danych. Mały poziom może łatwo skończyć jako 1Mb +. Chcę znacznie zmniejszyć te rozmiary, zwłaszcza jeśli system ma być używany do gry na iPhonie lub innych urządzeniach o stosunkowo ograniczonej pamięci.

Optymalnym rozwiązaniem dla pamięci i wydajności byłoby przekonwertowanie XML na format binarny. Ale nie chcę tego robić. Chcę, aby format był dość elastyczny. XML bardzo ułatwia dodawanie nowych atrybutów do obiektów i nadawanie im wartości domyślnej, jeśli załadowana jest stara wersja danych. Chcę więc zachować hierarchię węzłów, z atrybutami jako parami nazwa-wartość.

Ale muszę przechowywać to w bardziej zwartym formacie - aby usunąć masowe powielanie nazw znaczników / atrybutów. Może także nadać atrybutom typy rodzime, więc na przykład dane zmiennoprzecinkowe są przechowywane jako 4 bajty na zmiennoprzecinkowe, a nie jako ciąg tekstowy.

Google / Wikipedia ujawniają, że „binarny XML” nie jest nowym problemem - został już rozwiązany wiele razy. Czy ktoś tu ma doświadczenie w zakresie istniejących systemów / standardów? - czy są idealne do użytku w grach - z bezpłatną, lekką i wieloplatformową biblioteką parsera / modułu ładującego (C / C ++)?

Czy powinienem sam odkryć to koło?

A może lepiej zapomnieć o ideale i po prostu kompresować swoje nieprzetworzone dane .xml (powinno się dobrze spakować z kompresją typu zip) i po prostu wziąć obciążenie pamięci / wydajność po załadowaniu?


1
XML można bardzo dobrze skompresować za pomocą gzip i innych .
ThiefMaster

Odpowiedzi:


18

Często używaliśmy binarnego XML-a do Superman Returns: The Videogame . Mówimy o tysiącach plików. Działało OK, ale szczerze mówiąc nie wydawało się warte wysiłku. Zjadł zauważalną część naszego czasu ładowania, a „elastyczność” XML nie wzrosła. Po pewnym czasie nasze pliki danych miały zbyt wiele dziwnych identyfikatorów, referencje zewnętrzne, które musiały być zsynchronizowane, i inne dziwne wymagania, aby mogły być naprawdę edytowane przez człowieka.

Ponadto XML jest tak naprawdę formatem znaczników, a nie formatem danych. Jest zoptymalizowany pod kątem dużej ilości tekstu z okazjonalnymi tagami. Nie nadaje się do danych o pełnej strukturze. To nie był mój telefon, ale gdyby tak było i wiedziałbym wtedy, co wiem teraz, prawdopodobnie zrobiłbym JSON lub YAML. Oba są na tyle zwięzłe, że nie wymagają kompaktowania, i są zoptymalizowane do reprezentowania danych , a nie tekstu .


1
Istnieje binarna wersja JSON o nazwie BSON .
Philipp

12

Przechowuj i edytuj swoje poziomy jako normalne XML, ale silnik gry leniwie upiecz je w binarnym XML podczas ładowania i zapisz binarny XML z powrotem na dysku, aby mógł załadować go następnym razem (jeśli surowy XML nie zmienił się) .

Coś takiego:

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

W ten sposób uzyskasz to, co najlepsze z obu światów. Po wydaniu musisz tylko upewnić się, że wszystkie pliki binarne tam są.


5

Bufory protokołów Google wydają się właściwą drogą, ale sam ich nie używałem.
http://code.google.com/p/protobuf/

Definiujesz plik .proto, który opisuje format pliku:

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

Jest to następnie kompilowane za pomocą narzędzia wiersza poleceń, które generuje klasy C / C ++ do zapisywania i analizowania plików danych binarnych w uprzednio zdefiniowanym formacie danych. Istnieje również kilka rozszerzeń dla różnych języków programowania.

Minusem protokołu ProtocolBuffer jest to, że nie są one formatem zwykłego tekstu. Potrzebujesz narzędzia do ich generowania, czytania i edycji. Nie powinno to jednak stanowić problemu, jeśli używasz ich tylko do wymiany danych między edytorem gier a grą. Nie użyłbym tego do definiowania plików konfiguracyjnych;)

Kompresowanie nieprzetworzonych plików XML powinno również działać. Jakiego rodzaju grę tworzysz? Jeśli jest oparty na poziomie, wszystkie niezbędne zasoby należy załadować tylko raz, gdy poziom jest załadowany.

aktualizacja: Istnieje kilka projektów dla innych języków, takich jak C # do współpracy z ProtocolBuffers:
http://code.google.com/p/protobuf/wiki/ThirdPartyAddOns


Czy serializator nie jest przystosowany do tego rodzaju problemów? Chyba nie, ale nie widzę wyraźnej różnicy. Ale dla mnie ta odpowiedź wydaje się właściwa. Ale również pliki tar / gzip znacznie zmniejszą ich rozmiar (ponieważ jest to tekst, ale myślę, że będzie działać również dla xml), więc może to być „łatwiejsze” rozwiązanie. W każdym razie XML jest łatwym językiem, ale jest bardzo drogi pod względem parsowania / używania pamięci: kiedy używasz XML, powinieneś czytać / pisać tak mało, jak to możliwe.
Jokoon

Jest to interesująca opcja, ale wygląda bardziej na kompletną alternatywę dla używania XML w dowolnym miejscu potoku. Szczerze mówiąc, nie byłbym zbyt entuzjastycznie nastawiony do generowanego kodu - a kolejną komplikacją jest to, że używam C # po stronie narzędzi (cieszę się, że narzędzia mogą nadal pracować z dużymi plikami .XML ). Konwerter XML-> PB może być opcją, chociaż myślę, że wciąż szukam czegoś, co będzie bardziej „binarnym XMLem ogólnego przeznaczenia”, a nie sposobami upieczenia określonych „danych binarnych” (nawet jeśli byłoby to trochę więcej wydajne)
bluescrn

„Używam C # po stronie narzędzi rzeczy” jest kilka projektów dla c #. zaktualizowałem moją odpowiedź.
Stephen

@bluescrn, nie martwiłbym się zbytnio wygenerowanym kodem. Google zapewnia obsługę pierwszej klasy języków C ++, Java i Python. Używają go intensywnie wewnętrznie; wygenerowany kod jest dość solidny. Dużą zaletą PB jest program narzędziowy przeciwko .protoplikowi, który prawie eliminuje problemy z błędną komunikacją. Prototypy są znacznie łatwiejsze do odczytania / utrzymania niż schemat xml, jeśli masz dyscyplinę (i czas), aby używać schematów xml.
deft_code

4

Co z formatem JSON?

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


Wygląda nieco bardziej kompaktowo niż XML, ale nadal ma główny problem ze zduplikowanymi nazwami atrybutów. Jeśli plik zawiera listę obiektów gry z atrybutami „XPosition”, „YPosition” i „Skala”, ciągi znaków „XPosition” / „YPosition” / „Skala” byłyby duplikowane dla każdego obiektu gry. Jest to główna rzecz, którą obecnie zamierzam „skompresować”
bluescrn

1
@bluescrn: Nie, nie ma tego problemu. Obiekty są jedną strukturą; możesz także użyć tablic [które, po prostu, wyglądają tak]. Oznacza to, że możesz skończyć z czymś takim do przechowywania nazw i właściwości samochodów: "cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}możesz nawet pominąć identyfikator „samochodów” i po prostu przejść bezpośrednio do tablicy, jeśli wiesz, gdzie będzie pole samochodów. Można nawet pominąć „Ford” i „gospodarstwo” nazwy, jeśli nie ma potrzeby zapisywania tych danych, dzięki czemu można z: [...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]. Czy robi się bardziej kompaktowy?
doppelgreener

1
@Axidos: Jeśli chcesz, aby znaczniki były nieczytelne i nieustrukturyzowane, równie dobrze możesz po prostu uczynić je binarnymi. Poza tym są to fałszywe oszczędności, chyba że parsujesz nieskompresowane dane w czasie wykonywania (w takim przypadku prawdopodobnie i tak masz problem z wkręceniem), albo w jakiś sposób jesteś ograniczony przez kilkaset bajtów pamięci łańcuchowej podczas parsowania (chyba że jesteś włączony kuchenka mikrofalowa, nie jesteś).

@Joe: bluescrn szuka czytelnego formatu, który nie ma zduplikowanych nazw. Ilustrowałem zdolność JSON do zaoferowania właśnie tego. Zgadzam się jednak całkowicie, że w pewnym momencie możesz równie dobrze zastanawiać się, dlaczego tak niepokoisz się znacznikami.
doppelgreener

4

Użyj JSON.

(Opierając się na odpowiedzi Munificent i głównie w odpowiedzi na twoje obawy wyrażone gdzie indziej)

Wspomniałeś o obawie, że JSON ma problem z marnowaniem elementów nazewnictwa przestrzeni, takich jak XML. Tak nie jest.

JSON jest zbudowany na dwóch strukturach: parach nazwa / wartość ( obiekty ) i uporządkowanych listach wartości ( tablice ). XML jest zbudowany tylko na parach nazwa / wartość.

Jeśli uważasz, że JSON opiera się na obiektach, które czytasz JSON, które są zbudowane tak, aby były samoopisujące i czytelne dla człowieka, jak to poniżej (używając liczb ósemkowych do reprezentowania pojedynczych bajtów):

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

Masz jednak możliwość napisania tego w ten sposób, o ile wiesz, gdzie wszystko będzie (i możesz poszukać indeksu 4, a nie obiektu „samochody”, aby uzyskać listę samochodów):

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

Robi się bardziej zwięzły niż tylko o [, ], ,i swoich wartości?

Dzieje się tak, jeśli chcesz zbliżyć się do czystego strumienia binarnego.

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

Po prostu nie strzelaj sobie w nogę, optymalizując zbyt wiele.


2

Wiem, że zaakceptowałeś odpowiedź, ale Google zarówno „Fast Infoset” (binarny XML), jak i vtd-xml.

Chociaż ten ostatni (VTD) może nie rozwiązać aspektu kompresji użycia XML, może znacznie przyspieszyć dostęp do węzłów w dużych plikach (znacznie używa „słownika” przesunięć binarnych do przeskakiwania do węzłów i nie tworzy obiektów dla każdego węzła , zamiast tego działa na oryginalny ciąg XML). Dlatego jego wyszukiwanie XML jest [podobno] zarówno szybsze, jak i nie wymaga tak dużo pamięci w trakcie przetwarzania, aby uzyskać dostęp do dokumentu XML lub nim manipulować.

Oba powyższe mają powiązania w popularnych językach (w tym C #).

Twoje zdrowie

Bogaty


1

Możesz spróbować Karvonite . To ma być zwinne. Jest to struktura utrwalania, która dość dobrze dostosuje się do zmian w twoich danych (co jest miłe w porównaniu do obsługi binarnej twojej jaźni). Właściwie nie jestem pewien, w jaki sposób dane są ustrukturyzowane, ale pliki są znacznie mniejsze niż rozdęte pliki XML. (Zakładam, że zapisuje dane w formacie binarnym zamiast tekstu takiego jak xml)

Jedynym mankamentem, jaki mogę tutaj wymyślić, jest to, że jeśli twoje dane zostaną uszkodzone lub w jakiś sposób popsuty w taki sposób, że Karvonite go nie lubi, jesteś na łasce jego twórców, chyba że zorientujesz się, jak struktura dane działają.

Sposób, w jaki określasz sposób zapisywania / ładowania danych, polega na otwarciu ich edytora trwałości, zaimportowaniu zestawu ze wszystkimi obiektami danych i zaznaczeniu niektórych pól wyboru, aby pokazać, które obiekty mają być obsługiwane i jakie pola / właściwości zapisać.

Może warto spróbować. Odkąd używasz C #, to pasuje do twojego języka, ponieważ działa z XNA (Windows, Xbox360 i Windows Phone 7, który moim zdaniem jest zainteresowany odkąd wspomniałeś o iPhonie?).

Edycja: Właśnie zauważyłem, że używasz tylko C # dla narzędzi. Prawdopodobnie nie pasowałoby to zbyt dobrze do Twojego przepływu pracy. Z jakiegoś powodu miałem XNA w głowie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.