Achievements: Refactor state serialization
Fix load failures, and eliminate the buffer copy.
This commit is contained in:
parent
d360564cef
commit
00eb54cd15
|
@ -230,8 +230,6 @@ struct State
|
||||||
std::string game_icon;
|
std::string game_icon;
|
||||||
std::string game_icon_url;
|
std::string game_icon_url;
|
||||||
|
|
||||||
DynamicHeapArray<u8> state_buffer;
|
|
||||||
|
|
||||||
rc_client_async_handle_t* login_request = nullptr;
|
rc_client_async_handle_t* login_request = nullptr;
|
||||||
rc_client_async_handle_t* load_game_request = nullptr;
|
rc_client_async_handle_t* load_game_request = nullptr;
|
||||||
|
|
||||||
|
@ -1019,7 +1017,6 @@ void Achievements::IdentifyGame(const std::string& path, CDImage* image)
|
||||||
ClearGameHash();
|
ClearGameHash();
|
||||||
s_state.game_path = path;
|
s_state.game_path = path;
|
||||||
s_state.game_hash = std::move(game_hash);
|
s_state.game_hash = std::move(game_hash);
|
||||||
s_state.state_buffer.deallocate();
|
|
||||||
|
|
||||||
#ifdef ENABLE_RAINTEGRATION
|
#ifdef ENABLE_RAINTEGRATION
|
||||||
if (IsUsingRAIntegration())
|
if (IsUsingRAIntegration())
|
||||||
|
@ -1106,7 +1103,6 @@ void Achievements::ClientLoadGameCallback(int result, const char* error_message,
|
||||||
const bool was_disc_change = (userdata != nullptr);
|
const bool was_disc_change = (userdata != nullptr);
|
||||||
|
|
||||||
s_state.load_game_request = nullptr;
|
s_state.load_game_request = nullptr;
|
||||||
s_state.state_buffer.deallocate();
|
|
||||||
|
|
||||||
if (result == RC_NO_GAME_LOADED)
|
if (result == RC_NO_GAME_LOADED)
|
||||||
{
|
{
|
||||||
|
@ -1224,7 +1220,6 @@ void Achievements::ClearGameInfo()
|
||||||
s_state.game_title = {};
|
s_state.game_title = {};
|
||||||
s_state.game_icon = {};
|
s_state.game_icon = {};
|
||||||
s_state.game_icon_url = {};
|
s_state.game_icon_url = {};
|
||||||
s_state.state_buffer.deallocate();
|
|
||||||
s_state.has_achievements = false;
|
s_state.has_achievements = false;
|
||||||
s_state.has_leaderboards = false;
|
s_state.has_leaderboards = false;
|
||||||
s_state.has_rich_presence = false;
|
s_state.has_rich_presence = false;
|
||||||
|
@ -1768,7 +1763,7 @@ bool Achievements::DoState(StateWrapper& sw)
|
||||||
if (data_size == 0)
|
if (data_size == 0)
|
||||||
{
|
{
|
||||||
// reset runtime, no data (state might've been created without cheevos)
|
// reset runtime, no data (state might've been created without cheevos)
|
||||||
DEV_LOG("State is missing cheevos data, resetting runtime");
|
WARNING_LOG("State is missing cheevos data, resetting runtime");
|
||||||
#ifdef ENABLE_RAINTEGRATION
|
#ifdef ENABLE_RAINTEGRATION
|
||||||
if (IsUsingRAIntegration())
|
if (IsUsingRAIntegration())
|
||||||
RA_OnReset();
|
RA_OnReset();
|
||||||
|
@ -1781,21 +1776,18 @@ bool Achievements::DoState(StateWrapper& sw)
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data_size > s_state.state_buffer.size())
|
const std::span<u8> data = sw.GetDeferredBytes(data_size);
|
||||||
s_state.state_buffer.resize(data_size);
|
|
||||||
if (data_size > 0)
|
|
||||||
sw.DoBytes(s_state.state_buffer.data(), data_size);
|
|
||||||
if (sw.HasError())
|
if (sw.HasError())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
#ifdef ENABLE_RAINTEGRATION
|
#ifdef ENABLE_RAINTEGRATION
|
||||||
if (IsUsingRAIntegration())
|
if (IsUsingRAIntegration())
|
||||||
{
|
{
|
||||||
RA_RestoreState(reinterpret_cast<const char*>(s_state.state_buffer.data()));
|
RA_RestoreState(reinterpret_cast<const char*>(data.data()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const int result = rc_client_deserialize_progress_sized(s_state.client, s_state.state_buffer.data(), data_size);
|
const int result = rc_client_deserialize_progress_sized(s_state.client, data.data(), data_size);
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
{
|
{
|
||||||
WARNING_LOG("Failed to deserialize cheevos state ({}), resetting", result);
|
WARNING_LOG("Failed to deserialize cheevos state ({}), resetting", result);
|
||||||
|
@ -1808,49 +1800,51 @@ bool Achievements::DoState(StateWrapper& sw)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t data_size;
|
const size_t size_pos = sw.GetPosition();
|
||||||
|
|
||||||
#ifdef ENABLE_RAINTEGRATION
|
#ifdef ENABLE_RAINTEGRATION
|
||||||
if (IsUsingRAIntegration())
|
if (IsUsingRAIntegration())
|
||||||
{
|
{
|
||||||
const int size = RA_CaptureState(nullptr, 0);
|
const int size = RA_CaptureState(nullptr, 0);
|
||||||
|
u32 write_size = static_cast<u32>(std::max(size, 0));
|
||||||
|
sw.Do(&write_size);
|
||||||
|
|
||||||
data_size = (size >= 0) ? static_cast<u32>(size) : 0;
|
const std::span<u8> data = sw.GetDeferredBytes(write_size);
|
||||||
s_state.state_buffer.resize(data_size);
|
if (!data.empty())
|
||||||
|
|
||||||
if (data_size > 0)
|
|
||||||
{
|
{
|
||||||
const int result =
|
const int result = RA_CaptureState(reinterpret_cast<char*>(data.data()), size);
|
||||||
RA_CaptureState(reinterpret_cast<char*>(s_state.state_buffer.data()), static_cast<int>(data_size));
|
if (result != static_cast<int>(size))
|
||||||
if (result != static_cast<int>(data_size))
|
|
||||||
{
|
{
|
||||||
WARNING_LOG("Failed to serialize cheevos state from RAIntegration.");
|
WARNING_LOG("Failed to serialize cheevos state from RAIntegration.");
|
||||||
data_size = 0;
|
write_size = 0;
|
||||||
|
sw.SetPosition(size_pos);
|
||||||
|
sw.Do(&write_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
data_size = rc_client_progress_size(s_state.client);
|
u32 data_size = static_cast<u32>(rc_client_progress_size(s_state.client));
|
||||||
|
sw.Do(&data_size);
|
||||||
|
|
||||||
if (data_size > 0)
|
if (data_size > 0)
|
||||||
{
|
{
|
||||||
if (s_state.state_buffer.size() < data_size)
|
const std::span<u8> data = sw.GetDeferredBytes(data_size);
|
||||||
s_state.state_buffer.resize(data_size);
|
if (!sw.HasError()) [[likely]]
|
||||||
|
{
|
||||||
const int result = rc_client_serialize_progress_sized(s_state.client, s_state.state_buffer.data(), data_size);
|
const int result = rc_client_serialize_progress_sized(s_state.client, data.data(), data_size);
|
||||||
if (result != RC_OK)
|
if (result != RC_OK)
|
||||||
{
|
{
|
||||||
// set data to zero, effectively serializing nothing
|
// set data to zero, effectively serializing nothing
|
||||||
WARNING_LOG("Failed to serialize cheevos state ({})", result);
|
WARNING_LOG("Failed to serialize cheevos state ({})", result);
|
||||||
data_size = 0;
|
data_size = 0;
|
||||||
}
|
sw.SetPosition(size_pos);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sw.Do(&data_size);
|
sw.Do(&data_size);
|
||||||
if (data_size > 0)
|
}
|
||||||
sw.DoBytes(s_state.state_buffer.data(), data_size);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return !sw.HasError();
|
return !sw.HasError();
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,16 @@ bool StateWrapper::DoMarker(const char* marker)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::span<u8> StateWrapper::GetDeferredBytes(size_t size)
|
||||||
|
{
|
||||||
|
if ((m_error = (m_error || (m_pos + size) > m_size))) [[unlikely]]
|
||||||
|
return {};
|
||||||
|
|
||||||
|
const std::span<u8> ret(&m_data[m_pos], size);
|
||||||
|
m_pos += size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool StateWrapper::ReadData(void* buf, size_t size)
|
bool StateWrapper::ReadData(void* buf, size_t size)
|
||||||
{
|
{
|
||||||
if ((m_error = (m_error || (m_pos + size) > m_size))) [[unlikely]]
|
if ((m_error = (m_error || (m_pos + size) > m_size))) [[unlikely]]
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <string>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -206,6 +206,9 @@ public:
|
||||||
m_pos += count;
|
m_pos += count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// spans don't copy immediately
|
||||||
|
std::span<u8> GetDeferredBytes(size_t size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ReadData(void* buf, size_t size);
|
bool ReadData(void* buf, size_t size);
|
||||||
bool WriteData(const void* buf, size_t size);
|
bool WriteData(const void* buf, size_t size);
|
||||||
|
|
Loading…
Reference in New Issue