diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp index a1b1256c2..bf639cd6d 100644 --- a/src/core/host_interface.cpp +++ b/src/core/host_interface.cpp @@ -361,6 +361,19 @@ bool HostInterface::LoadState(const char* filename) return result; } +bool HostInterface::LoadState(bool global, u32 slot) +{ + const std::string& code = m_system->GetRunningCode(); + if (!global && code.empty()) + { + ReportFormattedError("Can't save per-game state without a running game code."); + return false; + } + + std::string save_path = global ? GetGlobalSaveStateFileName(slot) : GetGameSaveStateFileName(code.c_str(), slot); + return LoadState(save_path.c_str()); +} + bool HostInterface::SaveState(const char* filename) { std::unique_ptr stream = @@ -384,6 +397,19 @@ bool HostInterface::SaveState(const char* filename) return result; } +bool HostInterface::SaveState(bool global, u32 slot) +{ + const std::string& code = m_system->GetRunningCode(); + if (!global && code.empty()) + { + ReportFormattedError("Can't save per-game state without a running game code."); + return false; + } + + std::string save_path = global ? GetGlobalSaveStateFileName(slot) : GetGameSaveStateFileName(code.c_str(), slot); + return SaveState(save_path.c_str()); +} + void HostInterface::UpdateSpeedLimiterState() { m_speed_limiter_enabled = m_settings.speed_limiter_enabled && !m_speed_limiter_temp_disabled; @@ -543,6 +569,31 @@ std::string HostInterface::GetGameMemoryCardPath(const char* game_code, u32 slot return GetUserDirectoryRelativePath("memcards/game_card_%s_%d.mcd", game_code, slot + 1); } +std::vector HostInterface::GetAvailableSaveStates(const char* game_code) +{ + std::vector si; + std::string path; + + auto add_path = [&si](std::string path, s32 slot, bool global) { + FILESYSTEM_STAT_DATA sd; + if (!FileSystem::StatFile(path.c_str(), &sd)) + return; + + si.push_back(SaveStateInfo{std::move(path), sd.ModificationTime.AsUnixTimestamp(), static_cast(slot), global}); + }; + + if (game_code && std::strlen(game_code) > 0) + { + for (s32 i = 1; i <= PER_GAME_SAVE_STATE_SLOTS; i++) + add_path(GetGameSaveStateFileName(game_code, i), i, false); + } + + for (s32 i = 1; i <= GLOBAL_SAVE_STATE_SLOTS; i++) + add_path(GetGlobalSaveStateFileName(i), i, true); + + return si; +} + void HostInterface::SetDefaultSettings() { m_settings.region = ConsoleRegion::Auto; diff --git a/src/core/host_interface.h b/src/core/host_interface.h index f5c8a6144..31ba27a76 100644 --- a/src/core/host_interface.h +++ b/src/core/host_interface.h @@ -56,8 +56,6 @@ public: /// Loads the BIOS image for the specified region. virtual std::optional> GetBIOSImage(ConsoleRegion region); - bool LoadState(const char* filename); - bool SaveState(const char* filename); /// Returns the base user directory path. const std::string& GetUserDirectory() const { return m_user_directory; } @@ -71,7 +69,9 @@ protected: AUDIO_SAMPLE_RATE = 44100, AUDIO_CHANNELS = 2, AUDIO_BUFFER_SIZE = 2048, - AUDIO_BUFFERS = 2 + AUDIO_BUFFERS = 2, + PER_GAME_SAVE_STATE_SLOTS = 10, + GLOBAL_SAVE_STATE_SLOTS = 10 }; struct OSDMessage @@ -81,6 +81,14 @@ protected: float duration; }; + struct SaveStateInfo + { + std::string path; + u64 timestamp; + s32 slot; + bool global; + }; + virtual void SwitchGPURenderer(); virtual void OnSystemPerformanceCountersUpdated(); virtual void OnRunningGameChanged(); @@ -111,6 +119,17 @@ protected: /// Returns the default path to a memory card for a specific game. std::string GetGameMemoryCardPath(const char* game_code, u32 slot); + /// Returns a list of save states for the specified game code. + std::vector GetAvailableSaveStates(const char* game_code); + + /// Loads the current emulation state from file. Specifying a slot of -1 loads the "resume" game state. + bool LoadState(bool global, u32 slot); + bool LoadState(const char* filename); + + /// Saves the current emulation state to a file. Specifying a slot of -1 saves the "resume" save state. + bool SaveState(bool global, u32 slot); + bool SaveState(const char* filename); + /// Restores all settings to defaults. void SetDefaultSettings();