mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 01:25:51 +00:00
FrontendCommon: Add auto cheat loading option
This commit is contained in:
parent
bf6b4514a0
commit
03f052e12e
|
@ -324,6 +324,44 @@ bool CheatList::SaveToPCSXRFile(const char* filename)
|
||||||
return (std::ferror(fp.get()) == 0);
|
return (std::ferror(fp.get()) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 CheatList::GetEnabledCodeCount() const
|
||||||
|
{
|
||||||
|
u32 count = 0;
|
||||||
|
for (const CheatCode& cc : m_codes)
|
||||||
|
{
|
||||||
|
if (cc.enabled)
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatList::SetCodeEnabled(u32 index, bool state)
|
||||||
|
{
|
||||||
|
if (index >= m_codes.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_codes[index].enabled = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatList::EnableCode(u32 index)
|
||||||
|
{
|
||||||
|
SetCodeEnabled(index, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatList::DisableCode(u32 index)
|
||||||
|
{
|
||||||
|
SetCodeEnabled(index, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheatList::ApplyCode(u32 index)
|
||||||
|
{
|
||||||
|
if (index >= m_codes.size())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_codes[index].Apply();
|
||||||
|
}
|
||||||
|
|
||||||
void CheatCode::Apply() const
|
void CheatCode::Apply() const
|
||||||
{
|
{
|
||||||
const u32 count = static_cast<u32>(instructions.size());
|
const u32 count = static_cast<u32>(instructions.size());
|
||||||
|
|
|
@ -68,10 +68,16 @@ public:
|
||||||
ALWAYS_INLINE const CheatCode& GetCode(u32 i) const { return m_codes[i]; }
|
ALWAYS_INLINE const CheatCode& GetCode(u32 i) const { return m_codes[i]; }
|
||||||
ALWAYS_INLINE CheatCode& GetCode(u32 i) { return m_codes[i]; }
|
ALWAYS_INLINE CheatCode& GetCode(u32 i) { return m_codes[i]; }
|
||||||
ALWAYS_INLINE u32 GetCodeCount() const { return static_cast<u32>(m_codes.size()); }
|
ALWAYS_INLINE u32 GetCodeCount() const { return static_cast<u32>(m_codes.size()); }
|
||||||
|
ALWAYS_INLINE bool IsCodeEnabled(u32 index) const { return m_codes[index].enabled; }
|
||||||
|
|
||||||
void AddCode(CheatCode cc);
|
void AddCode(CheatCode cc);
|
||||||
void RemoveCode(u32 i);
|
void RemoveCode(u32 i);
|
||||||
|
|
||||||
|
u32 GetEnabledCodeCount() const;
|
||||||
|
void EnableCode(u32 index);
|
||||||
|
void DisableCode(u32 index);
|
||||||
|
void SetCodeEnabled(u32 index, bool state);
|
||||||
|
|
||||||
static std::optional<Format> DetectFileFormat(const char* filename);
|
static std::optional<Format> DetectFileFormat(const char* filename);
|
||||||
|
|
||||||
bool LoadFromFile(const char* filename, Format format);
|
bool LoadFromFile(const char* filename, Format format);
|
||||||
|
@ -82,6 +88,8 @@ public:
|
||||||
|
|
||||||
void Apply();
|
void Apply();
|
||||||
|
|
||||||
|
void ApplyCode(u32 index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<CheatCode> m_codes;
|
std::vector<CheatCode> m_codes;
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,6 +86,7 @@ void Settings::Load(SettingsInterface& si)
|
||||||
confim_power_off = si.GetBoolValue("Main", "ConfirmPowerOff", true);
|
confim_power_off = si.GetBoolValue("Main", "ConfirmPowerOff", true);
|
||||||
load_devices_from_save_states = si.GetBoolValue("Main", "LoadDevicesFromSaveStates", false);
|
load_devices_from_save_states = si.GetBoolValue("Main", "LoadDevicesFromSaveStates", false);
|
||||||
apply_game_settings = si.GetBoolValue("Main", "ApplyGameSettings", true);
|
apply_game_settings = si.GetBoolValue("Main", "ApplyGameSettings", true);
|
||||||
|
auto_load_cheats = si.GetBoolValue("Main", "AutoLoadCheats", false);
|
||||||
|
|
||||||
cpu_execution_mode =
|
cpu_execution_mode =
|
||||||
ParseCPUExecutionMode(
|
ParseCPUExecutionMode(
|
||||||
|
@ -204,6 +205,7 @@ void Settings::Save(SettingsInterface& si) const
|
||||||
si.SetBoolValue("Main", "ConfirmPowerOff", confim_power_off);
|
si.SetBoolValue("Main", "ConfirmPowerOff", confim_power_off);
|
||||||
si.SetBoolValue("Main", "LoadDevicesFromSaveStates", load_devices_from_save_states);
|
si.SetBoolValue("Main", "LoadDevicesFromSaveStates", load_devices_from_save_states);
|
||||||
si.SetBoolValue("Main", "ApplyGameSettings", apply_game_settings);
|
si.SetBoolValue("Main", "ApplyGameSettings", apply_game_settings);
|
||||||
|
si.SetBoolValue("Main", "AutoLoadCheats", auto_load_cheats);
|
||||||
|
|
||||||
si.SetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(cpu_execution_mode));
|
si.SetStringValue("CPU", "ExecutionMode", GetCPUExecutionModeName(cpu_execution_mode));
|
||||||
si.SetBoolValue("CPU", "RecompilerMemoryExceptions", cpu_recompiler_memory_exceptions);
|
si.SetBoolValue("CPU", "RecompilerMemoryExceptions", cpu_recompiler_memory_exceptions);
|
||||||
|
|
|
@ -80,6 +80,7 @@ struct Settings
|
||||||
bool confim_power_off = true;
|
bool confim_power_off = true;
|
||||||
bool load_devices_from_save_states = false;
|
bool load_devices_from_save_states = false;
|
||||||
bool apply_game_settings = true;
|
bool apply_game_settings = true;
|
||||||
|
bool auto_load_cheats = false;
|
||||||
|
|
||||||
GPURenderer gpu_renderer = GPURenderer::Software;
|
GPURenderer gpu_renderer = GPURenderer::Software;
|
||||||
std::string gpu_adapter;
|
std::string gpu_adapter;
|
||||||
|
|
|
@ -757,6 +757,7 @@ void Shutdown()
|
||||||
s_running_game_title.clear();
|
s_running_game_title.clear();
|
||||||
s_media_playlist.clear();
|
s_media_playlist.clear();
|
||||||
s_media_playlist_filename.clear();
|
s_media_playlist_filename.clear();
|
||||||
|
s_cheat_list.reset();
|
||||||
s_state = State::Shutdown;
|
s_state = State::Shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -733,27 +733,14 @@ void SDLHostInterface::DrawMainMenuBar()
|
||||||
{
|
{
|
||||||
nfdchar_t* path = nullptr;
|
nfdchar_t* path = nullptr;
|
||||||
if (NFD_OpenDialog("cht", nullptr, &path) && path && std::strlen(path) > 0)
|
if (NFD_OpenDialog("cht", nullptr, &path) && path && std::strlen(path) > 0)
|
||||||
{
|
LoadCheatList(path);
|
||||||
std::unique_ptr<CheatList> cl = std::make_unique<CheatList>();
|
|
||||||
if (cl->LoadFromFile(path, CheatList::Format::Autodetect))
|
|
||||||
{
|
|
||||||
System::SetCheatList(std::move(cl));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ReportFormattedMessage("Failed to load cheats from '%s'", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::MenuItem("Save Cheats...", nullptr, false, has_cheat_file))
|
if (ImGui::MenuItem("Save Cheats...", nullptr, false, has_cheat_file))
|
||||||
{
|
{
|
||||||
nfdchar_t* path = nullptr;
|
nfdchar_t* path = nullptr;
|
||||||
if (NFD_SaveDialog("cht", nullptr, &path) && path && std::strlen(path) > 0)
|
if (NFD_SaveDialog("cht", nullptr, &path) && path && std::strlen(path) > 0)
|
||||||
{
|
SaveCheatList(path);
|
||||||
if (!System::GetCheatList()->SaveToPCSXRFile(path))
|
|
||||||
ReportFormattedMessage("Failed to save cheats to '%s'", path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::BeginMenu("Enabled Cheats", has_cheat_file))
|
if (ImGui::BeginMenu("Enabled Cheats", has_cheat_file))
|
||||||
|
@ -761,8 +748,9 @@ void SDLHostInterface::DrawMainMenuBar()
|
||||||
CheatList* cl = System::GetCheatList();
|
CheatList* cl = System::GetCheatList();
|
||||||
for (u32 i = 0; i < cl->GetCodeCount(); i++)
|
for (u32 i = 0; i < cl->GetCodeCount(); i++)
|
||||||
{
|
{
|
||||||
CheatCode& cc = cl->GetCode(i);
|
const CheatCode& cc = cl->GetCode(i);
|
||||||
ImGui::MenuItem(cc.description.c_str(), nullptr, &cc.enabled, true);
|
if (ImGui::MenuItem(cc.description.c_str(), nullptr, cc.enabled, true))
|
||||||
|
SetCheatCodeState(i, !cc.enabled, g_settings.auto_load_cheats);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
|
@ -775,7 +763,7 @@ void SDLHostInterface::DrawMainMenuBar()
|
||||||
{
|
{
|
||||||
const CheatCode& cc = cl->GetCode(i);
|
const CheatCode& cc = cl->GetCode(i);
|
||||||
if (ImGui::MenuItem(cc.description.c_str()))
|
if (ImGui::MenuItem(cc.description.c_str()))
|
||||||
cc.Apply();
|
ApplyCheatCode(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
|
@ -1198,6 +1186,8 @@ void SDLHostInterface::DrawSettingsWindow()
|
||||||
settings_changed |= ImGui::Checkbox("Pause On Start", &m_settings_copy.start_paused);
|
settings_changed |= ImGui::Checkbox("Pause On Start", &m_settings_copy.start_paused);
|
||||||
settings_changed |= ImGui::Checkbox("Start Fullscreen", &m_settings_copy.start_fullscreen);
|
settings_changed |= ImGui::Checkbox("Start Fullscreen", &m_settings_copy.start_fullscreen);
|
||||||
settings_changed |= ImGui::Checkbox("Save State On Exit", &m_settings_copy.save_state_on_exit);
|
settings_changed |= ImGui::Checkbox("Save State On Exit", &m_settings_copy.save_state_on_exit);
|
||||||
|
settings_changed |= ImGui::Checkbox("Apply Game Settings", &m_settings_copy.apply_game_settings);
|
||||||
|
settings_changed |= ImGui::Checkbox("Automatically Load Cheats", &m_settings_copy.auto_load_cheats);
|
||||||
settings_changed |=
|
settings_changed |=
|
||||||
ImGui::Checkbox("Load Devices From Save States", &m_settings_copy.load_devices_from_save_states);
|
ImGui::Checkbox("Load Devices From Save States", &m_settings_copy.load_devices_from_save_states);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "controller_interface.h"
|
#include "controller_interface.h"
|
||||||
#include "core/cdrom.h"
|
#include "core/cdrom.h"
|
||||||
|
#include "core/cheats.h"
|
||||||
#include "core/cpu_code_cache.h"
|
#include "core/cpu_code_cache.h"
|
||||||
#include "core/dma.h"
|
#include "core/dma.h"
|
||||||
#include "core/gpu.h"
|
#include "core/gpu.h"
|
||||||
|
@ -116,6 +117,7 @@ void CommonHostInterface::InitializeUserDirectory()
|
||||||
|
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("bios").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("bios").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("cache").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("cache").c_str(), false);
|
||||||
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("cheats").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump/audio").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("dump/audio").c_str(), false);
|
||||||
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("inputprofiles").c_str(), false);
|
result &= FileSystem::CreateDirectory(GetUserDirectoryRelativePath("inputprofiles").c_str(), false);
|
||||||
|
@ -710,6 +712,13 @@ void CommonHostInterface::OnRunningGameChanged()
|
||||||
{
|
{
|
||||||
HostInterface::OnRunningGameChanged();
|
HostInterface::OnRunningGameChanged();
|
||||||
|
|
||||||
|
if (!System::IsShutdown())
|
||||||
|
{
|
||||||
|
System::SetCheatList(nullptr);
|
||||||
|
if (g_settings.auto_load_cheats)
|
||||||
|
LoadCheatListFromGameTitle();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WITH_DISCORD_PRESENCE
|
#ifdef WITH_DISCORD_PRESENCE
|
||||||
UpdateDiscordPresence();
|
UpdateDiscordPresence();
|
||||||
#endif
|
#endif
|
||||||
|
@ -2140,6 +2149,111 @@ void CommonHostInterface::ApplyGameSettings(bool display_osd_messages)
|
||||||
gs->ApplySettings(display_osd_messages);
|
gs->ApplySettings(display_osd_messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CommonHostInterface::GetCheatFileName() const
|
||||||
|
{
|
||||||
|
const std::string& title = System::GetRunningTitle();
|
||||||
|
if (title.empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return GetUserDirectoryRelativePath("cheats/%s.cht", title.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommonHostInterface::LoadCheatList(const char* filename)
|
||||||
|
{
|
||||||
|
if (System::IsShutdown())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::unique_ptr<CheatList> cl = std::make_unique<CheatList>();
|
||||||
|
if (!cl->LoadFromPCSXRFile(filename))
|
||||||
|
{
|
||||||
|
AddFormattedOSDMessage(15.0f, TranslateString("OSDMessage", "Failed to load cheats from '%s'."), filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddFormattedOSDMessage(10.0f, TranslateString("OSDMessage", "Loaded %u cheats from list. %u cheats are enabled."),
|
||||||
|
cl->GetCodeCount(), cl->GetEnabledCodeCount());
|
||||||
|
System::SetCheatList(std::move(cl));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommonHostInterface::LoadCheatListFromGameTitle()
|
||||||
|
{
|
||||||
|
const std::string filename(GetCheatFileName());
|
||||||
|
if (filename.empty() || !FileSystem::FileExists(filename.c_str()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return LoadCheatList(filename.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommonHostInterface::SaveCheatList(const char* filename)
|
||||||
|
{
|
||||||
|
if (!System::IsValid() || !System::HasCheatList())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!System::GetCheatList()->SaveToPCSXRFile(filename))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Saved %u cheats to '%s'."),
|
||||||
|
System::GetCheatList()->GetCodeCount(), filename);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::SetCheatCodeState(u32 index, bool enabled, bool save_to_file)
|
||||||
|
{
|
||||||
|
if (!System::IsValid() || !System::HasCheatList())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CheatList* cl = System::GetCheatList();
|
||||||
|
if (index >= cl->GetCodeCount())
|
||||||
|
return;
|
||||||
|
|
||||||
|
CheatCode& cc = cl->GetCode(index);
|
||||||
|
if (cc.enabled == enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cc.enabled = enabled;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Cheat '%s' enabled."), cc.description.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Cheat '%s' disabled."), cc.description.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (save_to_file)
|
||||||
|
{
|
||||||
|
const std::string filename(GetCheatFileName());
|
||||||
|
if (!filename.empty())
|
||||||
|
{
|
||||||
|
if (!cl->SaveToPCSXRFile(filename.c_str()))
|
||||||
|
{
|
||||||
|
AddFormattedOSDMessage(15.0f, TranslateString("OSDMessage", "Failed to save cheat list to '%s'"),
|
||||||
|
filename.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommonHostInterface::ApplyCheatCode(u32 index)
|
||||||
|
{
|
||||||
|
if (!System::HasCheatList() || index >= System::GetCheatList()->GetCodeCount())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const CheatCode& cc = System::GetCheatList()->GetCode(index);
|
||||||
|
if (!cc.enabled)
|
||||||
|
{
|
||||||
|
cc.Apply();
|
||||||
|
AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Applied cheat '%s'."), cc.description.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddFormattedOSDMessage(5.0f, TranslateString("OSDMessage", "Cheat '%s' is already enabled."),
|
||||||
|
cc.description.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef WITH_DISCORD_PRESENCE
|
#ifdef WITH_DISCORD_PRESENCE
|
||||||
|
|
||||||
void CommonHostInterface::SetDiscordPresenceEnabled(bool enabled)
|
void CommonHostInterface::SetDiscordPresenceEnabled(bool enabled)
|
||||||
|
|
|
@ -151,6 +151,21 @@ public:
|
||||||
/// Saves a screenshot to the specified file. IF no file name is provided, one will be generated automatically.
|
/// Saves a screenshot to the specified file. IF no file name is provided, one will be generated automatically.
|
||||||
bool SaveScreenshot(const char* filename = nullptr, bool full_resolution = true, bool apply_aspect_ratio = true);
|
bool SaveScreenshot(const char* filename = nullptr, bool full_resolution = true, bool apply_aspect_ratio = true);
|
||||||
|
|
||||||
|
/// Loads the cheat list from the specified file.
|
||||||
|
bool LoadCheatList(const char* filename);
|
||||||
|
|
||||||
|
/// Loads the cheat list for the current game title from the user directory.
|
||||||
|
bool LoadCheatListFromGameTitle();
|
||||||
|
|
||||||
|
/// Saves the current cheat list to the specified file.
|
||||||
|
bool SaveCheatList(const char* filename);
|
||||||
|
|
||||||
|
/// Enables/disabled the specified cheat code.
|
||||||
|
void SetCheatCodeState(u32 index, bool enabled, bool save_to_file);
|
||||||
|
|
||||||
|
/// Immediately applies the specified cheat code.
|
||||||
|
void ApplyCheatCode(u32 index);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
enum : u32
|
enum : u32
|
||||||
{
|
{
|
||||||
|
@ -248,6 +263,9 @@ protected:
|
||||||
/// Returns the most recent resume save state.
|
/// Returns the most recent resume save state.
|
||||||
std::string GetMostRecentResumeSaveStatePath() const;
|
std::string GetMostRecentResumeSaveStatePath() const;
|
||||||
|
|
||||||
|
/// Returns the path to the cheat file for the specified game title.
|
||||||
|
std::string GetCheatFileName() const;
|
||||||
|
|
||||||
/// Ensures the settings is valid and the correct version. If not, resets to defaults.
|
/// Ensures the settings is valid and the correct version. If not, resets to defaults.
|
||||||
void CheckSettings(SettingsInterface& si);
|
void CheckSettings(SettingsInterface& si);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue