diff --git a/pcsx2/Achievements.cpp b/pcsx2/Achievements.cpp index 0a8ab649bc..9b92704de8 100644 --- a/pcsx2/Achievements.cpp +++ b/pcsx2/Achievements.cpp @@ -14,6 +14,7 @@ #include "IopMem.h" #include "MTGS.h" #include "Memory.h" +#include "SaveState.h" #include "VMManager.h" #include "svnrev.h" #include "vtlb.h" @@ -23,6 +24,7 @@ #include "common/Error.h" #include "common/FileSystem.h" #include "common/HTTPDownloader.h" +#include "common/HeapArray.h" #include "common/MD5Digest.h" #include "common/Path.h" #include "common/ScopedGuard.h" @@ -1466,7 +1468,7 @@ void Achievements::SetHardcoreMode(bool enabled, bool force_display_message) Host::OnAchievementsHardcoreModeChanged(enabled); } -void Achievements::LoadState(const u8* state_data, u32 state_data_size) +void Achievements::LoadState(std::span data) { const auto lock = GetLock(); @@ -1479,14 +1481,14 @@ void Achievements::LoadState(const u8* state_data, u32 state_data_size) #ifdef ENABLE_RAINTEGRATION if (IsUsingRAIntegration()) { - if (state_data_size == 0) + if (data.empty()) { Console.Warning("State is missing cheevos data, resetting RAIntegration"); RA_OnReset(); } else { - RA_RestoreState(reinterpret_cast(state_data)); + RA_RestoreState(reinterpret_cast(data.data())); } return; @@ -1503,7 +1505,7 @@ void Achievements::LoadState(const u8* state_data, u32 state_data_size) EndLoadingScreen(was_running_idle); } - if (state_data_size == 0) + if (data.empty()) { // reset runtime, no data (state might've been created without cheevos) Console.Warning("State is missing cheevos data, resetting runtime"); @@ -1513,7 +1515,7 @@ void Achievements::LoadState(const u8* state_data, u32 state_data_size) // These routines scare me a bit.. the data isn't bounds checked. // Really hope that nobody puts any thing malicious in a save state... - const int result = rc_client_deserialize_progress(s_client, state_data); + const int result = rc_client_deserialize_progress_sized(s_client, data.data(), data.size()); if (result != RC_OK) { Console.Warning("Failed to deserialize cheevos state (%d), resetting", result); @@ -1521,10 +1523,8 @@ void Achievements::LoadState(const u8* state_data, u32 state_data_size) } } -std::vector Achievements::SaveState() +void Achievements::SaveState(SaveStateBase& writer) { - std::vector ret; - const auto lock = GetLock(); #ifdef ENABLE_RAINTEGRATION @@ -1533,16 +1533,18 @@ std::vector Achievements::SaveState() const int size = RA_CaptureState(nullptr, 0); const u32 data_size = (size >= 0) ? static_cast(size) : 0; - ret.resize(data_size); - - const int result = RA_CaptureState(reinterpret_cast(ret.data()), static_cast(data_size)); - if (result != static_cast(data_size)) + if (data_size > 0) { - Console.Warning("Failed to serialize cheevos state from RAIntegration."); - ret.clear(); + writer.PrepBlock(static_cast(data_size)); + + const int result = RA_CaptureState(reinterpret_cast(writer.GetBlockPtr()), static_cast(data_size)); + if (result != static_cast(data_size)) + Console.Warning("Failed to serialize cheevos state from RAIntegration."); + else + writer.CommitBlock(static_cast(data_size)); } - return ret; + return; } #endif @@ -1550,18 +1552,17 @@ std::vector Achievements::SaveState() { // internally this happens twice.. not great. const size_t data_size = rc_client_progress_size(s_client); - ret.resize(data_size); - - const int result = rc_client_serialize_progress(s_client, ret.data()); - if (result != RC_OK) + if (data_size > 0) { - // set data to zero, effectively serializing nothing - Console.Warning("Failed to serialize cheevos state (%d)", result); - ret.clear(); + writer.PrepBlock(static_cast(data_size)); + + const int result = rc_client_serialize_progress_sized(s_client, writer.GetBlockPtr(), data_size); + if (result != RC_OK) + Console.Warning("Failed to serialize cheevos state (%d)", result); + else + writer.CommitBlock(static_cast(data_size)); } } - - return ret; } diff --git a/pcsx2/Achievements.h b/pcsx2/Achievements.h index 2c1701778a..56aee188c1 100644 --- a/pcsx2/Achievements.h +++ b/pcsx2/Achievements.h @@ -9,12 +9,15 @@ #include #include +#include #include #include #include class Error; +class SaveStateBase; + namespace Achievements { enum class LoginRequestReason @@ -51,8 +54,8 @@ namespace Achievements void IdleUpdate(); /// Saves/loads state. - void LoadState(const u8* state_data, u32 state_data_size); - std::vector SaveState(); + void LoadState(std::span data); + void SaveState(SaveStateBase& writer); /// Attempts to log in to RetroAchievements using the specified credentials. /// If the login is successful, the token returned by the server will be saved. diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index f5301dbd0f..3d7eed14bd 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -656,10 +656,10 @@ class SaveStateEntry_Achievements final : public BaseSavestateEntry if (zf) data = ReadBinaryFileInZip(zf); - if (data.has_value() && !data->empty()) - Achievements::LoadState(data->data(), data->size()); + if (data.has_value()) + Achievements::LoadState(data.value()); else - Achievements::LoadState(nullptr, 0); + Achievements::LoadState(std::span()); return true; } @@ -669,14 +669,7 @@ class SaveStateEntry_Achievements final : public BaseSavestateEntry if (!Achievements::IsActive()) return true; - std::vector data(Achievements::SaveState()); - if (!data.empty()) - { - writer.PrepBlock(static_cast(data.size())); - std::memcpy(writer.GetBlockPtr(), data.data(), data.size()); - writer.CommitBlock(static_cast(data.size())); - } - + Achievements::SaveState(writer); return writer.IsOkay(); }