What is the SaveGame (ZDS) Format?

Archive of the old editing forum
Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. This forum is archived - please use this set of forums to ask new questions.
Locked
User avatar
Bio Hazard
Posts: 4019
Joined: Fri Aug 15, 2003 8:15 pm
Location: ferret ~/C/ZDL $
Contact:

What is the SaveGame (ZDS) Format?

Post by Bio Hazard »

I know it's just a PNG with some extra stuff, but what is this "extra stuff"?

What data is it possible to extract? I'd like to get as much as I can (health, ammo, pwads, etc...)

I want to write a savegame viewer/manager but I'm totally stumped with this format thing.

Also, could someone point me in the direction of info about decoding and displaying PNG's in an application? I've never used 3rd-party libraries with VCC yet.
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49230
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

Most of the data will be rather hard to extract. It uses a standard serializing method that makes it nearly impossible to get all the stuff back out without using ZDoom's original code. You'd practically have to rip out all of ZDoom's savegame code and put it into your program to be able to analyze it.

As for PNG decoding, there's libpng but to get a start I recommend to take a look at ZDoom's m_png.cpp file but it is limited to 8 bit graphics.
User avatar
thefwf
Posts: 146
Joined: Sat Dec 27, 2003 6:50 am
Location: Birmingham, England

Post by thefwf »

Is there any way to use zdoom save games with zdoomgl?
Ajapted
Posts: 71
Joined: Sat Apr 16, 2005 3:50 am
Location: Tasmania

Post by Ajapted »

Graf Zahl wrote:Most of the data will be rather hard to extract. It uses a standard serializing method that makes it nearly impossible to get all the stuff back out without using ZDoom's original code.
Perhaps you could switch to a new method, saving each structure as a sequence of key/values pairs, in a chunked format where each global array has its own chunk (mobjs, sectors, active buttons, etc).

This would make savegames fairly future-proof, as it can handle structure fields being added/removed, even whole arrays. Lot of work though (speaking from experience ;)).
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49230
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

Of course you could. But the current format generally assumes that when a pointer is serialized the object it points to is valid. Removing that from the savegame code would be a big issue.
Ajapted
Posts: 71
Joined: Sat Apr 16, 2005 3:50 am
Location: Tasmania

Post by Ajapted »

You lost me. Pointers would still be serialized like you do now (presumably as integer indexes into the conceptual array, e.g. 0 is NULL, 1 is the first mobj, etc...).
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49230
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

But the current system works differently. If it serializes a pointer to an actor or thinker it doesn't just save an index. If the object being referenced hasn't been saved yet it is serialized recursively, otherwise a reference in the savegame's index list is created. When loaded back the objects are being created when they are read from the savegame. This also implies that an object that serializes a pointer to another object can be certain that the pointer is valid immediately including all other objects it directly and indirectly references.

Large parts of the savegame code had to be altered completely if you wanted to do it by index alone.

For stuff like sectors, lindefs etc only an index is stored because those are static data.
User avatar
randi
Site Admin
Posts: 7749
Joined: Wed Jul 09, 2003 10:30 pm
Contact:

ZDoom savegame specs

Post by randi »

There is some information you can extract from the file without needing to parse the level snapshots. First, there are several tEXt chunks:
  • Software
    ZDoom <Version>
  • ZDoom Save Version
    ZDOOMSAVExxx
  • Title
    <Savegame name>
  • Current Map
    <MAPxx> or <ExMy>
  • Game WAD
    <The IWAD that was loaded when this savegame was made>
  • Map WAD
    <The WAD that this map is from>
  • Creation Time
    <The time this savegame was made>
  • Comment
    <Map name>
    time: <Time spent playing this map or hub>
  • Important CVARs
    <A backslash delimited set of key/value pairs for some cvars and their settings>
Then there are some binary chunks:
  • ptIc
    4 bytes: The tic rate
    4 bytes: The time spent on this level or hub, in tics
  • viSt
    A list of maps that have been visited in this save:
    1 byte: The length of the map's lump name
    <x> bytes: The map's name
    ...Repeat...
    1 byte: Zero terminates the list.
  • pcLs
    A list of the classes each player is playing as:
    1 byte: The player number
    <x> bytes: A token stream that represents the player's class. For the first player, this will always be a byte with the value 1, a byte with the length of the class name, and the class's name. For successive players, it is either a 1 byte as described if the player is a new class. Otherwise it is a zero byte and another byte that indexes a class that was already loaded. (This is the class's index, not the player's index!)
    ...Repeat...
    1 byte: 255 terminates the list.
  • wvAr (optional)
    Non-zero world variables.
  • gvAr (optional)
    Non-zero global variables.
  • waRr (optional)
    Non-zero world arrays.
  • gaRr (optional)
    Non-zero global arrays.
  • raNd
    The state of all random number generators that have been used since the game was started. This is an array of CRC/Seed pairs. They don't have any particular meaning outside of the game.
  • snAp
    Finally, this is the chunk that makes these actual savegames. There is one of these for each level you have visited in the hub (or just one if you aren't in a hub). It is usually compressed, although this can be disabled from the console. Its structure is subject to change with each version and pretty hairy to parse if you don't recreate all of the snapshot code from the game. If you're feeling adventurous, the tokens that can be present in this data stream are described in comments at the top of farchive.cpp, and the serialization process starts at G_SnapshotLevel() in g_level.cpp.
Ajapted
Posts: 71
Joined: Sat Apr 16, 2005 3:50 am
Location: Tasmania

Post by Ajapted »

Graf Zahl wrote:But the current system works differently. If it serializes a pointer to an actor or thinker it doesn't just save an index. If the object being referenced hasn't been saved yet it is serialized recursively, otherwise a reference in the savegame's index list is created.
Well, it's an interesting system, but unnecessarily complex. I think the system I wrote for EDGE could have been simpler, but it does the "future proofing" I described above. If you're interested, a description (partly out-of-date) is here:

http://cvs.sourceforge.net/viewcvs.py/e ... xt?rev=1.2

EDIT: the above idea (using key/value pairs in chunks) seemed promising since it was exactly the same as the new map format (discussed elsewhere). I was thinking it might be possible to create a common savegame spec (used by multiple ports). Pie in the sky?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49230
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

Ajapted wrote:
Graf Zahl wrote:But the current system works differently. If it serializes a pointer to an actor or thinker it doesn't just save an index. If the object being referenced hasn't been saved yet it is serialized recursively, otherwise a reference in the savegame's index list is created.
Well, it's an interesting system, but unnecessarily complex. I think the system I wrote for EDGE could have been simpler, but it does the "future proofing" I described above. If you're interested, a description (partly out-of-date) is here:
I agree. But I can't deny that once set up it is really easy to use because all the dirty stuff is done deep inside the savegame code!
User avatar
Bio Hazard
Posts: 4019
Joined: Fri Aug 15, 2003 8:15 pm
Location: ferret ~/C/ZDL $
Contact:

Re: ZDoom savegame specs

Post by Bio Hazard »

randy wrote:there are several tEXt chunks:
How do I read them? are they zero-teminated? length byte? fixed length?
randy wrote:Then there are some binary chunks:
Hmm, I'll have to play with this a bit...


Does all this stuff happen before or after the image data?
User avatar
Graf Zahl
Lead GZDoom+Raze Developer
Lead GZDoom+Raze Developer
Posts: 49230
Joined: Sat Jul 19, 2003 10:19 am
Location: Germany

Post by Graf Zahl »

It's a PNG. That means that the chunks can be everywhere. Length is always stored in the chunk header and all data is big endian so you have to convert it.
User avatar
Hirogen2
Posts: 2033
Joined: Sat Jul 19, 2003 6:15 am
Operating System Version (Optional): Tumbleweed x64
Graphics Processor: Intel with Vulkan/Metal Support
Location: Central Germany
Contact:

Post by Hirogen2 »

Who had the idea of making it bigendian...
Locked

Return to “Editing (Archive)”