diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp index 5c5c9f56617..f175dd84136 100644 --- a/src/common/engine/serializer.cpp +++ b/src/common/engine/serializer.cpp @@ -1263,12 +1263,15 @@ FSerializer& Serialize(FSerializer& arc, const char* key, FTranslationID& value, // //========================================================================== + +bool SerializerAllowWhenSerializingOnlyPlayer(FSerializer &arc, DObject * obj); + FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode) { if (retcode) *retcode = true; if (arc.isWriting()) { - if (value != nullptr && !(value->ObjectFlags & (OF_EuthanizeMe | OF_Transient))) + if (value != nullptr && !(value->ObjectFlags & (OF_EuthanizeMe | OF_Transient)) && SerializerAllowWhenSerializingOnlyPlayer(arc, value)) { int ndx; if (value == WP_NOCHANGE) diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index fb906aee888..0288b5d858a 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -227,6 +227,8 @@ class FSerializer int mErrors = 0; int mObjectErrors = 0; FString mLumpName; + + bool serializeOnlyPlayer = false; }; FSerializer& Serialize(FSerializer& arc, const char* key, char& value, char* defval); diff --git a/src/g_game.cpp b/src/g_game.cpp index 4c1a366c04a..4107a3b5513 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -114,6 +114,8 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c void G_DoAutoSave (); void G_DoQuickSave (); +FString G_SnapshotPlayer(AActor * pawn); + void STAT_Serialize(FSerializer &file); CVARD_NAMED(Int, gameskill, skill, 2, CVAR_SERVERINFO|CVAR_LATCH, "sets the skill for the next newly started game") diff --git a/src/g_level.cpp b/src/g_level.cpp index bc0cd378af5..8efa0eebaf0 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1565,6 +1565,17 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, WorldDone) // //========================================================================== +FString G_SnapshotPlayer(AActor * pawn) +{ + FSerializer s; + s.serializeOnlyPlayer = true; + s.OpenWriter(false); + s("Player", pawn); + unsigned len; + const char * str = s.GetOutput(&len); + return FString(str, len); +} + void G_DoWorldDone (void) { gamestate = GS_LEVEL; diff --git a/src/playsim/dthinker.cpp b/src/playsim/dthinker.cpp index e8438475209..dc48734c0d9 100644 --- a/src/playsim/dthinker.cpp +++ b/src/playsim/dthinker.cpp @@ -92,6 +92,11 @@ void FThinkerCollection::Link(DThinker *thinker, int statnum) list->AddTail(thinker); } +bool FThinkerCollection::IsTravelling(DThinker *thinker) +{ + return Thinkers[STAT_TRAVELLING].HasThinker(thinker); +} + //========================================================================== // // @@ -625,6 +630,24 @@ int FThinkerList::TickThinkers(FThinkerList *dest) return count; } +bool FThinkerList::HasThinker(DThinker * t) +{ + DThinker *node = GetHead(); + + if (node == nullptr) + { + return false; + } + + while (node != Sentinel) + { + if(node == t) return true; + node = node->NextThinker; + } + + return false; +} + //========================================================================== // // diff --git a/src/playsim/dthinker.h b/src/playsim/dthinker.h index 78dcd1520bd..bded9a1c745 100644 --- a/src/playsim/dthinker.h +++ b/src/playsim/dthinker.h @@ -64,6 +64,8 @@ struct FThinkerList int ProfileThinkers(FThinkerList *dest); void SaveList(FSerializer &arc); + bool HasThinker(DThinker *); + private: DThinker *Sentinel = nullptr; @@ -85,6 +87,8 @@ struct FThinkerCollection DThinker *FirstThinker(int statnum); void Link(DThinker *thinker, int statnum); + bool IsTravelling(DThinker *thinker); + private: FThinkerList Thinkers[MAX_STATNUM + 2]; FThinkerList FreshThinkers[MAX_STATNUM + 1]; diff --git a/src/serializer_doom.cpp b/src/serializer_doom.cpp index 2ec1c8b8616..278bfe5eac8 100644 --- a/src/serializer_doom.cpp +++ b/src/serializer_doom.cpp @@ -225,10 +225,18 @@ FSerializer& FDoomSerializer::StatePointer(const char* key, void* ptraddr, bool return *this; } +bool SerializerAllowWhenSerializingOnlyPlayer(FSerializer &arc, DObject * obj) +{ + return (!arc.serializeOnlyPlayer + || (!obj->GetClass()->IsDescendantOf(RUNTIME_CLASS(DThinker))) + || static_cast(obj)->Level->Thinkers.IsTravelling(static_cast(obj))); +} + template<> FSerializer &Serialize(FSerializer &ar, const char *key, FPolyObj *&value, FPolyObj **defval) { + if(ar.isWriting() && ar.serializeOnlyPlayer) return ar; auto arc = dynamic_cast(&ar); if (!arc || arc->Level == nullptr) I_Error("Trying to serialize polyobject without a valid level"); return SerializePointer(*arc, key, value, defval, arc->Level->Polyobjects); @@ -236,6 +244,7 @@ template<> FSerializer &Serialize(FSerializer &ar, const char *key, FPolyObj *&v template<> FSerializer &Serialize(FSerializer &ar, const char *key, side_t *&value, side_t **defval) { + if(ar.isWriting() && ar.serializeOnlyPlayer) return ar; auto arc = dynamic_cast(&ar); if (!arc || arc->Level == nullptr) I_Error("Trying to serialize SIDEDEF without a valid level"); return SerializePointer(*arc, key, value, defval, arc->Level->sides); @@ -243,6 +252,7 @@ template<> FSerializer &Serialize(FSerializer &ar, const char *key, side_t *&val template<> FSerializer &Serialize(FSerializer &ar, const char *key, sector_t *&value, sector_t **defval) { + if(ar.isWriting() && ar.serializeOnlyPlayer) return ar; auto arc = dynamic_cast(&ar); if (!arc || arc->Level == nullptr) I_Error("Trying to serialize sector without a valid level"); return SerializePointer(*arc, key, value, defval, arc->Level->sectors); @@ -255,6 +265,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *& template<> FSerializer &Serialize(FSerializer &ar, const char *key, line_t *&value, line_t **defval) { + if(ar.isWriting() && ar.serializeOnlyPlayer) return ar; auto arc = dynamic_cast(&ar); if (!arc || arc->Level == nullptr) I_Error("Trying to serialize linedef without a valid level"); return SerializePointer(*arc, key, value, defval, arc->Level->lines); @@ -262,6 +273,7 @@ template<> FSerializer &Serialize(FSerializer &ar, const char *key, line_t *&val template<> FSerializer &Serialize(FSerializer &ar, const char *key, vertex_t *&value, vertex_t **defval) { + if(ar.isWriting() && ar.serializeOnlyPlayer) return ar; auto arc = dynamic_cast(&ar); if (!arc || arc->Level == nullptr) I_Error("Trying to serialize vertex without a valid level"); return SerializePointer(*arc, key, value, defval, arc->Level->vertexes);