Save game format changes

edited 2006 May 21 in Developers
<i>This post was originally made by <b>danij</b> on the dengDevs blog. It was posted under the categories: Engine, Games, Version 1.9.</i>

Now that map data is managed mostly by the engine we should be begining to think about moving the save game code (at least partially) over to the engine. By doing so we'll be able to save the state of various types of data that previously we've been unable to do.

Given the way the game object data is split between the engine and the game we need to think carefully about how such a system should work.

One potential problem is that there is no easy split in the existing map object data properties for each element between engine and game side properties (eg there is no cutoff between engine side sector_t properties and game side xsector_t properties). So it may be that we'll have to have some game-side code to handle reading old saves.

In preperation for this in jDoom and jHeretic; I have removed the dependencies on compile time issues regarding struct member packing to provide byte offsets and also streamlined the way thinkers are handled. Not to mention numerous other changes.

Due to the amount of changes I would appreciate feedback on any issues with the save game functionality in jDoom and jHeretic.
«1

Comments

  • Update on the saved floormove_t issue:
    It would appear there is nothing wrong with the read/write routines as additional debug code reveals the read data is exactly the same as the written. So something else is going wrong with them. Now where does the spawning happen...

    Edit: Update 2:
    The issue seems to be limited to thinkers spawned via EV_BuildStairs and EV_DoDonut only. The search continues...

    Edit: Update 3:
    Fixed in SVN rev 3158. The problem was due to the speed properties of thinkers being expanded/contracted with FRACBITS during read/write respectively. This resulted in small speeds being reduced to 0 which meant that although the thinkers were being created, T_MovePlane never moved the plane(s).
  • New problem. I've just tried loading a 1.8.6 jDoom save game and currently Doomsday is crashing not far into the load process while reading the sectors.

    After some initial investigation it appears there is something is causing the read process to go out of sync long before it gets to the sectors.

    I added some debug code to dump the texarchive'd names to console and I'm getting a real mess. It seems to me that something is aliasing during the read process either something being read when it shouldn't or vice-versa (due to not being present in an earlier version).

    Here is a small sample of the output of the dumped names:
    <blockquote>0 "5_5"
    1 "5_1"
    2 "1"
    3 "5_2"
    4 "5_4"
    5 "E14"
    6 "K09"
    7 "1_2"
    8 "S1"
    9 "Y1"
    10 "3"
    11 "OP2"
    12 "3"
    13 "R7_1NUKA"
    14 "GE3"
    15 "E15"
    16 "GE2"
    17 "23"
    18 "ORBLU"
    19 "SHITTYBI"
    20 "GDOOR2ME"
    21 "TAL2"
    22 "AY4"
    23 "EP5"
    24 "PPORT2DO"</blockquote>
  • Perhaps related, I recived some emails about heretic crashing while loading with svn 3153. Tested it myself with a new save game made in svn 3153, tried to load it, and deng bombed out with
    SV_LoadGame: Bad savegame (consistency test failed!)

    Will test with 3158 shortly.
  • Actually, thinking ahead now to a 64bit deng, it would be nice to ensure savegames are compatable between big/little endian and 32/64 bit machines.
  • No change on 3158.
  • <blockquote>Perhaps related, I recived some emails about heretic crashing while loading with svn 3153. Tested it myself with a new save game made in svn 3153, tried to load it, and deng bombed out with
    SV_LoadGame: Bad savegame (consistency test failed!)

    Will test with 3158 shortly.</blockquote>
    <blockquote>No change on 3158.</blockquote>
    That will not be fixed.

    I have no desire to make sure save games work between every single SVN revision and to a large extent, even previous beta versions. I only intend compatibility between previous offical full version releases (and 1.9.0-beta3 due to it being so widely used and having been available for so long).

    However if you mean there is a problem loading a jHeretic save made in 3158 with 3158 then obviously it is a bug and I'll look into it.
    <blockquote>Actually, thinking ahead now to a 64bit deng, it would be nice to ensure savegames are compatable between big/little endian and 32/64 bit machines.</blockquote>
    Yes that would be nice. Given the complete lack of endianness handling stuff in Common/p_saveg.c I'm assuming that the LZSS lib takes care of that side of things though I don't know whether the save files are little or big endian.
  • <blockquote>However if you mean there is a problem loading a jHeretic save made in 3158 with 3158 then obviously it is a bug and I'll look into it.</blockquote>
    I'll assume that's what you meant as I've just tested the above case and had the consistency failure report.

    I've found the cause. I'll upload the fix to SVN in a minute.
  • <blockquote>However if you mean there is a problem loading a jHeretic save made in 3158 with 3158 then obviously it is a bug and I'll look into it.</blockquote>Yes, this is exactly what I mean.

    Considering how long beta3 has been out, we should have called it 1.9.0 ;) and say this is 1.9.1
  • In SVN rev 3159:

    FIXED: Consistency report issue in __JHERETIC__
    CHANGED: Removed MAX_ARCHIVED_THINGS fixed limit (speaks for itself).
  • Ok if you fire the bfg (in both doom and doom2), then save the game while its moving through the air. when you load it it will crash when the bfg ball hits.
  • hexen control options are present in doom (e.g. choosing what button you want to bind with fly up / down)

    The page up and page down buttons in the console take it to the top and bottom of the console (so you can see the text that has dissapeard higher than the screen)
  • <blockquote>Ok if you fire the bfg (in both doom and doom2), then save the game while its moving through the air. when you load it it will crash when the bfg ball hits.</blockquote>Could not reproduce this in svn 3159. Probally related to the bug that was fixed in jheretic.
  • OK. It is possible to reporduce KuriKai's bug under the following circumstances. get into a fight with a cyberdemon (level32 on doom2 is good for this). Launch a bfg shot at the cybedemon after it had lanched a few rockets at you. Now save the game before any of the projectiles impact. Load the saved game, and watch deng crash.
  • <blockquote>hexen control options are present in doom (e.g. choosing what button you want to bind with fly up / down)</blockquote>
    Not a bug. jDoom now has flying implemented as a cheat "give f" (as in give me the power of flight) accessible via the console. I don't know why I didn't just use "fly" instead, I'll change this.
    <blockquote>The page up and page down buttons in the console take it to the top and bottom of the console (so you can see the text that has dissapeard higher than the screen)</blockquote>
    Not a bug. I've recently added a bit more functionality to the console and some of the shortcuts had to be changed.

    Here are the currently available controls in the console:
    <ul>
    <li>PgUp/PgDn:
    Scroll history window to the start/end of history buffer respectively.</li>
    <li>PgUp/PgDn + Shift:
    Scroll history window up/down two lines in the buffer respectively.</li>
    <li>Insert:
    Toggle "insert mode" on the cmd line.</li>
    <li>Backspace:
    Delete the character behind the cursor.</li>
    <li>Delete:
    Delete the character under the cursor.</li>
    <li>Home/End:
    Move console window up/down one line respectively.</li>
    <li>Home/End + Shift:
    Move console window up/down three lines respectively.</li>
    <li>Tab:
    Use the default autocomplete mode.</li>
    <li>Tab + Shift:
    Use the console autocomplete mode NOT set as the default completion mode.</li>
    <li>Left/Right Arrow:
    Move the cursor on the input line left/right one character respectively.</li>
    <li>Left/Right Arrow + Shift:
    Move the cursor on the input line to the start/end of the input line respectively.</li>
    <li>Right Arrow (when cursor is at the end of the input line AND there is previous commands in the history buffer AND there are fewer characters on the input line than in that of the command in the current history point):
    Copy one character from the command in the current history position to the end of the input line. Works like a DOS terminal.</li>
    <li>Enter:
    Execute the command(s) on the current input line.</li>
    <li>F5
    Clear the console history buffer.</li>
    <li>Alt + "C":
    Clear the current input line.</li>
    <li>Tilde:
    Open/Close the console.</li>
    <li>Tilde + Shift:
    Switch between half and full screen mode.</li>
    </ul>
  • shouldn't "PgUp/PgDn" scroll the page up a line or too and "Home/End" take it to the start/End? I think that more logical.
  • <blockquote>
    <p>OK. It is possible to reporduce KuriKai's bug under the following circumstances. get into a fight with a cyberdemon (level32 on doom2 is good for this). Launch a bfg shot at the cybedemon after it had lanched a few rockets at you. Now save the game before any of the projectiles impact. Load the saved game, and watch deng crash.</p>
    </blockquote>
    <p>Thanks. I'll investigate this.</p>
    <p>I would imagine that this bug has been around a while though, not just in 1.9.0</p>
  • <blockquote>shouldn't "PgUp/PgDn" scroll the page up a line or too and "Home/End" take it to the start/End? I think that more logical.</blockquote>More logical yes but not as intuitive. Moving to the start/end and moving up/down two lines should be on the same control with a SHIFT function.

    Maybe we should swap all controls for moving the console window with the history window?
  • <blockquote>OK. It is possible to reporduce KuriKai's bug under the following circumstances. get into a fight with a cyberdemon (level32 on doom2 is good for this). Launch a bfg shot at the cybedemon after it had lanched a few rockets at you. Now save the game before any of the projectiles impact. Load the saved game, and watch deng crash.</blockquote>
    It's taken me a while but I can now reproduce this crash reliably. I'll fix the problem.

    Thanks for the bug report KuriKai.

    Update:
    OK, I've found the problem. I didn't update the way the thing_archive was accessed when making it dynamically allocated so each request for a new thing archive number was returning zero. When spawning the BFG ball after loading a save game this resulted in a null mobj->target pointer which leads to the crash when dereferenced in P_AimLineAttack.

    While debugging this I think I've found another error to do with the thing archive ids so I'm trying to fix that one too.

    I should have a fix commited to SVN shortly.
  • In SVN rev 3161:

    FIXED: Bugs introduced during removal of the hardcoded MAX_ARCHIVED_THINGS fixed limit. KuriKai's BFG spray crash.
  • <blockquote>After some initial investigation it appears there is something is causing the read process to go out of sync long before it gets to the sectors.</blockquote>
    Ok, found the problem. Should have a suitable fix implemented soon. It's due to NUMPOWERS being one larger in SVN 315? than it was in earlier releases.

    This highlights an issue with the way various stuff like this is saved. I'll implement an improved mechanism so that new powers, keys etc don't interfere with the save format.

    Update:
    In SVN rev 3162:

    Fixed: Loading of 1.8.6 save games was completely broken due to global counter changes the save game format is dependant upon. Removed these dependencies for players by implementing a playerheader which writes the size of the dependant counters.

    TODO: Its still not possible to load 1.8.6 save games in SVN rev 3162. Currently I'm getting a segfault at somepoint in the read. This will be fixed shortly.
  • In SVN 3163:

    FIXED: All known issues/bugs relating to loading 1.8.6 jDoom and jHeretic save games with Beta4.
  • dani, could you retest this. I needed to make a minor change to fix a FTBFS on linux with svn 3163.
  • Seems OK to me.

    What was the problem btw? Those routines arn't accessed outside of p_saveg.c so I made them static.
  • It was the static definitions. gcc 4.0 wasn't happy with them.

    From the build log
    <blockquote>../../../Src/jDoom/../Common/p_saveg.c:1150: error: static declaration of 'P_ArchivePlayers' follows non-static declaration
    ../../../Include/Common/p_saveg.h:56: error: previous declaration of 'P_ArchivePlayers' was here
    ../../../Src/jDoom/../Common/p_saveg.c:1163: error: static declaration of 'P_UnArchivePlayers' follows non-static declaration
    ../../../Include/Common/p_saveg.h:57: error: previous declaration of 'P_UnArchivePlayers' was here
    ../../../Src/jDoom/../Common/p_saveg.c:1217: error: static declaration of 'P_ArchiveWorld' follows non-static declaration
    ../../../Include/Common/p_saveg.h:58: error: previous declaration of 'P_ArchiveWorld' was here
    ../../../Src/jDoom/../Common/p_saveg.c:1231: error: static declaration of 'P_UnArchiveWorld' follows non-static declaration
    ../../../Include/Common/p_saveg.h:59: error: previous declaration of 'P_UnArchiveWorld' was here
    ../../../Src/jDoom/../Common/p_saveg.c:1847: error: static declaration of 'P_ArchiveThinkers' follows non-static declaration
    ../../../Include/Common/p_saveg.h:60: error: previous declaration of 'P_ArchiveThinkers' was here
    ../../../Src/jDoom/../Common/p_saveg.c:1941: error: static declaration of 'P_UnArchiveThinkers' follows non-static declaration
    ../../../Include/Common/p_saveg.h:61: error: previous declaration of 'P_UnArchiveThinkers' was here
    make[3]: *** [p_saveg.lo] Error 1
    make[2]: *** [all-recursive] Error 1
    make[1]: *** [all-recursive] Error 1
    make: *** [all] Error 2</blockquote>
  • Ah, there were prototypes in the header. I'll fix it since those routines should be static.
  • It should be possible (and preferred) to keep statics in there, but remove the declarations entirely from p_saveg.h. Those functions shouldn't be called from outside of p_saveg.c.
  • Done. In SVN 3167.
  • Hmm, one of my testers has reported an unusual bug (Thanks AndyAWS). Using svn 3187, start up heretic, and load any map. e1m1 is fine. run arround the docks, and take a few potshots the annoying red things. Save your game. Now load that save game. Run arround the docks a bit longer. Observe deng crash spectaculaly to the desktop.

    Doomsday.out is basically full of
    <blockquote>SV_GetArchiveThing: Invalid NUM 0??
    SV_GetArchiveThing: Invalid NUM 0??
    SV_GetArchiveThing: Invalid NUM 0??
    SV_GetArchiveThing: Invalid NUM 0??
    SV_GetArchiveThing: Invalid NUM 0??
    SV_GetArchiveThing: Invalid NUM 0??
    SV_GetArchiveThing: Invalid NUM 0??
    Fatal signal: Segmentation Fault (SDL Parachute Deployed)</blockquote> That was surprisngly easy to repoduce.

    He also has reported slow-downs in heretic, with very noticible frame rate drops in heretic, the longer it is played. It should be noticable in eg e1m4 after about 10 minutes. I'm having a bit of trouble reproducing this as I've been testing on a higher spec system. Can anyone else repoduce this ?
  • I can repoduce that first save bug.
    I could not reproduce that slowdown one.
  • <blockquote>SV_GetArchiveThing: Invalid NUM 0??</blockquote> I get these too in revision 3191.

    Could not get jHeretic to crash, though, or show any significant slowdown. Perhaps those would've occured if I had played longer.
Sign In or Register to comment.