mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-27 22:42:57 +00:00
- added polyobject serializer.
- added sanity checks to prevent a savegame from being loaded with an incompatible map - refactored a few things to simplify serialization. - started work on main level serializer function.
This commit is contained in:
parent
ab43e0c8cb
commit
daf43f9d35
13 changed files with 221 additions and 200 deletions
|
@ -38,7 +38,7 @@
|
|||
#include "gi.h"
|
||||
#include "p_setup.h"
|
||||
#include "c_bind.h"
|
||||
#include "farchive.h"
|
||||
#include "serializer.h"
|
||||
#include "r_renderer.h"
|
||||
#include "r_sky.h"
|
||||
#include "sbar.h"
|
||||
|
@ -3106,13 +3106,14 @@ void AM_Drawer ()
|
|||
//
|
||||
//=============================================================================
|
||||
|
||||
void AM_SerializeMarkers(FArchive &arc)
|
||||
void AM_SerializeMarkers(FSerializer &arc)
|
||||
{
|
||||
arc << markpointnum;
|
||||
for (int i=0; i<AM_NUMMARKPOINTS; i++)
|
||||
if (arc.BeginObject("automarkers"))
|
||||
{
|
||||
arc << markpoints[i].x << markpoints[i].y;
|
||||
arc("markpointnum", markpointnum)
|
||||
.Array("markpoints", &markpoints[0].x, AM_NUMMARKPOINTS*2) // write as a double array.
|
||||
("scale_mtof", scale_mtof)
|
||||
("scale_ftom", scale_ftom)
|
||||
.EndObject();
|
||||
}
|
||||
arc << scale_mtof;
|
||||
arc << scale_ftom;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#define __AMMAP_H__
|
||||
|
||||
struct event_t;
|
||||
class FArchive;
|
||||
class FSerializer;
|
||||
|
||||
|
||||
void AM_StaticInit();
|
||||
|
@ -45,7 +45,7 @@ void AM_Stop (void);
|
|||
void AM_NewResolution ();
|
||||
void AM_ToggleMap ();
|
||||
void AM_LevelInit ();
|
||||
void AM_SerializeMarkers(FArchive &arc);
|
||||
void AM_SerializeMarkers(FSerializer &arc);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1815,9 +1815,9 @@ void P_ReadACSDefereds (PNGHandle *png)
|
|||
void FLevelLocals::Tick ()
|
||||
{
|
||||
// Reset carry sectors
|
||||
if (Scrolls != NULL)
|
||||
if (Scrolls.Size() > 0)
|
||||
{
|
||||
memset (Scrolls, 0, sizeof(*Scrolls)*numsectors);
|
||||
memset (&Scrolls[0], 0, sizeof(Scrolls[0])*Scrolls.Size());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1832,10 +1832,10 @@ void FLevelLocals::AddScroller (int secnum)
|
|||
{
|
||||
return;
|
||||
}
|
||||
if (Scrolls == NULL)
|
||||
if (Scrolls.Size() == 0)
|
||||
{
|
||||
Scrolls = new FSectorScrollValues[numsectors];
|
||||
memset (Scrolls, 0, sizeof(*Scrolls)*numsectors);
|
||||
Scrolls.Resize(numsectors);
|
||||
memset (&Scrolls[0], 0, sizeof(Scrolls[0])*numsectors);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -375,17 +375,12 @@ struct level_info_t
|
|||
}
|
||||
};
|
||||
|
||||
// [RH] These get zeroed every tic and are updated by thinkers.
|
||||
struct FSectorScrollValues
|
||||
{
|
||||
DVector2 Scroll;
|
||||
};
|
||||
|
||||
struct FLevelLocals
|
||||
{
|
||||
void Tick ();
|
||||
void AddScroller (int secnum);
|
||||
|
||||
BYTE md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded.
|
||||
int time; // time in the hub
|
||||
int maptime; // time in the map
|
||||
int totaltime; // time in the game
|
||||
|
@ -436,7 +431,7 @@ struct FLevelLocals
|
|||
int airsupply;
|
||||
int DefaultEnvironment; // Default sound environment.
|
||||
|
||||
FSectorScrollValues *Scrolls; // NULL if no DScrollers in this level
|
||||
TArray<DVector2> Scrolls; // NULL if no DScrollers in this level
|
||||
|
||||
SBYTE WallVertLight; // Light diffs for vert/horiz walls
|
||||
SBYTE WallHorizLight;
|
||||
|
|
48
src/json.cpp
48
src/json.cpp
|
@ -5,6 +5,28 @@
|
|||
#include "i_system.h"
|
||||
#include "a_sharedglobal.h"
|
||||
|
||||
|
||||
|
||||
void DObject::SerializeUserVars(FSerializer &arc)
|
||||
{
|
||||
PSymbolTable *symt;
|
||||
FName varname;
|
||||
//DWORD count, j;
|
||||
int *varloc = NULL;
|
||||
|
||||
symt = &GetClass()->Symbols;
|
||||
|
||||
if (arc.isWriting())
|
||||
{
|
||||
// Write all fields that aren't serialized by native code.
|
||||
//GetClass()->WriteValue(arc, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
//GetClass()->ReadValue(arc, this);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -18,12 +40,15 @@ void DThinker::SaveList(FSerializer &arc, DThinker *node)
|
|||
while (!(node->ObjectFlags & OF_Sentinel))
|
||||
{
|
||||
assert(node->NextThinker != NULL && !(node->NextThinker->ObjectFlags & OF_EuthanizeMe));
|
||||
//node->SerializeUserVars(arc);
|
||||
::Serialize<DThinker>(arc, nullptr, node, nullptr);
|
||||
node->CheckIfSerialized();
|
||||
node = node->NextThinker;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad)
|
||||
{
|
||||
//DThinker *thinker;
|
||||
|
@ -50,29 +75,10 @@ void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad)
|
|||
|
||||
|
||||
|
||||
void DObject::SerializeUserVars(FSerializer &arc)
|
||||
{
|
||||
PSymbolTable *symt;
|
||||
FName varname;
|
||||
//DWORD count, j;
|
||||
int *varloc = NULL;
|
||||
|
||||
symt = &GetClass()->Symbols;
|
||||
|
||||
if (arc.isWriting())
|
||||
{
|
||||
// Write all fields that aren't serialized by native code.
|
||||
//GetClass()->WriteValue(arc, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
//GetClass()->ReadValue(arc, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SerializeWorld(FSerializer &arc);
|
||||
void G_SerializeLevel(FSerializer &arc, bool);
|
||||
|
||||
CCMD(writejson)
|
||||
{
|
||||
|
@ -81,7 +87,7 @@ CCMD(writejson)
|
|||
arc.OpenWriter();
|
||||
arc.BeginObject(nullptr);
|
||||
DThinker::SerializeThinkers(arc, false);
|
||||
SerializeWorld(arc);
|
||||
G_SerializeLevel(arc, false);
|
||||
arc.WriteObjects();
|
||||
arc.EndObject();
|
||||
DWORD tt = I_MSTime();
|
||||
|
|
|
@ -3432,7 +3432,7 @@ void AActor::Tick ()
|
|||
|
||||
// [RH] Consider carrying sectors here
|
||||
DVector2 cumm(0, 0);
|
||||
if ((level.Scrolls != NULL || player != NULL) && !(flags & MF_NOCLIP) && !(flags & MF_NOSECTOR))
|
||||
if ((level.Scrolls.Size() != 0 || player != NULL) && !(flags & MF_NOCLIP) && !(flags & MF_NOSECTOR))
|
||||
{
|
||||
double height, waterheight; // killough 4/4/98: add waterheight
|
||||
const msecnode_t *node;
|
||||
|
@ -3453,10 +3453,9 @@ void AActor::Tick ()
|
|||
sector_t *sec = node->m_sector;
|
||||
DVector2 scrollv;
|
||||
|
||||
if (level.Scrolls != NULL)
|
||||
if (level.Scrolls.Size() > (sec-sectors))
|
||||
{
|
||||
const FSectorScrollValues *scroll = &level.Scrolls[sec - sectors];
|
||||
scrollv = scroll->Scroll;
|
||||
scrollv = level.Scrolls[sec - sectors];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
216
src/p_saveg.cpp
216
src/p_saveg.cpp
|
@ -732,6 +732,36 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FSectorPortal &port, F
|
|||
return arc;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// one polyobject.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj &poly, FPolyObj *def)
|
||||
{
|
||||
if (arc.BeginObject(key))
|
||||
{
|
||||
DAngle angle = poly.Angle;
|
||||
DVector2 delta = poly.StartSpot.pos;
|
||||
arc("angle", angle)
|
||||
("pos", delta)
|
||||
("interpolation", poly.interpolation)
|
||||
("blocked", poly.bBlocked)
|
||||
("hasportals", poly.bHasPortals)
|
||||
("specialdata", poly.specialdata)
|
||||
.EndObject();
|
||||
|
||||
if (arc.isReading())
|
||||
{
|
||||
poly.RotatePolyobj(angle, true);
|
||||
delta -= poly.StartSpot.pos;
|
||||
poly.MovePolyobj(delta, true);
|
||||
}
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
|
@ -760,21 +790,89 @@ FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z, zone_t *def
|
|||
//
|
||||
//============================================================================
|
||||
|
||||
void SerializeWorld(FSerializer &arc)
|
||||
void G_SerializeLevel(FSerializer &arc, bool hubload)
|
||||
{
|
||||
int i = level.totaltime;
|
||||
|
||||
if (arc.isWriting())
|
||||
{
|
||||
arc.Array("checksum", level.md5, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// prevent bad things from happening by doing a check on the size of level arrays and the map's entire checksum.
|
||||
// The old code happily tried to load savegames with any mismatch here, often causing meaningless errors
|
||||
// deep down in the deserializer or just a crash if the few insufficient safeguards were not triggered.
|
||||
BYTE chk[16] = { 0 };
|
||||
arc.Array("checksum", chk, 16);
|
||||
if (arc.GetSize("linedefs") != numlines ||
|
||||
arc.GetSize("sidedefs") != numsides ||
|
||||
arc.GetSize("sectors") != numsectors ||
|
||||
arc.GetSize("polyobjs") != po_NumPolyobjs ||
|
||||
memcmp(chk, level.md5, 16))
|
||||
{
|
||||
I_Error("Savegame is from a different level");
|
||||
}
|
||||
}
|
||||
|
||||
//Renderer->StartSerialize(arc);
|
||||
if (arc.isReading())
|
||||
{
|
||||
P_DestroyThinkers(hubload);
|
||||
// ReadObjects
|
||||
}
|
||||
|
||||
arc("level.flags", level.flags)
|
||||
("level.flags2", level.flags2)
|
||||
("level.fadeto", level.fadeto)
|
||||
("level.found_secrets", level.found_secrets)
|
||||
("level.found_items", level.found_items)
|
||||
("level.killed_monsters", level.killed_monsters)
|
||||
("level.total_secrets", level.total_secrets)
|
||||
("level.total_items", level.total_items)
|
||||
("level.total_monsters", level.total_monsters)
|
||||
("level.gravity", level.gravity)
|
||||
("level.aircontrol", level.aircontrol)
|
||||
("level.teamdamage", level.teamdamage)
|
||||
("level.maptime", level.maptime)
|
||||
("level.totaltime", i)
|
||||
("level.skytexture1", level.skytexture1)
|
||||
("level.skytexture2", level.skytexture2)
|
||||
("level.scrolls", level.Scrolls);
|
||||
|
||||
// Hub transitions must keep the current total time
|
||||
if (!hubload)
|
||||
level.totaltime = i;
|
||||
|
||||
if (arc.isReading())
|
||||
{
|
||||
sky1texture = level.skytexture1;
|
||||
sky2texture = level.skytexture2;
|
||||
R_InitSkyMap();
|
||||
interpolator.ClearInterpolations();
|
||||
}
|
||||
|
||||
G_AirControlChanged();
|
||||
|
||||
// fixme: This needs to ensure it reads from the correct place. Should be one once there's enough of this code converted to JSON
|
||||
arc.Array("linedefs", lines, &loadlines[0], numlines)
|
||||
.Array("sidedefs", sides, &loadsides[0], numsides)
|
||||
.Array("sectors", sectors, &loadsectors[0], numsectors)
|
||||
("subsectors", subsectors)
|
||||
("zones", Zones)
|
||||
("lineportals", linePortals)
|
||||
("sectorportals", sectorPortals);
|
||||
AM_SerializeMarkers(arc);
|
||||
|
||||
//FBehavior::StaticSerializeModuleStates(arc);
|
||||
arc.Array("linedefs", lines, &loadlines[0], numlines);
|
||||
arc.Array("sidedefs", sides, &loadsides[0], numsides);
|
||||
arc.Array("sectors", sectors, &loadsectors[0], numsectors);
|
||||
arc.Array("polyobjs", polyobjs, po_NumPolyobjs);
|
||||
arc("subsectors", subsectors);
|
||||
//StatusBar->Serialize(arc);
|
||||
arc("zones", Zones);
|
||||
arc("lineportals", linePortals);
|
||||
arc("sectorportals", sectorPortals);
|
||||
|
||||
if (arc.isReading()) P_CollectLinkedPortals();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ArchiveSounds
|
||||
|
@ -830,33 +928,8 @@ void P_SerializePolyobjs (FArchive &arc)
|
|||
DAngle angle;
|
||||
DVector2 delta;
|
||||
|
||||
arc << data;
|
||||
if (data != ASEG_POLYOBJS)
|
||||
I_Error ("Polyobject marker missing");
|
||||
|
||||
arc << data;
|
||||
if (data != po_NumPolyobjs)
|
||||
{
|
||||
I_Error ("UnarchivePolyobjs: Bad polyobj count");
|
||||
}
|
||||
for (i = 0, po = polyobjs; i < po_NumPolyobjs; i++, po++)
|
||||
{
|
||||
arc << data;
|
||||
if (data != po->tag)
|
||||
{
|
||||
I_Error ("UnarchivePolyobjs: Invalid polyobj tag");
|
||||
}
|
||||
arc << angle << delta << po->interpolation;
|
||||
arc << po->bBlocked;
|
||||
arc << po->bHasPortals;
|
||||
if (SaveVersion >= 4548)
|
||||
{
|
||||
arc << po->specialdata;
|
||||
}
|
||||
|
||||
po->RotatePolyobj (angle, true);
|
||||
delta -= po->StartSpot.pos;
|
||||
po->MovePolyobj (delta, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -868,73 +941,7 @@ void P_SerializePolyobjs (FArchive &arc)
|
|||
|
||||
void G_SerializeLevel(FArchive &arc, bool hubLoad)
|
||||
{
|
||||
int i = level.totaltime;
|
||||
|
||||
unsigned tm = I_MSTime();
|
||||
|
||||
Renderer->StartSerialize(arc);
|
||||
if (arc.IsLoading()) P_DestroyThinkers(hubLoad);
|
||||
|
||||
arc << level.flags
|
||||
<< level.flags2
|
||||
<< level.fadeto
|
||||
<< level.found_secrets
|
||||
<< level.found_items
|
||||
<< level.killed_monsters
|
||||
<< level.gravity
|
||||
<< level.aircontrol
|
||||
<< level.teamdamage
|
||||
<< level.maptime
|
||||
<< i;
|
||||
|
||||
// Hub transitions must keep the current total time
|
||||
if (!hubLoad)
|
||||
level.totaltime = i;
|
||||
|
||||
arc << level.skytexture1 << level.skytexture2;
|
||||
if (arc.IsLoading())
|
||||
{
|
||||
sky1texture = level.skytexture1;
|
||||
sky2texture = level.skytexture2;
|
||||
R_InitSkyMap();
|
||||
}
|
||||
|
||||
G_AirControlChanged();
|
||||
|
||||
BYTE t;
|
||||
|
||||
// Does this level have scrollers?
|
||||
if (arc.IsStoring())
|
||||
{
|
||||
t = level.Scrolls ? 1 : 0;
|
||||
arc << t;
|
||||
}
|
||||
else
|
||||
{
|
||||
arc << t;
|
||||
if (level.Scrolls)
|
||||
{
|
||||
delete[] level.Scrolls;
|
||||
level.Scrolls = NULL;
|
||||
}
|
||||
if (t)
|
||||
{
|
||||
level.Scrolls = new FSectorScrollValues[numsectors];
|
||||
memset(level.Scrolls, 0, sizeof(level.Scrolls)*numsectors);
|
||||
}
|
||||
}
|
||||
|
||||
FBehavior::StaticSerializeModuleStates(arc);
|
||||
if (arc.IsLoading()) interpolator.ClearInterpolations();
|
||||
P_SerializeWorld(arc);
|
||||
P_SerializeThinkers(arc, hubLoad);
|
||||
P_SerializeWorldActors(arc); // serializing actor pointers in the world data must be done after SerializeWorld has restored the entire sector state, otherwise LinkToWorld may fail.
|
||||
P_SerializePolyobjs(arc);
|
||||
P_SerializeSubsectors(arc);
|
||||
StatusBar->Serialize(arc);
|
||||
|
||||
arc << level.total_monsters << level.total_items << level.total_secrets;
|
||||
|
||||
#if 0
|
||||
// Does this level have custom translations?
|
||||
FRemapTable *trans;
|
||||
WORD w;
|
||||
|
@ -969,17 +976,17 @@ void G_SerializeLevel(FArchive &arc, bool hubLoad)
|
|||
|
||||
// This must be saved, too, of course!
|
||||
FCanvasTextureInfo::Serialize(arc);
|
||||
AM_SerializeMarkers(arc);
|
||||
//AM_SerializeMarkers(arc);
|
||||
|
||||
P_SerializePlayers(arc, hubLoad);
|
||||
P_SerializeSounds(arc);
|
||||
if (arc.IsLoading())
|
||||
{
|
||||
for (i = 0; i < numsectors; i++)
|
||||
for (int i = 0; i < numsectors; i++)
|
||||
{
|
||||
P_Recalculate3DFloors(§ors[i]);
|
||||
}
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
for (int i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (playeringame[i] && players[i].mo != NULL)
|
||||
{
|
||||
|
@ -988,7 +995,6 @@ void G_SerializeLevel(FArchive &arc, bool hubLoad)
|
|||
}
|
||||
}
|
||||
Renderer->EndSerialize(arc);
|
||||
unsigned tt = I_MSTime();
|
||||
Printf("Serialization took %d ms\n", tt - tm);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -220,8 +220,8 @@ void DScroller::Tick ()
|
|||
|
||||
// [RH] Don't actually carry anything here. That happens later.
|
||||
case EScroll::sc_carry:
|
||||
level.Scrolls[m_Affectee].Scroll.X += dx;
|
||||
level.Scrolls[m_Affectee].Scroll.Y += dy;
|
||||
level.Scrolls[m_Affectee].X += dx;
|
||||
level.Scrolls[m_Affectee].Y += dy;
|
||||
break;
|
||||
|
||||
case EScroll::sc_carry_ceiling: // to be added later
|
||||
|
|
|
@ -3552,11 +3552,7 @@ void P_FreeLevelData ()
|
|||
po_NumPolyobjs = 0;
|
||||
Zones.Clear();
|
||||
P_FreeStrifeConversations ();
|
||||
if (level.Scrolls != NULL)
|
||||
{
|
||||
delete[] level.Scrolls;
|
||||
level.Scrolls = NULL;
|
||||
}
|
||||
level.Scrolls.Clear();
|
||||
P_ClearUDMFKeys();
|
||||
}
|
||||
|
||||
|
@ -3668,6 +3664,8 @@ void P_SetupLevel (const char *lumpname, int position)
|
|||
I_Error("Unable to open map '%s'\n", lumpname);
|
||||
}
|
||||
|
||||
// generate a checksum for the level, to be included and checked with savegames.
|
||||
map->GetChecksum(level.md5);
|
||||
// find map num
|
||||
level.lumpnum = map->lumpnum;
|
||||
hasglnodes = false;
|
||||
|
|
|
@ -197,48 +197,6 @@ void FLinePortalTraverse::AddLineIntercepts(int bx, int by)
|
|||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Save a line portal for savegames.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FLinePortal &port)
|
||||
{
|
||||
arc << port.mOrigin
|
||||
<< port.mDestination
|
||||
<< port.mDisplacement
|
||||
<< port.mType
|
||||
<< port.mFlags
|
||||
<< port.mDefFlags
|
||||
<< port.mAlign;
|
||||
return arc;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Save a sector portal for savegames.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FSectorPortal &port)
|
||||
{
|
||||
arc << port.mType
|
||||
<< port.mFlags
|
||||
<< port.mPartner
|
||||
<< port.mPlane
|
||||
<< port.mOrigin
|
||||
<< port.mDestination
|
||||
<< port.mDisplacement
|
||||
<< port.mPlaneZ;
|
||||
if (arc.IsLoading())
|
||||
{
|
||||
port.mSkybox = nullptr;
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// finds the destination for a line portal for spawning
|
||||
|
|
|
@ -534,6 +534,21 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr)
|
|||
return *this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
unsigned FSerializer::GetSize(const char *group)
|
||||
{
|
||||
if (isWriting()) return -1; // we do not know this when writing.
|
||||
|
||||
const rapidjson::Value &val = r->mDocObj[group];
|
||||
if (!val.IsArray()) return -1;
|
||||
return val.Size();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Writes out all collected objects
|
||||
|
|
|
@ -40,6 +40,7 @@ public:
|
|||
bool BeginArray(const char *name);
|
||||
void EndArray();
|
||||
void WriteObjects();
|
||||
unsigned GetSize(const char *group);
|
||||
const char *GetOutput(unsigned *len = nullptr);
|
||||
FSerializer &Args(const char *key, int *args, int *defargs, int special);
|
||||
FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr);
|
||||
|
|
|
@ -599,3 +599,45 @@ void P_SerializeACSScriptNumber(FArchive &arc, int &scriptnum, bool was2byte)
|
|||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Save a line portal for savegames.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FLinePortal &port)
|
||||
{
|
||||
arc << port.mOrigin
|
||||
<< port.mDestination
|
||||
<< port.mDisplacement
|
||||
<< port.mType
|
||||
<< port.mFlags
|
||||
<< port.mDefFlags
|
||||
<< port.mAlign;
|
||||
return arc;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// Save a sector portal for savegames.
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
FArchive &operator<< (FArchive &arc, FSectorPortal &port)
|
||||
{
|
||||
arc << port.mType
|
||||
<< port.mFlags
|
||||
<< port.mPartner
|
||||
<< port.mPlane
|
||||
<< port.mOrigin
|
||||
<< port.mDestination
|
||||
<< port.mDisplacement
|
||||
<< port.mPlaneZ;
|
||||
if (arc.IsLoading())
|
||||
{
|
||||
port.mSkybox = nullptr;
|
||||
}
|
||||
return arc;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue