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.
This commit is contained in:
EmptyChaos 2016-09-30 16:19:47 +00:00
parent b3547870ee
commit 09372a55da
4 changed files with 39 additions and 16 deletions

View File

@ -7,9 +7,9 @@
#include <mutex> #include <mutex>
#include <vector> #include <vector>
#include "Common/ChunkFile.h"
#include "Common/CommonPaths.h" #include "Common/CommonPaths.h"
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Thread.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/GeckoCode.h" #include "Core/GeckoCode.h"
@ -55,9 +55,12 @@ void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
std::lock_guard<std::mutex> lk(s_active_codes_lock); std::lock_guard<std::mutex> lk(s_active_codes_lock);
s_active_codes.clear(); s_active_codes.clear();
s_active_codes.reserve(gcodes.size()); if (SConfig::GetInstance().bEnableCheats)
std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes), {
[](const GeckoCode& code) { return code.enabled; }); 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_active_codes.shrink_to_fit();
s_code_handler_installed = Installation::Uninstalled; s_code_handler_installed = Installation::Uninstalled;
@ -158,11 +161,25 @@ static Installation InstallCodeHandlerLocked()
return Installation::Installed; return Installation::Installed;
} }
// FIXME: Gecko needs to participate in the savestate system (remember installation state). // Gecko needs to participate in the savestate system because the handler is embedded within the
// Current bug: Loading a savestate causes the handler to be replaced, if the PC is inside it // game directly. The PC may be inside the code handler in the save state and the codehandler.bin
// and the on disk codehandler.bin is different then the PC will effectively be pointing to // on the disk may be different resulting in the PC pointing at a different instruction and then
// a random instruction different from the one when the state was created and break or crash. // the game malfunctions or crashes. [Also, self-modifying codes will break since the
// [Also, self-modifying handler will break it since the modifications will be reset] // modifications will be reset]
void DoState(PointerWrap& p)
{
std::lock_guard<std::mutex> 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<std::mutex> codes_lock(s_active_codes_lock);
s_active_codes.clear();
s_code_handler_installed = Installation::Uninstalled;
}
void RunCodeHandler() void RunCodeHandler()
{ {
if (!SConfig::GetInstance().bEnableCheats) if (!SConfig::GetInstance().bEnableCheats)
@ -171,13 +188,12 @@ void RunCodeHandler()
// NOTE: Need to release the lock because of GUI deadlocks with PanicAlert in HostWrite_* // NOTE: Need to release the lock because of GUI deadlocks with PanicAlert in HostWrite_*
{ {
std::lock_guard<std::mutex> codes_lock(s_active_codes_lock); std::lock_guard<std::mutex> 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) 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(); s_code_handler_installed = InstallCodeHandlerLocked();
// A warning was already issued for the install failing // A warning was already issued for the install failing

View File

@ -9,6 +9,8 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
class PointerWrap;
namespace Gecko namespace Gecko
{ {
class GeckoCode class GeckoCode
@ -53,5 +55,7 @@ constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
void SetActiveCodes(const std::vector<GeckoCode>& gcodes); void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
void RunCodeHandler(); void RunCodeHandler();
void Shutdown();
void DoState(PointerWrap&);
} // namespace Gecko } // namespace Gecko

View File

@ -260,7 +260,7 @@ void Shutdown()
onFrame.clear(); onFrame.clear();
speedHacks.clear(); speedHacks.clear();
ActionReplay::ApplyCodes({}); ActionReplay::ApplyCodes({});
Gecko::SetActiveCodes({}); Gecko::Shutdown();
} }
} // namespace } // namespace

View File

@ -23,6 +23,7 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/GeckoCode.h"
#include "Core/HW/HW.h" #include "Core/HW/HW.h"
#include "Core/HW/Wiimote.h" #include "Core/HW/Wiimote.h"
#include "Core/Host.h" #include "Core/Host.h"
@ -70,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // 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. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // 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"); p.DoMarker("HW");
Movie::DoState(p); Movie::DoState(p);
p.DoMarker("Movie"); p.DoMarker("Movie");
Gecko::DoState(p);
p.DoMarker("Gecko");
#if defined(HAVE_LIBAV) || defined(_WIN32) #if defined(HAVE_LIBAV) || defined(_WIN32)
AVIDump::DoState(); AVIDump::DoState();