From 810ef8f7750d7328ce295dcff8bd507371bbd87a Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 21 Sep 2016 12:19:13 +0200 Subject: [PATCH] - save global savegame data to JSON as well. This is incomplete and untested, just a safety commit before going on. --- src/c_cmds.cpp | 4 +- src/d_main.cpp | 2 +- src/dthinker.cpp | 85 ------------------- src/dthinker.h | 1 - src/g_game.cpp | 105 ++++++++++------------- src/g_hub.cpp | 88 ++++++++++---------- src/g_hub.h | 6 +- src/g_level.cpp | 49 +++++------ src/g_level.h | 10 ++- src/g_mapinfo.cpp | 19 +---- src/json.cpp | 2 - src/m_misc.cpp | 2 +- src/m_random.cpp | 27 +++--- src/m_random.h | 3 +- src/menu/loadsavemenu.cpp | 2 +- src/p_acs.cpp | 171 ++++++++++++++++---------------------- src/p_acs.h | 11 ++- src/p_saveg.cpp | 11 --- src/p_saveg.h | 4 +- src/r_defs.h | 1 - src/s_sound.h | 2 - src/serializer.cpp | 21 ++++- src/serializer.h | 1 + src/statistics.cpp | 92 +++++++++----------- src/tarray.h | 5 -- src/textures/textures.h | 3 - src/zzz_old.cpp | 80 +++++++++++++----- 27 files changed, 346 insertions(+), 461 deletions(-) diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp index 03a7495e4..f9cea4005 100644 --- a/src/c_cmds.cpp +++ b/src/c_cmds.cpp @@ -811,7 +811,7 @@ CCMD (load) return; } FString fname = argv[1]; - DefaultExtension (fname, ".zds"); + DefaultExtension (fname, "." SAVEGAME_EXT); G_LoadGame (fname); } @@ -831,7 +831,7 @@ CCMD (save) return; } FString fname = argv[1]; - DefaultExtension (fname, ".zds"); + DefaultExtension (fname, "." SAVEGAME_EXT); G_SaveGame (fname, argv.argc() > 2 ? argv[2] : argv[1]); } diff --git a/src/d_main.cpp b/src/d_main.cpp index 9f4568614..689603084 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2580,7 +2580,7 @@ void D_DoomMain (void) { FString file(v); FixPathSeperator (file); - DefaultExtension (file, ".zds"); + DefaultExtension (file, ".zds" SAVEGAME_EXT); G_LoadGame (file); } diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 06295a4b3..0e57f05cf 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -117,91 +117,6 @@ void DThinker::SaveList(FSerializer &arc, DThinker *node) } } -void DThinker::SerializeAll(FArchive &arc, bool hubLoad) -{ -#if 0 - DThinker *thinker; - BYTE stat; - int statcount; - int i; - - // Save lists of thinkers, but not by storing the first one and letting - // the archiver catch the rest. (Which leads to buttloads of recursion - // and makes the file larger.) Instead, we explicitly save each thinker - // in sequence. When restoring an archive, we also have to maintain - // the thinker lists here instead of relying on the archiver to do it - // for us. - - if (arc.IsStoring()) - { - for (statcount = i = 0; i <= MAX_STATNUM; i++) - { - statcount += (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty()); - } - arc << statcount; - for (i = 0; i <= MAX_STATNUM; i++) - { - if (!Thinkers[i].IsEmpty() || !FreshThinkers[i].IsEmpty()) - { - stat = i; - arc << stat; - SaveList(arc, Thinkers[i].GetHead()); - SaveList(arc, FreshThinkers[i].GetHead()); - thinker = NULL; - arc << thinker; // Save a final NULL for this list - } - } - } - else - { - // Prevent the constructor from inserting thinkers into a list. - bSerialOverride = true; - - try - { - arc << statcount; - while (statcount > 0) - { - arc << stat << thinker; - while (thinker != NULL) - { - // This may be a player stored in their ancillary list. Remove - // them first before inserting them into the new list. - if (thinker->NextThinker != NULL) - { - thinker->Remove(); - } - // Thinkers with the OF_JustSpawned flag set go in the FreshThinkers - // list. Anything else goes in the regular Thinkers list. - if (thinker->ObjectFlags & OF_EuthanizeMe) - { - // This thinker was destroyed during the loading process. Do - // not link it in to any list. - } - else if (thinker->ObjectFlags & OF_JustSpawned) - { - FreshThinkers[stat].AddTail(thinker); - } - else - { - Thinkers[stat].AddTail(thinker); - } - arc << thinker; - } - statcount--; - } - } - catch (class CDoomError &) - { - bSerialOverride = false; - DestroyAllThinkers(); - throw; - } - bSerialOverride = false; - } -#endif -} - DThinker::DThinker (int statnum) throw() { NextThinker = NULL; diff --git a/src/dthinker.h b/src/dthinker.h index 4785c0035..c6a27e3a6 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -84,7 +84,6 @@ public: DestroyThinkersInList(Thinkers[statnum]); DestroyThinkersInList(FreshThinkers[statnum]); } - static void SerializeAll (FArchive &arc, bool keepPlayers); static void SerializeThinkers(FSerializer &arc, bool keepPlayers); static void MarkRoots(); diff --git a/src/g_game.cpp b/src/g_game.cpp index a221d3a5a..46bd3f7e4 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -84,6 +84,7 @@ #include "a_morph.h" #include "p_spec.h" #include "r_data/colormaps.h" +#include "serializer.h" #include @@ -110,8 +111,7 @@ void G_DoWorldDone (void); void G_DoSaveGame (bool okForQuicksave, FString filename, const char *description); void G_DoAutoSave (); -void STAT_Write(FILE *file); -void STAT_Read(PNGHandle *png); +void STAT_Serialize(FSerializer &file); FIntCVar gameskill ("skill", 2, CVAR_SERVERINFO|CVAR_LATCH); CVAR (Int, deathmatch, 0, CVAR_SERVERINFO|CVAR_LATCH); @@ -2045,7 +2045,7 @@ FString G_BuildSaveName (const char *prefix, int slot) name << prefix; if (slot >= 0) { - name.AppendFormat("%d.zds", slot); + name.AppendFormat("%d.zds" SAVEGAME_EXT, slot); } return name; } @@ -2102,27 +2102,24 @@ void G_DoAutoSave () } -static void PutSaveWads (FILE *file) +static void PutSaveWads (FSerializer &arc) { -#if 0 // SAVEGAME const char *name; // Name of IWAD name = Wads.GetWadName (FWadCollection::IWAD_FILENUM); - M_AppendPNGText (file, "Game WAD", name); + arc.AddString("Game WAD", name); // Name of wad the map resides in if (Wads.GetLumpFile (level.lumpnum) > 1) { name = Wads.GetWadName (Wads.GetLumpFile (level.lumpnum)); - M_AppendPNGText (file, "Map WAD", name); + arc.AddString("Map WAD", name); } -#endif } -static void PutSaveComment (FILE *file) +static void PutSaveComment (FSerializer &arc) { -#if 0 // SAVEGAME char comment[256]; const char *readableTime; WORD len; @@ -2136,7 +2133,7 @@ static void PutSaveComment (FILE *file) strncpy (comment+15, readableTime+10, 9); comment[24] = 0; - M_AppendPNGText (file, "Creation Time", comment); + arc.AddString("Creation Time", comment); // Get level name //strcpy (comment, level.level_name); @@ -2151,8 +2148,7 @@ static void PutSaveComment (FILE *file) comment[len+16] = 0; // Write out the comment - M_AppendPNGText (file, "Comment", comment); -#endif + arc.AddString("Comment", comment); } static void PutSavePic (FileWriter *file, int width, int height) @@ -2169,6 +2165,8 @@ static void PutSavePic (FileWriter *file, int width, int height) void G_DoSaveGame (bool okForQuicksave, FString filename, const char *description) { + TArray savegame_content; + char buf[100]; // Do not even try, if we're not in a level. (Can happen after @@ -2180,7 +2178,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio if (demoplayback) { - filename = G_BuildSaveName ("demosave.zds", -1); + filename = G_BuildSaveName ("demosave." SAVEGAME_EXT, -1); } if (cl_waitforsave) @@ -2189,74 +2187,63 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio insave = true; G_SnapshotLevel (); - FILE *stdfile = fopen (filename, "wb"); + BufferWriter savepic; + FSerializer savegameinfo; // this is for displayable info about the savegame + FSerializer savegameglobals; // and this for non-level related info that must be saved. - if (stdfile == NULL) - { - Printf ("Could not create savegame '%s'\n", filename.GetChars()); - insave = false; - I_FreezeTime(false); - return; - } + savegameinfo.OpenWriter(); + savegameglobals.OpenWriter(); SaveVersion = SAVEVER; -#if 0 // SAVEGAME - PutSavePic (stdfile, SAVEPICWIDTH, SAVEPICHEIGHT); + PutSavePic(&savepic, SAVEPICWIDTH, SAVEPICHEIGHT); mysnprintf(buf, countof(buf), GAMENAME " %s", GetVersionString()); - M_AppendPNGText (stdfile, "Software", buf); - M_AppendPNGText (stdfile, "Engine", GAMESIG); - M_AppendPNGText (stdfile, "ZDoom Save Version", SAVESIG); - M_AppendPNGText (stdfile, "Title", description); - M_AppendPNGText (stdfile, "Current Map", level.MapName); - PutSaveWads (stdfile); - PutSaveComment (stdfile); + // put some basic info into the PNG so that this isn't lost when the image gets extracted. + M_AppendPNGText(&savepic, "Software", buf); + M_AppendPNGText(&savepic, "Title", description); + M_AppendPNGText(&savepic, "Current Map", level.MapName); + M_FinishPNG(&savepic); + + savegameinfo.AddString("Software", buf) + .AddString("Engine", GAMESIG) + .AddString("Save Version", SAVESIG) + .AddString("Title", description) + .AddString("Current Map", level.MapName); + + + PutSaveWads (savegameinfo); + PutSaveComment (savegameinfo); // Intermission stats for hubs - G_WriteHubInfo(stdfile); + G_SerializeHub(savegameglobals); { FString vars = C_GetMassCVarString(CVAR_SERVERINFO); - M_AppendPNGText (stdfile, "Important CVARs", vars.GetChars()); + savegameglobals.AddString("importantcvars", vars.GetChars()); } if (level.time != 0 || level.maptime != 0) { - DWORD time[2] = { DWORD(BigLong(TICRATE)), DWORD(BigLong(level.time)) }; - M_AppendPNGChunk (stdfile, MAKE_ID('p','t','I','c'), (BYTE *)&time, 8); + int tic = TICRATE; + savegameglobals("ticrate", tic); + savegameglobals("leveltime", level.time); } - G_WriteSnapshots (stdfile); - STAT_Write(stdfile); - FRandom::StaticWriteRNGState (stdfile); - P_WriteACSDefereds (stdfile); - - P_WriteACSVars(stdfile); + STAT_Serialize(savegameglobals); + FRandom::StaticWriteRNGState(savegameglobals); + P_WriteACSDefereds(savegameglobals); + P_WriteACSVars(savegameglobals); if (NextSkill != -1) { - BYTE next = NextSkill; - M_AppendPNGChunk (stdfile, MAKE_ID('s','n','X','t'), &next, 1); + savegameglobals("nextskill", NextSkill); } - M_FinishPNG (stdfile); - fclose (stdfile); + //G_WriteSnapshots (stdfile); + M_NotifyNewSave (filename.GetChars(), description, okForQuicksave); - // Check whether the file is ok. - bool success = false; - stdfile = fopen (filename.GetChars(), "rb"); - if (stdfile != NULL) - { - PNGHandle *pngh = M_VerifyPNG(stdfile); - if (pngh != NULL) - { - success = true; - delete pngh; - } - fclose(stdfile); - } -#endif + // Check whether the file is ok. (todo when new format is ready) bool success = true; if (success) { diff --git a/src/g_hub.cpp b/src/g_hub.cpp index e43607710..cabcef2d3 100644 --- a/src/g_hub.cpp +++ b/src/g_hub.cpp @@ -43,7 +43,7 @@ #include "m_png.h" #include "gstrings.h" #include "wi_stuff.h" -#include "farchive.h" +#include "serializer.h" //========================================================================== @@ -54,7 +54,7 @@ struct FHubInfo { - int finished_ep; + int levelnum; int maxkills; int maxitems; @@ -65,7 +65,7 @@ struct FHubInfo FHubInfo &operator=(const wbstartstruct_t &wbs) { - finished_ep = wbs.finished_ep; + levelnum = wbs.finished_ep; maxkills = wbs.maxkills; maxsecret= wbs.maxsecret; maxitems = wbs.maxitems; @@ -80,54 +80,54 @@ static TArray hubdata; void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs) { - unsigned int i,j; + unsigned int i, j; if (cluster->flags & CLUSTER_HUB) { - for(i=0;imaxkills=wbs->maxitems=wbs->maxsecret=0; - for(i=0;imaxkills = wbs->maxitems = wbs->maxsecret = 0; + for (i = 0; i < MAXPLAYERS; i++) { - wbs->plyr[i].sitems=wbs->plyr[i].skills=wbs->plyr[i].ssecret=0; + wbs->plyr[i].sitems = wbs->plyr[i].skills = wbs->plyr[i].ssecret = 0; } - for(i=0;imaxkills += hubdata[i].maxkills; wbs->maxitems += hubdata[i].maxitems; wbs->maxsecret += hubdata[i].maxsecret; - for(j=0;jplyr[j].sitems += hubdata[i].plyr[j].sitems; wbs->plyr[j].skills += hubdata[i].plyr[j].skills; wbs->plyr[j].ssecret += hubdata[i].plyr[j].ssecret; } } - if (cluster->ClusterName.IsNotEmpty()) + if (cluster->ClusterName.IsNotEmpty()) { if (cluster->flags & CLUSTER_LOOKUPNAME) { @@ -140,7 +140,7 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs) } } } - if (mode!=FINISH_SameHub) hubdata.Clear(); + if (mode != FINISH_SameHub) hubdata.Clear(); } //========================================================================== @@ -148,39 +148,41 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs) // Serialize intermission info for hubs // //========================================================================== -#define HUBS_ID MAKE_ID('h','u','B','s') -static void G_SerializeHub(FArchive & arc) +FSerializer &Serialize(FSerializer &arc, const char *key, wbplayerstruct_t &h, wbplayerstruct_t *def) { - int i=hubdata.Size(); - arc << i; - if (i>0) + if (arc.BeginObject(key)) { - if (arc.IsStoring()) arc.Write(&hubdata[0], i * sizeof(FHubInfo)); - else - { - hubdata.Resize(i); - arc.Read(&hubdata[0], i * sizeof(FHubInfo)); - } + arc("in", h.in) + ("kills", h.skills) + ("items", h.sitems) + ("secrets", h.ssecret) + ("time", h.stime) + ("fragcount", h.fragcount) + .Array("frags", h.frags, MAXPLAYERS) + .EndObject(); } - else hubdata.Clear(); + return arc; } -void G_WriteHubInfo (FILE *file) +FSerializer &Serialize(FSerializer &arc, const char *key, FHubInfo &h, FHubInfo *def) { - FPNGChunkArchive arc(file, HUBS_ID); - G_SerializeHub(arc); + if (arc.BeginObject(key)) + { + arc("levelnum", h.levelnum) + ("maxkills", h.maxkills) + ("maxitems", h.maxitems) + ("maxsecret", h.maxsecret) + ("maxfrags", h.maxfrags) + .Array("players", h.plyr, MAXPLAYERS) + .EndObject(); + } + return arc; } -void G_ReadHubInfo (PNGHandle *png) +void G_SerializeHub(FSerializer &arc) { - int chunklen; - - if ((chunklen = M_FindPNGChunk (png, HUBS_ID)) != 0) - { - FPNGChunkArchive arc (png->File->GetFile(), HUBS_ID, chunklen); - G_SerializeHub(arc); - } + arc("hubinfo", hubdata); } void G_ClearHubInfo() diff --git a/src/g_hub.h b/src/g_hub.h index 8f148479c..245bb8f93 100644 --- a/src/g_hub.h +++ b/src/g_hub.h @@ -1,14 +1,12 @@ #ifndef __G_HUB_H #define __G_HUB_H -#include - struct PNGHandle; struct cluster_info_t; struct wbstartstruct_t; +class FSerializer; -void G_WriteHubInfo (FILE *file); -void G_ReadHubInfo (PNGHandle *png); +void G_SerializeHub (FSerializer &file); void G_LeavingHub(int mode, cluster_info_t * cluster, struct wbstartstruct_t * wbs); #endif diff --git a/src/g_level.cpp b/src/g_level.cpp index 5908a2b9f..d917794b3 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1748,38 +1748,33 @@ CCMD(listsnapshots) // //========================================================================== -static void writeDefereds (FArchive &arc, level_info_t *i) +void P_WriteACSDefereds (FSerializer &arc) { - arc << i->MapName << i->defered; -} + bool found = false; -//========================================================================== -// -// -//========================================================================== - -void P_WriteACSDefereds (FILE *file) -{ - FPNGChunkArchive *arc = NULL; - - for (unsigned int i = 0; i < wadlevelinfos.Size(); i++) + // only write this stuff if needed + for (auto &wi : wadlevelinfos) { - if (wadlevelinfos[i].defered) + if (wi.deferred.Size() > 0) { - if (arc == NULL) - { - arc = new FPNGChunkArchive (file, ACSD_ID); - } - writeDefereds (*arc, (level_info_t *)&wadlevelinfos[i]); + found = true; + break; } } - - if (arc != NULL) + if (found && arc.BeginObject("deferred")) { - // Signal end of defereds - FString empty = ""; - (*arc) << empty; - delete arc; + for (auto &wi : wadlevelinfos) + { + if (wi.deferred.Size() > 0) + { + if (wi.deferred.Size() > 0 && arc.BeginObject(nullptr)) + { + arc(wi.MapName, wi.deferred) + .EndObject(); + } + } + } + arc.EndObject(); } } @@ -1790,6 +1785,7 @@ void P_WriteACSDefereds (FILE *file) void P_ReadACSDefereds (PNGHandle *png) { +#if 0 FString MapName; size_t chunklen; @@ -1806,10 +1802,11 @@ void P_ReadACSDefereds (PNGHandle *png) { I_Error("Unknown map '%s' in savegame", MapName.GetChars()); } - arc << i->defered; + arc << i->deferred; } } png->File->ResetFilePtr(); +#endif } diff --git a/src/g_level.h b/src/g_level.h index 70872bc46..4d730b2f2 100644 --- a/src/g_level.h +++ b/src/g_level.h @@ -38,6 +38,7 @@ #include "doomdef.h" #include "sc_man.h" #include "s_sound.h" +#include "p_acs.h" #include "textures/textures.h" #include "resourcefiles/file_zip.h" @@ -224,8 +225,6 @@ enum ELevelFlags : unsigned int }; -struct acsdefered_t; - struct FSpecialAction { FName Type; // this is initialized before the actors... @@ -297,7 +296,7 @@ struct level_info_t int musicorder; FCompressedBuffer Snapshot; DWORD snapshotVer; - struct acsdefered_t *defered; + TArray deferred; float skyspeed1; float skyspeed2; DWORD fadeto; @@ -352,7 +351,10 @@ struct level_info_t void Reset(); bool isValid(); FString LookupLevelName (); - void ClearDefered(); + void ClearDefered() + { + deferred.Clear(); + } level_info_t *CheckLevelRedirect (); template diff --git a/src/g_mapinfo.cpp b/src/g_mapinfo.cpp index ff4ef0e87..e6b9c093b 100644 --- a/src/g_mapinfo.cpp +++ b/src/g_mapinfo.cpp @@ -250,7 +250,7 @@ void level_info_t::Reset() musicorder = 0; Snapshot = { 0,0,0,0,nullptr }; snapshotVer = 0; - defered = 0; + deferred.Clear(); skyspeed1 = skyspeed2 = 0.f; fadeto = 0; outsidefog = 0xff000000; @@ -334,23 +334,6 @@ FString level_info_t::LookupLevelName() } -//========================================================================== -// -// -//========================================================================== - -void level_info_t::ClearDefered() -{ - acsdefered_t *def = defered; - while (def) - { - acsdefered_t *next = def->next; - delete def; - def = next; - } - defered = NULL; -} - //========================================================================== // // diff --git a/src/json.cpp b/src/json.cpp index 1d8d506f8..982d9fb79 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -50,10 +50,8 @@ CCMD(writejson) DWORD t = I_MSTime(); FSerializer arc; arc.OpenWriter(); - arc.BeginObject(nullptr); G_SerializeLevel(arc, false); arc.WriteObjects(); - arc.EndObject(); DWORD tt = I_MSTime(); Printf("JSON generation took %d ms\n", tt - t); FILE *f = fopen("out.json", "wb"); diff --git a/src/m_misc.cpp b/src/m_misc.cpp index a37c32094..824fe0533 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -449,7 +449,7 @@ struct pcx_t }; -inline void putc(char chr, FileWriter *file) +inline void putc(unsigned char chr, FileWriter *file) { file->Write(&chr, 1); } diff --git a/src/m_random.cpp b/src/m_random.cpp index c0516e1f5..cc63fd5ed 100644 --- a/src/m_random.cpp +++ b/src/m_random.cpp @@ -61,7 +61,7 @@ #include "doomstat.h" #include "m_random.h" -#include "farchive.h" +#include "serializer.h" #include "b_bot.h" #include "m_png.h" #include "m_crc32.h" @@ -291,24 +291,29 @@ DWORD FRandom::StaticSumSeeds () // //========================================================================== -void FRandom::StaticWriteRNGState (FILE *file) +void FRandom::StaticWriteRNGState (FSerializer &arc) { FRandom *rng; - FPNGChunkArchive arc (file, RAND_ID); - arc << rngseed; + arc("rngseed", rngseed); - for (rng = FRandom::RNGList; rng != NULL; rng = rng->Next) + if (arc.BeginArray("rngs")) { - // Only write those RNGs that have names - if (rng->NameCRC != 0) + for (rng = FRandom::RNGList; rng != NULL; rng = rng->Next) { - arc << rng->NameCRC << rng->idx; - for (int i = 0; i < SFMT::N32; ++i) + // Only write those RNGs that have names + if (rng->NameCRC != 0) { - arc << rng->sfmt.u[i]; + if (arc.BeginObject(nullptr)) + { + arc("crc", rng->NameCRC) + ("index", rng->idx) + .Array("u", rng->sfmt.u, SFMT::N32) + .EndObject(); + } } } + arc.EndArray(); } } @@ -323,6 +328,7 @@ void FRandom::StaticWriteRNGState (FILE *file) void FRandom::StaticReadRNGState (PNGHandle *png) { +#if 0 FRandom *rng; size_t len = M_FindPNGChunk (png, RAND_ID); @@ -367,6 +373,7 @@ void FRandom::StaticReadRNGState (PNGHandle *png) } png->File->ResetFilePtr(); } +#endif } //========================================================================== diff --git a/src/m_random.h b/src/m_random.h index fab21b4ee..141585925 100644 --- a/src/m_random.h +++ b/src/m_random.h @@ -40,6 +40,7 @@ #include "sfmt/SFMT.h" struct PNGHandle; +class FSerializer; class FRandom { @@ -175,7 +176,7 @@ public: static void StaticClearRandom (); static DWORD StaticSumSeeds (); static void StaticReadRNGState (PNGHandle *png); - static void StaticWriteRNGState (FILE *file); + static void StaticWriteRNGState (FSerializer &file); static FRandom *StaticFindRNG(const char *name); #ifndef NDEBUG diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index f32146d50..4ccd21db6 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -213,7 +213,7 @@ void DLoadSaveMenu::ReadSaveStrings () LastSaved = LastAccessed = -1; quickSaveSlot = NULL; - filter = G_BuildSaveName ("*.zds", -1); + filter = G_BuildSaveName ("*." SAVEGAME_EXT, -1); filefirst = I_FindFirst (filter.GetChars(), &c_file); if (filefirst != ((void *)(-1))) { diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 22b44aa1c..c5ef8e2ee 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -770,11 +770,11 @@ void ACSStringPool::ReadStrings(PNGHandle *png, DWORD id) // // ACSStringPool :: WriteStrings // -// Writes strings to a PNG chunk. +// Writes strings to a serializer // //============================================================================ -void ACSStringPool::WriteStrings(FILE *file, DWORD id) const +void ACSStringPool::WriteStrings(FSerializer &file, const char *key) const { int32_t i, poolsize = (int32_t)Pool.Size(); @@ -782,20 +782,29 @@ void ACSStringPool::WriteStrings(FILE *file, DWORD id) const { // No need to write if we don't have anything. return; } - FPNGChunkArchive arc(file, id); - - arc << poolsize; - for (i = 0; i < poolsize; ++i) + if (file.BeginObject(key)) { - PoolEntry *entry = &Pool[i]; - if (entry->Next != FREE_ENTRY) + file("poolsize", poolsize); + if (file.BeginArray("pool")) { - arc.WriteCount(i); - arc.WriteString(entry->Str); - arc.WriteCount(entry->LockCount); + for (i = 0; i < poolsize; ++i) + { + PoolEntry *entry = &Pool[i]; + if (entry->Next != FREE_ENTRY) + { + if (file.BeginObject(nullptr)) + { + file("index", i) + ("string", entry->Str) + ("lockcount", entry->LockCount) + .EndObject(); + } + } + } + file.EndArray(); } + file.EndObject(); } - arc.WriteCount(-1); } //============================================================================ @@ -945,7 +954,7 @@ void P_ClearACSVars(bool alsoglobal) // //============================================================================ -static void WriteVars (FILE *file, SDWORD *vars, size_t count, DWORD id) +static void WriteVars (FSerializer &file, SDWORD *vars, size_t count, const char *key) { size_t i, j; @@ -963,12 +972,7 @@ static void WriteVars (FILE *file, SDWORD *vars, size_t count, DWORD id) if (vars[j] != 0) break; } - FPNGChunkArchive arc (file, id); - for (i = 0; i <= j; ++i) - { - DWORD var = vars[i]; - arc << var; - } + file.Array(key, vars, int(j+1)); } } @@ -1009,9 +1013,9 @@ static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id) // //============================================================================ -static void WriteArrayVars (FILE *file, FWorldGlobalArray *vars, unsigned int count, DWORD id) +static void WriteArrayVars (FSerializer &file, FWorldGlobalArray *vars, unsigned int count, const char *key) { - unsigned int i, j; + unsigned int i; // Find the first non-empty array. for (i = 0; i < count; ++i) @@ -1021,28 +1025,31 @@ static void WriteArrayVars (FILE *file, FWorldGlobalArray *vars, unsigned int co } if (i < count) { - // Find last non-empty array. Anything beyond the last stored array - // will be emptied at load time. - for (j = count-1; j > i; --j) + if (file.BeginObject(key)) { - if (vars[j].CountUsed() != 0) - break; - } - FPNGChunkArchive arc (file, id); - arc.WriteCount (i); - arc.WriteCount (j); - for (; i <= j; ++i) - { - arc.WriteCount (vars[i].CountUsed()); - - FWorldGlobalArray::ConstIterator it(vars[i]); - const FWorldGlobalArray::Pair *pair; - - while (it.NextPair (pair)) + for(;iKey); - arc.WriteCount (pair->Value); + if (vars[i].CountUsed()) + { + FString arraykey; + + arraykey.Format("%d", i); + if (file.BeginObject(arraykey)) + { + FWorldGlobalArray::ConstIterator it(vars[i]); + const FWorldGlobalArray::Pair *pair; + + while (it.NextPair(pair)) + { + arraykey.Format("%d", pair->Key); + int v = pair->Value; + file(arraykey.GetChars(), v); + } + file.EndObject(); + } + } } + file.EndObject(); } } } @@ -1108,13 +1115,13 @@ void P_ReadACSVars(PNGHandle *png) // //============================================================================ -void P_WriteACSVars(FILE *stdfile) +void P_WriteACSVars(FSerializer &arc) { - WriteVars (stdfile, ACS_WorldVars, NUM_WORLDVARS, MAKE_ID('w','v','A','r')); - WriteVars (stdfile, ACS_GlobalVars, NUM_GLOBALVARS, MAKE_ID('g','v','A','r')); - WriteArrayVars (stdfile, ACS_WorldArrays, NUM_WORLDVARS, MAKE_ID('w','a','R','r')); - WriteArrayVars (stdfile, ACS_GlobalArrays, NUM_GLOBALVARS, MAKE_ID('g','a','R','r')); - GlobalACSStrings.WriteStrings(stdfile, MAKE_ID('a','s','T','r')); + WriteVars (arc, ACS_WorldVars, NUM_WORLDVARS, "acsworldvars"); + WriteVars (arc, ACS_GlobalVars, NUM_GLOBALVARS, "acsglobalvars"); + WriteArrayVars (arc, ACS_WorldArrays, NUM_WORLDVARS, "acsworldarrays"); + WriteArrayVars (arc, ACS_GlobalArrays, NUM_GLOBALVARS, "acsglobalarrays"); + GlobalACSStrings.WriteStrings(arc, "acsglobalstrings"); } //---- Inventory functions --------------------------------------// @@ -9672,15 +9679,13 @@ static void SetScriptState (int script, DLevelScript::EScriptState state) void P_DoDeferedScripts () { - acsdefered_t *def; const ScriptPtr *scriptdata; FBehavior *module; // Handle defered scripts in this step, too - def = level.info->defered; - while (def) + for(int i = level.info->deferred.Size()-1; i>=0; i--) { - acsdefered_t *next = def->next; + acsdefered_t *def = &level.info->deferred[i]; switch (def->type) { case acsdefered_t::defexecute: @@ -9711,39 +9716,35 @@ void P_DoDeferedScripts () DPrintf (DMSG_SPAMMY, "Deferred terminate of %s\n", ScriptPresentation(def->script).GetChars()); break; } - delete def; - def = next; } - level.info->defered = NULL; + level.info->deferred.Clear(); } static void addDefered (level_info_t *i, acsdefered_t::EType type, int script, const int *args, int argcount, AActor *who) { if (i) { - acsdefered_t *def = new acsdefered_t; + acsdefered_t &def = i->deferred[i->deferred.Reserve(1)]; int j; - def->next = i->defered; - def->type = type; - def->script = script; - for (j = 0; (size_t)j < countof(def->args) && j < argcount; ++j) + def.type = type; + def.script = script; + for (j = 0; (size_t)j < countof(def.args) && j < argcount; ++j) { - def->args[j] = args[j]; + def.args[j] = args[j]; } - while ((size_t)j < countof(def->args)) + while ((size_t)j < countof(def.args)) { - def->args[j++] = 0; + def.args[j++] = 0; } if (who != NULL && who->player != NULL) { - def->playernum = int(who->player - players); + def.playernum = int(who->player - players); } else { - def->playernum = -1; + def.playernum = -1; } - i->defered = def; DPrintf (DMSG_SPAMMY, "%s on map %s deferred\n", ScriptPresentation(script).GetChars(), i->MapName.GetChars()); } } @@ -9821,43 +9822,15 @@ void P_TerminateScript (int script, const char *map) SetScriptState (script, DLevelScript::SCRIPT_PleaseRemove); } -FArchive &operator<< (FArchive &arc, acsdefered_t *&defertop) +FSerializer &Serialize(FSerializer &arc, const char *key, acsdefered_t &defer, acsdefered_t *def) { - BYTE more; - - if (arc.IsStoring ()) + if (arc.BeginObject(key)) { - acsdefered_t *defer = defertop; - more = 1; - while (defer) - { - BYTE type; - arc << more; - type = (BYTE)defer->type; - arc << type; - P_SerializeACSScriptNumber(arc, defer->script, false); - arc << defer->playernum << defer->args[0] << defer->args[1] << defer->args[2]; - defer = defer->next; - } - more = 0; - arc << more; - } - else - { - acsdefered_t **defer = &defertop; - - arc << more; - while (more) - { - *defer = new acsdefered_t; - arc << more; - (*defer)->type = (acsdefered_t::EType)more; - P_SerializeACSScriptNumber(arc, (*defer)->script, false); - arc << (*defer)->playernum << (*defer)->args[0] << (*defer)->args[1] << (*defer)->args[2]; - defer = &((*defer)->next); - arc << more; - } - *defer = NULL; + arc.Enum("type", defer.type) + .ScriptNum("script", defer.script) + .Array("args", defer.args, 3) + ("player", defer.playernum) + .EndObject(); } return arc; } diff --git a/src/p_acs.h b/src/p_acs.h index 512780f8c..5ff048e8b 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -44,6 +44,8 @@ class FFont; class FileReader; +struct line_t; +struct PNGHandle; enum @@ -95,7 +97,7 @@ public: void Clear(); void Dump() const; void ReadStrings(PNGHandle *png, DWORD id); - void WriteStrings(FILE *file, DWORD id) const; + void WriteStrings(FSerializer &file, const char *key) const; private: int FindString(const char *str, size_t len, unsigned int h, unsigned int bucketnum); @@ -121,9 +123,8 @@ extern ACSStringPool GlobalACSStrings; void P_CollectACSGlobalStrings(); void P_ReadACSVars(PNGHandle *); -void P_WriteACSVars(FILE*); +void P_WriteACSVars(FSerializer &); void P_ClearACSVars(bool); -void P_SerializeACSScriptNumber(FArchive &arc, int &scriptnum, bool was2byte); struct ACSProfileInfo { @@ -964,8 +965,6 @@ private: // The structure used to control scripts between maps struct acsdefered_t { - struct acsdefered_t *next; - enum EType { defexecute, @@ -978,6 +977,6 @@ struct acsdefered_t int playernum; }; -FArchive &operator<< (FArchive &arc, acsdefered_t *&defer); +FSerializer &Serialize(FSerializer &arc, const char *key, acsdefered_t &defer, acsdefered_t *def); #endif //__P_ACS_H__ diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 8f6038bf5..3b9b33c3f 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -72,17 +72,6 @@ // Thinkers // -// -// P_ArchiveThinkers -// - -void P_SerializeThinkers (FArchive &arc, bool hubLoad) -{ - arc.EnableThinkers(); - //DImpactDecal::Im ::SerializeTime (arc); - DThinker::SerializeAll (arc, hubLoad); -} - void P_DestroyThinkers(bool hubLoad) { if (hubLoad) diff --git a/src/p_saveg.h b/src/p_saveg.h index 43293c57a..f09ca48da 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -34,8 +34,8 @@ #ifndef __P_SAVEG_H__ #define __P_SAVEG_H__ -class FArchive; struct PNGHandle; +class FSerializer; // Persistent storage/archiving. // These are the load / save game routines. @@ -43,7 +43,7 @@ struct PNGHandle; void P_DestroyThinkers(bool hubLoad); void P_ReadACSDefereds (PNGHandle *png); -void P_WriteACSDefereds (FILE *file); +void P_WriteACSDefereds (FSerializer &); void G_SerializeLevel(FSerializer &arc, bool hubLoad); diff --git a/src/r_defs.h b/src/r_defs.h index efd9fc641..a21d23616 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -159,7 +159,6 @@ class FScanner; class FBitmap; struct FCopyInfo; class DInterpolation; -class FArchive; enum { diff --git a/src/s_sound.h b/src/s_sound.h index 29b5dfb2d..86915ea40 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -176,8 +176,6 @@ public: } }; -FArchive &operator<<(FArchive &arc, FSoundID &sid); - extern FRolloffInfo S_Rolloff; extern BYTE *S_SoundCurve; extern int S_SoundCurveSize; diff --git a/src/serializer.cpp b/src/serializer.cpp index 939c3fc7d..884475413 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -149,11 +149,12 @@ struct FReader // //========================================================================== -bool FSerializer::OpenWriter() +bool FSerializer::OpenWriter(bool randomaccess) { if (w != nullptr || r != nullptr) return false; w = new FWriter; + BeginObject(nullptr, randomaccess); return true; } @@ -587,6 +588,22 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr) // //========================================================================== +FSerializer &FSerializer::AddString(const char *key, const char *charptr) +{ + if (isWriting()) + { + WriteKey(key); + w->mWriter.String(charptr); + } + return *this; +} + +//========================================================================== +// +// +// +//========================================================================== + unsigned FSerializer::GetSize(const char *group) { if (isWriting()) return -1; // we do not know this when writing. @@ -657,6 +674,7 @@ void FSerializer::WriteObjects() const char *FSerializer::GetOutput(unsigned *len) { if (isReading()) return nullptr; + EndObject(); if (len != nullptr) { *len = (unsigned)w->mOutString.GetSize(); @@ -674,6 +692,7 @@ FCompressedBuffer FSerializer::GetCompressedOutput() { if (isReading()) return{ 0,0,0,0,nullptr }; FCompressedBuffer buff; + EndObject(); buff.mSize = (unsigned)w->mOutString.GetSize(); buff.mZipFlags = 0; diff --git a/src/serializer.h b/src/serializer.h index 12edc2e99..4d910aec6 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -75,6 +75,7 @@ public: FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr); FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def); FSerializer &StringPtr(const char *key, const char *&charptr); // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer. + FSerializer &AddString(const char *key, const char *charptr); FSerializer &ScriptNum(const char *key, int &num); bool isReading() const { diff --git a/src/statistics.cpp b/src/statistics.cpp index 5d14bad0a..536d60a44 100644 --- a/src/statistics.cpp +++ b/src/statistics.cpp @@ -70,7 +70,7 @@ #include "r_sky.h" #include "p_lnspec.h" #include "m_crc32.h" -#include "farchive.h" +#include "serializer.h" CVAR(Int, savestatistics, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(String, statfile, "zdoomstat.txt", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) @@ -87,7 +87,7 @@ struct OneLevel int totalkills, killcount; int totalsecrets, secretcount; int leveltime; - char levelname[9]; + FString Levelname; }; // Current game's statistics @@ -408,13 +408,12 @@ static void StoreLevelStats() { for(i=0;imEpisodeMap; - arc << startlevel; - } - for(int j = 0; j < i; j++) - { - OneLevel &l = LevelData[j]; - - arc << l.totalkills - << l.killcount - << l.totalsecrets - << l.secretcount - << l.leveltime; - - if (arc.IsStoring()) arc.WriteName(l.levelname); - else strcpy(l.levelname, arc.ReadName()); + else + { + if (StartEpisode != NULL) startlevel = StartEpisode->mEpisodeMap; + arc("startlevel", startlevel); + } + arc("levels", LevelData); + arc.EndObject(); } } -#define STAT_ID MAKE_ID('s','T','a','t') - -void STAT_Write(FILE *file) -{ - FPNGChunkArchive arc (file, STAT_ID); - SerializeStatistics(arc); -} - -void STAT_Read(PNGHandle *png) -{ - DWORD chunkLen = (DWORD)M_FindPNGChunk (png, STAT_ID); - if (chunkLen != 0) - { - FPNGChunkArchive arc (png->File->GetFile(), STAT_ID, chunkLen); - SerializeStatistics(arc); - } -} //========================================================================== // @@ -588,7 +574,7 @@ FString GetStatString() { OneLevel *l = &LevelData[i]; compose.AppendFormat("Level %s - Kills: %d/%d - Secrets: %d/%d - Time: %d:%02d\n", - l->levelname, l->killcount, l->totalkills, l->secretcount, l->totalsecrets, + l->Levelname.GetChars(), l->killcount, l->totalkills, l->secretcount, l->totalsecrets, l->leveltime/(60*TICRATE), (l->leveltime/TICRATE)%60); } return compose; diff --git a/src/tarray.h b/src/tarray.h index 4d16ddfe2..6e37ea039 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -49,9 +49,6 @@ #include "m_alloc.h" -class FArchive; - - template class TIterator { public: @@ -83,8 +80,6 @@ struct FArray template class TArray { - template friend FArchive &operator<< (FArchive &arc, TArray &self); - public: typedef TIterator iterator; diff --git a/src/textures/textures.h b/src/textures/textures.h index 954936fe1..298b169f2 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -9,7 +9,6 @@ struct FRemapTable; struct FCopyInfo; class FScanner; class PClassInventory; -class FArchive; // Texture IDs class FTextureManager; @@ -21,8 +20,6 @@ public: FNullTextureID() : FTextureID(0) {} }; -FArchive &operator<< (FArchive &arc, FTextureID &tex); - // // Animating textures and planes // diff --git a/src/zzz_old.cpp b/src/zzz_old.cpp index e6193b3aa..f2ce37bfd 100644 --- a/src/zzz_old.cpp +++ b/src/zzz_old.cpp @@ -37,26 +37,6 @@ -void P_SerializeACSScriptNumber(FArchive &arc, int &scriptnum, bool was2byte) -{ - arc << scriptnum; - // If the script number is negative, then it's really a name. - // So read/store the name after it. - if (scriptnum < 0) - { - if (arc.IsStoring()) - { - arc.WriteName(FName(ENamedName(-scriptnum)).GetChars()); - } - else - { - const char *nam = arc.ReadName(); - scriptnum = -FName(nam); - } - } -} - - #if 0 // still needed as reference. FCrap &FCrap::ReadObject(DObject* &obj, PClass *wanttype) @@ -181,3 +161,63 @@ FCrap &FCrap::ReadObject(DObject* &obj, PClass *wanttype) } #endif +#if 0 +void DThinker::SerializeAll(FArchive &arc, bool hubLoad) +{ + DThinker *thinker; + BYTE stat; + int statcount; + int i; + + if (arc.IsStoring()) + { + } + else + { + // Prevent the constructor from inserting thinkers into a list. + bSerialOverride = true; + + try + { + arc << statcount; + while (statcount > 0) + { + arc << stat << thinker; + while (thinker != NULL) + { + // This may be a player stored in their ancillary list. Remove + // them first before inserting them into the new list. + if (thinker->NextThinker != NULL) + { + thinker->Remove(); + } + // Thinkers with the OF_JustSpawned flag set go in the FreshThinkers + // list. Anything else goes in the regular Thinkers list. + if (thinker->ObjectFlags & OF_EuthanizeMe) + { + // This thinker was destroyed during the loading process. Do + // not link it in to any list. + } + else if (thinker->ObjectFlags & OF_JustSpawned) + { + FreshThinkers[stat].AddTail(thinker); + } + else + { + Thinkers[stat].AddTail(thinker); + } + arc << thinker; + } + statcount--; + } + } + catch (class CDoomError &) + { + bSerialOverride = false; + DestroyAllThinkers(); + throw; + } + bSerialOverride = false; + } +} +#endif