From 09372a55da3ed91bff343c6bfda1405149fddbd6 Mon Sep 17 00:00:00 2001 From: EmptyChaos Date: Fri, 30 Sep 2016 16:19:47 +0000 Subject: [PATCH] GeckoCode: Save installation state to savestates Because of the way this works, randomly overwriting the handler when loading a savestate will break things because of the self-modifying nature of the handler. --- Source/Core/Core/GeckoCode.cpp | 44 ++++++++++++++++++++++---------- Source/Core/Core/GeckoCode.h | 4 +++ Source/Core/Core/PatchEngine.cpp | 2 +- Source/Core/Core/State.cpp | 5 +++- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Source/Core/Core/GeckoCode.cpp b/Source/Core/Core/GeckoCode.cpp index 2eaead2f8d..b3f6b096f6 100644 --- a/Source/Core/Core/GeckoCode.cpp +++ b/Source/Core/Core/GeckoCode.cpp @@ -7,9 +7,9 @@ #include #include +#include "Common/ChunkFile.h" #include "Common/CommonPaths.h" #include "Common/FileUtil.h" -#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/GeckoCode.h" @@ -55,9 +55,12 @@ void SetActiveCodes(const std::vector& gcodes) std::lock_guard lk(s_active_codes_lock); s_active_codes.clear(); - s_active_codes.reserve(gcodes.size()); - std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes), - [](const GeckoCode& code) { return code.enabled; }); + if (SConfig::GetInstance().bEnableCheats) + { + s_active_codes.reserve(gcodes.size()); + std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes), + [](const GeckoCode& code) { return code.enabled; }); + } s_active_codes.shrink_to_fit(); s_code_handler_installed = Installation::Uninstalled; @@ -158,11 +161,25 @@ static Installation InstallCodeHandlerLocked() return Installation::Installed; } -// FIXME: Gecko needs to participate in the savestate system (remember installation state). -// Current bug: Loading a savestate causes the handler to be replaced, if the PC is inside it -// and the on disk codehandler.bin is different then the PC will effectively be pointing to -// a random instruction different from the one when the state was created and break or crash. -// [Also, self-modifying handler will break it since the modifications will be reset] +// Gecko needs to participate in the savestate system because the handler is embedded within the +// game directly. The PC may be inside the code handler in the save state and the codehandler.bin +// on the disk may be different resulting in the PC pointing at a different instruction and then +// the game malfunctions or crashes. [Also, self-modifying codes will break since the +// modifications will be reset] +void DoState(PointerWrap& p) +{ + std::lock_guard codes_lock(s_active_codes_lock); + p.Do(s_code_handler_installed); + // FIXME: The active codes list will disagree with the embedded GCT +} + +void Shutdown() +{ + std::lock_guard codes_lock(s_active_codes_lock); + s_active_codes.clear(); + s_code_handler_installed = Installation::Uninstalled; +} + void RunCodeHandler() { if (!SConfig::GetInstance().bEnableCheats) @@ -171,13 +188,12 @@ void RunCodeHandler() // NOTE: Need to release the lock because of GUI deadlocks with PanicAlert in HostWrite_* { std::lock_guard codes_lock(s_active_codes_lock); - // Don't spam retry if the install failed. The corrupt / missing disk file is not likely to be - // fixed within 1 frame of the last error. - if (s_active_codes.empty() || s_code_handler_installed == Installation::Failed) - return; - if (s_code_handler_installed != Installation::Installed) { + // Don't spam retry if the install failed. The corrupt / missing disk file is not likely to be + // fixed within 1 frame of the last error. + if (s_active_codes.empty() || s_code_handler_installed == Installation::Failed) + return; s_code_handler_installed = InstallCodeHandlerLocked(); // A warning was already issued for the install failing diff --git a/Source/Core/Core/GeckoCode.h b/Source/Core/Core/GeckoCode.h index 4fa17c8c5e..8324f85b02 100644 --- a/Source/Core/Core/GeckoCode.h +++ b/Source/Core/Core/GeckoCode.h @@ -9,6 +9,8 @@ #include "Common/CommonTypes.h" +class PointerWrap; + namespace Gecko { class GeckoCode @@ -53,5 +55,7 @@ constexpr u32 MAGIC_GAMEID = 0xD01F1BAD; void SetActiveCodes(const std::vector& gcodes); void RunCodeHandler(); +void Shutdown(); +void DoState(PointerWrap&); } // namespace Gecko diff --git a/Source/Core/Core/PatchEngine.cpp b/Source/Core/Core/PatchEngine.cpp index f9e9890f0a..656bb44c72 100644 --- a/Source/Core/Core/PatchEngine.cpp +++ b/Source/Core/Core/PatchEngine.cpp @@ -260,7 +260,7 @@ void Shutdown() onFrame.clear(); speedHacks.clear(); ActionReplay::ApplyCodes({}); - Gecko::SetActiveCodes({}); + Gecko::Shutdown(); } } // namespace diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index c8801a9373..89bd1d7211 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -23,6 +23,7 @@ #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" +#include "Core/GeckoCode.h" #include "Core/HW/HW.h" #include "Core/HW/Wiimote.h" #include "Core/Host.h" @@ -70,7 +71,7 @@ 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 = 60; // Last changed in PR 4242 +static const u32 STATE_VERSION = 61; // Last changed in PR 4216 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list, @@ -174,6 +175,8 @@ static std::string DoState(PointerWrap& p) p.DoMarker("HW"); Movie::DoState(p); p.DoMarker("Movie"); + Gecko::DoState(p); + p.DoMarker("Gecko"); #if defined(HAVE_LIBAV) || defined(_WIN32) AVIDump::DoState();