diff --git a/src/common/state_wrapper.cpp b/src/common/state_wrapper.cpp index 34e5d6cbc..ef9439e83 100644 --- a/src/common/state_wrapper.cpp +++ b/src/common/state_wrapper.cpp @@ -5,7 +5,10 @@ #include Log_SetChannel(StateWrapper); -StateWrapper::StateWrapper(ByteStream* stream, Mode mode) : m_stream(stream), m_mode(mode) {} +StateWrapper::StateWrapper(ByteStream* stream, Mode mode, u32 version) + : m_stream(stream), m_mode(mode), m_version(version) +{ +} StateWrapper::~StateWrapper() = default; diff --git a/src/common/state_wrapper.h b/src/common/state_wrapper.h index e6aeb0d39..38ad4a357 100644 --- a/src/common/state_wrapper.h +++ b/src/common/state_wrapper.h @@ -20,7 +20,7 @@ public: Write }; - StateWrapper(ByteStream* stream, Mode mode); + StateWrapper(ByteStream* stream, Mode mode, u32 version); StateWrapper(const StateWrapper&) = delete; ~StateWrapper(); @@ -30,6 +30,7 @@ public: bool IsWriting() const { return (m_mode == Mode::Write); } Mode GetMode() const { return m_mode; } void SetMode(Mode mode) { m_mode = mode; } + u32 GetVersion() const { return m_version; } /// Overload for integral or floating-point types. Writes bytes as-is. template || std::is_floating_point_v, int> = 0> @@ -175,8 +176,21 @@ public: bool DoMarker(const char* marker); + template + void DoEx(T* data, u32 version_introduced, T default_value) + { + if (m_version < version_introduced) + { + *data = std::move(default_value); + return; + } + + Do(data); + } + private: ByteStream* m_stream; Mode m_mode; + u32 m_version; bool m_error = false; }; diff --git a/src/core/save_state_version.h b/src/core/save_state_version.h index fdada360f..215b4ea00 100644 --- a/src/core/save_state_version.h +++ b/src/core/save_state_version.h @@ -3,6 +3,7 @@ static constexpr u32 SAVE_STATE_MAGIC = 0x43435544; static constexpr u32 SAVE_STATE_VERSION = 42; +static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42; #pragma pack(push, 4) struct SAVE_STATE_HEADER diff --git a/src/core/system.cpp b/src/core/system.cpp index 30cf5149b..0038902ad 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -491,7 +491,7 @@ bool RecreateGPU(GPURenderer renderer) // save current state std::unique_ptr state_stream = ByteStream_CreateGrowableMemoryStream(); - StateWrapper sw(state_stream.get(), StateWrapper::Mode::Write); + StateWrapper sw(state_stream.get(), StateWrapper::Mode::Write, SAVE_STATE_VERSION); const bool state_valid = g_gpu->DoState(sw) && TimingEvents::DoState(sw); if (!state_valid) Log_ErrorPrintf("Failed to save old GPU state when switching renderers"); @@ -946,12 +946,12 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer) if (header.magic != SAVE_STATE_MAGIC) return false; - if (header.version != SAVE_STATE_VERSION) + if (header.version < SAVE_STATE_MINIMUM_VERSION) { g_host_interface->ReportFormattedError( g_host_interface->TranslateString("System", - "Save state is incompatible: expecting version %u but state is version %u."), - SAVE_STATE_VERSION, header.version); + "Save state is incompatible: minimum version is %u but state is version %u."), + SAVE_STATE_MINIMUM_VERSION, header.version); return false; } @@ -1041,7 +1041,7 @@ bool DoLoadState(ByteStream* state, bool force_software_renderer) if (!state->SeekAbsolute(header.offset_to_data)) return false; - StateWrapper sw(state, StateWrapper::Mode::Read); + StateWrapper sw(state, StateWrapper::Mode::Read, header.version); if (!DoState(sw)) return false; @@ -1108,7 +1108,7 @@ bool SaveState(ByteStream* state, u32 screenshot_size /* = 128 */) g_gpu->RestoreGraphicsAPIState(); - StateWrapper sw(state, StateWrapper::Mode::Write); + StateWrapper sw(state, StateWrapper::Mode::Write, SAVE_STATE_VERSION); const bool result = DoState(sw); g_gpu->ResetGraphicsAPIState();