- added the last missing bits of the savegame code - thinker list deserialization and handling of players during hub travel. Now testing is what remains...

This commit is contained in:
Christoph Oelckers 2016-09-23 17:49:33 +02:00
parent edb7f7959e
commit 01d28e3eb2
6 changed files with 130 additions and 63 deletions

View file

@ -1001,7 +1001,6 @@ set( FASTMATH_SOURCES
) )
set (PCH_SOURCES set (PCH_SOURCES
json.cpp
actorptrselect.cpp actorptrselect.cpp
am_map.cpp am_map.cpp
b_bot.cpp b_bot.cpp

View file

@ -116,6 +116,85 @@ void DThinker::SaveList(FSerializer &arc, DThinker *node)
} }
} }
//==========================================================================
//
//
//
//==========================================================================
void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad)
{
//DThinker *thinker;
//BYTE stat;
//int statcount;
int i;
if (arc.isWriting())
{
arc.BeginArray("thinkers");
for (i = 0; i <= MAX_STATNUM; i++)
{
arc.BeginArray(nullptr);
SaveList(arc, Thinkers[i].GetHead());
SaveList(arc, FreshThinkers[i].GetHead());
arc.EndArray();
}
arc.EndArray();
}
else
{
if (arc.BeginArray("thinkers"))
{
for (i = 0; i <= MAX_STATNUM; i++)
{
if (arc.BeginArray(nullptr))
{
int size = arc.ArraySize();
for (int j = 0; j < size; j++)
{
DThinker *thinker;
arc(nullptr, thinker);
if (thinker != nullptr)
{
// This may be a player stored in their ancillary list. Remove
// them first before inserting them into the new list.
if (thinker->NextThinker != nullptr)
{
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 into any list.
}
else if (thinker->ObjectFlags & OF_JustSpawned)
{
FreshThinkers[i].AddTail(thinker);
thinker->PostSerialize();
}
else
{
Thinkers[i].AddTail(thinker);
thinker->PostSerialize();
}
}
}
arc.EndArray();
}
}
arc.EndArray();
}
}
}
//==========================================================================
//
//
//
//==========================================================================
DThinker::DThinker (int statnum) throw() DThinker::DThinker (int statnum) throw()
{ {
NextThinker = NULL; NextThinker = NULL;

View file

@ -1,39 +0,0 @@
#include "serializer.h"
#include "r_local.h"
#include "p_setup.h"
#include "c_dispatch.h"
#include "i_system.h"
#include "a_sharedglobal.h"
//==========================================================================
//
//
//
//==========================================================================
void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad)
{
//DThinker *thinker;
//BYTE stat;
//int statcount;
int i;
if (arc.isWriting())
{
arc.BeginArray("thinkers");
for (i = 0; i <= MAX_STATNUM; i++)
{
arc.BeginArray(nullptr);
SaveList(arc, Thinkers[i].GetHead());
SaveList(arc, FreshThinkers[i].GetHead());
arc.EndArray();
}
arc.EndArray();
}
else
{
}
}

View file

@ -63,10 +63,6 @@
#include "r_renderer.h" #include "r_renderer.h"
#include "serializer.h" #include "serializer.h"
// just the stuff that already got converted to FSerializer so that it can be seen as 'done' when searching.
#include "zzz_old.cpp"
// //
// Thinkers // Thinkers
// //
@ -905,7 +901,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload)
{ {
P_DestroyThinkers(hubload); P_DestroyThinkers(hubload);
interpolator.ClearInterpolations(); interpolator.ClearInterpolations();
arc.ReadObjects(); arc.ReadObjects(hubload);
} }
arc("level.flags", level.flags) arc("level.flags", level.flags)

View file

@ -31,6 +31,7 @@
#include "v_text.h" #include "v_text.h"
char nulspace[1024 * 1024 * 4]; char nulspace[1024 * 1024 * 4];
bool save_full = false; // for testing. Should be removed afterward.
//========================================================================== //==========================================================================
// //
@ -206,7 +207,7 @@ struct FReader
rapidjson::Document doc; rapidjson::Document doc;
mDoc.Parse(buffer, length); mDoc.Parse(buffer, length);
mObjects.Push(FJSONObject(&mDoc)); mObjects.Push(FJSONObject(&mDoc));
memset(mPlayers, 0, sizeof(mPlayers)); memset(mPlayers, -1, sizeof(mPlayers));
} }
rapidjson::Value *FindKey(const char *key) rapidjson::Value *FindKey(const char *key)
@ -806,7 +807,7 @@ void FSerializer::WriteObjects()
// //
//========================================================================== //==========================================================================
void FSerializer::ReadObjects() void FSerializer::ReadObjects(bool hubtravel)
{ {
bool founderrors = false; bool founderrors = false;
@ -823,6 +824,7 @@ void FSerializer::ReadObjects()
if (BeginObject(nullptr)) if (BeginObject(nullptr))
{ {
FString clsname; // do not deserialize the class type directly so that we can print appropriate errors. FString clsname; // do not deserialize the class type directly so that we can print appropriate errors.
int pindex = -1;
Serialize(*this, "classtype", clsname, nullptr); Serialize(*this, "classtype", clsname, nullptr);
PClass *cls = PClass::FindClass(clsname); PClass *cls = PClass::FindClass(clsname);
@ -830,6 +832,7 @@ void FSerializer::ReadObjects()
{ {
Printf("Unknown object class '%d' in savegame", clsname.GetChars()); Printf("Unknown object class '%d' in savegame", clsname.GetChars());
founderrors = true; founderrors = true;
r->mDObjects[i] = RUNTIME_CLASS(AActor)->CreateNew(); // make sure we got at least a valid pointer for the duration of the loading process.
} }
else else
{ {
@ -849,33 +852,60 @@ void FSerializer::ReadObjects()
for (unsigned i = 0; i < r->mDObjects.Size(); i++) for (unsigned i = 0; i < r->mDObjects.Size(); i++)
{ {
auto obj = r->mDObjects[i]; auto obj = r->mDObjects[i];
try if (BeginObject(nullptr))
{ {
if (BeginObject(nullptr)) if (obj != nullptr)
{ {
int pindex = -1; int pindex = -1;
Serialize(*this, "playerindex", pindex, nullptr); if (hubtravel)
if (obj != nullptr)
{ {
if (pindex >= 0 && pindex < MAXPLAYERS) // mark this as a hub travelling player. This needs to be taken care of later and be replaced with the real travelling player,
// but that's better done at the end of this loop so that inventory ownership is not getting messed up.
Serialize(*this, "playerindex", pindex, nullptr);
if (hubtravel && pindex >= 0 && pindex < MAXPLAYERS)
{ {
obj->ObjectFlags |= OF_LoadedPlayer;
r->mPlayers[pindex] = int(i); r->mPlayers[pindex] = int(i);
} }
}
try
{
obj->SerializeUserVars(*this); obj->SerializeUserVars(*this);
obj->Serialize(*this); obj->Serialize(*this);
} }
EndObject(); catch (CRecoverableError &err)
{
// In case something in here throws an error, let's continue and deal with it later.
Printf(TEXTCOLOR_RED "'%s'\n while restoring %s", err.GetMessage(), obj ? obj->GetClass()->TypeName.GetChars() : "invalid object");
mErrors++;
}
} }
} EndObject();
catch (CRecoverableError &err)
{
Printf(TEXTCOLOR_RED "'%s'\n while restoring %s", err.GetMessage(),obj? obj->GetClass()->TypeName.GetChars() : "invalid object");
mErrors++;
} }
} }
} }
EndArray(); EndArray();
if (hubtravel)
{
for (int i = 0; i < MAXPLAYERS; i++)
{
int pindex = r->mPlayers[i];
if (pindex != -1)
{
if (players[i].mo != nullptr)
{
r->mDObjects[pindex]->Destroy();
DObject::StaticPointerSubstitution(r->mDObjects[pindex], players[i].mo);
r->mDObjects[pindex] = players[i].mo;
}
else
{
players[i].mo = static_cast<APlayerPawn*>(r->mDObjects[pindex]);
}
}
}
}
DThinker::bSerialOverride = false; DThinker::bSerialOverride = false;
assert(!founderrors); assert(!founderrors);
if (founderrors) if (founderrors)

View file

@ -7,6 +7,8 @@
#include "r_defs.h" #include "r_defs.h"
#include "resourcefiles/file_zip.h" #include "resourcefiles/file_zip.h"
extern bool save_full;
struct ticcmd_t; struct ticcmd_t;
struct usercmd_t; struct usercmd_t;
@ -72,7 +74,7 @@ public:
bool OpenReader(const char *buffer, size_t length); bool OpenReader(const char *buffer, size_t length);
bool OpenReader(FCompressedBuffer *input); bool OpenReader(FCompressedBuffer *input);
void Close(); void Close();
void ReadObjects(); void ReadObjects(bool hubtravel);
bool BeginObject(const char *name); bool BeginObject(const char *name);
void EndObject(); void EndObject();
bool BeginArray(const char *name); bool BeginArray(const char *name);
@ -108,13 +110,13 @@ public:
template<class T> template<class T>
FSerializer &operator()(const char *key, T &obj, T &def) FSerializer &operator()(const char *key, T &obj, T &def)
{ {
return Serialize(*this, key, obj, &def); return Serialize(*this, key, obj, save_full? nullptr : &def);
} }
template<class T> template<class T>
FSerializer &Array(const char *key, T *obj, int count, bool fullcompare = false) FSerializer &Array(const char *key, T *obj, int count, bool fullcompare = false)
{ {
if (fullcompare && isWriting() && nullcmp(obj, count * sizeof(T))) if (!save_full && fullcompare && isWriting() && nullcmp(obj, count * sizeof(T)))
{ {
return *this; return *this;
} }
@ -138,7 +140,7 @@ public:
template<class T> template<class T>
FSerializer &Array(const char *key, T *obj, T *def, int count, bool fullcompare = false) FSerializer &Array(const char *key, T *obj, T *def, int count, bool fullcompare = false)
{ {
if (fullcompare && isWriting() && def != nullptr && !memcmp(obj, def, count * sizeof(T))) if (!save_full && fullcompare && isWriting() && def != nullptr && !memcmp(obj, def, count * sizeof(T)))
{ {
return *this; return *this;
} }