From c665cc53f9aa455a156a6dfe7b13ec9d165437ef Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 19 Sep 2016 10:34:54 +0200 Subject: [PATCH] - moved new code to its proper location and started moving the replaced old archive code to a placeholder file for easy removal later. --- src/actor.h | 1 + src/dobject.cpp | 3 +- src/dthinker.cpp | 4 + src/dthinker.h | 1 + src/farchive.cpp | 145 --------- src/g_level.cpp | 131 -------- src/json.cpp | 496 +---------------------------- src/p_mobj.cpp | 388 +++++++++++------------ src/p_saveg.cpp | 775 ++++++++++++++++++++++++++++++--------------- src/p_saveg.h | 2 + src/p_states.cpp | 65 ---- src/serializer.cpp | 16 +- src/zzz_old.cpp | 697 ++++++++++++++++++++++++++++++++++++++++ 13 files changed, 1431 insertions(+), 1293 deletions(-) create mode 100644 src/zzz_old.cpp diff --git a/src/actor.h b/src/actor.h index d01f8db88..fcfeb4fce 100644 --- a/src/actor.h +++ b/src/actor.h @@ -585,6 +585,7 @@ public: void Serialize (FArchive &arc); void Serialize(FSerializer &arc); + void PostSerialize(); static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false); diff --git a/src/dobject.cpp b/src/dobject.cpp index 82014c133..c70a51e9a 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -48,6 +48,7 @@ #include "a_sharedglobal.h" #include "dsectoreffect.h" #include "farchive.h" +#include "serializer.h" ClassReg DObject::RegistrationInfo = { @@ -479,7 +480,7 @@ void DObject::SerializeUserVars(FArchive &arc) } } -void DObject::Serialize (FArchive &arc) +void DObject::Serialize(FSerializer &arc) { ObjectFlags |= OF_SerialSuccess; } diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 176df6c18..0efcecbdd 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -261,6 +261,10 @@ void DThinker::PostBeginPlay () { } +void DThinker::PostSerialize() +{ +} + DThinker *DThinker::FirstThinker (int statnum) { DThinker *node; diff --git a/src/dthinker.h b/src/dthinker.h index b68c2e320..d423c3454 100644 --- a/src/dthinker.h +++ b/src/dthinker.h @@ -70,6 +70,7 @@ public: virtual ~DThinker (); virtual void Tick (); virtual void PostBeginPlay (); // Called just before the first tick + virtual void PostSerialize(); size_t PropagateMark(); void ChangeStatNum (int statnum); diff --git a/src/farchive.cpp b/src/farchive.cpp index de3e248a4..8bb39b35f 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -1085,109 +1085,6 @@ FArchive &FArchive::SerializeObject (DObject *&object, PClass *type) } } -FArchive &FArchive::WriteObject (DObject *obj) -{ - player_t *player; - BYTE id[2]; - - if (obj == NULL) - { - id[0] = NULL_OBJ; - Write (id, 1); - } - else if (obj == (DObject*)~0) - { - id[0] = M1_OBJ; - Write (id, 1); - } - else if (obj->ObjectFlags & OF_EuthanizeMe) - { - // Objects that want to die are not saved to the archive, but - // we leave the pointers to them alone. - id[0] = NULL_OBJ; - Write (id, 1); - } - else - { - PClass *type = obj->GetClass(); - DWORD *classarcid; - - if (type == RUNTIME_CLASS(DObject)) - { - //I_Error ("Tried to save an instance of DObject.\n" - // "This should not happen.\n"); - id[0] = NULL_OBJ; - Write (id, 1); - } - else if (NULL == (classarcid = ClassToArchive.CheckKey(type))) - { - // No instances of this class have been written out yet. - // Write out the class, then write out the object. If this - // is an actor controlled by a player, make note of that - // so that it can be overridden when moving around in a hub. - if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && - (player = static_cast(obj)->player) && - player->mo == obj) - { - id[0] = NEW_PLYR_CLS_OBJ; - id[1] = (BYTE)(player - players); - Write (id, 2); - } - else - { - id[0] = NEW_CLS_OBJ; - Write (id, 1); - } - WriteClass (type); -// Printf ("Make class %s (%u)\n", type->Name, m_File->Tell()); - MapObject (obj); - obj->SerializeUserVars (*this); - obj->Serialize (*this); - obj->CheckIfSerialized (); - } - else - { - // An instance of this class has already been saved. If - // this object has already been written, save a reference - // to the saved object. Otherwise, save a reference to the - // class, then save the object. Again, if this is a player- - // controlled actor, remember that. - DWORD *objarcid = ObjectToArchive.CheckKey(obj); - - if (objarcid == NULL) - { - - if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && - (player = static_cast(obj)->player) && - player->mo == obj) - { - id[0] = NEW_PLYR_OBJ; - id[1] = (BYTE)(player - players); - Write (id, 2); - } - else - { - id[0] = NEW_OBJ; - Write (id, 1); - } - WriteCount (*classarcid); -// Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell()); - MapObject (obj); - obj->SerializeUserVars (*this); - obj->Serialize (*this); - obj->CheckIfSerialized (); - } - else - { - id[0] = OLD_OBJ; - Write (id, 1); - WriteCount (*objarcid); - } - } - } - return *this; -} - FArchive &FArchive::ReadObject (DObject* &obj, PClass *wanttype) { BYTE objHead; @@ -1545,45 +1442,3 @@ void FArchive::UserReadClass (PClass *&type) } } -FArchive &operator<< (FArchive &arc, sector_t *&sec) -{ - return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors)); -} - -FArchive &operator<< (FArchive &arc, const sector_t *&sec) -{ - return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors)); -} - -FArchive &operator<< (FArchive &arc, line_t *&line) -{ - return arc.SerializePointer (lines, (BYTE **)&line, sizeof(*lines)); -} - -FArchive &operator<< (FArchive &arc, vertex_t *&vert) -{ - return arc.SerializePointer (vertexes, (BYTE **)&vert, sizeof(*vertexes)); -} - -FArchive &operator<< (FArchive &arc, side_t *&side) -{ - return arc.SerializePointer (sides, (BYTE **)&side, sizeof(*sides)); -} - -FArchive &operator<<(FArchive &arc, DAngle &ang) -{ - arc << ang.Degrees; - return arc; -} - -FArchive &operator<<(FArchive &arc, DVector3 &vec) -{ - arc << vec.X << vec.Y << vec.Z; - return arc; -} - -FArchive &operator<<(FArchive &arc, DVector2 &vec) -{ - arc << vec.X << vec.Y; - return arc; -} diff --git a/src/g_level.cpp b/src/g_level.cpp index e71ecc1a1..4388fc00c 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1474,137 +1474,6 @@ void G_AirControlChanged () } } -//========================================================================== -// -// -//========================================================================== - -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; - - // Does this level have custom translations? - FRemapTable *trans; - WORD w; - if (arc.IsStoring ()) - { - for (unsigned int i = 0; i < translationtables[TRANSLATION_LevelScripted].Size(); ++i) - { - trans = translationtables[TRANSLATION_LevelScripted][i]; - if (trans != NULL && !trans->IsIdentity()) - { - w = WORD(i); - arc << w; - trans->Serialize(arc); - } - } - w = 0xffff; - arc << w; - } - else - { - while (arc << w, w != 0xffff) - { - trans = translationtables[TRANSLATION_LevelScripted].GetVal(w); - if (trans == NULL) - { - trans = new FRemapTable; - translationtables[TRANSLATION_LevelScripted].SetVal(w, trans); - } - trans->Serialize(arc); - } - } - - // This must be saved, too, of course! - FCanvasTextureInfo::Serialize (arc); - AM_SerializeMarkers(arc); - - P_SerializePlayers (arc, hubLoad); - P_SerializeSounds (arc); - if (arc.IsLoading()) - { - for (i = 0; i < numsectors; i++) - { - P_Recalculate3DFloors(§ors[i]); - } - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].mo != NULL) - { - players[i].mo->SetupWeaponSlots(); - } - } - } - Renderer->EndSerialize(arc); - unsigned tt = I_MSTime(); - Printf("Serialization took %d ms\n", tt - tm); -} - //========================================================================== // // Archives the current level diff --git a/src/json.cpp b/src/json.cpp index 3c455d52c..c3fb88247 100644 --- a/src/json.cpp +++ b/src/json.cpp @@ -11,324 +11,6 @@ // //========================================================================== -FSerializer &Serialize(FSerializer &arc, const char *key, line_t &line, line_t *def) -{ - if (arc.BeginObject(key)) - { - arc("flags", line.flags, def->flags) - ("activation", line.activation, def->activation) - ("special", line.special, def->special) - ("alpha", line.alpha, def->alpha) - .Args("args", line.args, def->args, line.special) - ("portalindex", line.portalindex, def->portalindex) - // no need to store the sidedef references. Unless the map loader is changed they will not change between map loads. - //.Array("sides", line.sidedef, 2) - .EndObject(); - } - return arc; - -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, side_t::part *def) -{ - if (arc.canSkip() && def != nullptr && !memcmp(&part, def, sizeof(part))) - { - return arc; - } - - if (arc.BeginObject(key)) - { - arc("xoffset", part.xOffset, def->xOffset) - ("yoffset", part.yOffset, def->yOffset) - ("xscale", part.xScale, def->xScale) - ("yscale", part.yScale, def->yScale) - ("texture", part.texture, def->texture) - ("interpolation", part.interpolation) - .EndObject(); - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, side_t &side, side_t *def) -{ - if (arc.BeginObject(key)) - { - arc.Array("textures", side.textures, def->textures, 3, true) - ("light", side.Light, def->Light) - ("flags", side.Flags, def->Flags) - //("leftside", side.LeftSide) - //("rightside", side.RightSide) - //("index", side.Index) - ("attacheddecals", side.AttachedDecals) - .EndObject(); - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, FLinkedSector &ls, FLinkedSector *def) -{ - if (arc.BeginObject(key)) - { - arc("sector", ls.Sector) - ("type", ls.Type) - .EndObject(); - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, sector_t::splane &p, sector_t::splane *def) -{ - if (arc.canSkip() && def != nullptr && !memcmp(&p, def, sizeof(p))) - { - return arc; - } - - if (arc.BeginObject(key)) - { - arc("xoffs", p.xform.xOffs, def->xform.xOffs) - ("yoffs", p.xform.yOffs, def->xform.yOffs) - ("xscale", p.xform.xScale, def->xform.xScale) - ("yscale", p.xform.yScale, def->xform.yScale) - ("angle", p.xform.Angle, def->xform.Angle) - ("baseyoffs", p.xform.baseyOffs, def->xform.baseyOffs) - ("baseangle", p.xform.baseAngle, def->xform.baseAngle) - ("flags", p.Flags, def->Flags) - ("light", p.Light, def->Light) - ("texture", p.Texture, def->Texture) - ("texz", p.TexZ, def->TexZ) - ("alpha", p.alpha, def->alpha) - .EndObject(); - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def) -{ - if (arc.canSkip() && def != nullptr && !memcmp(&p, def, sizeof(p))) - { - return arc; - } - - if (arc.BeginObject(key)) - { - arc("normal", p.normal, def->normal) - ("d", p.D, def->D) - .EndObject(); - - if (arc.isReading() && p.normal.Z != 0) - { - p.negiC = 1 / p.normal.Z; - } - } - return arc; -} - -//========================================================================== -// -// -// -//========================================================================== - -FSerializer &Serialize(FSerializer &arc, const char *key, sector_t &p, sector_t *def) -{ - if (arc.BeginObject(key)) - { - arc("floorplane", p.floorplane, def->floorplane) - ("ceilingplane", p.ceilingplane, def->ceilingplane) - ("lightlevel", p.lightlevel, def->lightlevel) - ("special", p.special, def->special) - ("soundtraversed", p.soundtraversed, def->soundtraversed) - ("seqtype", p.seqType, def->seqType) - ("seqname", p.SeqName, def->SeqName) - ("friction", p.friction, def->friction) - ("movefactor", p.movefactor, def->movefactor) - ("stairlock", p.stairlock, def->stairlock) - ("prevsec", p.prevsec, def->prevsec) - ("nextsec", p.nextsec, def->nextsec) - .Array("planes", p.planes, def->planes, 2, true) - //("heightsec", p.heightsec) - //("bottommap", p.bottommap) - //("midmap", p.midmap) - //("topmap", p.topmap) - ("damageamount", p.damageamount, def->damageamount) - ("damageinterval", p.damageinterval, def->damageinterval) - ("leakydamage", p.leakydamage, def->leakydamage) - ("damagetype", p.damagetype, def->damagetype) - ("sky", p.sky, def->sky) - ("moreflags", p.MoreFlags, def->MoreFlags) - ("flags", p.Flags, def->Flags) - .Array("portals", p.Portals, def->Portals, 2, true) - ("zonenumber", p.ZoneNumber, def->ZoneNumber) - .Array("interpolations", p.interpolations, 4, true) - ("soundtarget", p.SoundTarget) - ("secacttarget", p.SecActTarget) - ("floordata", p.floordata) - ("ceilingdata", p.ceilingdata) - ("lightingdata", p.lightingdata) - ("fakefloor_sectors", p.e->FakeFloor.Sectors) - ("midtexf_lines", p.e->Midtex.Floor.AttachedLines) - ("midtexf_sectors", p.e->Midtex.Floor.AttachedSectors) - ("midtexc_lines", p.e->Midtex.Ceiling.AttachedLines) - ("midtexc_sectors", p.e->Midtex.Ceiling.AttachedSectors) - ("linked_floor", p.e->Linked.Floor.Sectors) - ("linked_ceiling", p.e->Linked.Ceiling.Sectors) - ("colormap", p.ColorMap, def->ColorMap) - .Terrain("floorterrain", p.terrainnum[0], &def->terrainnum[0]) - .Terrain("ceilingterrain", p.terrainnum[1], &def->terrainnum[1]) - .EndObject(); - } - return arc; -} - - -FSerializer &Serialize(FSerializer &arc, const char *key, subsector_t *&ss, subsector_t **) -{ - BYTE by; - const char *str; - - if (arc.isWriting()) - { - if (hasglnodes) - { - TArray encoded(1 + (numsubsectors + 5) / 6); - int p = 0; - for (int i = 0; i < numsubsectors; i += 6) - { - by = 0; - for (int j = 0; j < 6; j++) - { - if (i + j < numsubsectors && (subsectors[i + j].flags & SSECF_DRAWN)) - { - by |= (1 << j); - } - } - if (by < 10) by += '0'; - else if (by < 36) by += 'A' - 10; - else if (by < 62) by += 'a' - 36; - else if (by == 62) by = '-'; - else if (by == 63) by = '+'; - encoded[p++] = by; - } - encoded[p] = 0; - str = &encoded[0]; - if (arc.BeginArray(key)) - { - arc(nullptr, numvertexes) - (nullptr, numsubsectors) - .StringPtr(nullptr, str) - .EndArray(); - } - } - } - else - { - int num_verts, num_subs; - - if (arc.BeginArray(key)) - { - arc(nullptr, num_verts) - (nullptr, num_subs) - .StringPtr(nullptr, str) - .EndArray(); - } - - } - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, ReverbContainer *&c, ReverbContainer **def) -{ - int id = (arc.isReading() || c == nullptr) ? 0 : c->ID; - Serialize(arc, key, id, nullptr); - if (arc.isReading()) - { - c = S_FindEnvironment(id); - } - return arc; -} - -FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z, zone_t *def) -{ - return Serialize(arc, key, z.Environment, nullptr); -} - -//============================================================================ -// -// Save a line portal for savegames. -// -//============================================================================ - -FSerializer &Serialize(FSerializer &arc, const char *key, FLinePortal &port, FLinePortal *def) -{ - if (arc.BeginObject(key)) - { - arc("origin", port.mOrigin) - ("destination", port.mDestination) - ("displacement", port.mDisplacement) - ("type", port.mType) - ("flags", port.mFlags) - ("defflags", port.mDefFlags) - ("align", port.mAlign) - .EndObject(); - } - return arc; -} - -//============================================================================ -// -// Save a sector portal for savegames. -// -//============================================================================ - -FSerializer &Serialize(FSerializer &arc, const char *key, FSectorPortal &port, FSectorPortal *def) -{ - if (arc.BeginObject(key)) - { - arc("type", port.mType) - ("flags", port.mFlags) - ("partner", port.mPartner) - ("plane", port.mPlane) - ("origin", port.mOrigin) - ("destination", port.mDestination) - ("displacement", port.mDisplacement) - ("planez", port.mPlaneZ) - ("skybox", port.mSkybox) - .EndObject(); - } - return arc; -} - - void DThinker::SaveList(FSerializer &arc, DThinker *node) { if (node != NULL) @@ -368,17 +50,6 @@ void DThinker::SerializeThinkers(FSerializer &arc, bool hubLoad) -void SerializeWorld(FSerializer &arc) -{ - 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); -} - void DObject::SerializeUserVars(FSerializer &arc) { PSymbolTable *symt; @@ -399,174 +70,9 @@ void DObject::SerializeUserVars(FSerializer &arc) } } -void DObject::Serialize(FSerializer &arc) -{ - ObjectFlags |= OF_SerialSuccess; -} - -//========================================================================== -// -// AActor :: Serialize -// -//========================================================================== - -#define A(a,b) ((a), (b), def->b) - -void AActor::Serialize(FSerializer &arc) -{ - int damage = 0; // just a placeholder until the insanity surrounding the damage property can be fixed - AActor *def = GetDefault(); - - Super::Serialize(arc); - - arc - .Sprite("sprite", sprite, &def->sprite) - A("pos", __Pos) - A("angles", Angles) - A("frame", frame) - A("scale", Scale) - A("renderstyle", RenderStyle) - A("renderflags", renderflags) - A("picnum", picnum) - A("floorpic", floorpic) - A("ceilingpic", ceilingpic) - A("tidtohate", TIDtoHate) - A("lastlookpn", LastLookPlayerNumber) - ("lastlookactor", LastLookActor) - A("effects", effects) - A("alpha", Alpha) - A("fillcolor", fillcolor) - A("sector", Sector) - A("floorz", floorz) - A("ceilingz", ceilingz) - A("dropoffz", dropoffz) - A("floorsector", floorsector) - A("ceilingsector", ceilingsector) - A("radius", radius) - A("height", Height) - A("ppassheight", projectilepassheight) - A("vel", Vel) - A("tics", tics) - A("state", state) - ("damage", damage) - .Terrain("floorterrain", floorterrain, &def->floorterrain) - A("projectilekickback", projectileKickback) - A("flags", flags) - A("flags2", flags2) - A("flags3", flags3) - A("flags4", flags4) - A("flags5", flags5) - A("flags6", flags6) - A("flags7", flags7) - A("weaponspecial", weaponspecial) - A("special1", special1) - A("special2", special2) - A("specialf1", specialf1) - A("specialf2", specialf2) - A("health", health) - A("movedir", movedir) - A("visdir", visdir) - A("movecount", movecount) - A("strafecount", strafecount) - ("target", target) - ("lastenemy", lastenemy) - ("lastheard", LastHeard) - A("reactiontime", reactiontime) - A("threshold", threshold) - A("player", player) - A("spawnpoint", SpawnPoint) - A("spawnangle", SpawnAngle) - A("starthealth", StartHealth) - A("skillrespawncount", skillrespawncount) - ("tracer", tracer) - A("floorclip", Floorclip) - A("tid", tid) - A("special", special) - .Args("args", args, def->args, special) - A("accuracy", accuracy) - A("stamina", stamina) - ("goal", goal) - A("waterlevel", waterlevel) - A("minmissilechance", MinMissileChance) - A("spawnflags", SpawnFlags) - ("inventory", Inventory) - A("inventoryid", InventoryID) - A("floatbobphase", FloatBobPhase) - A("translation", Translation) - A("seesound", SeeSound) - A("attacksound", AttackSound) - A("paimsound", PainSound) - A("deathsound", DeathSound) - A("activesound", ActiveSound) - A("usesound", UseSound) - A("bouncesound", BounceSound) - A("wallbouncesound", WallBounceSound) - A("crushpainsound", CrushPainSound) - A("speed", Speed) - A("floatspeed", FloatSpeed) - A("mass", Mass) - A("painchance", PainChance) - A("spawnstate", SpawnState) - A("seestate", SeeState) - A("meleestate", MeleeState) - A("missilestate", MissileState) - A("maxdropoffheight", MaxDropOffHeight) - A("maxstepheight", MaxStepHeight) - A("bounceflags", BounceFlags) - A("bouncefactor", bouncefactor) - A("wallbouncefactor", wallbouncefactor) - A("bouncecount", bouncecount) - A("maxtargetrange", maxtargetrange) - A("meleethreshold", meleethreshold) - A("meleerange", meleerange) - A("damagetype", DamageType) - A("damagetypereceived", DamageTypeReceived) - A("paintype", PainType) - A("deathtype", DeathType) - A("gravity", Gravity) - A("fastchasestrafecount", FastChaseStrafeCount) - ("master", master) - A("smokecounter", smokecounter) - ("blockingmobj", BlockingMobj) - A("blockingline", BlockingLine) - A("visibletoteam", VisibleToTeam) - A("pushfactor", pushfactor) - A("species", Species) - A("score", Score) - A("designatedteam", DesignatedTeam) - A("lastpush", lastpush) - A("lastbump", lastbump) - A("painthreshold", PainThreshold) - A("damagefactor", DamageFactor) - A("damagemultiply", DamageMultiply) - A("waveindexxy", WeaveIndexXY) - A("weaveindexz", WeaveIndexZ) - A("pdmgreceived", PoisonDamageReceived) - A("pdurreceived", PoisonDurationReceived) - A("ppreceived", PoisonPeriodReceived) - ("poisoner", Poisoner) - A("posiondamage", PoisonDamage) - A("poisonduration", PoisonDuration) - A("poisonperiod", PoisonPeriod) - A("poisondamagetype", PoisonDamageType) - A("poisondmgtypereceived", PoisonDamageTypeReceived) - A("conversationroot", ConversationRoot) - A("conversation", Conversation) - A("friendplayer", FriendPlayer) - A("telefogsourcetype", TeleFogSourceType) - A("telefogdesttype", TeleFogDestType) - A("ripperlevel", RipperLevel) - A("riplevelmin", RipLevelMin) - A("riplevelmax", RipLevelMax) - A("devthreshold", DefThreshold) - A("spriteangle", SpriteAngle) - A("spriterotation", SpriteRotation) - ("alternative", alternative) - A("tag", Tag); -} - +void SerializeWorld(FSerializer &arc); CCMD(writejson) { diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 3ecf5c76c..2459f79af 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -70,6 +70,7 @@ #include "po_man.h" #include "p_spec.h" #include "p_checkposition.h" +#include "serializer.h" // MACROS ------------------------------------------------------------------ @@ -155,214 +156,195 @@ AActor::~AActor () // //========================================================================== -void AActor::Serialize(FArchive &arc) +#define A(a,b) ((a), (b), def->b) + +void AActor::Serialize(FSerializer &arc) { + AActor *def = GetDefault(); + Super::Serialize(arc); - if (arc.IsStoring()) - { - arc.WriteSprite(sprite); - } - else - { - sprite = arc.ReadSprite(); - } - - arc << __Pos - << Angles.Yaw - << Angles.Pitch - << Angles.Roll - << frame - << Scale - << RenderStyle - << renderflags - << picnum - << floorpic - << ceilingpic - << TIDtoHate - << LastLookPlayerNumber - << LastLookActor - << effects - << Alpha - << fillcolor - << Sector - << floorz - << ceilingz - << dropoffz - << floorsector - << ceilingsector - << radius - << Height - << projectilepassheight - << Vel - << tics - << state - << DamageVal; - if (DamageVal == 0x40000000 || DamageVal == -1) - { - DamageVal = -1; - DamageFunc = GetDefault()->DamageFunc; - } - else - { - DamageFunc = nullptr; - } - P_SerializeTerrain(arc, floorterrain); - arc << projectileKickback - << flags - << flags2 - << flags3 - << flags4 - << flags5 - << flags6 - << flags7 - << weaponspecial - << special1 - << special2 - << specialf1 - << specialf2 - << health - << movedir - << visdir - << movecount - << strafecount - << target - << lastenemy - << LastHeard - << reactiontime - << threshold - << player - << SpawnPoint - << SpawnAngle - << StartHealth - << skillrespawncount - << tracer - << Floorclip - << tid - << special; - if (P_IsACSSpecial(special)) - { - P_SerializeACSScriptNumber(arc, args[0], false); - } - else - { - arc << args[0]; - } - arc << args[1] << args[2] << args[3] << args[4]; - arc << accuracy << stamina; - arc << goal - << waterlevel - << MinMissileChance - << SpawnFlags - << Inventory - << InventoryID; - arc << FloatBobPhase - << Translation - << SeeSound - << AttackSound - << PainSound - << DeathSound - << ActiveSound - << UseSound - << BounceSound - << WallBounceSound - << CrushPainSound - << Speed - << FloatSpeed - << Mass - << PainChance - << SpawnState - << SeeState - << MeleeState - << MissileState - << MaxDropOffHeight - << MaxStepHeight - << BounceFlags - << bouncefactor - << wallbouncefactor - << bouncecount - << maxtargetrange - << meleethreshold - << meleerange - << DamageType; - arc << DamageTypeReceived; - arc << PainType - << DeathType; - arc << Gravity - << FastChaseStrafeCount - << master - << smokecounter - << BlockingMobj - << BlockingLine - << VisibleToTeam // [BB] - << pushfactor - << Species - << Score; - arc << DesignatedTeam; - arc << lastpush << lastbump - << PainThreshold - << DamageFactor; - arc << DamageMultiply; - arc << WeaveIndexXY << WeaveIndexZ - << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner - << PoisonDamage << PoisonDuration << PoisonPeriod; - arc << PoisonDamageType << PoisonDamageTypeReceived; - arc << ConversationRoot << Conversation; - arc << FriendPlayer; - arc << TeleFogSourceType - << TeleFogDestType; - arc << RipperLevel - << RipLevelMin - << RipLevelMax; - arc << DefThreshold; - if (SaveVersion >= 4549) - { - arc << SpriteAngle; - arc << SpriteRotation; - } - - if (SaveVersion >= 4550) - { - arc << alternative; - } - - { - FString tagstr; - if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; - arc << tagstr; - if (arc.IsLoading()) - { - if (tagstr.Len() == 0) Tag = NULL; - else Tag = mStringPropertyData.Alloc(tagstr); - } - } - - if (arc.IsLoading ()) - { - touching_sectorlist = NULL; - LinkToWorld(false, Sector); - - AddToHash (); - SetShade (fillcolor); - if (player) - { - if (playeringame[player - players] && - player->cls != NULL && - !(flags4 & MF4_NOSKIN) && - state->sprite == GetDefaultByType (player->cls)->SpawnState->sprite) - { // Give player back the skin - sprite = skins[player->userinfo.GetSkin()].sprite; - } - if (Speed == 0) - { - Speed = GetDefault()->Speed; - } - } - ClearInterpolation(); - UpdateWaterLevel(false); - } + arc + .Sprite("sprite", sprite, &def->sprite) + A("pos", __Pos) + A("angles", Angles) + A("frame", frame) + A("scale", Scale) + A("renderstyle", RenderStyle) + A("renderflags", renderflags) + A("picnum", picnum) + A("floorpic", floorpic) + A("ceilingpic", ceilingpic) + A("tidtohate", TIDtoHate) + A("lastlookpn", LastLookPlayerNumber) + ("lastlookactor", LastLookActor) + A("effects", effects) + A("alpha", Alpha) + A("fillcolor", fillcolor) + A("sector", Sector) + A("floorz", floorz) + A("ceilingz", ceilingz) + A("dropoffz", dropoffz) + A("floorsector", floorsector) + A("ceilingsector", ceilingsector) + A("radius", radius) + A("height", Height) + A("ppassheight", projectilepassheight) + A("vel", Vel) + A("tics", tics) + A("state", state) + A("damage", DamageVal) + .Terrain("floorterrain", floorterrain, &def->floorterrain) + A("projectilekickback", projectileKickback) + A("flags", flags) + A("flags2", flags2) + A("flags3", flags3) + A("flags4", flags4) + A("flags5", flags5) + A("flags6", flags6) + A("flags7", flags7) + A("weaponspecial", weaponspecial) + A("special1", special1) + A("special2", special2) + A("specialf1", specialf1) + A("specialf2", specialf2) + A("health", health) + A("movedir", movedir) + A("visdir", visdir) + A("movecount", movecount) + A("strafecount", strafecount) + ("target", target) + ("lastenemy", lastenemy) + ("lastheard", LastHeard) + A("reactiontime", reactiontime) + A("threshold", threshold) + A("player", player) + A("spawnpoint", SpawnPoint) + A("spawnangle", SpawnAngle) + A("starthealth", StartHealth) + A("skillrespawncount", skillrespawncount) + ("tracer", tracer) + A("floorclip", Floorclip) + A("tid", tid) + A("special", special) + .Args("args", args, def->args, special) + A("accuracy", accuracy) + A("stamina", stamina) + ("goal", goal) + A("waterlevel", waterlevel) + A("minmissilechance", MinMissileChance) + A("spawnflags", SpawnFlags) + ("inventory", Inventory) + A("inventoryid", InventoryID) + A("floatbobphase", FloatBobPhase) + A("translation", Translation) + A("seesound", SeeSound) + A("attacksound", AttackSound) + A("paimsound", PainSound) + A("deathsound", DeathSound) + A("activesound", ActiveSound) + A("usesound", UseSound) + A("bouncesound", BounceSound) + A("wallbouncesound", WallBounceSound) + A("crushpainsound", CrushPainSound) + A("speed", Speed) + A("floatspeed", FloatSpeed) + A("mass", Mass) + A("painchance", PainChance) + A("spawnstate", SpawnState) + A("seestate", SeeState) + A("meleestate", MeleeState) + A("missilestate", MissileState) + A("maxdropoffheight", MaxDropOffHeight) + A("maxstepheight", MaxStepHeight) + A("bounceflags", BounceFlags) + A("bouncefactor", bouncefactor) + A("wallbouncefactor", wallbouncefactor) + A("bouncecount", bouncecount) + A("maxtargetrange", maxtargetrange) + A("meleethreshold", meleethreshold) + A("meleerange", meleerange) + A("damagetype", DamageType) + A("damagetypereceived", DamageTypeReceived) + A("paintype", PainType) + A("deathtype", DeathType) + A("gravity", Gravity) + A("fastchasestrafecount", FastChaseStrafeCount) + ("master", master) + A("smokecounter", smokecounter) + ("blockingmobj", BlockingMobj) + A("blockingline", BlockingLine) + A("visibletoteam", VisibleToTeam) + A("pushfactor", pushfactor) + A("species", Species) + A("score", Score) + A("designatedteam", DesignatedTeam) + A("lastpush", lastpush) + A("lastbump", lastbump) + A("painthreshold", PainThreshold) + A("damagefactor", DamageFactor) + A("damagemultiply", DamageMultiply) + A("waveindexxy", WeaveIndexXY) + A("weaveindexz", WeaveIndexZ) + A("pdmgreceived", PoisonDamageReceived) + A("pdurreceived", PoisonDurationReceived) + A("ppreceived", PoisonPeriodReceived) + ("poisoner", Poisoner) + A("posiondamage", PoisonDamage) + A("poisonduration", PoisonDuration) + A("poisonperiod", PoisonPeriod) + A("poisondamagetype", PoisonDamageType) + A("poisondmgtypereceived", PoisonDamageTypeReceived) + A("conversationroot", ConversationRoot) + A("conversation", Conversation) + A("friendplayer", FriendPlayer) + A("telefogsourcetype", TeleFogSourceType) + A("telefogdesttype", TeleFogDestType) + A("ripperlevel", RipperLevel) + A("riplevelmin", RipLevelMin) + A("riplevelmax", RipLevelMax) + A("devthreshold", DefThreshold) + A("spriteangle", SpriteAngle) + A("spriterotation", SpriteRotation) + ("alternative", alternative) + A("tag", Tag); } +#undef A + +//========================================================================== +// +// This must be done after the world is set up. +// +//========================================================================== + +void AActor::PostSerialize() +{ + touching_sectorlist = NULL; + LinkToWorld(false, Sector); + + AddToHash(); + SetShade(fillcolor); + if (player) + { + if (playeringame[player - players] && + player->cls != NULL && + !(flags4 & MF4_NOSKIN) && + state->sprite == GetDefaultByType(player->cls)->SpawnState->sprite) + { // Give player back the skin + sprite = skins[player->userinfo.GetSkin()].sprite; + } + if (Speed == 0) + { + Speed = GetDefault()->Speed; + } + } + ClearInterpolation(); + UpdateWaterLevel(false); +} + + + AActor::AActor () throw() { } diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 3bbae666a..550e9455d 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -3,7 +3,8 @@ ** Code for serializing the world state in an archive ** **--------------------------------------------------------------------------- -** Copyright 1998-2006 Randy Heit +** Copyright 1998-2016 Randy Heit +** Copyright 2005-2016 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -55,18 +56,22 @@ #include "p_lnspec.h" #include "p_acs.h" #include "p_terrain.h" +#include "am_map.h" +#include "r_data/r_translate.h" +#include "sbar.h" +#include "r_utility.h" +#include "r_sky.h" +#include "r_renderer.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" void CopyPlayer (player_t *dst, player_t *src, const char *name); static void ReadOnePlayer (FArchive &arc, bool skipload); static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNow, bool skipload); static void SpawnExtraPlayers (); -inline FArchive &operator<< (FArchive &arc, FLinkedSector &link) -{ - arc << link.Sector << link.Type; - return arc; -} - // // P_ArchivePlayers // @@ -339,179 +344,6 @@ static void SpawnExtraPlayers () } } -// -// P_ArchiveWorld -// -void P_SerializeWorld (FArchive &arc) -{ - int i, j; - sector_t *sec; - line_t *li; - zone_t *zn; - - // do sectors - for (i = 0, sec = sectors; i < numsectors; i++, sec++) - { - arc << sec->floorplane - << sec->ceilingplane; - arc << sec->lightlevel; - arc << sec->special; - arc << sec->soundtraversed - << sec->seqType - << sec->friction - << sec->movefactor - << sec->stairlock - << sec->prevsec - << sec->nextsec - << sec->planes[sector_t::floor] - << sec->planes[sector_t::ceiling] - << sec->heightsec - << sec->bottommap << sec->midmap << sec->topmap - << sec->gravity; - P_SerializeTerrain(arc, sec->terrainnum[0]); - P_SerializeTerrain(arc, sec->terrainnum[1]); - arc << sec->damageamount; - arc << sec->damageinterval - << sec->leakydamage - << sec->damagetype - << sec->sky - << sec->MoreFlags - << sec->Flags - << sec->Portals[sector_t::floor] << sec->Portals[sector_t::ceiling] - << sec->ZoneNumber; - arc << sec->interpolations[0] - << sec->interpolations[1] - << sec->interpolations[2] - << sec->interpolations[3] - << sec->SeqName; - - sec->e->Serialize(arc); - if (arc.IsStoring ()) - { - arc << sec->ColorMap->Color - << sec->ColorMap->Fade; - BYTE sat = sec->ColorMap->Desaturate; - arc << sat; - } - else - { - PalEntry color, fade; - BYTE desaturate; - arc << color << fade - << desaturate; - sec->ColorMap = GetSpecialLights (color, fade, desaturate); - } - } - - // do lines - for (i = 0, li = lines; i < numlines; i++, li++) - { - arc << li->flags - << li->activation - << li->special - << li->alpha; - - if (P_IsACSSpecial(li->special)) - { - P_SerializeACSScriptNumber(arc, li->args[0], false); - } - else - { - arc << li->args[0]; - } - arc << li->args[1] << li->args[2] << li->args[3] << li->args[4]; - - arc << li->portalindex; - for (j = 0; j < 2; j++) - { - if (li->sidedef[j] == NULL) - continue; - - side_t *si = li->sidedef[j]; - arc << si->textures[side_t::top] - << si->textures[side_t::mid] - << si->textures[side_t::bottom] - << si->Light - << si->Flags - << si->LeftSide - << si->RightSide - << si->Index; - } - } - - // do zones - unsigned numzones = Zones.Size(); - arc << numzones; - - if (arc.IsLoading()) - { - Zones.Resize(numzones); - } - - for (i = 0, zn = &Zones[0]; i < numzones; ++i, ++zn) - { - arc << zn->Environment; - } - - arc << linePortals << sectorPortals; - P_CollectLinkedPortals(); -} - -void P_SerializeWorldActors(FArchive &arc) -{ - int i; - sector_t *sec; - line_t *line; - - for (i = 0, sec = sectors; i < numsectors; i++, sec++) - { - arc << sec->SoundTarget - << sec->SecActTarget - << sec->floordata - << sec->ceilingdata - << sec->lightingdata; - } - for (auto &s : sectorPortals) - { - arc << s.mSkybox; - } - for (i = 0, line = lines; i < numlines; i++, line++) - { - for (int s = 0; s < 2; s++) - { - if (line->sidedef[s] != NULL) - { - DBaseDecal::SerializeChain(arc, &line->sidedef[s]->AttachedDecals); - } - } - } -} - -void extsector_t::Serialize(FArchive &arc) -{ - arc << FakeFloor.Sectors - << Midtex.Floor.AttachedLines - << Midtex.Floor.AttachedSectors - << Midtex.Ceiling.AttachedLines - << Midtex.Ceiling.AttachedSectors - << Linked.Floor.Sectors - << Linked.Ceiling.Sectors; -} - -FArchive &operator<< (FArchive &arc, side_t::part &p) -{ - arc << p.xOffset << p.yOffset << p.interpolation << p.texture - << p.xScale << p.yScale;// << p.Light; - return arc; -} - -FArchive &operator<< (FArchive &arc, sector_t::splane &p) -{ - arc << p.xform.xOffs << p.xform.yOffs << p.xform.xScale << p.xform.yScale - << p.xform.Angle << p.xform.baseyOffs << p.xform.baseAngle - << p.Flags << p.Light << p.Texture << p.TexZ << p.alpha; - return arc; -} // @@ -537,6 +369,411 @@ void P_DestroyThinkers(bool hubLoad) DThinker::DestroyAllThinkers(); } +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, line_t &line, line_t *def) +{ + if (arc.BeginObject(key)) + { + arc("flags", line.flags, def->flags) + ("activation", line.activation, def->activation) + ("special", line.special, def->special) + ("alpha", line.alpha, def->alpha) + .Args("args", line.args, def->args, line.special) + ("portalindex", line.portalindex, def->portalindex) + // Unless the map loader is changed the sidedef references will not change between map loads so there's no need to save them. + //.Array("sides", line.sidedef, 2) + .EndObject(); + } + return arc; + +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, side_t::part &part, side_t::part *def) +{ + if (arc.canSkip() && def != nullptr && !memcmp(&part, def, sizeof(part))) + { + return arc; + } + + if (arc.BeginObject(key)) + { + arc("xoffset", part.xOffset, def->xOffset) + ("yoffset", part.yOffset, def->yOffset) + ("xscale", part.xScale, def->xScale) + ("yscale", part.yScale, def->yScale) + ("texture", part.texture, def->texture) + ("interpolation", part.interpolation) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, side_t &side, side_t *def) +{ + if (arc.BeginObject(key)) + { + arc.Array("textures", side.textures, def->textures, 3, true) + ("light", side.Light, def->Light) + ("flags", side.Flags, def->Flags) + // These also remain identical across map loads + //("leftside", side.LeftSide) + //("rightside", side.RightSide) + //("index", side.Index) + ("attacheddecals", side.AttachedDecals) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, FLinkedSector &ls, FLinkedSector *def) +{ + if (arc.BeginObject(key)) + { + arc("sector", ls.Sector) + ("type", ls.Type) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, sector_t::splane &p, sector_t::splane *def) +{ + if (arc.canSkip() && def != nullptr && !memcmp(&p, def, sizeof(p))) + { + return arc; + } + + if (arc.BeginObject(key)) + { + arc("xoffs", p.xform.xOffs, def->xform.xOffs) + ("yoffs", p.xform.yOffs, def->xform.yOffs) + ("xscale", p.xform.xScale, def->xform.xScale) + ("yscale", p.xform.yScale, def->xform.yScale) + ("angle", p.xform.Angle, def->xform.Angle) + ("baseyoffs", p.xform.baseyOffs, def->xform.baseyOffs) + ("baseangle", p.xform.baseAngle, def->xform.baseAngle) + ("flags", p.Flags, def->Flags) + ("light", p.Light, def->Light) + ("texture", p.Texture, def->Texture) + ("texz", p.TexZ, def->TexZ) + ("alpha", p.alpha, def->alpha) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def) +{ + if (arc.canSkip() && def != nullptr && !memcmp(&p, def, sizeof(p))) + { + return arc; + } + + if (arc.BeginObject(key)) + { + arc("normal", p.normal, def->normal) + ("d", p.D, def->D) + .EndObject(); + + if (arc.isReading() && p.normal.Z != 0) + { + p.negiC = 1 / p.normal.Z; + } + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, sector_t &p, sector_t *def) +{ + if (arc.BeginObject(key)) + { + arc("floorplane", p.floorplane, def->floorplane) + ("ceilingplane", p.ceilingplane, def->ceilingplane) + ("lightlevel", p.lightlevel, def->lightlevel) + ("special", p.special, def->special) + ("soundtraversed", p.soundtraversed, def->soundtraversed) + ("seqtype", p.seqType, def->seqType) + ("seqname", p.SeqName, def->SeqName) + ("friction", p.friction, def->friction) + ("movefactor", p.movefactor, def->movefactor) + ("stairlock", p.stairlock, def->stairlock) + ("prevsec", p.prevsec, def->prevsec) + ("nextsec", p.nextsec, def->nextsec) + .Array("planes", p.planes, def->planes, 2, true) + // These cannot change during play. + //("heightsec", p.heightsec) + //("bottommap", p.bottommap) + //("midmap", p.midmap) + //("topmap", p.topmap) + ("damageamount", p.damageamount, def->damageamount) + ("damageinterval", p.damageinterval, def->damageinterval) + ("leakydamage", p.leakydamage, def->leakydamage) + ("damagetype", p.damagetype, def->damagetype) + ("sky", p.sky, def->sky) + ("moreflags", p.MoreFlags, def->MoreFlags) + ("flags", p.Flags, def->Flags) + .Array("portals", p.Portals, def->Portals, 2, true) + ("zonenumber", p.ZoneNumber, def->ZoneNumber) + .Array("interpolations", p.interpolations, 4, true) + ("soundtarget", p.SoundTarget) + ("secacttarget", p.SecActTarget) + ("floordata", p.floordata) + ("ceilingdata", p.ceilingdata) + ("lightingdata", p.lightingdata) + ("fakefloor_sectors", p.e->FakeFloor.Sectors) + ("midtexf_lines", p.e->Midtex.Floor.AttachedLines) + ("midtexf_sectors", p.e->Midtex.Floor.AttachedSectors) + ("midtexc_lines", p.e->Midtex.Ceiling.AttachedLines) + ("midtexc_sectors", p.e->Midtex.Ceiling.AttachedSectors) + ("linked_floor", p.e->Linked.Floor.Sectors) + ("linked_ceiling", p.e->Linked.Ceiling.Sectors) + ("colormap", p.ColorMap, def->ColorMap) + .Terrain("floorterrain", p.terrainnum[0], &def->terrainnum[0]) + .Terrain("ceilingterrain", p.terrainnum[1], &def->terrainnum[1]) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// RecalculateDrawnSubsectors +// +// In case the subsector data is unusable this function tries to reconstruct +// if from the linedefs' ML_MAPPED info. +// +//========================================================================== + +void RecalculateDrawnSubsectors() +{ + for (int i = 0; inumlines; j++) + { + if (sub->firstline[j].linedef != NULL && + (sub->firstline[j].linedef->flags & ML_MAPPED)) + { + sub->flags |= SSECF_DRAWN; + } + } + } +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, subsector_t *&ss, subsector_t **) +{ + BYTE by; + const char *str; + + if (arc.isWriting()) + { + if (hasglnodes) + { + TArray encoded(1 + (numsubsectors + 5) / 6); + int p = 0; + for (int i = 0; i < numsubsectors; i += 6) + { + by = 0; + for (int j = 0; j < 6; j++) + { + if (i + j < numsubsectors && (subsectors[i + j].flags & SSECF_DRAWN)) + { + by |= (1 << j); + } + } + if (by < 10) by += '0'; + else if (by < 36) by += 'A' - 10; + else if (by < 62) by += 'a' - 36; + else if (by == 62) by = '-'; + else if (by == 63) by = '+'; + encoded[p++] = by; + } + encoded[p] = 0; + str = &encoded[0]; + if (arc.BeginArray(key)) + { + arc(nullptr, numvertexes) + (nullptr, numsubsectors) + .StringPtr(nullptr, str) + .EndArray(); + } + } + } + else + { + int num_verts, num_subs; + bool success = false; + if (arc.BeginArray(key)) + { + arc(nullptr, num_verts) + (nullptr, num_subs) + .StringPtr(nullptr, str) + .EndArray(); + + if (num_verts == numvertexes && num_subs == numsubsectors && hasglnodes) + { + success = true; + for (int i = 0; str[i] != 0; i++) + { + by = str[i]; + if (by >= '0' && by <= '9') by -= '0'; + else if (by >= 'A' && by <= 'Z') by -= 'A' - 10; + else if (by >= 'a' && by <= 'z') by -= 'a' - 36; + else if (by == '-') by = 62; + else if (by == '+') by = 63; + else + { + success = false; + break; + } + } + } + if (hasglnodes && !success) + { + RecalculateDrawnSubsectors(); + } + } + + } + return arc; +} + +//============================================================================ +// +// Save a line portal for savegames. +// +//============================================================================ + +FSerializer &Serialize(FSerializer &arc, const char *key, FLinePortal &port, FLinePortal *def) +{ + if (arc.BeginObject(key)) + { + arc("origin", port.mOrigin) + ("destination", port.mDestination) + ("displacement", port.mDisplacement) + ("type", port.mType) + ("flags", port.mFlags) + ("defflags", port.mDefFlags) + ("align", port.mAlign) + .EndObject(); + } + return arc; +} + +//============================================================================ +// +// Save a sector portal for savegames. +// +//============================================================================ + +FSerializer &Serialize(FSerializer &arc, const char *key, FSectorPortal &port, FSectorPortal *def) +{ + if (arc.BeginObject(key)) + { + arc("type", port.mType) + ("flags", port.mFlags) + ("partner", port.mPartner) + ("plane", port.mPlane) + ("origin", port.mOrigin) + ("destination", port.mDestination) + ("displacement", port.mDisplacement) + ("planez", port.mPlaneZ) + ("skybox", port.mSkybox) + .EndObject(); + } + return arc; +} + +//========================================================================== +// +// +// +//========================================================================== + +FSerializer &Serialize(FSerializer &arc, const char *key, ReverbContainer *&c, ReverbContainer **def) +{ + int id = (arc.isReading() || c == nullptr) ? 0 : c->ID; + Serialize(arc, key, id, nullptr); + if (arc.isReading()) + { + c = S_FindEnvironment(id); + } + return arc; +} + +FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z, zone_t *def) +{ + return Serialize(arc, key, z.Environment, nullptr); +} + +//============================================================================ +// +// +// +//============================================================================ + +void SerializeWorld(FSerializer &arc) +{ + // 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); + + if (arc.isReading()) P_CollectLinkedPortals(); +} + + //========================================================================== // // ArchiveSounds @@ -625,96 +862,132 @@ void P_SerializePolyobjs (FArchive &arc) //========================================================================== // -// RecalculateDrawnSubsectors -// -// In case the subsector data is unusable this function tries to reconstruct -// if from the linedefs' ML_MAPPED info. // //========================================================================== -void RecalculateDrawnSubsectors() +void G_SerializeLevel(FArchive &arc, bool hubLoad) { - for(int i=0;iStartSerialize(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()) { - subsector_t *sub = &subsectors[i]; - for(unsigned int j=0;jnumlines;j++) - { - if (sub->firstline[j].linedef != NULL && - (sub->firstline[j].linedef->flags & ML_MAPPED)) - { - sub->flags |= SSECF_DRAWN; - } - } + sky1texture = level.skytexture1; + sky2texture = level.skytexture2; + R_InitSkyMap(); } -} -//========================================================================== -// -// ArchiveSubsectors -// -//========================================================================== + G_AirControlChanged(); -void P_SerializeSubsectors(FArchive &arc) -{ - int num_verts, num_subs, num_nodes; - BYTE by; + BYTE t; + // Does this level have scrollers? if (arc.IsStoring()) { - if (hasglnodes) - { - arc << numvertexes << numsubsectors << numnodes; // These are only for verification - for(int i=0;iSerialize(arc); + + arc << level.total_monsters << level.total_items << level.total_secrets; + + // Does this level have custom translations? + FRemapTable *trans; + WORD w; + if (arc.IsStoring()) + { + for (unsigned int i = 0; i < translationtables[TRANSLATION_LevelScripted].Size(); ++i) + { + trans = translationtables[TRANSLATION_LevelScripted][i]; + if (trans != NULL && !trans->IsIdentity()) { - arc << by; - for(int j=0;j<8;j++) - { - if ((by & (1<Serialize(arc); + } + } + w = 0xffff; + arc << w; + } + else + { + while (arc << w, w != 0xffff) + { + trans = translationtables[TRANSLATION_LevelScripted].GetVal(w); + if (trans == NULL) + { + trans = new FRemapTable; + translationtables[TRANSLATION_LevelScripted].SetVal(w, trans); + } + trans->Serialize(arc); + } + } + + // This must be saved, too, of course! + FCanvasTextureInfo::Serialize(arc); + AM_SerializeMarkers(arc); + + P_SerializePlayers(arc, hubLoad); + P_SerializeSounds(arc); + if (arc.IsLoading()) + { + for (i = 0; i < numsectors; i++) + { + P_Recalculate3DFloors(§ors[i]); + } + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].mo != NULL) + { + players[i].mo->SetupWeaponSlots(); } } } + Renderer->EndSerialize(arc); + unsigned tt = I_MSTime(); + Printf("Serialization took %d ms\n", tt - tm); } + diff --git a/src/p_saveg.h b/src/p_saveg.h index eb3e4de2b..a62e5c5b8 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -52,4 +52,6 @@ void P_SerializeSounds (FArchive &arc); void P_ReadACSDefereds (PNGHandle *png); void P_WriteACSDefereds (FILE *file); +void G_SerializeLevel(FArchive &arc, bool hubLoad); + #endif // __P_SAVEG_H__ diff --git a/src/p_states.cpp b/src/p_states.cpp index 2e61a7844..a56229e05 100644 --- a/src/p_states.cpp +++ b/src/p_states.cpp @@ -47,71 +47,6 @@ // actor. States are archived by recording the actor they belong // to and the index into that actor's list of states. -// For NULL states, which aren't owned by any actor, the owner -// is recorded as AActor with the following state. AActor should -// never actually have this many states of its own, so this -// is (relatively) safe. - -#define NULL_STATE_INDEX 127 - -//========================================================================== -// -// -//========================================================================== - -FArchive &operator<< (FArchive &arc, FState *&state) -{ - PClassActor *info; - - if (arc.IsStoring ()) - { - if (state == NULL) - { - arc.UserWriteClass (RUNTIME_CLASS(AActor)); - arc.WriteCount (NULL_STATE_INDEX); - return arc; - } - - info = FState::StaticFindStateOwner (state); - - if (info != NULL) - { - arc.UserWriteClass (info); - arc.WriteCount ((DWORD)(state - info->OwnedStates)); - } - else - { - /* this was never working as intended. - I_Error ("Cannot find owner for state %p:\n" - "%s %c%c %3d [%p] -> %p", state, - sprites[state->sprite].name, - state->GetFrame() + 'A', - state->GetFullbright() ? '*' : ' ', - state->GetTics(), - state->GetAction(), - state->GetNextState()); - */ - } - } - else - { - PClassActor *info; - DWORD ofs; - - arc.UserReadClass(info); - ofs = arc.ReadCount (); - if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor)) - { - state = NULL; - } - else - { - state = info->OwnedStates + ofs; - } - } - return arc; -} - //========================================================================== // // Find the actor that a state belongs to. diff --git a/src/serializer.cpp b/src/serializer.cpp index db467c21a..06625b054 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -504,7 +504,9 @@ void FSerializer::WriteObjects() BeginObject(nullptr); WriteKey("classtype"); w->mWriter.String(w->mDObjects[i]->GetClass()->TypeName.GetChars()); + w->mDObjects[i]->SerializeUserVars(*this); w->mDObjects[i]->Serialize(*this); + w->mDObjects[i]->CheckIfSerialized(); EndObject(); } EndArray(); @@ -1144,8 +1146,18 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState } else if (val->IsArray()) { - //rapidjson::Value cls = (*val)[0]; - //rapidjson::Value ndx = (*val)[1]; + const rapidjson::Value &cls = (*val)[0]; + const rapidjson::Value &ndx = (*val)[1]; + + state = nullptr; + if (cls.IsString() && ndx.IsInt()) + { + PClassActor *clas = PClass::FindActor(cls.GetString()); + if (clas) + { + state = clas->OwnedStates + ndx.GetInt(); + } + } } else { diff --git a/src/zzz_old.cpp b/src/zzz_old.cpp new file mode 100644 index 000000000..a4d6df95d --- /dev/null +++ b/src/zzz_old.cpp @@ -0,0 +1,697 @@ +// For NULL states, which aren't owned by any actor, the owner +// is recorded as AActor with the following state. AActor should +// never actually have this many states of its own, so this +// is (relatively) safe. + +#define NULL_STATE_INDEX 127 + +// These are special tokens found in the data stream of an archive. +// Whenever a new object is encountered, it gets created using new and +// is then asked to serialize itself before processing of the previous +// object continues. This can result in some very deep recursion if +// you aren't careful about how you organize your data. + +#define NEW_OBJ ((BYTE)1) // Data for a new object follows +#define NEW_CLS_OBJ ((BYTE)2) // Data for a new class and object follows +#define OLD_OBJ ((BYTE)3) // Reference to an old object follows +#define NULL_OBJ ((BYTE)4) // Load as NULL +#define M1_OBJ ((BYTE)44) // Load as (DObject*)-1 + +#define NEW_PLYR_OBJ ((BYTE)5) // Data for a new player follows +#define NEW_PLYR_CLS_OBJ ((BYTE)6) // Data for a new class and player follows + +#define NEW_NAME ((BYTE)27) // A new name follows +#define OLD_NAME ((BYTE)28) // Reference to an old name follows +#define NIL_NAME ((BYTE)33) // Load as NULL + +#define NEW_SPRITE ((BYTE)11) // A new sprite name follows +#define OLD_SPRITE ((BYTE)12) // Reference to an old sprite name follows + +inline FArchive &operator<< (FArchive &arc, FLinkedSector &link) +{ + arc << link.Sector << link.Type; + return arc; +} + +// +// P_ArchiveWorld +// +void P_SerializeWorld (FArchive &arc) +{ + int i, j; + sector_t *sec; + line_t *li; + zone_t *zn; + + // do sectors + for (i = 0, sec = sectors; i < numsectors; i++, sec++) + { + arc << sec->floorplane + << sec->ceilingplane; + arc << sec->lightlevel; + arc << sec->special; + arc << sec->soundtraversed + << sec->seqType + << sec->friction + << sec->movefactor + << sec->stairlock + << sec->prevsec + << sec->nextsec + << sec->planes[sector_t::floor] + << sec->planes[sector_t::ceiling] + << sec->heightsec + << sec->bottommap << sec->midmap << sec->topmap + << sec->gravity; + P_SerializeTerrain(arc, sec->terrainnum[0]); + P_SerializeTerrain(arc, sec->terrainnum[1]); + arc << sec->damageamount; + arc << sec->damageinterval + << sec->leakydamage + << sec->damagetype + << sec->sky + << sec->MoreFlags + << sec->Flags + << sec->Portals[sector_t::floor] << sec->Portals[sector_t::ceiling] + << sec->ZoneNumber; + arc << sec->interpolations[0] + << sec->interpolations[1] + << sec->interpolations[2] + << sec->interpolations[3] + << sec->SeqName; + + sec->e->Serialize(arc); + if (arc.IsStoring ()) + { + arc << sec->ColorMap->Color + << sec->ColorMap->Fade; + BYTE sat = sec->ColorMap->Desaturate; + arc << sat; + } + else + { + PalEntry color, fade; + BYTE desaturate; + arc << color << fade + << desaturate; + sec->ColorMap = GetSpecialLights (color, fade, desaturate); + } + } + + // do lines + for (i = 0, li = lines; i < numlines; i++, li++) + { + arc << li->flags + << li->activation + << li->special + << li->alpha; + + if (P_IsACSSpecial(li->special)) + { + P_SerializeACSScriptNumber(arc, li->args[0], false); + } + else + { + arc << li->args[0]; + } + arc << li->args[1] << li->args[2] << li->args[3] << li->args[4]; + + arc << li->portalindex; + for (j = 0; j < 2; j++) + { + if (li->sidedef[j] == NULL) + continue; + + side_t *si = li->sidedef[j]; + arc << si->textures[side_t::top] + << si->textures[side_t::mid] + << si->textures[side_t::bottom] + << si->Light + << si->Flags + << si->LeftSide + << si->RightSide + << si->Index; + } + } + + // do zones + unsigned numzones = Zones.Size(); + arc << numzones; + + if (arc.IsLoading()) + { + Zones.Resize(numzones); + } + + for (i = 0, zn = &Zones[0]; i < (int)numzones; ++i, ++zn) + { + arc << zn->Environment; + } + + arc << linePortals << sectorPortals; + P_CollectLinkedPortals(); +} + +void P_SerializeWorldActors(FArchive &arc) +{ + int i; + sector_t *sec; + line_t *line; + + for (i = 0, sec = sectors; i < numsectors; i++, sec++) + { + arc << sec->SoundTarget + << sec->SecActTarget + << sec->floordata + << sec->ceilingdata + << sec->lightingdata; + } + for (auto &s : sectorPortals) + { + arc << s.mSkybox; + } + for (i = 0, line = lines; i < numlines; i++, line++) + { + for (int s = 0; s < 2; s++) + { + if (line->sidedef[s] != NULL) + { + DBaseDecal::SerializeChain(arc, &line->sidedef[s]->AttachedDecals); + } + } + } +} + +void extsector_t::Serialize(FArchive &arc) +{ + arc << FakeFloor.Sectors + << Midtex.Floor.AttachedLines + << Midtex.Floor.AttachedSectors + << Midtex.Ceiling.AttachedLines + << Midtex.Ceiling.AttachedSectors + << Linked.Floor.Sectors + << Linked.Ceiling.Sectors; +} + +FArchive &operator<< (FArchive &arc, side_t::part &p) +{ + arc << p.xOffset << p.yOffset << p.interpolation << p.texture + << p.xScale << p.yScale;// << p.Light; + return arc; +} + +FArchive &operator<< (FArchive &arc, sector_t::splane &p) +{ + arc << p.xform.xOffs << p.xform.yOffs << p.xform.xScale << p.xform.yScale + << p.xform.Angle << p.xform.baseyOffs << p.xform.baseAngle + << p.Flags << p.Light << p.Texture << p.TexZ << p.alpha; + return arc; +} + +//========================================================================== +// +// ArchiveSubsectors +// +//========================================================================== +void RecalculateDrawnSubsectors(); + +void P_SerializeSubsectors(FArchive &arc) +{ + int num_verts, num_subs, num_nodes; + BYTE by; + + if (arc.IsStoring()) + { + if (hasglnodes) + { + arc << numvertexes << numsubsectors << numnodes; // These are only for verification + for(int i=0;iObjectFlags & OF_EuthanizeMe) + { + // Objects that want to die are not saved to the archive, but + // we leave the pointers to them alone. + id[0] = NULL_OBJ; + Write (id, 1); + } + else + { + PClass *type = obj->GetClass(); + DWORD *classarcid; + + if (type == RUNTIME_CLASS(DObject)) + { + //I_Error ("Tried to save an instance of DObject.\n" + // "This should not happen.\n"); + id[0] = NULL_OBJ; + Write (id, 1); + } + else if (NULL == (classarcid = ClassToArchive.CheckKey(type))) + { + // No instances of this class have been written out yet. + // Write out the class, then write out the object. If this + // is an actor controlled by a player, make note of that + // so that it can be overridden when moving around in a hub. + if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && + (player = static_cast(obj)->player) && + player->mo == obj) + { + id[0] = NEW_PLYR_CLS_OBJ; + id[1] = (BYTE)(player - players); + Write (id, 2); + } + else + { + id[0] = NEW_CLS_OBJ; + Write (id, 1); + } + WriteClass (type); +// Printf ("Make class %s (%u)\n", type->Name, m_File->Tell()); + MapObject (obj); + obj->SerializeUserVars (*this); + obj->Serialize (*this); + obj->CheckIfSerialized (); + } + else + { + // An instance of this class has already been saved. If + // this object has already been written, save a reference + // to the saved object. Otherwise, save a reference to the + // class, then save the object. Again, if this is a player- + // controlled actor, remember that. + DWORD *objarcid = ObjectToArchive.CheckKey(obj); + + if (objarcid == NULL) + { + + if (obj->IsKindOf (RUNTIME_CLASS (AActor)) && + (player = static_cast(obj)->player) && + player->mo == obj) + { + id[0] = NEW_PLYR_OBJ; + id[1] = (BYTE)(player - players); + Write (id, 2); + } + else + { + id[0] = NEW_OBJ; + Write (id, 1); + } + WriteCount (*classarcid); +// Printf ("Reuse class %s (%u)\n", type->Name, m_File->Tell()); + MapObject (obj); + obj->SerializeUserVars (*this); + obj->Serialize (*this); + obj->CheckIfSerialized (); + } + else + { + id[0] = OLD_OBJ; + Write (id, 1); + WriteCount (*objarcid); + } + } + } + return *this; +} + +void AActor::Serialize(FArchive &arc) +{ + Super::Serialize(arc); + + if (arc.IsStoring()) + { + arc.WriteSprite(sprite); + } + else + { + sprite = arc.ReadSprite(); + } + + arc << __Pos + << Angles.Yaw + << Angles.Pitch + << Angles.Roll + << frame + << Scale + << RenderStyle + << renderflags + << picnum + << floorpic + << ceilingpic + << TIDtoHate + << LastLookPlayerNumber + << LastLookActor + << effects + << Alpha + << fillcolor + << Sector + << floorz + << ceilingz + << dropoffz + << floorsector + << ceilingsector + << radius + << Height + << projectilepassheight + << Vel + << tics + << state + << DamageVal; + if (DamageVal == 0x40000000 || DamageVal == -1) + { + DamageVal = -1; + DamageFunc = GetDefault()->DamageFunc; + } + else + { + DamageFunc = nullptr; + } + P_SerializeTerrain(arc, floorterrain); + arc << projectileKickback + << flags + << flags2 + << flags3 + << flags4 + << flags5 + << flags6 + << flags7 + << weaponspecial + << special1 + << special2 + << specialf1 + << specialf2 + << health + << movedir + << visdir + << movecount + << strafecount + << target + << lastenemy + << LastHeard + << reactiontime + << threshold + << player + << SpawnPoint + << SpawnAngle + << StartHealth + << skillrespawncount + << tracer + << Floorclip + << tid + << special; + if (P_IsACSSpecial(special)) + { + P_SerializeACSScriptNumber(arc, args[0], false); + } + else + { + arc << args[0]; + } + arc << args[1] << args[2] << args[3] << args[4]; + arc << accuracy << stamina; + arc << goal + << waterlevel + << MinMissileChance + << SpawnFlags + << Inventory + << InventoryID; + arc << FloatBobPhase + << Translation + << SeeSound + << AttackSound + << PainSound + << DeathSound + << ActiveSound + << UseSound + << BounceSound + << WallBounceSound + << CrushPainSound + << Speed + << FloatSpeed + << Mass + << PainChance + << SpawnState + << SeeState + << MeleeState + << MissileState + << MaxDropOffHeight + << MaxStepHeight + << BounceFlags + << bouncefactor + << wallbouncefactor + << bouncecount + << maxtargetrange + << meleethreshold + << meleerange + << DamageType; + arc << DamageTypeReceived; + arc << PainType + << DeathType; + arc << Gravity + << FastChaseStrafeCount + << master + << smokecounter + << BlockingMobj + << BlockingLine + << VisibleToTeam // [BB] + << pushfactor + << Species + << Score; + arc << DesignatedTeam; + arc << lastpush << lastbump + << PainThreshold + << DamageFactor; + arc << DamageMultiply; + arc << WeaveIndexXY << WeaveIndexZ + << PoisonDamageReceived << PoisonDurationReceived << PoisonPeriodReceived << Poisoner + << PoisonDamage << PoisonDuration << PoisonPeriod; + arc << PoisonDamageType << PoisonDamageTypeReceived; + arc << ConversationRoot << Conversation; + arc << FriendPlayer; + arc << TeleFogSourceType + << TeleFogDestType; + arc << RipperLevel + << RipLevelMin + << RipLevelMax; + arc << DefThreshold; + if (SaveVersion >= 4549) + { + arc << SpriteAngle; + arc << SpriteRotation; + } + + if (SaveVersion >= 4550) + { + arc << alternative; + } + + { + FString tagstr; + if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; + arc << tagstr; + if (arc.IsLoading()) + { + if (tagstr.Len() == 0) Tag = NULL; + else Tag = mStringPropertyData.Alloc(tagstr); + } + } + + if (arc.IsLoading ()) + { + touching_sectorlist = NULL; + LinkToWorld(false, Sector); + + AddToHash (); + SetShade (fillcolor); + if (player) + { + if (playeringame[player - players] && + player->cls != NULL && + !(flags4 & MF4_NOSKIN) && + state->sprite == GetDefaultByType (player->cls)->SpawnState->sprite) + { // Give player back the skin + sprite = skins[player->userinfo.GetSkin()].sprite; + } + if (Speed == 0) + { + Speed = GetDefault()->Speed; + } + } + ClearInterpolation(); + UpdateWaterLevel(false); + } +} + +FArchive &operator<< (FArchive &arc, sector_t *&sec) +{ + return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors)); +} + +FArchive &operator<< (FArchive &arc, const sector_t *&sec) +{ + return arc.SerializePointer (sectors, (BYTE **)&sec, sizeof(*sectors)); +} + +FArchive &operator<< (FArchive &arc, line_t *&line) +{ + return arc.SerializePointer (lines, (BYTE **)&line, sizeof(*lines)); +} + +FArchive &operator<< (FArchive &arc, vertex_t *&vert) +{ + return arc.SerializePointer (vertexes, (BYTE **)&vert, sizeof(*vertexes)); +} + +FArchive &operator<< (FArchive &arc, side_t *&side) +{ + return arc.SerializePointer (sides, (BYTE **)&side, sizeof(*sides)); +} + +FArchive &operator<<(FArchive &arc, DAngle &ang) +{ + arc << ang.Degrees; + return arc; +} + +FArchive &operator<<(FArchive &arc, DVector3 &vec) +{ + arc << vec.X << vec.Y << vec.Z; + return arc; +} + +FArchive &operator<<(FArchive &arc, DVector2 &vec) +{ + arc << vec.X << vec.Y; + return arc; +} + +//========================================================================== +// +// +//========================================================================== + +FArchive &operator<< (FArchive &arc, FState *&state) +{ + PClassActor *info; + + if (arc.IsStoring ()) + { + if (state == NULL) + { + arc.UserWriteClass (RUNTIME_CLASS(AActor)); + arc.WriteCount (NULL_STATE_INDEX); + return arc; + } + + info = FState::StaticFindStateOwner (state); + + if (info != NULL) + { + arc.UserWriteClass (info); + arc.WriteCount ((DWORD)(state - info->OwnedStates)); + } + else + { + /* this was never working as intended. + I_Error ("Cannot find owner for state %p:\n" + "%s %c%c %3d [%p] -> %p", state, + sprites[state->sprite].name, + state->GetFrame() + 'A', + state->GetFullbright() ? '*' : ' ', + state->GetTics(), + state->GetAction(), + state->GetNextState()); + */ + } + } + else + { + PClassActor *info; + DWORD ofs; + + arc.UserReadClass(info); + ofs = arc.ReadCount (); + if (ofs == NULL_STATE_INDEX && info == RUNTIME_CLASS(AActor)) + { + state = NULL; + } + else + { + state = info->OwnedStates + ofs; + } + } + return arc; +} + +void DObject::Serialize (FArchive &arc) +{ + ObjectFlags |= OF_SerialSuccess; +}