- save global savegame data to JSON as well.

This is incomplete and untested, just a safety commit before going on.
This commit is contained in:
Christoph Oelckers 2016-09-21 12:19:13 +02:00
parent dbea80e943
commit 810ef8f775
27 changed files with 346 additions and 461 deletions

View file

@ -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]);
}

View file

@ -2580,7 +2580,7 @@ void D_DoomMain (void)
{
FString file(v);
FixPathSeperator (file);
DefaultExtension (file, ".zds");
DefaultExtension (file, ".zds" SAVEGAME_EXT);
G_LoadGame (file);
}

View file

@ -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;

View file

@ -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();

View file

@ -84,6 +84,7 @@
#include "a_morph.h"
#include "p_spec.h"
#include "r_data/colormaps.h"
#include "serializer.h"
#include <zlib.h>
@ -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<FCompressedBuffer> 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)
{

View file

@ -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;
@ -86,7 +86,7 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
{
for (i = 0; i < hubdata.Size(); i++)
{
if (hubdata[i].finished_ep==level.levelnum)
if (hubdata[i].levelnum == level.levelnum)
{
hubdata[i] = *wbs;
break;
@ -97,7 +97,7 @@ void G_LeavingHub(int mode, cluster_info_t * cluster, wbstartstruct_t * wbs)
hubdata[hubdata.Reserve(1)] = *wbs;
}
hubdata[i].finished_ep=level.levelnum;
hubdata[i].levelnum = level.levelnum;
if (!multiplayer && !deathmatch)
{
// The player counters don't work in hubs
@ -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()

View file

@ -1,14 +1,12 @@
#ifndef __G_HUB_H
#define __G_HUB_H
#include <stdio.h>
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

View file

@ -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)
// only write this stuff if needed
for (auto &wi : wadlevelinfos)
{
FPNGChunkArchive *arc = NULL;
for (unsigned int i = 0; i < wadlevelinfos.Size(); i++)
if (wi.deferred.Size() > 0)
{
if (wadlevelinfos[i].defered)
{
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
}

View file

@ -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<acsdefered_t> 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<class T>

View file

@ -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;
}
//==========================================================================
//
//

View file

@ -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");

View file

@ -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);
}

View file

@ -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,25 +291,30 @@ 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);
if (arc.BeginArray("rngs"))
{
for (rng = FRandom::RNGList; rng != NULL; rng = rng->Next)
{
// Only write those RNGs that have names
if (rng->NameCRC != 0)
{
arc << rng->NameCRC << rng->idx;
for (int i = 0; i < SFMT::N32; ++i)
if (arc.BeginObject(nullptr))
{
arc << rng->sfmt.u[i];
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
}
//==========================================================================

View file

@ -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

View file

@ -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)))
{

View file

@ -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;
if (file.BeginObject(key))
{
file("poolsize", poolsize);
if (file.BeginArray("pool"))
{
for (i = 0; i < poolsize; ++i)
{
PoolEntry *entry = &Pool[i];
if (entry->Next != FREE_ENTRY)
{
arc.WriteCount(i);
arc.WriteString(entry->Str);
arc.WriteCount(entry->LockCount);
if (file.BeginObject(nullptr))
{
file("index", i)
("string", entry->Str)
("lockcount", entry->LockCount)
.EndObject();
}
}
arc.WriteCount(-1);
}
file.EndArray();
}
file.EndObject();
}
}
//============================================================================
@ -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)
for(;i<count;i++)
{
arc.WriteCount (vars[i].CountUsed());
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))
{
arc.WriteCount (pair->Key);
arc.WriteCount (pair->Value);
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;
}

View file

@ -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__

View file

@ -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)

View file

@ -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);

View file

@ -159,7 +159,6 @@ class FScanner;
class FBitmap;
struct FCopyInfo;
class DInterpolation;
class FArchive;
enum
{

View file

@ -176,8 +176,6 @@ public:
}
};
FArchive &operator<<(FArchive &arc, FSoundID &sid);
extern FRolloffInfo S_Rolloff;
extern BYTE *S_SoundCurve;
extern int S_SoundCurveSize;

View file

@ -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;

View file

@ -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
{

View file

@ -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;i<LevelData.Size();i++)
{
if (!stricmp(LevelData[i].levelname, level.MapName)) break;
if (!LevelData[i].Levelname.CompareNoCase(level.MapName)) break;
}
if (i==LevelData.Size())
{
LevelData.Reserve(1);
strncpy(LevelData[i].levelname, level.MapName, 8);
LevelData[i].levelname[8] = 0;
LevelData[i].Levelname = level.MapName;
}
LevelData[i].totalkills = level.total_monsters;
LevelData[i].killcount = level.killed_monsters;
@ -494,7 +493,7 @@ void STAT_ChangeLevel(const char *newl)
for(unsigned i = 0; i < LevelData.Size(); i++)
{
FString lsection = LevelData[i].levelname;
FString lsection = LevelData[i].Levelname;
lsection.ToUpper();
infostring.Format("%4d/%4d, %3d/%3d",
LevelData[i].killcount, LevelData[i].totalkills, LevelData[i].secretcount, LevelData[i].totalsecrets);
@ -516,16 +515,30 @@ void STAT_ChangeLevel(const char *newl)
//
//==========================================================================
static void SerializeStatistics(FArchive &arc)
FSerializer &Serialize(FSerializer &arc, const char *key, OneLevel &l, OneLevel *def)
{
if (arc.BeginObject(key))
{
arc("totalkills", l.totalkills)
("killcount", l.killcount)
("totalsecrets", l.totalsecrets)
("secretcount", l.secretcount)
("leveltime", l.leveltime)
("levelname", l.Levelname)
.EndObject();
}
}
void STAT_Serialize(FSerializer &arc)
{
FString startlevel;
int i = LevelData.Size();
arc << i;
if (arc.IsLoading())
if (arc.BeginObject("statistics"))
{
arc << startlevel;
if (arc.isReading())
{
arc("startlevel", startlevel);
StartEpisode = NULL;
for (unsigned int j = 0; j < AllEpisodes.Size(); j++)
{
@ -540,40 +553,13 @@ static void SerializeStatistics(FArchive &arc)
else
{
if (StartEpisode != NULL) startlevel = StartEpisode->mEpisodeMap;
arc << startlevel;
arc("startlevel", 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());
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;

View file

@ -49,9 +49,6 @@
#include "m_alloc.h"
class FArchive;
template<typename T> class TIterator
{
public:
@ -83,8 +80,6 @@ struct FArray
template <class T, class TT=T>
class TArray
{
template<class U, class UU> friend FArchive &operator<< (FArchive &arc, TArray<U,UU> &self);
public:
typedef TIterator<T> iterator;

View file

@ -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
//

View file

@ -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