From 1c9dbc3c360eea7d664b7de7fa6369ea78bff023 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Thu, 22 Sep 2016 00:18:31 +0200 Subject: [PATCH] - converted the basic savegame loader so that all remnant of FArchive have been removed now. --- src/g_doom/a_doommisc.cpp | 1 - src/g_game.cpp | 132 +++++++++++++++++++------------------ src/g_level.cpp | 93 +++++++++++--------------- src/g_level.h | 1 + src/m_random.cpp | 50 +++++--------- src/m_random.h | 2 +- src/p_acs.cpp | 135 +++++++++++++++----------------------- src/p_acs.h | 4 +- src/p_saveg.h | 2 +- src/serializer.cpp | 4 +- src/serializer.h | 2 + 11 files changed, 187 insertions(+), 239 deletions(-) diff --git a/src/g_doom/a_doommisc.cpp b/src/g_doom/a_doommisc.cpp index c281173afc..129c32f1ed 100644 --- a/src/g_doom/a_doommisc.cpp +++ b/src/g_doom/a_doommisc.cpp @@ -14,7 +14,6 @@ #include "a_specialspot.h" #include "templates.h" #include "m_bbox.h" -#include "farchive.h" #include "portal.h" #include "d_player.h" #include "p_maputl.h" diff --git a/src/g_game.cpp b/src/g_game.cpp index aee960345e..6eeb402196 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1830,10 +1830,6 @@ bool G_CheckSaveGameWads (FSerializer &arc, bool printwarn) void G_DoLoadGame () { -#if 0 // SAVEGAME - char sigcheck[20]; - char *text = NULL; - char *map; bool hidecon; if (gameaction != ga_autoloadgame) @@ -1843,76 +1839,82 @@ void G_DoLoadGame () hidecon = gameaction == ga_loadgamehidecon; gameaction = ga_nothing; - FILE *stdfile = fopen (savename.GetChars(), "rb"); - if (stdfile == NULL) + FResourceFile *resfile = FResourceFile::OpenResourceFile(savename.GetChars(), nullptr, true, true); + if (resfile == nullptr) { Printf ("Could not read savegame '%s'\n", savename.GetChars()); return; } - PNGHandle *png = M_VerifyPNG (stdfile); - if (png == NULL) + FResourceLump *info = resfile->FindLump("info.json"); + if (info == nullptr) { - fclose (stdfile); - Printf ("'%s' is not a valid (PNG) savegame\n", savename.GetChars()); + delete resfile; + Printf ("'%s' is not a valid savegame: Missing 'info.json'.\n", savename.GetChars()); return; } SaveVersion = 0; + void *data = info->CacheLump(); + FSerializer arc; + if (!arc.OpenReader((const char *)data, info->LumpSize, true)) + { + Printf("Failed to access savegame info\n"); + delete resfile; + return; + } + // Check whether this savegame actually has been created by a compatible engine. // Since there are ZDoom derivates using the exact same savegame format but // with mutual incompatibilities this check simplifies things significantly. - char *engine = M_GetPNGText (png, "Engine"); - if (engine == NULL || 0 != strcmp (engine, GAMESIG)) + FString savever, engine, map; + arc("Save Version", SaveVersion); + arc("Engine", engine); + arc("Current Map", map); + + if (engine.CompareNoCase(GAMESIG) != 0) { // Make a special case for the message printed for old savegames that don't // have this information. - if (engine == NULL) + if (engine.IsEmpty()) { Printf ("Savegame is from an incompatible version\n"); } else { Printf ("Savegame is from another ZDoom-based engine: %s\n", engine); - delete[] engine; } - delete png; - fclose (stdfile); + delete resfile; return; } - if (engine != NULL) - { - delete[] engine; - } - SaveVersion = 0; - if (!M_GetPNGText (png, "ZDoom Save Version", sigcheck, 20) || - 0 != strncmp (sigcheck, "SAVEVER", 9) || // ZDOOMSAVE is the first 9 chars - (SaveVersion = atoi (sigcheck+9)) < MINSAVEVER) + if (SaveVersion < MINSAVEVER || SaveVersion > SAVEVER) { - delete png; - fclose (stdfile); + delete resfile; Printf ("Savegame is from an incompatible version"); - if (SaveVersion != 0) + if (SaveVersion < MINSAVEVER) { Printf(": %d (%d is the oldest supported)", SaveVersion, MINSAVEVER); } + else + { + Printf(": %d (%d is the highest supported)", SaveVersion, SAVEVER); + } Printf("\n"); return; } - if (!G_CheckSaveGameWads (png, true)) + if (!G_CheckSaveGameWads (arc, true)) { - fclose (stdfile); + delete resfile; return; } - map = M_GetPNGText (png, "Current Map"); - if (map == NULL) + if (map.IsEmpty()) { Printf ("Savegame is missing the current map\n"); - fclose (stdfile); + delete resfile; return; } @@ -1922,35 +1924,46 @@ void G_DoLoadGame () { gamestate = GS_HIDECONSOLE; } + // we are done with info.json. + arc.Close(); + + info = resfile->FindLump("global.json"); + if (info == nullptr) + { + delete resfile; + Printf("'%s' is not a valid savegame: Missing 'global.json'.\n", savename.GetChars()); + return; + } + + data = info->CacheLump(); + if (!arc.OpenReader((const char *)data, info->LumpSize, true)) + { + Printf("Failed to access savegame info\n"); + delete resfile; + return; + } + // Read intermission data for hubs - G_ReadHubInfo(png); + G_SerializeHub(arc); bglobal.RemoveAllBots (true); - text = M_GetPNGText (png, "Important CVARs"); - if (text != NULL) + arc("importantcvars", map); + if (!map.IsEmpty()) { - BYTE *vars_p = (BYTE *)text; + BYTE *vars_p = (BYTE *)map.GetChars(); C_ReadCVars (&vars_p); - delete[] text; } + DWORD time[2] = { 0,1 }; + + arc("ticrate", time[0]) + ("leveltime", time[1]); // dearchive all the modifications - if (M_FindPNGChunk (png, MAKE_ID('p','t','I','c')) == 8) - { - DWORD time[2]; - fread (&time, 8, 1, stdfile); - time[0] = BigLong((unsigned int)time[0]); - time[1] = BigLong((unsigned int)time[1]); - level.time = Scale (time[1], TICRATE, time[0]); - } - else - { // No ptIc chunk so we don't know how long the user was playing - level.time = 0; - } + level.time = Scale (time[1], TICRATE, time[0]); - G_ReadSnapshots (png); + //G_ReadSnapshots(png); // load a base level savegamerestore = true; // Use the player actors in the savegame @@ -1960,31 +1973,24 @@ void G_DoLoadGame () delete[] map; savegamerestore = false; - STAT_Read(png); - FRandom::StaticReadRNGState(png); - P_ReadACSDefereds(png); - P_ReadACSVars(png); + STAT_Serialize(arc); + FRandom::StaticReadRNGState(arc); + P_ReadACSDefereds(arc); + P_ReadACSVars(arc); NextSkill = -1; - if (M_FindPNGChunk (png, MAKE_ID('s','n','X','t')) == 1) - { - BYTE next; - fread (&next, 1, 1, stdfile); - NextSkill = next; - } + arc("nextskill", NextSkill); level.info->Snapshot.Clean(); BackupSaveName = savename; - delete png; - fclose (stdfile); + delete resfile; // At this point, the GC threshold is likely a lot higher than the // amount of memory in use, so bring it down now by starting a // collection. GC::StartCollection(); -#endif } diff --git a/src/g_level.cpp b/src/g_level.cpp index e795f4a345..76b67a9bb1 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1630,83 +1630,71 @@ void G_WriteVisited(FSerializer &arc) // //========================================================================== -void G_ReadSnapshots (PNGHandle *png) +void G_ReadSnapshots(PNGHandle *png) { DWORD chunkLen; FString MapName; level_info_t *i; - G_ClearSnapshots (); + G_ClearSnapshots(); - chunkLen = (DWORD)M_FindPNGChunk (png, SNAP_ID); + chunkLen = (DWORD)M_FindPNGChunk(png, SNAP_ID); while (chunkLen != 0) { - FPNGChunkArchive arc (png->File->GetFile(), SNAP_ID, chunkLen); +#if 0 + FPNGChunkArchive arc(png->File->GetFile(), SNAP_ID, chunkLen); DWORD snapver; arc << snapver; arc << MapName; - i = FindLevelInfo (MapName); -#if 0 + i = FindLevelInfo(MapName); i->snapshot = new FCompressedMemFile; - i->snapshot->Serialize (arc); + i->snapshot->Serialize(arc); + chunkLen = (DWORD)M_NextPNGChunk(png, SNAP_ID); #endif - chunkLen = (DWORD)M_NextPNGChunk (png, SNAP_ID); } - chunkLen = (DWORD)M_FindPNGChunk (png, DSNP_ID); + chunkLen = (DWORD)M_FindPNGChunk(png, DSNP_ID); if (chunkLen != 0) { - FPNGChunkArchive arc (png->File->GetFile(), DSNP_ID, chunkLen); +#if 0 + FPNGChunkArchive arc(png->File->GetFile(), DSNP_ID, chunkLen); DWORD snapver; arc << snapver; arc << MapName; -#if 0 TheDefaultLevelInfo.snapshot = new FCompressedMemFile; - TheDefaultLevelInfo.snapshot->Serialize (arc); + TheDefaultLevelInfo.snapshot->Serialize(arc); #endif } +} - chunkLen = (DWORD)M_FindPNGChunk (png, VIST_ID); - if (chunkLen != 0) +void G_ReadVisited(FSerializer &arc) +{ + if (arc.BeginArray("visited")) { - FPNGChunkArchive arc (png->File->GetFile(), VIST_ID, chunkLen); - - while (arc << MapName, MapName.Len() > 0) + for (int s = arc.ArraySize(); s > 0; s--) { - i = FindLevelInfo(MapName); - i->flags |= LEVEL_VISITED; + FString str; + arc(nullptr, str); + auto i = FindLevelInfo(str); + if (i != nullptr) i->flags |= LEVEL_VISITED; } + arc.EndArray(); } - chunkLen = (DWORD)M_FindPNGChunk (png, RCLS_ID); - if (chunkLen != 0) + arc.Array("randomclasses", SinglePlayerClass, MAXPLAYERS); + + if (arc.BeginObject("playerclasses")) { - FPNGChunkArchive arc (png->File->GetFile(), PCLS_ID, chunkLen); - SBYTE cnum; - - for (DWORD j = 0; j < chunkLen; ++j) + for (int i = 0; i < MAXPLAYERS; ++i) { - arc << cnum; - SinglePlayerClass[j] = cnum; + FString key; + key.Format("%d", i); + arc(key, players[i].cls); } + arc.EndObject(); } - - chunkLen = (DWORD)M_FindPNGChunk (png, PCLS_ID); - if (chunkLen != 0) - { - FPNGChunkArchive arc (png->File->GetFile(), RCLS_ID, chunkLen); - BYTE pnum; - - arc << pnum; - while (pnum != 255) - { - arc.UserReadClass (players[pnum].cls); - arc << pnum; - } - } - png->File->ResetFilePtr(); } //========================================================================== @@ -1749,8 +1737,7 @@ void P_WriteACSDefereds (FSerializer &arc) { if (wi.deferred.Size() > 0 && arc.BeginObject(nullptr)) { - arc(wi.MapName, wi.deferred) - .EndObject(); + arc(wi.MapName, wi.deferred); } } } @@ -1763,30 +1750,28 @@ void P_WriteACSDefereds (FSerializer &arc) // //========================================================================== -void P_ReadACSDefereds (PNGHandle *png) +void P_ReadACSDefereds (FSerializer &arc) { -#if 0 FString MapName; size_t chunklen; P_RemoveDefereds (); - if ((chunklen = M_FindPNGChunk (png, ACSD_ID)) != 0) + if (arc.BeginObject("deferred")) { - FPNGChunkArchive arc (png->File->GetFile(), ACSD_ID, chunklen); + const char *key; - while (arc << MapName, MapName.Len() > 0) + while ((key = arc.GetKey())) { - level_info_t *i = FindLevelInfo(MapName); + level_info_t *i = FindLevelInfo(key); if (i == NULL) { - I_Error("Unknown map '%s' in savegame", MapName.GetChars()); + I_Error("Unknown map '%s' in savegame", key); } - arc << i->deferred; + arc(key, i->deferred); } + arc.EndObject(); } - png->File->ResetFilePtr(); -#endif } diff --git a/src/g_level.h b/src/g_level.h index 4e86978ced..55a6647ab5 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -536,6 +536,7 @@ struct PNGHandle; void G_ReadSnapshots (PNGHandle *png); void G_WriteSnapshots (TArray &, TArray &); void G_WriteVisited(FSerializer &arc); +void G_ReadVisited(FSerializer &arc); void G_ClearHubInfo(); enum ESkillProperty diff --git a/src/m_random.cpp b/src/m_random.cpp index cc63fd5ed3..ec6200a7df 100644 --- a/src/m_random.cpp +++ b/src/m_random.cpp @@ -326,54 +326,36 @@ void FRandom::StaticWriteRNGState (FSerializer &arc) // //========================================================================== -void FRandom::StaticReadRNGState (PNGHandle *png) +void FRandom::StaticReadRNGState(FSerializer &arc) { -#if 0 FRandom *rng; - size_t len = M_FindPNGChunk (png, RAND_ID); - - if (len != 0) + arc("rngseed", rng); + if (arc.BeginArray("rngs")) { - const size_t sizeof_rng = sizeof(rng->NameCRC) + sizeof(rng->idx) + sizeof(rng->sfmt.u); - const int rngcount = (int)((len-4) / sizeof_rng); - int i; - DWORD crc; + int count = arc.ArraySize(); - FPNGChunkArchive arc (png->File->GetFile(), RAND_ID, len); - - arc << rngseed; - FRandom::StaticClearRandom (); - - for (i = rngcount; i; --i) + for (int i = 0; i < count; i++) { - arc << crc; - for (rng = FRandom::RNGList; rng != NULL; rng = rng->Next) + if (arc.BeginObject(nullptr)) { - if (rng->NameCRC == crc) + uint32_t crc; + arc("crc", crc); + + for (rng = FRandom::RNGList; rng != NULL; rng = rng->Next) { - arc << rng->idx; - for (int i = 0; i < SFMT::N32; ++i) + if (rng->NameCRC == crc) { - arc << rng->sfmt.u[i]; + arc("index", rng->idx) + .Array("u", rng->sfmt.u, SFMT::N32); + break; } - break; - } - } - if (rng == NULL) - { // The RNG was removed. Skip it. - int idx; - DWORD sfmt; - arc << idx; - for (int i = 0; i < SFMT::N32; ++i) - { - arc << sfmt; } + arc.EndObject(); } + arc.EndArray(); } - png->File->ResetFilePtr(); } -#endif } //========================================================================== diff --git a/src/m_random.h b/src/m_random.h index 141585925d..d8c94cb9fa 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -175,7 +175,7 @@ public: // Static interface static void StaticClearRandom (); static DWORD StaticSumSeeds (); - static void StaticReadRNGState (PNGHandle *png); + static void StaticReadRNGState (FSerializer &arc); static void StaticWriteRNGState (FSerializer &file); static FRandom *StaticFindRNG(const char *name); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index c5ef8e2ee6..59373237fc 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -722,47 +722,42 @@ void ACSStringPool::FindFirstFreeEntry(unsigned base) // //============================================================================ -void ACSStringPool::ReadStrings(PNGHandle *png, DWORD id) +void ACSStringPool::ReadStrings(FSerializer &file, const char *key) { Clear(); - size_t len = M_FindPNGChunk(png, id); - if (len != 0) + int32_t i, j, poolsize; + + file("poolsize", poolsize); + Pool.Resize(poolsize); + for (auto &p : Pool) { - FPNGChunkArchive arc(png->File->GetFile(), id, len); - int32_t i, j, poolsize; - unsigned int h, bucketnum; - char *str = NULL; - - arc << poolsize; - - Pool.Resize(poolsize); - i = 0; - j = arc.ReadCount(); - while (j >= 0) + p.Next = FREE_ENTRY; + p.LockCount = 0; + } + if (file.BeginArray("pool")) + { + j = file.ArraySize(); + for (int i = 0; i < j; i++) { - // Mark skipped entries as free - for (; i < j; ++i) + if (file.BeginObject(nullptr)) { - Pool[i].Next = FREE_ENTRY; - Pool[i].LockCount = 0; + i = -1; + file("index", i); + if (i >= 0 && i < Pool.Size()) + { + file("string", Pool[i].Str) + ("lockcount", Pool[i].LockCount); + + unsigned h = SuperFastHash(Pool[i].Str, Pool[i].Str.Len()); + unsigned bucketnum = h % NUM_BUCKETS; + Pool[i].Hash = h; + Pool[i].Next = PoolBuckets[bucketnum]; + PoolBuckets[bucketnum] = i; + } + file.EndObject(); } - arc << str; - h = SuperFastHash(str, strlen(str)); - bucketnum = h % NUM_BUCKETS; - Pool[i].Str = str; - Pool[i].Hash = h; - Pool[i].LockCount = arc.ReadCount(); - Pool[i].Next = PoolBuckets[bucketnum]; - PoolBuckets[bucketnum] = i; - i++; - j = arc.ReadCount(); } - if (str != NULL) - { - delete[] str; - } - FindFirstFreeEntry(0); } } @@ -982,29 +977,10 @@ static void WriteVars (FSerializer &file, SDWORD *vars, size_t count, const char // //============================================================================ -static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id) +static void ReadVars (FSerializer &arc, SDWORD *vars, size_t count, const char *key) { - size_t len = M_FindPNGChunk (png, id); - size_t used = 0; - - if (len != 0) - { - DWORD var; - size_t i; - FPNGChunkArchive arc (png->File->GetFile(), id, len); - used = len / 4; - - for (i = 0; i < used; ++i) - { - arc << var; - vars[i] = var; - } - png->File->ResetFilePtr(); - } - if (used < count) - { - memset (&vars[used], 0, (count-used)*4); - } + memset(&vars[0], 0, count * 4); + arc.Array(key, vars, count); } //============================================================================ @@ -1060,37 +1036,32 @@ static void WriteArrayVars (FSerializer &file, FWorldGlobalArray *vars, unsigned // //============================================================================ -static void ReadArrayVars (PNGHandle *png, FWorldGlobalArray *vars, size_t count, DWORD id) +static void ReadArrayVars (FSerializer &file, FWorldGlobalArray *vars, size_t count, const char *key) { - size_t len = M_FindPNGChunk (png, id); - unsigned int i, k; - for (i = 0; i < count; ++i) { - vars[i].Clear (); + vars[i].Clear(); } - if (len != 0) + if (file.BeginObject(key)) { - DWORD max, size; - FPNGChunkArchive arc (png->File->GetFile(), id, len); - - i = arc.ReadCount (); - max = arc.ReadCount (); - - for (; i <= max; ++i) + const char *arraykey; + while ((arraykey = file.GetKey())) { - size = arc.ReadCount (); - for (k = 0; k < size; ++k) + int i = (int)strtol(arraykey, nullptr, 10); + if (file.BeginObject(arraykey)) { - SDWORD key, val; - key = arc.ReadCount(); - - val = arc.ReadCount(); - vars[i].Insert (key, val); + while ((arraykey = file.GetKey())) + { + int k = (int)strtol(arraykey, nullptr, 10); + int val; + file(arraykey, val); + vars[i].Insert(k, val); + } + file.EndObject(); } } - png->File->ResetFilePtr(); + file.EndObject(); } } @@ -1100,13 +1071,13 @@ static void ReadArrayVars (PNGHandle *png, FWorldGlobalArray *vars, size_t count // //============================================================================ -void P_ReadACSVars(PNGHandle *png) +void P_ReadACSVars(FSerializer &arc) { - ReadVars (png, ACS_WorldVars, NUM_WORLDVARS, MAKE_ID('w','v','A','r')); - ReadVars (png, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r')); - ReadArrayVars (png, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r')); - ReadArrayVars (png, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r')); - GlobalACSStrings.ReadStrings(png, MAKE_ID('a','s','T','r')); + ReadVars (arc, ACS_WorldVars, NUM_WORLDVARS, "acsworldvars"); + ReadVars (arc, ACS_GlobalVars, NUM_GLOBALVARS, "acsglobalvars"); + ReadArrayVars (arc, ACS_WorldArrays, NUM_WORLDVARS, "acsworldarrays"); + ReadArrayVars (arc, ACS_GlobalArrays, NUM_GLOBALVARS, "acsglobalarrays"); + GlobalACSStrings.ReadStrings(arc, "acsglobalstrings"); } //============================================================================ diff --git a/src/p_acs.h b/src/p_acs.h index 5ff048e8be..9cd2092975 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -96,7 +96,7 @@ public: void PurgeStrings(); void Clear(); void Dump() const; - void ReadStrings(PNGHandle *png, DWORD id); + void ReadStrings(FSerializer &file, const char *key); void WriteStrings(FSerializer &file, const char *key) const; private: @@ -122,7 +122,7 @@ private: extern ACSStringPool GlobalACSStrings; void P_CollectACSGlobalStrings(); -void P_ReadACSVars(PNGHandle *); +void P_ReadACSVars(FSerializer &); void P_WriteACSVars(FSerializer &); void P_ClearACSVars(bool); diff --git a/src/p_saveg.h b/src/p_saveg.h index f09ca48da9..05d7e3fd4a 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -42,7 +42,7 @@ class FSerializer; // Also see farchive.(h|cpp) void P_DestroyThinkers(bool hubLoad); -void P_ReadACSDefereds (PNGHandle *png); +void P_ReadACSDefereds (FSerializer &); void P_WriteACSDefereds (FSerializer &); void G_SerializeLevel(FSerializer &arc, bool hubLoad); diff --git a/src/serializer.cpp b/src/serializer.cpp index 33b90524f7..301e284a92 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -730,7 +730,7 @@ const char *FSerializer::GetKey() void FSerializer::WriteObjects() { - if (isWriting()) + if (isWriting() && w->mDObjects.Size()) { BeginArray("objects"); // we cannot use the C++11 shorthand syntax here because the array may grow while being processed. @@ -769,6 +769,7 @@ void FSerializer::WriteObjects() const char *FSerializer::GetOutput(unsigned *len) { if (isReading()) return nullptr; + WriteObjects(); EndObject(); if (len != nullptr) { @@ -787,6 +788,7 @@ FCompressedBuffer FSerializer::GetCompressedOutput() { if (isReading()) return{ 0,0,0,0,0,nullptr }; FCompressedBuffer buff; + WriteObjects(); EndObject(); buff.mSize = (unsigned)w->mOutString.GetSize(); buff.mZipFlags = 0; diff --git a/src/serializer.h b/src/serializer.h index a5a7fda521..1592d41e0d 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -111,6 +111,8 @@ public: if (BeginArray(key)) { + int max = ArraySize(); + if (max < count) count = max; for (int i = 0; i < count; i++) { Serialize(*this, nullptr, obj[i], (T*)nullptr);