From ae7b84a85f3bb409ac84a6888b8ed975eb050dd7 Mon Sep 17 00:00:00 2001 From: Christian Kenny Date: Wed, 8 Sep 2021 18:26:56 -0400 Subject: [PATCH] Savestates: Use folders for organizing savestates per game. --- pcsx2/R5900.cpp | 2 +- pcsx2/SaveState.cpp | 54 ++++++++++++++++++++++++++++++++----- pcsx2/SaveState.h | 5 ++-- pcsx2/gui/AppConfig.cpp | 6 +++++ pcsx2/gui/AppConfig.h | 2 +- pcsx2/gui/AppCoreThread.cpp | 5 ++++ pcsx2/gui/Saveslots.cpp | 2 +- pcsx2/gui/Saveslots.h | 4 +-- pcsx2/gui/SysState.cpp | 11 +++++--- pcsx2/gui/UpdateUI.cpp | 3 ++- pcsx2/ps2/BiosTools.cpp | 2 +- pcsx2/ps2/BiosTools.h | 1 + 12 files changed, 78 insertions(+), 19 deletions(-) diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index b190d5ab17..2da3cfc42a 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -715,7 +715,7 @@ void __fastcall eeloadHook() } } - if (!g_GameStarted && (disctype == 2 || disctype == 1) && fromUTF8(elfname) == discelf) + if (!g_GameStarted && ((disctype == 2 && elfname == discelf.ToStdString()) || disctype == 1)) g_GameLoading = true; } diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index dd67687afe..9816727105 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -73,16 +73,56 @@ static void PostLoadPrep() // -------------------------------------------------------------------------------------- // SaveStateBase (implementations) // -------------------------------------------------------------------------------------- -wxString SaveStateBase::GetFilename( int slot ) +wxString SaveStateBase::GetSavestateFolder( int slot, bool isSavingOrLoading ) { - wxString serialName( DiscSerial ); - if (serialName.IsEmpty()) serialName = L"BIOS"; + wxString CRCvalue = wxString::Format(wxT("%08X"), ElfCRC); + wxString serialName(DiscSerial); - return (EmuFolders::Savestates + - pxsFmt( L"%s (%08X).%02d.p2s", WX_STR(serialName), ElfCRC, slot )).GetFullPath(); + if (g_GameStarted || g_GameLoading) + { + if (DiscSerial.IsEmpty()) + { + std::string ElfString = LastELF.ToStdString(); + std::string ElfString_delimiter = "/"; - //return (g_Conf->Folders.Savestates + - // pxsFmt( L"%08X.%03d", ElfCRC, slot )).GetFullPath(); +#ifndef _UNIX_ + std::replace(ElfString.begin(), ElfString.end(), '\\', '/'); +#endif + size_t pos = 0; + while ((pos = ElfString.find(ElfString_delimiter)) != std::string::npos) + { + // Running homebrew/standalone ELF, return only the ELF name. + ElfString.erase(0, pos + ElfString_delimiter.length()); + } + wxString ElfString_toWxString(ElfString.c_str(), wxConvUTF8); + serialName = ElfString_toWxString; + } + else + { + // Running a normal retail game + // Folder format is "SLXX-XXXX - (00000000)" + serialName = DiscSerial; + } + } + else + { + // Still inside the BIOS/not running a game (why would anyone want to do this?) + wxString biosString = (pxsFmt(L"BIOS (%s v%u.%u)", WX_STR(biosZone), (BiosVersion >> 8), BiosVersion & 0xff)); + serialName = biosString; + CRCvalue = L"None"; + } + + wxFileName dirname = wxFileName::DirName(g_Conf->FullpathToSaveState(serialName, CRCvalue)); + + if (isSavingOrLoading) + { + if (!wxDirExists(g_Conf->FullpathToSaveState(serialName, CRCvalue))) + { + wxMkdir(g_Conf->FullpathToSaveState(serialName, CRCvalue)); + } + } + return (dirname.GetPath() + "/" + + pxsFmt( L"%s (%s).%02d.p2s", WX_STR(serialName), WX_STR(CRCvalue), slot )); } SaveStateBase::SaveStateBase( SafeArray& memblock ) diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 30998ec7a1..417f6f512b 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -31,7 +31,7 @@ enum class FreezeAction // the lower 16 bit value. IF the change is breaking of all compatibility with old // states, increment the upper 16 bit value, and clear the lower 16 bits to 0. -static const u32 g_SaveVersion = (0x9A28 << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A29 << 16) | 0x0000; // the freezing data between submodules and core // an interesting thing to note is that this dates back from before plugin @@ -74,7 +74,7 @@ public: SaveStateBase( VmStateBuffer* memblock ); virtual ~SaveStateBase() { } - static wxString GetFilename( int slot ); + static wxString GetSavestateFolder( int slot, bool isSavingOrLoading = false ); // Gets the version of savestate that this object is acting on. // The version refers to the low 16 bits only (high 16 bits classifies Pcsx2 build types) @@ -349,3 +349,4 @@ namespace Exception }; }; // namespace Exception +extern wxString GetSavestateFolder( int slot ); diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 1d7ad44f5c..c8edbcf02c 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -485,6 +485,12 @@ void AppConfig::FolderOptions::Set(FoldersEnum_t folderidx, const wxString& src, } } +wxString AppConfig::FullpathToSaveState(wxString serialName, wxString CRCvalue) const +{ + wxString Sstate_append = serialName + " - " + "(" + CRCvalue + ")"; + return Path::Combine(Folders.Savestates, Sstate_append); +} + bool IsPortable() { return InstallationMode == InstallMode_Portable; diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index d768c2a654..ce3149f2d2 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -294,7 +294,7 @@ public: public: AppConfig(); - + wxString FullpathToSaveState(wxString serialName, wxString CRCvalue) const; void LoadSave(IniInterface& ini, SettingsWrapper& wrap); void LoadSaveRootItems(IniInterface& ini); diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index 21e2d89663..1512ba5381 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -460,6 +460,11 @@ static void _ApplySettings(const Pcsx2Config& src, Pcsx2Config& fixup) gameCompat = L" [Status = " + compatToStringWX(game.compat) + L"]"; gameMemCardFilter = fromUTF8(game.memcardFiltersAsString()); } + else + { + // Set correct title for loading standalone/homebrew ELFs + GameInfo::gameName = LastELF.AfterLast('\\'); + } if (fixup.EnablePatches) { diff --git a/pcsx2/gui/Saveslots.cpp b/pcsx2/gui/Saveslots.cpp index 25b449cf56..d6a2c2670e 100644 --- a/pcsx2/gui/Saveslots.cpp +++ b/pcsx2/gui/Saveslots.cpp @@ -116,7 +116,7 @@ void States_DefrostCurrentSlotBackup() void States_updateLoadBackupMenuItem() { - wxString file = SaveStateBase::GetFilename(StatesC) + ".backup"; + wxString file(SaveStateBase::GetSavestateFolder(StatesC) + ".backup"); sMainFrame.EnableMenuItem(MenuId_State_LoadBackup, wxFileExists(file)); sMainFrame.SetMenuItemLabel(MenuId_State_LoadBackup, wxsFormat(L"%s %d", _("Backup"), StatesC)); diff --git a/pcsx2/gui/Saveslots.h b/pcsx2/gui/Saveslots.h index 12d58435d2..8903d949c9 100644 --- a/pcsx2/gui/Saveslots.h +++ b/pcsx2/gui/Saveslots.h @@ -68,14 +68,14 @@ public: bool isUsed() { - return wxFileExists(SaveStateBase::GetFilename(slot_num)); + return wxFileExists(SaveStateBase::GetSavestateFolder(slot_num, false)); } wxDateTime GetTimestamp() { if (!isUsed()) return wxInvalidDateTime; - return wxDateTime(wxFileModificationTime(SaveStateBase::GetFilename(slot_num))); + return wxDateTime(wxFileModificationTime(SaveStateBase::GetSavestateFolder(slot_num, false))); } void UpdateCache() diff --git a/pcsx2/gui/SysState.cpp b/pcsx2/gui/SysState.cpp index 2c6e7fd126..cdb5712f2d 100644 --- a/pcsx2/gui/SysState.cpp +++ b/pcsx2/gui/SysState.cpp @@ -33,6 +33,11 @@ #include "Patch.h" +// Required for savestate folder creation +#include "CDVD/CDVD.h" +#include "ps2/BiosTools.h" +#include "Elfheader.h" + // -------------------------------------------------------------------------------------- // SysExecEvent_DownloadState // -------------------------------------------------------------------------------------- @@ -176,12 +181,12 @@ void StateCopy_LoadFromFile(const wxString& file) // the one in the memory save. :) void StateCopy_SaveToSlot(uint num) { - const wxString file(SaveStateBase::GetFilename(num)); + const wxString file(SaveStateBase::GetSavestateFolder(num, true)); // Backup old Savestate if one exists. if (wxFileExists(file) && EmuConfig.BackupSavestate) { - const wxString copy(SaveStateBase::GetFilename(num) + pxsFmt(L".backup")); + const wxString copy(SaveStateBase::GetSavestateFolder(num, true) + pxsFmt(L".backup")); Console.Indent().WriteLn(Color_StrongGreen, L"Backing up existing state in slot %d.", num); wxRenameFile(file, copy); @@ -198,7 +203,7 @@ void StateCopy_SaveToSlot(uint num) void StateCopy_LoadFromSlot(uint slot, bool isFromBackup) { - wxString file(SaveStateBase::GetFilename(slot) + wxString(isFromBackup ? L".backup" : L"")); + wxString file(SaveStateBase::GetSavestateFolder(slot, true) + wxString(isFromBackup ? L".backup" : L"")); if (!wxFileExists(file)) { diff --git a/pcsx2/gui/UpdateUI.cpp b/pcsx2/gui/UpdateUI.cpp index c8b4b262a7..69370f8bb4 100644 --- a/pcsx2/gui/UpdateUI.cpp +++ b/pcsx2/gui/UpdateUI.cpp @@ -56,7 +56,8 @@ static void _SaveLoadStuff(bool enabled) for (Saveslot &slot : saveslot_cache) { // We need to reload the file information if the crc or serial # changed. - if ((slot.crc != ElfCRC)|| (slot.serialName != DiscSerial)) + // Invalidate slot cache when using full boot (g_GameLoading) otherwise it won't see the new folder path + if ((g_GameLoading || slot.crc != ElfCRC) || (slot.serialName != DiscSerial)) { slot.invalid_cache = true; crcChanged = true; diff --git a/pcsx2/ps2/BiosTools.cpp b/pcsx2/ps2/BiosTools.cpp index 252090fef0..5e3ff7f55f 100644 --- a/pcsx2/ps2/BiosTools.cpp +++ b/pcsx2/ps2/BiosTools.cpp @@ -46,6 +46,7 @@ static_assert( sizeof(romdir) == DIRENTRY_SIZE, "romdir struct not packed to 16 u32 BiosVersion; u32 BiosChecksum; u32 BiosRegion; +wxString biosZone; bool NoOSD; bool AllowParams1; bool AllowParams2; @@ -272,7 +273,6 @@ void LoadBIOS() BiosChecksum = 0; - wxString biosZone; wxFFile fp( Bios , "rb"); fp.Read( eeMem->ROM, std::min( Ps2MemSize::Rom, filesize ) ); diff --git a/pcsx2/ps2/BiosTools.h b/pcsx2/ps2/BiosTools.h index fadddd987e..e8513d0f5b 100644 --- a/pcsx2/ps2/BiosTools.h +++ b/pcsx2/ps2/BiosTools.h @@ -48,5 +48,6 @@ extern bool AllowParams1; extern bool AllowParams2; extern u32 BiosChecksum; extern wxString BiosDescription; +extern wxString biosZone; extern void LoadBIOS(); extern bool IsBIOS(const wxString& filename, wxString& description);