diff --git a/source/common/console/c_enginecmds.cpp b/source/common/console/c_enginecmds.cpp index 542abe91d..0af6f3b56 100644 --- a/source/common/console/c_enginecmds.cpp +++ b/source/common/console/c_enginecmds.cpp @@ -293,8 +293,8 @@ CCMD (md5sum) } for (int i = 1; i < argv.argc(); ++i) { - FileReader fr = fileSystem.OpenFileReader(argv[i]); - if (!fr.isOpen()) + FileReader fr; + if (!fr.OpenFile(argv[i])) { Printf("%s: %s\n", argv[i], strerror(errno)); } diff --git a/source/common/menu/savegamemanager.cpp b/source/common/menu/savegamemanager.cpp index 22dd8c6a3..935b6dedd 100644 --- a/source/common/menu/savegamemanager.cpp +++ b/source/common/menu/savegamemanager.cpp @@ -232,7 +232,6 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring) { - RemoveNewSaveNode(); if (Selected != 0) { auto node = SaveGames[Selected]; diff --git a/source/common/platform/posix/sdl/sdlglvideo.cpp b/source/common/platform/posix/sdl/sdlglvideo.cpp index 9487854f9..43bd99a64 100644 --- a/source/common/platform/posix/sdl/sdlglvideo.cpp +++ b/source/common/platform/posix/sdl/sdlglvideo.cpp @@ -449,13 +449,14 @@ DFrameBuffer *SDLVideo::CreateFrameBuffer () device = new VulkanDevice(); fb = new VulkanFrameBuffer(nullptr, vid_fullscreen, device); } - catch (CVulkanError const&) + catch (CVulkanError const &error) { if (Priv::window != nullptr) { Priv::DestroyWindow(); } + Printf(TEXTCOLOR_RED "Initialization of Vulkan failed: %s\n", error.what()); Priv::vulkanEnabled = false; } } diff --git a/source/common/statusbar/base_sbar.cpp b/source/common/statusbar/base_sbar.cpp index 948b2504b..1dc34da9c 100644 --- a/source/common/statusbar/base_sbar.cpp +++ b/source/common/statusbar/base_sbar.cpp @@ -594,7 +594,7 @@ void DStatusBarCore::DrawGraphic(FGameTexture* tex, double x, double y, int flag DTA_FillColor, (flags & DI_ALPHAMAPPED) ? 0 : -1, DTA_FlipX, !!(flags & DI_MIRROR), DTA_FlipY, !!(flags& DI_MIRRORY), - DTA_LegacyRenderStyle, style, + DTA_LegacyRenderStyle, (flags & DI_ALPHAMAPPED) ? STYLE_Shaded : style, TAG_DONE); } diff --git a/source/core/cheats.h b/source/core/cheats.h index 7398073ae..d014dd03a 100644 --- a/source/core/cheats.h +++ b/source/core/cheats.h @@ -9,3 +9,4 @@ EXTERN_CVAR(Bool, sv_cheats) void genericCheat(int player, uint8_t** stream, bool skip); void changeMap(int player, uint8_t** stream, bool skip); void endScreenJob(int player, uint8_t** stream, bool skip); +void startSaveGame(int player, uint8_t** stream, bool skip); diff --git a/source/core/d_net.cpp b/source/core/d_net.cpp index 30c7891d1..041eada4f 100644 --- a/source/core/d_net.cpp +++ b/source/core/d_net.cpp @@ -1674,6 +1674,7 @@ bool D_CheckNetGame (void) Net_SetCommandHandler(DEM_GENERICCHEAT, genericCheat); Net_SetCommandHandler(DEM_CHANGEMAP, changeMap); Net_SetCommandHandler(DEM_ENDSCREENJOB, endScreenJob); + Net_SetCommandHandler(DEM_SAVEGAME, startSaveGame); for (i = 0; i < MAXNETNODES; i++) { diff --git a/source/core/d_protocol.h b/source/core/d_protocol.h index cac55b56e..4da710112 100644 --- a/source/core/d_protocol.h +++ b/source/core/d_protocol.h @@ -90,6 +90,7 @@ enum EDemoCommand DEM_GIVE, DEM_CHANGEMAP, DEM_ENDSCREENJOB, + DEM_SAVEGAME, DEM_MAX }; diff --git a/source/core/gamecontrol.h b/source/core/gamecontrol.h index cbf015712..a9c163947 100644 --- a/source/core/gamecontrol.h +++ b/source/core/gamecontrol.h @@ -12,6 +12,10 @@ #include "i_time.h" #include "palentry.h" +extern bool sendsave; +extern FString savedescription; +extern FString savegamefile; + extern FString currentGame; extern FString LumpFilter; extern int PlayClock; diff --git a/source/core/mainloop.cpp b/source/core/mainloop.cpp index ae596dcf1..f264739a3 100644 --- a/source/core/mainloop.cpp +++ b/source/core/mainloop.cpp @@ -110,6 +110,9 @@ FString BackupSaveGame; void DoLoadGame(const char* name); +bool sendsave; +FString savedescription; +FString savegamefile; //========================================================================== // @@ -119,6 +122,14 @@ void DoLoadGame(const char* name); void G_BuildTiccmd(ticcmd_t* cmd) { + if (sendsave) + { + sendsave = false; + Net_WriteByte(DEM_SAVEGAME); + Net_WriteString(savegamefile); + Net_WriteString(savedescription); + savegamefile = ""; + } cmd->ucmd = {}; I_GetEvent(); auto input = CONTROL_GetInput(); @@ -240,8 +251,10 @@ static void GameTicker() break; case ga_savegame: - // We only need this for multiplayer saves that need to go through the network. - // gi->SaveGame(); + G_DoSaveGame(true, false, savegamefile, savedescription); + gameaction = ga_nothing; + savegamefile = ""; + savedescription = ""; break; case ga_autosave: diff --git a/source/core/menu/loadsavemenu.cpp b/source/core/menu/loadsavemenu.cpp index ef9ba4e88..e1e4ddb0a 100644 --- a/source/core/menu/loadsavemenu.cpp +++ b/source/core/menu/loadsavemenu.cpp @@ -119,7 +119,7 @@ void FSavegameManager::PerformLoadGame(const char *f, bool s) void FSavegameManager::PerformSaveGame(const char *f, const char *s) { - G_SaveGame(f, s, true, false); + G_SaveGame(f, s); } FString FSavegameManager::BuildSaveName(const char* fn, int slot) diff --git a/source/core/menu/razemenu.cpp b/source/core/menu/razemenu.cpp index 764f2f096..cc2f4f156 100644 --- a/source/core/menu/razemenu.cpp +++ b/source/core/menu/razemenu.cpp @@ -309,7 +309,7 @@ CCMD(quicksave) // [mxd]. Just save the game, no questions asked. if (!saveloadconfirmation) { - G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle, true, true); + G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle); return; } @@ -320,7 +320,7 @@ CCMD(quicksave) DMenu* newmenu = CreateMessageBoxMenu(CurrentMenu, tempstring, 0, false, NAME_None, []() { M_ClearMenus(); - G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle, true, true); + G_SaveGame(savegameManager.quickSaveSlot->Filename, savegameManager.quickSaveSlot->SaveTitle); }); M_ActivateMenu(newmenu); diff --git a/source/core/savegamehelp.cpp b/source/core/savegamehelp.cpp index 1df080525..df576bafd 100644 --- a/source/core/savegamehelp.cpp +++ b/source/core/savegamehelp.cpp @@ -69,6 +69,7 @@ walltype wallbackup[MAXWALLS]; void WriteSavePic(FileWriter* file, int width, int height); bool WriteZip(const char* filename, TArray& filenames, TArray& content); extern FString BackupSaveGame; + void SerializeMap(FSerializer &arc); FixedBitArray activeSprites; @@ -694,18 +695,80 @@ static int nextquicksave = -1; BackupSaveGame = filename; } - void G_SaveGame(const char *fn, const char *desc, bool ok4q, bool forceq) + extern bool sendsave; + extern FString savedescription; + extern FString savegamefile; + + void G_SaveGame(const char* filename, const char* description) + { + if (sendsave || gameaction == ga_savegame) + { + Printf("%s\n", GStrings("TXT_SAVEPENDING")); + } + else if (gamestate != GS_LEVEL) + { + Printf("%s\n", GStrings("TXT_NOTINLEVEL")); + } + else if (!gi->CanSave()) + { + Printf("%s\n", GStrings("TXT_SPPLAYERDEAD")); + } + else + { + savegamefile = filename; + savedescription = description; + sendsave = true; + } + } + + //--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + + void startSaveGame(int player, uint8_t** stream, bool skip) + { + auto s = ReadString(stream); + savegamefile = s; + delete[] s; + s = ReadString(stream); + savedescription = s; + if (!skip && gi->CanSave()) + { + if (player != consoleplayer) + { + // Paths sent over the network will be valid for the system that sent + // the save command. For other systems, the path needs to be changed. + savegamefile = G_BuildSaveName(ExtractFileBase(savegamefile, true)); + } + gameaction = ga_savegame; + } + } + +//--------------------------------------------------------------------------- +// +// +// +//--------------------------------------------------------------------------- + + void G_DoSaveGame(bool ok4q, bool forceq, const char* fn, const char* desc) { if (WriteSavegame(fn, desc)) { - savegameManager.NotifyNewSave(fn, desc, ok4q, forceq); - Printf(PRINT_NOTIFY, "%s\n", GStrings("GAME SAVED")); - BackupSaveGame = fn; - } + savegameManager.NotifyNewSave(fn, desc, ok4q, forceq); + Printf(PRINT_NOTIFY, "%s\n", GStrings("GGSAVED")); + BackupSaveGame = fn; } + } + + //--------------------------------------------------------------------------- + // + // + // + //--------------------------------------------------------------------------- - -void M_Autosave() + void M_Autosave() { if (disableautosave) return; if (!gi->CanSave()) return; @@ -728,7 +791,7 @@ void M_Autosave() readableTime = myasctime(); FStringf SaveTitle("Autosave %s", readableTime); nextautosave = (nextautosave + 1) % count; - G_SaveGame(Filename, SaveTitle, false, false); + G_DoSaveGame(false, false, Filename, SaveTitle); } CCMD(autosave) @@ -759,7 +822,7 @@ CCMD(rotatingquicksave) readableTime = myasctime(); FStringf SaveTitle("Quicksave %s", readableTime); nextquicksave = (nextquicksave + 1) % count; - G_SaveGame(Filename, SaveTitle, false, false); + G_SaveGame(Filename, SaveTitle); } diff --git a/source/core/savegamehelp.h b/source/core/savegamehelp.h index 84502debb..486b8a4fe 100644 --- a/source/core/savegamehelp.h +++ b/source/core/savegamehelp.h @@ -12,7 +12,8 @@ FString G_BuildSaveName (const char *prefix); int G_ValidateSavegame(FileReader &fr, FString *savetitle, bool formenu); void G_LoadGame(const char* filename); -void G_SaveGame(const char* fn, const char* desc, bool ok4q, bool forceq); +void G_SaveGame(const char* fn, const char* desc); +void G_DoSaveGame(bool okForQuicksave, bool forceQuicksave, const char* filename, const char* description); void M_Autosave();