diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 80cad3eb5..e2178f995 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -65,287 +65,8 @@ #include "serializer.h" // just the stuff that already got converted to FSerializer so that it can be seen as 'done' when searching. -#define COMMON_STUFF #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 (); - -// -// P_ArchivePlayers -// -void P_SerializePlayers (FArchive &arc, bool skipload) -{ - BYTE numPlayers, numPlayersNow; - int i; - - // Count the number of players present right now. - for (numPlayersNow = 0, i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - ++numPlayersNow; - } - } - - if (arc.IsStoring()) - { - // Record the number of players in this save. - arc << numPlayersNow; - - // Record each player's name, followed by their data. - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - arc.WriteString (players[i].userinfo.GetName()); - players[i].Serialize (arc); - } - } - } - else - { - arc << numPlayers; - - // If there is only one player in the game, they go to the - // first player present, no matter what their name. - if (numPlayers == 1) - { - ReadOnePlayer (arc, skipload); - } - else - { - ReadMultiplePlayers (arc, numPlayers, numPlayersNow, skipload); - } - if (!skipload && numPlayersNow > numPlayers) - { - SpawnExtraPlayers (); - } - // Redo pitch limits, since the spawned player has them at 0. - players[consoleplayer].SendPitchLimits(); - } -} - -static void ReadOnePlayer (FArchive &arc, bool skipload) -{ - int i; - char *name = NULL; - bool didIt = false; - - arc << name; - - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i]) - { - if (!didIt) - { - didIt = true; - player_t playerTemp; - playerTemp.Serialize (arc); - if (!skipload) - { - CopyPlayer (&players[i], &playerTemp, name); - } - } - else - { - if (players[i].mo != NULL) - { - players[i].mo->Destroy(); - players[i].mo = NULL; - } - } - } - } - delete[] name; -} - -static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNow, bool skipload) -{ - // For two or more players, read each player into a temporary array. - int i, j; - char **nametemp = new char *[numPlayers]; - player_t *playertemp = new player_t[numPlayers]; - BYTE *tempPlayerUsed = new BYTE[numPlayers]; - BYTE playerUsed[MAXPLAYERS]; - - for (i = 0; i < numPlayers; ++i) - { - nametemp[i] = NULL; - arc << nametemp[i]; - playertemp[i].Serialize (arc); - tempPlayerUsed[i] = 0; - } - for (i = 0; i < MAXPLAYERS; ++i) - { - playerUsed[i] = playeringame[i] ? 0 : 2; - } - - if (!skipload) - { - // Now try to match players from the savegame with players present - // based on their names. If two players in the savegame have the - // same name, then they are assigned to players in the current game - // on a first-come, first-served basis. - for (i = 0; i < numPlayers; ++i) - { - for (j = 0; j < MAXPLAYERS; ++j) - { - if (playerUsed[j] == 0 && stricmp(players[j].userinfo.GetName(), nametemp[i]) == 0) - { // Found a match, so copy our temp player to the real player - Printf ("Found player %d (%s) at %d\n", i, nametemp[i], j); - CopyPlayer (&players[j], &playertemp[i], nametemp[i]); - playerUsed[j] = 1; - tempPlayerUsed[i] = 1; - break; - } - } - } - - // Any players that didn't have matching names are assigned to existing - // players on a first-come, first-served basis. - for (i = 0; i < numPlayers; ++i) - { - if (tempPlayerUsed[i] == 0) - { - for (j = 0; j < MAXPLAYERS; ++j) - { - if (playerUsed[j] == 0) - { - Printf ("Assigned player %d (%s) to %d (%s)\n", i, nametemp[i], j, players[j].userinfo.GetName()); - CopyPlayer (&players[j], &playertemp[i], nametemp[i]); - playerUsed[j] = 1; - tempPlayerUsed[i] = 1; - break; - } - } - } - } - - // Make sure any extra players don't have actors spawned yet. Happens if the players - // present now got the same slots as they had in the save, but there are not as many - // as there were in the save. - for (j = 0; j < MAXPLAYERS; ++j) - { - if (playerUsed[j] == 0) - { - if (players[j].mo != NULL) - { - players[j].mo->Destroy(); - players[j].mo = NULL; - } - } - } - - // Remove any temp players that were not used. Happens if there are fewer players - // than there were in the save, and they got shuffled. - for (i = 0; i < numPlayers; ++i) - { - if (tempPlayerUsed[i] == 0) - { - playertemp[i].mo->Destroy(); - playertemp[i].mo = NULL; - } - } - } - - delete[] tempPlayerUsed; - delete[] playertemp; - for (i = 0; i < numPlayers; ++i) - { - delete[] nametemp[i]; - } - delete[] nametemp; -} - -void CopyPlayer (player_t *dst, player_t *src, const char *name) -{ - // The userinfo needs to be saved for real players, but it - // needs to come from the save for bots. - userinfo_t uibackup; - userinfo_t uibackup2; - - uibackup.TransferFrom(dst->userinfo); - uibackup2.TransferFrom(src->userinfo); - - int chasecam = dst->cheats & CF_CHASECAM; // Remember the chasecam setting - bool attackdown = dst->attackdown; - bool usedown = dst->usedown; - - - *dst = *src; // To avoid memory leaks at this point the userinfo in src must be empty which is taken care of by the TransferFrom call above. - - dst->cheats |= chasecam; - - if (dst->Bot != nullptr) - { - botinfo_t *thebot = bglobal.botinfo; - while (thebot && stricmp (name, thebot->name)) - { - thebot = thebot->next; - } - if (thebot) - { - thebot->inuse = BOTINUSE_Yes; - } - bglobal.botnum++; - dst->userinfo.TransferFrom(uibackup2); - } - else - { - dst->userinfo.TransferFrom(uibackup); - } - // Validate the skin - dst->userinfo.SkinNumChanged(R_FindSkin(skins[dst->userinfo.GetSkin()].name, dst->CurrentPlayerClass)); - - // Make sure the player pawn points to the proper player struct. - if (dst->mo != nullptr) - { - dst->mo->player = dst; - } - - // Same for the psprites. - DPSprite *pspr = dst->psprites; - while (pspr) - { - pspr->Owner = dst; - - pspr = pspr->Next; - } - - // Don't let the psprites be destroyed when src is destroyed. - src->psprites = nullptr; - - // These 2 variables may not be overwritten. - dst->attackdown = attackdown; - dst->usedown = usedown; -} - -static void SpawnExtraPlayers () -{ - // If there are more players now than there were in the savegame, - // be sure to spawn the extra players. - int i; - - if (deathmatch) - { - return; - } - - for (i = 0; i < MAXPLAYERS; ++i) - { - if (playeringame[i] && players[i].mo == NULL) - { - players[i].playerstate = PST_ENTER; - P_SpawnPlayer(&playerstarts[i], i, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); - } - } -} - - // // Thinkers @@ -807,6 +528,351 @@ FSerializer &Serialize(FSerializer &arc, const char *key, zone_t &z, zone_t *def return Serialize(arc, key, z.Environment, nullptr); } +//========================================================================== +// +// ArchiveSounds +// +//========================================================================== + +void P_SerializeSounds(FSerializer &arc) +{ + S_SerializeSounds(arc); + DSeqNode::SerializeSequences (arc); + char *name = NULL; + BYTE order; + + if (arc.isWriting()) + { + order = S_GetMusic(&name); + } + arc("musicname", name) + ("musicorder", order); + + if (arc.isReading()) + { + if (!S_ChangeMusic(name, order)) + if (level.cdtrack == 0 || !S_ChangeCDMusic(level.cdtrack, level.cdid)) + S_ChangeMusic(level.Music, level.musicorder); + } + delete[] name; +} + +//========================================================================== +// +// +// +//========================================================================== + +void CopyPlayer(player_t *dst, player_t *src, const char *name); +static void ReadOnePlayer(FSerializer &arc, bool skipload); +static void ReadMultiplePlayers(FSerializer &arc, int numPlayers, int numPlayersNow, bool skipload); +static void SpawnExtraPlayers(); + +//========================================================================== +// +// P_ArchivePlayers +// +//========================================================================== + +void P_SerializePlayers(FSerializer &arc, bool skipload) +{ + BYTE numPlayers, numPlayersNow; + int i; + + // Count the number of players present right now. + for (numPlayersNow = 0, i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + ++numPlayersNow; + } + } + +#if 0 + if (arc.isWriting()) + { + // Record the number of players in this save. + arc << numPlayersNow; + + // Record each player's name, followed by their data. + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + arc.WriteString(players[i].userinfo.GetName()); + players[i].Serialize(arc); + } + } + } + else + { + arc << numPlayers; + + // If there is only one player in the game, they go to the + // first player present, no matter what their name. + if (numPlayers == 1) + { + ReadOnePlayer(arc, skipload); + } + else + { + ReadMultiplePlayers(arc, numPlayers, numPlayersNow, skipload); + } + if (!skipload && numPlayersNow > numPlayers) + { + SpawnExtraPlayers(); + } + // Redo pitch limits, since the spawned player has them at 0. + players[consoleplayer].SendPitchLimits(); + } +#endif +} + +//========================================================================== +// +// +// +//========================================================================== + +static void ReadOnePlayer(FSerializer &arc, bool skipload) +{ +#if 0 + int i; + char *name = NULL; + bool didIt = false; + + arc << name; + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + if (!didIt) + { + didIt = true; + player_t playerTemp; + playerTemp.Serialize(arc); + if (!skipload) + { + CopyPlayer(&players[i], &playerTemp, name); + } + } + else + { + if (players[i].mo != NULL) + { + players[i].mo->Destroy(); + players[i].mo = NULL; + } + } + } + } + delete[] name; +#endif +} + +//========================================================================== +// +// +// +//========================================================================== + +static void ReadMultiplePlayers(FSerializer &arc, int numPlayers, int numPlayersNow, bool skipload) +{ +#if 0 + // For two or more players, read each player into a temporary array. + int i, j; + char **nametemp = new char *[numPlayers]; + player_t *playertemp = new player_t[numPlayers]; + BYTE *tempPlayerUsed = new BYTE[numPlayers]; + BYTE playerUsed[MAXPLAYERS]; + + for (i = 0; i < numPlayers; ++i) + { + nametemp[i] = NULL; + arc << nametemp[i]; + playertemp[i].Serialize(arc); + tempPlayerUsed[i] = 0; + } + for (i = 0; i < MAXPLAYERS; ++i) + { + playerUsed[i] = playeringame[i] ? 0 : 2; + } + + if (!skipload) + { + // Now try to match players from the savegame with players present + // based on their names. If two players in the savegame have the + // same name, then they are assigned to players in the current game + // on a first-come, first-served basis. + for (i = 0; i < numPlayers; ++i) + { + for (j = 0; j < MAXPLAYERS; ++j) + { + if (playerUsed[j] == 0 && stricmp(players[j].userinfo.GetName(), nametemp[i]) == 0) + { // Found a match, so copy our temp player to the real player + Printf("Found player %d (%s) at %d\n", i, nametemp[i], j); + CopyPlayer(&players[j], &playertemp[i], nametemp[i]); + playerUsed[j] = 1; + tempPlayerUsed[i] = 1; + break; + } + } + } + + // Any players that didn't have matching names are assigned to existing + // players on a first-come, first-served basis. + for (i = 0; i < numPlayers; ++i) + { + if (tempPlayerUsed[i] == 0) + { + for (j = 0; j < MAXPLAYERS; ++j) + { + if (playerUsed[j] == 0) + { + Printf("Assigned player %d (%s) to %d (%s)\n", i, nametemp[i], j, players[j].userinfo.GetName()); + CopyPlayer(&players[j], &playertemp[i], nametemp[i]); + playerUsed[j] = 1; + tempPlayerUsed[i] = 1; + break; + } + } + } + } + + // Make sure any extra players don't have actors spawned yet. Happens if the players + // present now got the same slots as they had in the save, but there are not as many + // as there were in the save. + for (j = 0; j < MAXPLAYERS; ++j) + { + if (playerUsed[j] == 0) + { + if (players[j].mo != NULL) + { + players[j].mo->Destroy(); + players[j].mo = NULL; + } + } + } + + // Remove any temp players that were not used. Happens if there are fewer players + // than there were in the save, and they got shuffled. + for (i = 0; i < numPlayers; ++i) + { + if (tempPlayerUsed[i] == 0) + { + playertemp[i].mo->Destroy(); + playertemp[i].mo = NULL; + } + } + } + + delete[] tempPlayerUsed; + delete[] playertemp; + for (i = 0; i < numPlayers; ++i) + { + delete[] nametemp[i]; + } + delete[] nametemp; +#endif +} + +//========================================================================== +// +// +// +//========================================================================== + +void CopyPlayer(player_t *dst, player_t *src, const char *name) +{ + // The userinfo needs to be saved for real players, but it + // needs to come from the save for bots. + userinfo_t uibackup; + userinfo_t uibackup2; + + uibackup.TransferFrom(dst->userinfo); + uibackup2.TransferFrom(src->userinfo); + + int chasecam = dst->cheats & CF_CHASECAM; // Remember the chasecam setting + bool attackdown = dst->attackdown; + bool usedown = dst->usedown; + + + *dst = *src; // To avoid memory leaks at this point the userinfo in src must be empty which is taken care of by the TransferFrom call above. + + dst->cheats |= chasecam; + + if (dst->Bot != nullptr) + { + botinfo_t *thebot = bglobal.botinfo; + while (thebot && stricmp(name, thebot->name)) + { + thebot = thebot->next; + } + if (thebot) + { + thebot->inuse = BOTINUSE_Yes; + } + bglobal.botnum++; + dst->userinfo.TransferFrom(uibackup2); + } + else + { + dst->userinfo.TransferFrom(uibackup); + } + // Validate the skin + dst->userinfo.SkinNumChanged(R_FindSkin(skins[dst->userinfo.GetSkin()].name, dst->CurrentPlayerClass)); + + // Make sure the player pawn points to the proper player struct. + if (dst->mo != nullptr) + { + dst->mo->player = dst; + } + + // Same for the psprites. + DPSprite *pspr = dst->psprites; + while (pspr) + { + pspr->Owner = dst; + + pspr = pspr->Next; + } + + // Don't let the psprites be destroyed when src is destroyed. + src->psprites = nullptr; + + // These 2 variables may not be overwritten. + dst->attackdown = attackdown; + dst->usedown = usedown; +} + +//========================================================================== +// +// +// +//========================================================================== + +static void SpawnExtraPlayers() +{ + // If there are more players now than there were in the savegame, + // be sure to spawn the extra players. + int i; + + if (deathmatch) + { + return; + } + + for (i = 0; i < MAXPLAYERS; ++i) + { + if (playeringame[i] && players[i].mo == NULL) + { + players[i].playerstate = PST_ENTER; + P_SpawnPlayer(&playerstarts[i], i, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); + } + } +} + //============================================================================ // // @@ -838,7 +904,7 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) } } - //Renderer->StartSerialize(arc); + Renderer->StartSerialize(arc); if (arc.isReading()) { P_DestroyThinkers(hubload); @@ -894,53 +960,10 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) StatusBar->SerializeMessages(arc); AM_SerializeMarkers(arc); FRemapTable::StaticSerializeTranslations(arc); - -} - - - -//========================================================================== -// -// ArchiveSounds -// -//========================================================================== - -void P_SerializeSounds (FArchive &arc) -{ - S_SerializeSounds (arc); - //DSeqNode::SerializeSequences (arc); - char *name = NULL; - BYTE order; - - if (arc.IsStoring ()) - { - order = S_GetMusic (&name); - } - arc << name << order; - if (arc.IsLoading ()) - { - if (!S_ChangeMusic (name, order)) - if (level.cdtrack == 0 || !S_ChangeCDMusic (level.cdtrack, level.cdid)) - S_ChangeMusic (level.Music, level.musicorder); - } - delete[] name; -} - -//========================================================================== -// -// -//========================================================================== - -void G_SerializeLevel(FArchive &arc, bool hubLoad) -{ -#if 0 - - // This must be saved, too, of course! FCanvasTextureInfo::Serialize(arc); - - P_SerializePlayers(arc, hubLoad); + //P_SerializePlayers(arc, hubLoad); P_SerializeSounds(arc); - if (arc.IsLoading()) + if (arc.isReading()) { for (int i = 0; i < numsectors; i++) { @@ -955,6 +978,16 @@ void G_SerializeLevel(FArchive &arc, bool hubLoad) } } Renderer->EndSerialize(arc); -#endif + +} + + +//========================================================================== +// +// +//========================================================================== + +void G_SerializeLevel(FArchive &arc, bool hubLoad) +{ } diff --git a/src/p_saveg.h b/src/p_saveg.h index fee2874fd..63beb72b8 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -40,9 +40,7 @@ struct PNGHandle; // Persistent storage/archiving. // These are the load / save game routines. // Also see farchive.(h|cpp) -void P_SerializePlayers (FArchive &arc, bool fakeload); void P_DestroyThinkers(bool hubLoad); -void P_SerializeSounds (FArchive &arc); void P_ReadACSDefereds (PNGHandle *png); void P_WriteACSDefereds (FILE *file); diff --git a/src/r_defs.h b/src/r_defs.h index 4a0f038de..efd9fc641 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -272,14 +272,13 @@ class ASkyViewpoint; struct secplane_t { - friend FArchive &operator<< (FArchive &arc, secplane_t &plane); // the plane is defined as a*x + b*y + c*z + d = 0 // ic is 1/c, for faster Z calculations -//private: // restore when JSON serializer is done. DVector3 normal; double D, negiC; // negative iC because that also saves a negation in all methods using this. public: + friend FSerializer &Serialize(FSerializer &arc, const char *key, secplane_t &p, secplane_t *def); void set(double aa, double bb, double cc, double dd) { @@ -437,9 +436,6 @@ public: }; -FArchive &operator<< (FArchive &arc, secplane_t &plane); - - #include "p_3dfloors.h" // Ceiling/floor flags enum @@ -544,8 +540,6 @@ struct extsector_t TArray lightlist; // 3D light list TArray attached; // 3D floors attached to this sector } XFloor; - - void Serialize(FArchive &arc); }; struct FTransform @@ -1033,9 +1027,6 @@ public: extsector_t * e; // This stores data that requires construction/destruction. Such data must not be copied by R_FakeFlat. }; -FArchive &operator<< (FArchive &arc, sector_t::splane &p); - - struct ReverbContainer; struct zone_t { @@ -1198,8 +1189,6 @@ struct side_t vertex_t *V2() const; }; -FArchive &operator<< (FArchive &arc, side_t::part &p); - struct line_t { vertex_t *v1, *v2; // vertices, from v1 to v2 diff --git a/src/r_renderer.h b/src/r_renderer.h index a39520b49..c5385aadc 100644 --- a/src/r_renderer.h +++ b/src/r_renderer.h @@ -5,7 +5,7 @@ struct FRenderer; extern FRenderer *Renderer; -class FArchive; +class FSerializer; class FTexture; class AActor; class player_t; @@ -46,8 +46,8 @@ struct FRenderer virtual void StateChanged(AActor *actor) {} // notify the renderer that serialization of the curent level is about to start/end - virtual void StartSerialize(FArchive &arc) {} - virtual void EndSerialize(FArchive &arc) {} + virtual void StartSerialize(FSerializer &arc) {} + virtual void EndSerialize(FSerializer &arc) {} virtual int GetMaxViewPitch(bool down) = 0; // return value is in plain degrees diff --git a/src/r_utility.cpp b/src/r_utility.cpp index 985081a4b..b7276fe22 100644 --- a/src/r_utility.cpp +++ b/src/r_utility.cpp @@ -53,7 +53,7 @@ #include "v_font.h" #include "r_renderer.h" #include "r_data/colormaps.h" -#include "farchive.h" +#include "serializer.h" #include "r_utility.h" #include "d_player.h" #include "p_local.h" @@ -1041,37 +1041,49 @@ void FCanvasTextureInfo::EmptyList () // //========================================================================== -void FCanvasTextureInfo::Serialize(FArchive &arc) +void FCanvasTextureInfo::Serialize(FSerializer &arc) { -#if 0 - if (arc.IsStoring ()) + if (arc.isWriting()) { - FCanvasTextureInfo *probe; - - for (probe = List; probe != NULL; probe = probe->Next) + if (List != nullptr) { - if (probe->Texture != NULL && probe->Viewpoint != NULL) + if (arc.BeginArray("canvastextures")) { - arc << probe->Viewpoint << probe->FOV << probe->PicNum; + FCanvasTextureInfo *probe; + + for (probe = List; probe != nullptr; probe = probe->Next) + { + if (probe->Texture != nullptr && probe->Viewpoint != nullptr) + { + if (arc.BeginObject(nullptr)) + { + arc("viewpoint", probe->Viewpoint) + ("fov", probe->FOV) + ("texture", probe->PicNum) + .EndObject(); + } + } + } } } - AActor *nullactor = NULL; - arc << nullactor; } else { - AActor *viewpoint; - int fov; - FTextureID picnum; - - EmptyList (); - while (arc << viewpoint, viewpoint != NULL) + if (arc.BeginArray("canvastextures")) { - arc << fov << picnum; - Add (viewpoint, picnum, fov); + AActor *viewpoint; + int fov; + FTextureID picnum; + while (arc.BeginObject(nullptr)) + { + arc("viewpoint", viewpoint) + ("fov", fov) + ("texture", picnum) + .EndObject(); + Add(viewpoint, picnum, fov); + } } } -#endif } //========================================================================== diff --git a/src/r_utility.h b/src/r_utility.h index 4d004e835..da9a32d11 100644 --- a/src/r_utility.h +++ b/src/r_utility.h @@ -3,6 +3,8 @@ #include "r_state.h" #include "vectors.h" + +class FSerializer; // // Stuff from r_main.h that's needed outside the rendering code. @@ -113,7 +115,7 @@ struct FCanvasTextureInfo static void Add (AActor *viewpoint, FTextureID picnum, int fov); static void UpdateAll (); static void EmptyList (); - static void Serialize(FArchive &arc); + static void Serialize(FSerializer &arc); static void Mark(); private: diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 0506a0f3f..fcf5523ad 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -33,7 +33,7 @@ ** */ -#include "resourcefile.h" +#include "file_zip.h" #include "cmdlib.h" #include "templates.h" #include "v_text.h" @@ -44,6 +44,69 @@ #define BUFREADCOMMENT (0x400) +//========================================================================== +// +// Decompression subroutine +// +//========================================================================== + +static bool UncompressZipLump(char *Cache, FileReader *Reader, int Method, int LumpSize, int CompressedSize, int GPFlags) +{ + switch (Method) + { + case METHOD_STORED: + { + Reader->Read(Cache, LumpSize); + break; + } + + case METHOD_DEFLATE: + { + FileReaderZ frz(*Reader, true); + frz.Read(Cache, LumpSize); + break; + } + + case METHOD_BZIP2: + { + FileReaderBZ2 frz(*Reader); + frz.Read(Cache, LumpSize); + break; + } + + case METHOD_LZMA: + { + FileReaderLZMA frz(*Reader, LumpSize, true); + frz.Read(Cache, LumpSize); + break; + } + + case METHOD_IMPLODE: + { + FZipExploder exploder; + exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); + break; + } + + case METHOD_SHRINK: + { + ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); + break; + } + + default: + assert(0); + return false; + } + return true; +} + +bool FCompressedBuffer::Decompress(char *destbuffer) +{ + MemoryReader mr(mBuffer, mCompressedSize); + return UncompressZipLump(destbuffer, &mr, mMethod, mSize, mCompressedSize, mZipFlags); +} + //----------------------------------------------------------------------- // // Finds the central directory end record in the end of the file. @@ -96,56 +159,6 @@ static DWORD Zip_FindCentralDir(FileReader * fin) return uPosFound; } - -enum -{ - LUMPFZIP_NEEDFILESTART = 128 -}; - -//========================================================================== -// -// Zip Lump -// -//========================================================================== - -struct FZipLump : public FResourceLump -{ - WORD GPFlags; - BYTE Method; - int CompressedSize; - int Position; - - virtual FileReader *GetReader(); - virtual int FillCache(); - -private: - void SetLumpAddress(); - virtual int GetFileOffset() - { - if (Method != METHOD_STORED) return -1; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); return Position; - } -}; - - -//========================================================================== -// -// Zip file -// -//========================================================================== - -class FZipFile : public FResourceFile -{ - FZipLump *Lumps; - -public: - FZipFile(const char * filename, FileReader *file); - virtual ~FZipFile(); - bool Open(bool quiet); - virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } -}; - - //========================================================================== // // Zip file @@ -285,6 +298,24 @@ FZipFile::~FZipFile() if (Lumps != NULL) delete [] Lumps; } +//========================================================================== +// +// +// +//========================================================================== + +FCompressedBuffer FZipFile::GetRawLump(int lumpnum) +{ + if ((unsigned)lumpnum >= NumLumps) + { + return{ 0,0,0,0,nullptr }; + } + FZipLump *lmp = &Lumps[lumpnum]; + FCompressedBuffer cbuf = { (unsigned)lmp->LumpSize, (unsigned)lmp->CompressedSize, lmp->Method, lmp->GPFlags, new char[lmp->CompressedSize] }; + Reader->Seek(lmp->Position, SEEK_SET); + Reader->Read(cbuf.mBuffer, lmp->CompressedSize); +} + //========================================================================== // // SetLumpAddress @@ -348,56 +379,22 @@ int FZipLump::FillCache() Owner->Reader->Seek(Position, SEEK_SET); Cache = new char[LumpSize]; - switch (Method) - { - case METHOD_STORED: - { - Owner->Reader->Read(Cache, LumpSize); - break; - } - - case METHOD_DEFLATE: - { - FileReaderZ frz(*Owner->Reader, true); - frz.Read(Cache, LumpSize); - break; - } - - case METHOD_BZIP2: - { - FileReaderBZ2 frz(*Owner->Reader); - frz.Read(Cache, LumpSize); - break; - } - - case METHOD_LZMA: - { - FileReaderLZMA frz(*Owner->Reader, LumpSize, true); - frz.Read(Cache, LumpSize); - break; - } - - case METHOD_IMPLODE: - { - FZipExploder exploder; - exploder.Explode((unsigned char *)Cache, LumpSize, Owner->Reader, CompressedSize, GPFlags); - break; - } - - case METHOD_SHRINK: - { - ShrinkLoop((unsigned char *)Cache, LumpSize, Owner->Reader, CompressedSize); - break; - } - - default: - assert(0); - return 0; - } + UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); RefCount = 1; return 1; } +//========================================================================== +// +// +// +//========================================================================== + +int FZipLump::GetFileOffset() +{ + if (Method != METHOD_STORED) return -1; + if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); return Position; +} //========================================================================== // diff --git a/src/resourcefiles/file_zip.h b/src/resourcefiles/file_zip.h new file mode 100644 index 000000000..54fbde92b --- /dev/null +++ b/src/resourcefiles/file_zip.h @@ -0,0 +1,64 @@ +#ifndef __FILE_ZIP_H +#define __FILE_ZIP_H + +#include "resourcefile.h" + +// This holds a compresed Zip entry with all needed info to decompress it. +struct FCompressedBuffer +{ + unsigned mSize; + unsigned mCompressedSize; + int mMethod; + int mZipFlags; + char *mBuffer; + + bool Decompress(char *destbuffer); +}; + +enum +{ + LUMPFZIP_NEEDFILESTART = 128 +}; + +//========================================================================== +// +// Zip Lump +// +//========================================================================== + +struct FZipLump : public FResourceLump +{ + WORD GPFlags; + BYTE Method; + int CompressedSize; + int Position; + + virtual FileReader *GetReader(); + virtual int FillCache(); + +private: + void SetLumpAddress(); + virtual int GetFileOffset(); +}; + + +//========================================================================== +// +// Zip file +// +//========================================================================== + +class FZipFile : public FResourceFile +{ + FZipLump *Lumps; + +public: + FZipFile(const char * filename, FileReader *file); + virtual ~FZipFile(); + bool Open(bool quiet); + virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } + FCompressedBuffer GetRawLump(int lumpnum); +}; + + +#endif \ No newline at end of file diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 0f7d690fa..7716a8d27 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -50,8 +50,9 @@ #include "timidity/timidity.h" #include "g_level.h" #include "po_man.h" -#include "farchive.h" +#include "serializer.h" #include "d_player.h" +#include "r_state.h" // MACROS ------------------------------------------------------------------ @@ -2208,58 +2209,41 @@ void S_StopChannel(FSoundChan *chan) //========================================================================== // -// (FArchive &) << (FSoundID &) +// // //========================================================================== -FArchive &operator<<(FArchive &arc, FSoundID &sid) +static FSerializer &Serialize(FSerializer &arc, const char *key, FSoundChan &chan, FSoundChan *def) { - if (arc.IsStoring()) + if (arc.BeginObject(key)) { - arc.WriteName((const char *)sid); - } - else - { - sid = arc.ReadName(); - } - return arc; -} + arc("sourcetype", chan.SourceType) + ("soundid", chan.SoundID) + ("orgid", chan.OrgID) + ("volume", chan.Volume) + ("distancescale", chan.DistanceScale) + ("pitch", chan.Pitch) + ("chanflags", chan.ChanFlags) + ("entchannel", chan.EntChannel) + ("priority", chan.Priority) + ("nearlimit", chan.NearLimit) + ("starttime", chan.StartTime.AsOne) + ("rolloftype", chan.Rolloff.RolloffType) + ("rolloffmin", chan.Rolloff.MinDistance) + ("rolloffmax", chan.Rolloff.MaxDistance) + ("limitrange", chan.LimitRange); -//========================================================================== -// -// (FArchive &) << (FSoundChan &) -// -//========================================================================== - -static FArchive &operator<<(FArchive &arc, FSoundChan &chan) -{ - arc << chan.SourceType; -#if 0 - switch (chan.SourceType) - { - case SOURCE_None: break; - case SOURCE_Actor: arc << chan.Actor; break; - case SOURCE_Sector: arc << chan.Sector; break; - case SOURCE_Polyobj: /*arc << chan.Poly;*/ break; - case SOURCE_Unattached: arc << chan.Point[0] << chan.Point[1] << chan.Point[2]; break; - default: I_Error("Unknown sound source type %d\n", chan.SourceType); break; + switch (chan.SourceType) + { + case SOURCE_None: break; + case SOURCE_Actor: arc("actor", chan.Actor); break; + case SOURCE_Sector: arc("sector", chan.Sector); break; + case SOURCE_Polyobj: arc("poly", chan.Poly); break; + case SOURCE_Unattached: arc.Array("point", chan.Point, 3); break; + default: I_Error("Unknown sound source type %d\n", chan.SourceType); break; + } + arc.EndObject(); } -#endif - arc << chan.SoundID - << chan.OrgID - << chan.Volume - << chan.DistanceScale - << chan.Pitch - << chan.ChanFlags - << chan.EntChannel - << chan.Priority - << chan.NearLimit - << chan.StartTime - << chan.Rolloff.RolloffType - << chan.Rolloff.MinDistance - << chan.Rolloff.MaxDistance - << chan.LimitRange; - return arc; } @@ -2269,13 +2253,13 @@ static FArchive &operator<<(FArchive &arc, FSoundChan &chan) // //========================================================================== -void S_SerializeSounds(FArchive &arc) +void S_SerializeSounds(FSerializer &arc) { FSoundChan *chan; GSnd->Sync(true); - if (arc.IsStoring()) + if (arc.isWriting()) { TArray chans; @@ -2292,16 +2276,17 @@ void S_SerializeSounds(FArchive &arc) chans.Push(chan); } } - - arc.WriteCount(chans.Size()); - - for (unsigned int i = chans.Size(); i-- != 0; ) + if (chans.Size() > 0 && arc.BeginArray("sounds")) { - // Replace start time with sample position. - QWORD start = chans[i]->StartTime.AsOne; - chans[i]->StartTime.AsOne = GSnd ? GSnd->GetPosition(chans[i]) : 0; - arc << *chans[i]; - chans[i]->StartTime.AsOne = start; + for (unsigned int i = chans.Size(); i-- != 0; ) + { + // Replace start time with sample position. + QWORD start = chans[i]->StartTime.AsOne; + chans[i]->StartTime.AsOne = GSnd ? GSnd->GetPosition(chans[i]) : 0; + arc(nullptr, *chans[i]); + chans[i]->StartTime.AsOne = start; + } + arc.EndArray(); } } else @@ -2309,13 +2294,17 @@ void S_SerializeSounds(FArchive &arc) unsigned int count; S_StopAllChannels(); - count = arc.ReadCount(); - for (unsigned int i = 0; i < count; ++i) + if (arc.BeginArray("sounds")) { - chan = (FSoundChan*)S_GetChannel(NULL); - arc << *chan; - // Sounds always start out evicted when restored from a save. - chan->ChanFlags |= CHAN_EVICTED | CHAN_ABSTIME; + count = arc.ArraySize(); + for (unsigned int i = 0; i < count; ++i) + { + chan = (FSoundChan*)S_GetChannel(NULL); + arc(nullptr, *chan); + // Sounds always start out evicted when restored from a save. + chan->ChanFlags |= CHAN_EVICTED | CHAN_ABSTIME; + } + arc.EndArray(); } // The two tic delay is to make sure any screenwipes have finished. // This needs to be two because the game is run for one tic before @@ -2326,7 +2315,6 @@ void S_SerializeSounds(FArchive &arc) // sounds might be heard briefly before pausing for the wipe. RestartEvictionsAt = level.time + 2; } - //DSeqNode::SerializeSequences(arc); GSnd->Sync(false); GSnd->UpdateSounds(); } diff --git a/src/s_sound.h b/src/s_sound.h index c2e0f187e..29b5dfb2d 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -321,7 +321,7 @@ bool S_ChangeSoundVolume(AActor *actor, int channel, float volume); void S_RelinkSound (AActor *from, AActor *to); // Stores/retrieves playing channel information in an archive. -void S_SerializeSounds(FArchive &arc); +void S_SerializeSounds(FSerializer &arc); // Start music using bool S_StartMusic (const char *music_name); diff --git a/src/serializer.cpp b/src/serializer.cpp index 66d23cd72..511bc6086 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -30,6 +30,7 @@ #include "g_shared/a_sharedglobal.h" #include "po_man.h" #include "v_font.h" +#include "w_zip.h" char nulspace[1024 * 1024 * 4]; @@ -133,7 +134,7 @@ struct FReader return &it->value; } } - else if (obj.mObject->IsArray() && obj.mIndex < obj.mObject->Size()) + else if (obj.mObject->IsArray() && (unsigned)obj.mIndex < obj.mObject->Size()) { return &(*obj.mObject)[obj.mIndex++]; } @@ -175,8 +176,33 @@ bool FSerializer::OpenReader(const char *buffer, size_t length) // //========================================================================== -void FSerializer::Close() +bool FSerializer::OpenReader(FCompressedBuffer *input) { + if (input->mSize <= 0 || input->mBuffer == nullptr) return false; + if (w != nullptr || r != nullptr) return false; + + if (input->mMethod == METHOD_STORED) + { + r = new FReader((char*)input->mBuffer, input->mSize); + return true; + } + else + { + char *unpacked = new char[input->mSize]; + input->Decompress(unpacked); + r = new FReader(unpacked, input->mSize); + return true; + } +} + +//========================================================================== +// +// +// +//========================================================================== + +void FSerializer::Close() +{ if (w != nullptr) { delete w; @@ -622,8 +648,15 @@ void FSerializer::WriteObjects() } } +//========================================================================== +// +// +// +//========================================================================== + const char *FSerializer::GetOutput(unsigned *len) { + if (isReading()) return nullptr; if (len != nullptr) { *len = (unsigned)w->mOutString.GetSize(); @@ -637,6 +670,63 @@ const char *FSerializer::GetOutput(unsigned *len) // //========================================================================== +FCompressedBuffer FSerializer::GetCompressedOutput() +{ + if (isReading()) return{ 0,0,0,0,nullptr }; + FCompressedBuffer buff; + buff.mSize = (unsigned)w->mOutString.GetSize(); + buff.mZipFlags = 0; + + uint8_t *compressbuf = new uint8_t[buff.mSize+1]; + + z_stream stream; + int err; + + stream.next_in = (Bytef *)w->mOutString.GetString(); + stream.avail_in = buff.mSize; + stream.next_out = (Bytef*)compressbuf; + stream.avail_out = buff.mSize; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + // create output in zip-compatible form as required by FCompressedBuffer + err = deflateInit2(&stream, 8, Z_DEFLATED, -15, 9, Z_DEFAULT_STRATEGY); + if (err != Z_OK) + { + goto error; + } + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) + { + deflateEnd(&stream); + goto error; + } + buff.mCompressedSize = stream.total_out; + + err = deflateEnd(&stream); + if (err == Z_OK) + { + buff.mBuffer = new char[buff.mCompressedSize]; + buff.mMethod = METHOD_DEFLATE; + memcpy(buff.mBuffer, compressbuf, buff.mCompressedSize); + delete[] compressbuf; + } + +error: + memcpy(compressbuf, w->mOutString.GetString(), buff.mSize + 1); + buff.mCompressedSize = buff.mSize; + buff.mMethod = METHOD_STORED; + return buff; +} + +//========================================================================== +// +// +// +//========================================================================== + FSerializer &Serialize(FSerializer &arc, const char *key, bool &value, bool *defval) { if (arc.isWriting()) @@ -916,6 +1006,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *& return SerializePointer(arc, key, value, defval, polyobjs); } +template<> FSerializer &Serialize(FSerializer &arc, const char *key, const FPolyObj *&value, const FPolyObj **defval) +{ + return SerializePointer(arc, key, value, defval, polyobjs); +} + template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval) { return SerializePointer(arc, key, value, defval, sides); @@ -926,6 +1021,11 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *& return SerializePointer(arc, key, value, defval, sectors); } +template<> FSerializer &Serialize(FSerializer &arc, const char *key, const sector_t *&value, const sector_t **defval) +{ + return SerializePointer(arc, key, value, defval, sectors); +} + template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval) { return SerializePointer(arc, key, value, defval, players); diff --git a/src/serializer.h b/src/serializer.h index cec13ae1c..7b35d4d9a 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -5,6 +5,7 @@ #include #include "tarray.h" #include "r_defs.h" +#include "resourcefiles/file_zip.h" struct FWriter; struct FReader; @@ -38,7 +39,6 @@ struct NumericValue }; - class FSerializer { @@ -57,6 +57,7 @@ public: } bool OpenWriter(); bool OpenReader(const char *buffer, size_t length); + bool OpenReader(FCompressedBuffer *input); void Close(); bool BeginObject(const char *name, bool randomaccess = false); void EndObject(); @@ -66,6 +67,7 @@ public: unsigned GetSize(const char *group); const char *GetKey(); const char *GetOutput(unsigned *len = nullptr); + FCompressedBuffer GetCompressedOutput(); FSerializer &Args(const char *key, int *args, int *defargs, int special); FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr); FSerializer &Sprite(const char *key, int32_t &spritenum, int32_t *def); @@ -203,6 +205,8 @@ FSerializer &Serialize(FSerializer &arc, const char *key, TArray &value, template<> FSerializer &Serialize(FSerializer &arc, const char *key, FPolyObj *&value, FPolyObj **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, const FPolyObj *&value, const FPolyObj **defval); +template<> FSerializer &Serialize(FSerializer &arc, const char *key, const sector_t *&value, const sector_t **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, player_t *&value, player_t **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, line_t *&value, line_t **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&value, side_t **defval); @@ -216,6 +220,9 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimat template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); + +template<> FSerializer &Serialize(FSerializer &arc, const char *key, sector_t *&value, sector_t **defval); + FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode); template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) { @@ -250,7 +257,7 @@ inline FSerializer &Serialize(FSerializer &arc, const char *key, PalEntry &pe, P inline FSerializer &Serialize(FSerializer &arc, const char *key, FRenderStyle &style, FRenderStyle *def) { - return Serialize(arc, key, style.AsDWORD, def ? &def->AsDWORD : nullptr); + return arc.Array(key, &style.BlendOp, def ? &def->BlendOp : nullptr, 4); } template