System: Include cheevos state in save states

This commit is contained in:
Connor McLaughlin 2022-03-27 00:52:11 +10:00
parent 584525cb11
commit a55b5022c7
6 changed files with 124 additions and 17 deletions

View file

@ -188,6 +188,18 @@ public:
Do(data); Do(data);
} }
void SkipBytes(size_t count)
{
if (m_mode != Mode::Read)
{
m_error = true;
return;
}
if (!m_error)
m_error = !m_stream->SeekRelative(static_cast<s64>(count));
}
private: private:
ByteStream* m_stream; ByteStream* m_stream;
Mode m_mode; Mode m_mode;

View file

@ -6,6 +6,7 @@
#include "common/log.h" #include "common/log.h"
#include "common/md5_digest.h" #include "common/md5_digest.h"
#include "common/platform.h" #include "common/platform.h"
#include "common/state_wrapper.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "common/timestamp.h" #include "common/timestamp.h"
#include "core/bios.h" #include "core/bios.h"
@ -310,6 +311,69 @@ void Update()
} }
} }
bool DoState(StateWrapper& sw)
{
// if we're inactive, we still need to skip the data (if any)
if (!g_active)
{
u32 data_size = 0;
sw.Do(&data_size);
if (data_size > 0)
sw.SkipBytes(data_size);
return !sw.HasError();
}
if (sw.IsReading())
{
u32 data_size = 0;
sw.Do(&data_size);
if (data_size == 0)
{
// reset runtime, no data (state might've been created without cheevos)
Log_DevPrintf("State is missing cheevos data, resetting runtime");
rc_runtime_reset(&s_rcheevos_runtime);
return !sw.HasError();
}
const std::unique_ptr<u8[]> data(new u8[data_size]);
sw.DoBytes(data.get(), data_size);
if (sw.HasError())
return false;
const int result = rc_runtime_deserialize_progress(&s_rcheevos_runtime, data.get(), nullptr);
if (result != RC_OK)
{
Log_WarningPrintf("Failed to deserialize cheevos state (%d), resetting", result);
rc_runtime_reset(&s_rcheevos_runtime);
}
return true;
}
else
{
// internally this happens twice.. not great.
const int size = rc_runtime_progress_size(&s_rcheevos_runtime, nullptr);
u32 data_size = (size >= 0) ? static_cast<u32>(size) : 0;
std::unique_ptr<u8[]> data(new u8[data_size]);
const int result = rc_runtime_serialize_progress(data.get(), &s_rcheevos_runtime, nullptr);
if (result != RC_OK)
{
// set data to zero, effectively serializing nothing
Log_WarningPrintf("Failed to serialize cheevos state (%d)", result);
data_size = 0;
}
sw.Do(&data_size);
if (data_size > 0)
sw.DoBytes(data.get(), data_size);
return !sw.HasError();
}
}
bool IsLoggedIn() bool IsLoggedIn()
{ {
return s_logged_in; return s_logged_in;
@ -410,8 +474,8 @@ bool LoginAsync(const char* username, const char* password)
if (ImGuiFullscreen::IsInitialized()) if (ImGuiFullscreen::IsInitialized())
{ {
ImGuiFullscreen::OpenBackgroundProgressDialog( ImGuiFullscreen::OpenBackgroundProgressDialog(
"cheevos_async_login", g_host_interface->TranslateStdString("Cheevos", "Logging in to RetroAchivements..."), 0, "cheevos_async_login", g_host_interface->TranslateStdString("Cheevos", "Logging in to RetroAchivements..."), 0, 1,
1, 0); 0);
} }
SendLogin(username, password, s_http_downloader.get(), LoginASyncCallback); SendLogin(username, password, s_http_downloader.get(), LoginASyncCallback);
@ -545,8 +609,8 @@ static std::string GetBadgeImageFilename(const char* badge_name, bool locked, bo
SmallString clean_name(badge_name); SmallString clean_name(badge_name);
FileSystem::SanitizeFileName(clean_name); FileSystem::SanitizeFileName(clean_name);
return g_host_interface->GetUserDirectoryRelativePath("cache" FS_OSPATH_SEPARATOR_STR return g_host_interface->GetUserDirectoryRelativePath("cache" FS_OSPATH_SEPARATOR_STR
"achievement_badge" FS_OSPATH_SEPARATOR_STR "%s%s.png", "achievement_badge" FS_OSPATH_SEPARATOR_STR "%s%s.png",
clean_name.GetCharArray(), locked ? "_lock" : ""); clean_name.GetCharArray(), locked ? "_lock" : "");
} }
} }
@ -1019,9 +1083,9 @@ void GameChanged(const std::string& path, CDImage* image)
if (s_game_hash.empty()) if (s_game_hash.empty())
{ {
g_host_interface->AddOSDMessage(g_host_interface->TranslateStdString( g_host_interface->AddOSDMessage(
"OSDMessage", "Failed to read executable from disc. Achievements disabled."), g_host_interface->TranslateStdString("OSDMessage", "Failed to read executable from disc. Achievements disabled."),
10.0f); 10.0f);
return; return;
} }

View file

@ -6,6 +6,7 @@
#include <string> #include <string>
class CDImage; class CDImage;
class StateWrapper;
namespace Cheevos { namespace Cheevos {
@ -79,7 +80,9 @@ bool Initialize(bool test_mode, bool use_first_disc_from_playlist, bool enable_r
bool include_unofficial); bool include_unofficial);
void Reset(); void Reset();
void Shutdown(); void Shutdown();
void Update(); void Update();
bool DoState(StateWrapper& sw);
bool IsLoggedIn(); bool IsLoggedIn();
bool IsTestModeActive(); bool IsTestModeActive();

View file

@ -2,7 +2,7 @@
#include "types.h" #include "types.h"
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 55; static constexpr u32 SAVE_STATE_VERSION = 56;
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42; static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION); static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);

View file

@ -45,6 +45,10 @@
#include <thread> #include <thread>
Log_SetChannel(System); Log_SetChannel(System);
#ifdef WITH_CHEEVOS
#include "cheevos.h"
#endif
// #define PROFILE_MEMORY_SAVE_STATES 1 // #define PROFILE_MEMORY_SAVE_STATES 1
SystemBootParameters::SystemBootParameters() = default; SystemBootParameters::SystemBootParameters() = default;
@ -71,7 +75,8 @@ static bool LoadEXE(const char* filename);
/// Opens CD image, preloading if needed. /// Opens CD image, preloading if needed.
static std::unique_ptr<CDImage> OpenCDImage(const char* path, Common::Error* error, bool force_preload, static std::unique_ptr<CDImage> OpenCDImage(const char* path, Common::Error* error, bool force_preload,
bool check_for_patches); bool check_for_patches);
static bool ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name, std::vector<u8>* out_executable_data); static bool ReadExecutableFromImage(ISOReader& iso, std::string* out_executable_name,
std::vector<u8>* out_executable_data);
static bool ShouldCheckForImagePatches(); static bool ShouldCheckForImagePatches();
static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display); static bool DoLoadState(ByteStream* stream, bool force_software_renderer, bool update_display);
@ -1142,6 +1147,33 @@ bool DoState(StateWrapper& sw, HostDisplayTexture** host_texture, bool update_di
UpdateOverclock(); UpdateOverclock();
} }
if (!is_memory_state)
{
if (sw.GetVersion() >= 56)
{
if (!sw.DoMarker("Cheevos"))
return false;
#ifdef WITH_CHEEVOS
if (!Cheevos::DoState(sw))
return false;
#else
// if we compiled without cheevos, we need to toss out the data from states which were
u32 data_size = 0;
sw.Do(&data_size);
if (data_size > 0)
sw.SkipBytes(data_size);
#endif
}
else
{
#ifdef WITH_CHEEVOS
// loading an old state without cheevos, so reset the runtime
Cheevos::Reset();
#endif
}
}
return !sw.HasError(); return !sw.HasError();
} }
@ -1172,6 +1204,10 @@ void Reset()
TimingEvents::Reset(); TimingEvents::Reset();
ResetPerformanceCounters(); ResetPerformanceCounters();
#ifdef WITH_CHEEVOS
Cheevos::Reset();
#endif
g_gpu->ResetGraphicsAPIState(); g_gpu->ResetGraphicsAPIState();
} }

View file

@ -250,10 +250,6 @@ void CommonHostInterface::PowerOffSystem(bool save_resume_state)
void CommonHostInterface::ResetSystem() void CommonHostInterface::ResetSystem()
{ {
HostInterface::ResetSystem(); HostInterface::ResetSystem();
#ifdef WITH_CHEEVOS
Cheevos::Reset();
#endif
} }
static void PrintCommandLineVersion(const char* frontend_name) static void PrintCommandLineVersion(const char* frontend_name)
@ -768,10 +764,6 @@ bool CommonHostInterface::UndoLoadState()
System::ResetPerformanceCounters(); System::ResetPerformanceCounters();
System::ResetThrottler(); System::ResetThrottler();
#ifdef WITH_CHEEVOS
Cheevos::Reset();
#endif
Log_InfoPrintf("Loaded undo save state."); Log_InfoPrintf("Loaded undo save state.");
m_undo_load_state.reset(); m_undo_load_state.reset();
return true; return true;