From 66c5beccbd00a8b114bcb3a8f2f924a5a89aebcf Mon Sep 17 00:00:00 2001 From: Boondorl Date: Sun, 20 Jul 2025 14:00:05 -0400 Subject: [PATCH] Added UUID for game sessions Allows the SavegameManager to destroy all saves related to the current UUID session so hardcore mods can enforce this safely instead of needing to go nuclear. --- src/common/engine/i_interface.cpp | 10 +++++++ src/common/engine/i_interface.h | 3 ++ src/common/menu/savegamemanager.cpp | 30 +++++++++++++++++++ src/common/menu/savegamemanager.h | 2 ++ src/g_game.cpp | 2 ++ src/g_level.cpp | 1 + src/menu/loadsavemenu.cpp | 2 ++ .../zscript/engine/ui/menu/loadsavemenu.zs | 2 ++ 8 files changed, 52 insertions(+) diff --git a/src/common/engine/i_interface.cpp b/src/common/engine/i_interface.cpp index 338f36c6c..a78b5b30f 100644 --- a/src/common/engine/i_interface.cpp +++ b/src/common/engine/i_interface.cpp @@ -6,6 +6,7 @@ #include "gstrings.h" #include "version.h" #include "m_argv.h" +#include "m_random.h" static_assert(sizeof(void*) == 8, "Only LP64/LLP64 builds are officially supported. " @@ -182,3 +183,12 @@ int FStartupSelectionInfo::SaveInfo() return DefaultIWAD; } +FString GameUUID; +static FRandom pr_uuid("GameUUID"); + +FString GenerateUUID() +{ + FString uuid; + uuid.AppendFormat("%08X-%04X-4%03X-9%03X-%08X%04X", pr_uuid.GenRand32(), pr_uuid(UINT16_MAX), pr_uuid(4095), pr_uuid(4095), pr_uuid.GenRand32(), pr_uuid(UINT16_MAX)); + return uuid; +} diff --git a/src/common/engine/i_interface.h b/src/common/engine/i_interface.h index e901705f2..ecff3f6b1 100644 --- a/src/common/engine/i_interface.h +++ b/src/common/engine/i_interface.h @@ -13,6 +13,9 @@ class FConfigFile; class FArgs; struct FTranslationID; +extern FString GameUUID; +FString GenerateUUID(); + struct SystemCallbacks { bool (*G_Responder)(event_t* ev); // this MUST be set, otherwise nothing will work diff --git a/src/common/menu/savegamemanager.cpp b/src/common/menu/savegamemanager.cpp index 961a01ea6..ac041d622 100644 --- a/src/common/menu/savegamemanager.cpp +++ b/src/common/menu/savegamemanager.cpp @@ -48,6 +48,7 @@ #include "savegamemanager.h" #include "m_argv.h" #include "i_specialpaths.h" +#include "i_interface.h" CVAR(String, save_dir, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_SYSTEM_ONLY); FString SavegameFolder; @@ -191,6 +192,7 @@ void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &tit { node->SaveTitle = title; node->CreationTime = myasctime(); + node->UUID = GameUUID; node->bOldVersion = false; node->bMissingWads = false; @@ -210,6 +212,7 @@ void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &tit auto node = new FSaveGameNode; node->SaveTitle = title; node->CreationTime = myasctime(); + node->UUID = GameUUID; node->Filename = file; node->bOldVersion = false; node->bMissingWads = false; @@ -560,6 +563,27 @@ bool FSavegameManagerBase::RemoveNewSaveNode() return false; } +int FSavegameManagerBase::RemoveUUIDSaveSlots() +{ + if (GameUUID.IsEmpty()) + return -1; + + // Make sure there's any saves in the list first. + if (!SaveGames.Size()) + ReadSaveStrings(); + + int index = -1; + for (int i = SaveGames.Size() - 1; i >= 0; --i) + { + auto& save = SaveGames[i]; + if (save == &NewSaveNode || save->UUID.Compare(GameUUID)) + continue; + + index = RemoveSaveSlot(i); + } + return index; +} + DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) { PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); @@ -581,9 +605,15 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) ACTION_RETURN_INT(self->ExtractSaveData(sel)); } +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveUUIDSaveSlots) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + ACTION_RETURN_INT(self->RemoveUUIDSaveSlots()); +} DEFINE_FIELD(FSaveGameNode, SaveTitle); DEFINE_FIELD(FSaveGameNode, Filename); +DEFINE_FIELD(FSaveGameNode, UUID); DEFINE_FIELD(FSaveGameNode, bOldVersion); DEFINE_FIELD(FSaveGameNode, bMissingWads); DEFINE_FIELD(FSaveGameNode, bNoDelete); diff --git a/src/common/menu/savegamemanager.h b/src/common/menu/savegamemanager.h index 4dd2eb69d..a5d84d212 100644 --- a/src/common/menu/savegamemanager.h +++ b/src/common/menu/savegamemanager.h @@ -12,6 +12,7 @@ struct FSaveGameNode FString SaveTitle; FString Filename; FString CreationTime; + FString UUID; bool bOldVersion = false; bool bMissingWads = false; bool bNoDelete = false; @@ -57,6 +58,7 @@ public: FSaveGameNode *GetSavegame(int i); void InsertNewSaveNode(); bool RemoveNewSaveNode(); + int RemoveUUIDSaveSlots(); }; diff --git a/src/g_game.cpp b/src/g_game.cpp index 9c38bd5aa..1bad3c24c 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2009,6 +2009,7 @@ void G_DoLoadGame () arc("Save Version", SaveVersion); arc("Engine", engine); arc("Current Map", map); + arc("GameUUID", GameUUID); if (engine.CompareNoCase(GAMESIG) != 0) { @@ -2386,6 +2387,7 @@ void G_DoSaveGame (bool okForQuicksave, bool forceQuicksave, FString filename, c savegameinfo.AddString("Software", buf) .AddString("Engine", GAMESIG) ("Save Version", ver) + ("GameUUID", GameUUID) .AddString("Title", description) .AddString("Current Map", primaryLevel->MapName.GetChars()); diff --git a/src/g_level.cpp b/src/g_level.cpp index 825979d4d..11d06c844 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -636,6 +636,7 @@ void G_InitNew (const char *mapname, bool bTitleLevel) players[i].playerstate = PST_ENTER; // [BC] STAT_StartNewGame(mapname); + GameUUID = GenerateUUID(); } usergame = !bTitleLevel; // will be set false if a demo diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index f701083fc..429d1c60b 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -102,6 +102,7 @@ void FSavegameManager::ReadSaveStrings() FString iwad = arc.GetString("Game WAD"); FString title = arc.GetString("Title"); FString creationtime = arc.GetString("Creation Time"); + FString uuid = arc.GetString("GameUUID"); if (engine.Compare(GAMESIG) != 0 || savever > SAVEVER) @@ -128,6 +129,7 @@ void FSavegameManager::ReadSaveStrings() FSaveGameNode *node = new FSaveGameNode; node->Filename = entry.FilePath.c_str(); + node->UUID = uuid; node->bOldVersion = oldVer; node->bMissingWads = missing; node->SaveTitle = title; diff --git a/wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs b/wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs index 82b5ea4bf..589951b2e 100644 --- a/wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/loadsavemenu.zs @@ -38,6 +38,7 @@ struct SaveGameNode native { native String SaveTitle; native readonly String Filename; + native readonly String UUID; native bool bOldVersion; native bool bMissingWads; native bool bNoDelete; @@ -68,6 +69,7 @@ struct SavegameManager native ui native SaveGameNode GetSavegame(int i); native void InsertNewSaveNode(); native bool RemoveNewSaveNode(); + native int RemoveUUIDSaveSlots(); }