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:
parent
b3547870ee
commit
09372a55da
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -260,7 +260,7 @@ void Shutdown()
|
||||||
onFrame.clear();
|
onFrame.clear();
|
||||||
speedHacks.clear();
|
speedHacks.clear();
|
||||||
ActionReplay::ApplyCodes({});
|
ActionReplay::ApplyCodes({});
|
||||||
Gecko::SetActiveCodes({});
|
Gecko::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue