From 85073675a5edccbf546930059d9e8de087383b46 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 30 Mar 2015 09:02:43 +0200 Subject: [PATCH] When loading incompatible savestate, display which version created it --- Source/Core/Core/State.cpp | 80 +++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index bc96632bc3..1ce1427c19 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include @@ -64,7 +65,42 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 42; // Last changed in PR2193 +static const u32 STATE_VERSION = 43; // Last changed in PR 2232 + +// Maps savestate versions to Dolphin versions. +// Versions after 42 don't need to be added to this list, +// beacuse they save the exact Dolphin version to savestates. +static const std::map> s_old_versions = +{ + // The 16 -> 17 change modified the size of StateHeader, + // so version older than that can't even be decompressed anymore + { 17, { "3.5-1311", "3.5-1364" } }, + { 18, { "3.5-1366", "3.5-1371" } }, + { 19, { "3.5-1372", "3.5-1408" } }, + { 20, { "3.5-1409", "4.0-704" } }, + { 21, { "4.0-705", "4.0-889" } }, + { 22, { "4.0-905", "4.0-1871" } }, + { 23, { "4.0-1873", "4.0-1900" } }, + { 24, { "4.0-1902", "4.0-1919" } }, + { 25, { "4.0-1921", "4.0-1936" } }, + { 26, { "4.0-1939", "4.0-1959" } }, + { 27, { "4.0-1961", "4.0-2018" } }, + { 28, { "4.0-2020", "4.0-2291" } }, + { 29, { "4.0-2293", "4.0-2360" } }, + { 30, { "4.0-2362", "4.0-2628" } }, + { 31, { "4.0-2632", "4.0-3331" } }, + { 32, { "4.0-3334", "4.0-3340" } }, + { 33, { "4.0-3342", "4.0-3373" } }, + { 34, { "4.0-3376", "4.0-3402" } }, + { 35, { "4.0-3409", "4.0-3603" } }, + { 36, { "4.0-3610", "4.0-4480" } }, + { 37, { "4.0-4484", "4.0-4943" } }, + { 38, { "4.0-4963", "4.0-5267" } }, + { 39, { "4.0-5279", "4.0-5525" } }, + { 40, { "4.0-5531", "4.0-5809" } }, + { 41, { "4.0-5811", "4.0-5923" } }, + { 42, { "4.0-5925", "4.0-5946" } } +}; enum { @@ -80,7 +116,7 @@ void EnableCompression(bool compression) g_use_compression = compression; } -static void DoState(PointerWrap &p) +static std::string DoState(PointerWrap& p) { u32 version = STATE_VERSION; { @@ -90,18 +126,38 @@ static void DoState(PointerWrap &p) version = cookie - COOKIE_BASE; } + std::string version_created_by = scm_rev_str; + if (version > 42) + p.Do(version_created_by); + else + version_created_by.clear(); + if (version != STATE_VERSION) { - // if the version doesn't match, fail. - // this will trigger a message like "Can't load state from other revisions" + if (version_created_by.empty() && s_old_versions.count(version)) + { + // The savestate is from an old version that doesn't + // save the Dolphin version number to savestates, but + // by looking up the savestate version number, it is possible + // to know approximately which Dolphin version was used. + + std::pair version_range = s_old_versions.find(version)->second; + std::string oldest_version = version_range.first; + std::string newest_version = version_range.second; + + version_created_by = "Dolphin " + oldest_version + " - " + newest_version; + } + + // because the version doesn't match, fail. + // this will trigger an OSD message like "Can't load state from other revisions" // we could use the version numbers to maintain some level of backward compatibility, but currently don't. p.SetMode(PointerWrap::MODE_MEASURE); - return; + return version_created_by; } p.DoMarker("Version"); - // Begin with video backend, so that it gets a chance to clear it's caches and writeback modified things to RAM + // Begin with video backend, so that it gets a chance to clear its caches and writeback modified things to RAM g_video_backend->DoState(p); p.DoMarker("video_backend"); @@ -117,9 +173,12 @@ static void DoState(PointerWrap &p) p.DoMarker("CoreTiming"); Movie::DoState(p); p.DoMarker("Movie"); + #if defined(HAVE_LIBAV) || defined (WIN32) AVIDump::DoState(); #endif + + return version_created_by; } void LoadFromBuffer(std::vector& buffer) @@ -340,7 +399,7 @@ void SaveAs(const std::string& filename, bool wait) else { // someone aborted the save by changing the mode? - Core::DisplayMessage("Unable to Save : Internal DoState Error", 4000); + Core::DisplayMessage("Unable to save: Internal DoState Error", 4000); } // Resume the core and disable stepping @@ -450,6 +509,7 @@ void LoadAs(const std::string& filename) bool loaded = false; bool loadedSuccessfully = false; + std::string version_created_by; // brackets here are so buffer gets freed ASAP { @@ -460,7 +520,7 @@ void LoadAs(const std::string& filename) { u8 *ptr = &buffer[0]; PointerWrap p(&ptr, PointerWrap::MODE_READ); - DoState(p); + version_created_by = DoState(p); loaded = true; loadedSuccessfully = (p.GetMode() == PointerWrap::MODE_READ); } @@ -479,7 +539,9 @@ void LoadAs(const std::string& filename) else { // failed to load - Core::DisplayMessage("Unable to Load : Can't load state from other revisions !", 4000); + Core::DisplayMessage("Unable to load: Can't load state from other versions!", 4000); + if (!version_created_by.empty()) + Core::DisplayMessage("The savestate was created using " + version_created_by, 4000); // since we could be in an inconsistent state now (and might crash or whatever), undo. if (g_loadDepth < 2)