- added a pseudo-serializer for FLevelLocals pointers.

This doesn't really write out any info for the pointer, if the level does not match it just errors out.
This is both for quick detection of badly used level data and for automatic restoring of the pointer from the serializer's working level.

This also removed the temporary workarounds in DAutomap and DLevelScript to restore these pointers when a savegame is loaded.
This commit is contained in:
Christoph Oelckers 2019-01-26 21:23:19 +01:00
commit 9b1b6db85d
12 changed files with 152 additions and 90 deletions

View file

@ -1450,27 +1450,32 @@ FSerializer &SerializePointer(FSerializer &arc, const char *key, T *&value, T **
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *&value, FPolyObj **defval)
{
return SerializePointer(arc, key, value, defval, level.Polyobjects.Data());
if (arc.Level == nullptr) I_Error("Trying to serialize polyobject without a valid level");
return SerializePointer(arc, key, value, defval, arc.Level->Polyobjects.Data());
}
template<> FSerializer &Serialize(FSerializer &arc, const char *key, const FPolyObj *&value, const FPolyObj **defval)
{
return SerializePointer<const FPolyObj>(arc, key, value, defval, level.Polyobjects.Data());
if (arc.Level == nullptr) I_Error("Trying to serialize polyobject without a valid level");
return SerializePointer<const FPolyObj>(arc, key, value, defval, arc.Level->Polyobjects.Data());
}
template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval)
{
return SerializePointer(arc, key, value, defval, &level.sides[0]);
if (arc.Level == nullptr) I_Error("Trying to serialize SIDEDEF without a valid level");
return SerializePointer(arc, key, value, defval, &arc.Level->sides[0]);
}
template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval)
{
return SerializePointer(arc, key, value, defval, &level.sectors[0]);
if (arc.Level == nullptr) I_Error("Trying to serialize sector without a valid level");
return SerializePointer(arc, key, value, defval, &arc.Level->sectors[0]);
}
template<> FSerializer &Serialize(FSerializer &arc, const char *key, const sector_t *&value, const sector_t **defval)
{
return SerializePointer<const sector_t>(arc, key, value, defval, &level.sectors[0]);
if (arc.Level == nullptr) I_Error("Trying to serialize sector without a valid level");
return SerializePointer<const sector_t>(arc, key, value, defval, &arc.Level->sectors[0]);
}
template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval)
@ -1480,12 +1485,14 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&
template<> FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value, line_t **defval)
{
return SerializePointer(arc, key, value, defval, &level.lines[0]);
if (arc.Level == nullptr) I_Error("Trying to serialize linedef without a valid level");
return SerializePointer(arc, key, value, defval, &arc.Level->lines[0]);
}
template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval)
{
return SerializePointer(arc, key, value, defval, &level.vertexes[0]);
if (arc.Level == nullptr) I_Error("Trying to serialize verte without a valid level");
return SerializePointer(arc, key, value, defval, &arc.Level->vertexes[0]);
}
//==========================================================================
@ -1968,13 +1975,13 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDial
}
else if (val->IsUint())
{
if (val->GetUint() >= level.StrifeDialogues.Size())
if (val->GetUint() >= arc.Level->StrifeDialogues.Size())
{
node = nullptr;
}
else
{
node = level.StrifeDialogues[val->GetUint()];
node = arc.Level->StrifeDialogues[val->GetUint()];
}
}
else
@ -2128,6 +2135,65 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr
return arc;
}
//==========================================================================
//
// This is a bit of a cheat because it never actually writes out the pointer.
// The rules for levels are that they must be self-contained.
// No level and no pbject that is part of a level may reference a different level.
//
// When writing, this merely checks if the rules are obeyed and if not errors out.
// When reading, it assumes that the object was properly written and restores
// the reference from the owning level.
//
// The only exception are null pointers which are allowed
//
//==========================================================================
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FLevelLocals *&lev, FLevelLocals **def)
{
if (arc.isWriting())
{
if (!arc.w->inObject() || lev == nullptr)
{
arc.WriteKey(key);
if (lev == nullptr)
{
arc.w->Null();
}
else
{
// This MUST be the currently serialized level. Anything else will error out here as a sanity check.
if (arc.Level == nullptr || lev != arc.Level)
{
I_Error("Attempt to serialize invalid level reference");
}
if (!arc.w->inObject())
{
arc.w->Bool(true); // In the unlikely case this is used in an array, write a filler.
}
}
}
}
else
{
auto val = arc.r->FindKey(key);
if (val != nullptr)
{
assert(val->IsNull() || val->IsBool());
if (val->IsNull())
{
lev = nullptr;
}
else
{
lev = arc.Level;
}
}
else lev = arc.Level;
}
return arc;
}
//==========================================================================
//
//