Skip to content

Commit

Permalink
libcommon|Refactor: Use Reader/Writer for save game header (de)serial…
Browse files Browse the repository at this point in the history
…ization

Bumped MY_SAVE_VERSION for all games other than Hexen to v10 as the
serialized format has changed (support a variable length save name
and no junk values from the old serialized saveheader_t structure).
  • Loading branch information
danij-deng committed Jun 21, 2012
1 parent 5d97dca commit afbf605
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 66 deletions.
23 changes: 3 additions & 20 deletions doomsday/plugins/common/include/p_savedef.h
Expand Up @@ -28,7 +28,7 @@
#if __JDOOM__
# define MY_SAVE_MAGIC 0x1DEAD666
# define MY_CLIENT_SAVE_MAGIC 0x2DEAD666
# define MY_SAVE_VERSION 9
# define MY_SAVE_VERSION 10
# define SAVESTRINGSIZE 24
# define CONSISTENCY 0x2c
# define SAVEGAMENAME "DoomSav"
Expand All @@ -41,7 +41,7 @@
#elif __JDOOM64__
# define MY_SAVE_MAGIC 0x1D6420F4
# define MY_CLIENT_SAVE_MAGIC 0x2D6420F4
# define MY_SAVE_VERSION 8
# define MY_SAVE_VERSION 10
# define SAVESTRINGSIZE 24
# define CONSISTENCY 0x2c
# define SAVEGAMENAME "D64Sav"
Expand All @@ -54,7 +54,7 @@
#elif __JHERETIC__
# define MY_SAVE_MAGIC 0x7D9A12C5
# define MY_CLIENT_SAVE_MAGIC 0x1062AF43
# define MY_SAVE_VERSION 8
# define MY_SAVE_VERSION 10
# define SAVESTRINGSIZE 24
# define CONSISTENCY 0x9d
# define SAVEGAMENAME "HticSav"
Expand Down Expand Up @@ -94,24 +94,7 @@ typedef struct targetplraddress_s {
#endif

#if !__JHEXEN__
typedef struct saveheader_s {
int magic;
int version;
int gameMode;
char name[SAVESTRINGSIZE];
byte skill;
byte episode;
byte map;
byte deathmatch;
byte noMonsters;
byte respawnMonsters;
int mapTime;
byte players[MAXPLAYERS];
unsigned int gameId;
} saveheader_t;

#define PRE_VER5_END_SPECIALS 7

#endif

#endif
28 changes: 28 additions & 0 deletions doomsday/plugins/common/include/p_saveio.h
Expand Up @@ -29,6 +29,24 @@
#include "lzss.h"
#include "p_savedef.h"

#if !__JHEXEN__
typedef struct saveheader_s {
int magic;
int version;
int gameMode;
char name[SAVESTRINGSIZE];
byte skill;
byte episode;
byte map;
byte deathmatch;
byte noMonsters;
byte respawnMonsters;
int mapTime;
byte players[MAXPLAYERS];
unsigned int gameId;
} saveheader_t;
#endif

typedef struct gamesaveinfo_s {
ddstring_t filePath;
ddstring_t name;
Expand Down Expand Up @@ -142,6 +160,11 @@ void SV_CopySaveSlot(int sourceSlot, int destSlot);
saveptr_t* SV_HxSavePtr(void);
#endif // __JHEXEN__

/**
* Seek forward @a offset bytes in the save file.
*/
void SV_Seek(uint offset);

/*
* Writing and reading values
*/
Expand All @@ -165,6 +188,11 @@ short SV_ReadShort(void);
long SV_ReadLong(void);
float SV_ReadFloat(void);

#if !__JHEXEN__
void SV_Header_Write(saveheader_t* hdr);
void SV_Header_Read(saveheader_t* hdr);
#endif

void SV_MaterialArchive_Write(MaterialArchive* arc);
void SV_MaterialArchive_Read(MaterialArchive* arc, int version);

Expand Down
48 changes: 4 additions & 44 deletions doomsday/plugins/common/src/p_saveg.c
Expand Up @@ -4563,7 +4563,7 @@ static boolean readSaveHeader(saveheader_t *hdr, LZFILE *savefile)
randomClassParm = SV_ReadByte();

#else
lzRead(hdr, sizeof(*hdr), SV_File());
SV_Header_Read(hdr);

if(hdr->magic != MY_SAVE_MAGIC)
{
Expand All @@ -4577,46 +4577,6 @@ static boolean readSaveHeader(saveheader_t *hdr, LZFILE *savefile)
return false; // A future version.
}

#if __JDOOM__ || __JHERETIC__
# if __JDOOM__ //|| __JHEXEN__
if(hdr->version < 9)
# elif __JHERETIC__
if(hdr->version < 8)
# endif
{
static const gamemode_t oldGameModes[] = {
# if __JDOOM__
doom_shareware,
doom,
doom2,
doom_ultimate
# elif __JHERETIC__
heretic_shareware,
heretic,
heretic_extended
# elif __JHEXEN__
hexen_demo,
hexen,
hexen_deathkings
# endif
};
hdr->gameMode = oldGameModes[(int)hdr->gameMode];
# if __JDOOM__
/**
* \kludge Older versions did not differentiate between versions of
* Doom2 (i.e., Plutonia and TNT are marked as Doom2). If we detect
* that this save is from some version of Doom2, replace the marked
* gamemode with the current gamemode.
*/
if(hdr->gameMode == doom2 && (gameModeBits & GM_ANY_DOOM2))
{
hdr->gameMode = gameMode;
}
/// kludge end.
# endif
}
#endif

if(hdr->gameMode != gameMode)
{
Con_Message("SV_LoadGame: Game Mode missmatch (%i!=%i), aborting load.\n", (int)gameMode, (int)hdr->gameMode);
Expand Down Expand Up @@ -4914,7 +4874,7 @@ void SV_SaveClient(uint gameId)
hdr.respawnMonsters = respawnMonsters;
hdr.mapTime = mapTime;
hdr.gameId = gameId;
SV_Write(&hdr, sizeof(hdr));
SV_Header_Write(&hdr);

// Some important information.
// Our position and look angles.
Expand Down Expand Up @@ -4970,7 +4930,7 @@ void SV_LoadClient(uint gameId)
}
Str_Free(&gameSavePath);

SV_Read(&hdr, sizeof(hdr));
SV_Header_Read(&hdr);
if(hdr.magic != MY_CLIENT_SAVE_MAGIC)
{
SV_CloseFile();
Expand Down Expand Up @@ -5133,7 +5093,7 @@ int SV_SaveGameWorker(void* ptr)
hdr.gameId = SV_GenerateGameId();
for(i = 0; i < MAXPLAYERS; i++)
hdr.players[i] = players[i].plr->inGame;
lzWrite(&hdr, sizeof(hdr), SV_File());
SV_Header_Write(&hdr);

// In netgames the server tells the clients to save their games.
NetSv_SaveGame(hdr.gameId);
Expand Down
135 changes: 133 additions & 2 deletions doomsday/plugins/common/src/p_saveio.c
Expand Up @@ -371,9 +371,10 @@ static boolean readGameSaveHeaderFromFile(const ddstring_t* savePath, ddstring_t
if(SV_OpenFile(Str_Text(savePath), "rp"))
{
saveheader_t* hdr = SV_SaveHeader();
// Read the header.
lzRead(hdr, sizeof(*hdr), SV_File());

SV_Header_Read(hdr);
SV_CloseFile();

if(MY_SAVE_MAGIC == hdr->magic)
{
Str_Set(name, hdr->name);
Expand Down Expand Up @@ -683,6 +684,16 @@ void SV_WriteFloat(float val)
lzPutL(temp, savefile);
}

void SV_Seek(uint offset)
{
errorIfNotInited("SV_SetPos");
#if __JHEXEN__
saveptr.b += offset;
#else
lzSeek(savefile, offset);
#endif
}

void SV_Read(void *data, int len)
{
errorIfNotInited("SV_Read");
Expand Down Expand Up @@ -772,6 +783,39 @@ static void swd(Writer* w, const char* data, int len)
SV_Write(data, len);
}

#if !__JHEXEN__
void SV_Header_Write(saveheader_t* hdr)
{
Writer* svWriter = Writer_NewWithCallbacks(swi8, swi16, swi32, swf, swd);
ddstring_t name;

Writer_WriteInt32(svWriter, hdr->magic);
Writer_WriteInt32(svWriter, hdr->version);
Writer_WriteInt32(svWriter, hdr->gameMode);

Str_InitStatic(&name, hdr->name);
Str_Write(&name, svWriter);

Writer_WriteByte(svWriter, hdr->skill);
Writer_WriteByte(svWriter, hdr->episode);
Writer_WriteByte(svWriter, hdr->map);
Writer_WriteByte(svWriter, hdr->deathmatch);
Writer_WriteByte(svWriter, hdr->noMonsters);
Writer_WriteByte(svWriter, hdr->respawnMonsters);
Writer_WriteInt32(svWriter, hdr->mapTime);

{ int i;
for(i = 0; i < MAXPLAYERS; ++i)
{
Writer_WriteByte(svWriter, hdr->players[i]);
}}

Writer_WriteInt32(svWriter, hdr->gameId);

Writer_Delete(svWriter);
}
#endif

void SV_MaterialArchive_Write(MaterialArchive* arc)
{
Writer* svWriter = Writer_NewWithCallbacks(swi8, swi16, swi32, swf, swd);
Expand Down Expand Up @@ -809,6 +853,93 @@ static void srd(Reader* r, char* data, int len)
SV_Read(data, len);
}

#if !__JHEXEN__
void SV_Header_Read(saveheader_t* hdr)
{
Reader* svReader = Reader_NewWithCallbacks(sri8, sri16, sri32, srf, srd);

hdr->magic = Reader_ReadInt32(svReader);
hdr->version = Reader_ReadInt32(svReader);
hdr->gameMode = Reader_ReadInt32(svReader);

if(hdr->version >= 10)
{
ddstring_t buf;
Str_InitStd(&buf);
Str_Read(&buf, svReader);
memcpy(hdr->name, Str_Text(&buf), SAVESTRINGSIZE);
hdr->name[SAVESTRINGSIZE] = '\0';
Str_Free(&buf);
}
else
{
// Older formats use a fixed-length name (24 characters).
Reader_Read(svReader, hdr->name, SAVESTRINGSIZE);
}
hdr->skill = Reader_ReadByte(svReader);
hdr->episode = Reader_ReadByte(svReader);
hdr->map = Reader_ReadByte(svReader);
hdr->deathmatch = Reader_ReadByte(svReader);
hdr->noMonsters = Reader_ReadByte(svReader);
hdr->respawnMonsters = Reader_ReadByte(svReader);

// Older formats serialize the unpacked header struct; skip the junk values (alignment).
if(hdr->version < 10) SV_Seek(2);

hdr->mapTime = Reader_ReadInt32(svReader);

{ int i;
for(i = 0; i < MAXPLAYERS; ++i)
{
hdr->players[i] = Reader_ReadByte(svReader);
}}
hdr->gameId = Reader_ReadInt32(svReader);

Reader_Delete(svReader);

// Translate gameMode identifiers from older save versions.
#if __JDOOM__ || __JHERETIC__
# if __JDOOM__ //|| __JHEXEN__
if(hdr->version < 9)
# elif __JHERETIC__
if(hdr->version < 8)
# endif
{
static const gamemode_t oldGameModes[] = {
# if __JDOOM__
doom_shareware,
doom,
doom2,
doom_ultimate
# elif __JHERETIC__
heretic_shareware,
heretic,
heretic_extended
# elif __JHEXEN__
hexen_demo,
hexen,
hexen_deathkings
# endif
};
hdr->gameMode = oldGameModes[(int)hdr->gameMode];
# if __JDOOM__
/**
* \kludge Older versions did not differentiate between versions of
* Doom2 (i.e., Plutonia and TNT are marked as Doom2). If we detect
* that this save is from some version of Doom2, replace the marked
* gamemode with the current gamemode.
*/
if(hdr->gameMode == doom2 && (gameModeBits & GM_ANY_DOOM2))
{
hdr->gameMode = gameMode;
}
/// kludge end.
# endif
}
#endif
}
#endif

void SV_MaterialArchive_Read(MaterialArchive* arc, int version)
{
Reader* svReader = Reader_NewWithCallbacks(sri8, sri16, sri32, srf, srd);
Expand Down

0 comments on commit afbf605

Please sign in to comment.