diff --git a/Source/Core/Core/ActionReplay.cpp b/Source/Core/Core/ActionReplay.cpp index 39a05d00b8..c3004cf148 100644 --- a/Source/Core/Core/ActionReplay.cpp +++ b/Source/Core/Core/ActionReplay.cpp @@ -114,7 +114,7 @@ struct ARAddr // AR Remote Functions void ApplyCodes(std::span codes) { - if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (!Config::AreCheatsEnabled()) return; std::lock_guard guard(s_lock); @@ -143,7 +143,7 @@ void UpdateSyncedCodes(std::span codes) std::vector ApplyAndReturnCodes(std::span codes) { - if (Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (Config::AreCheatsEnabled()) { std::lock_guard guard(s_lock); s_disable_logging = false; @@ -158,7 +158,7 @@ std::vector ApplyAndReturnCodes(std::span codes) void AddCode(ARCode code) { - if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (!Config::AreCheatsEnabled()) return; if (code.enabled) @@ -990,7 +990,7 @@ static bool RunCodeLocked(const Core::CPUThreadGuard& guard, const ARCode& arcod void RunAllActive(const Core::CPUThreadGuard& cpu_guard) { - if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (!Config::AreCheatsEnabled()) return; // If the mutex is idle then acquiring it should be cheap, fast mutexes diff --git a/Source/Core/Core/CheatSearch.cpp b/Source/Core/Core/CheatSearch.cpp index 78f206ecfb..6ff7f6ceaf 100644 --- a/Source/Core/Core/CheatSearch.cpp +++ b/Source/Core/Core/CheatSearch.cpp @@ -16,6 +16,7 @@ #include "Common/BitUtils.h" #include "Common/StringUtil.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Core.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/MMU.h" @@ -206,6 +207,10 @@ Cheats::NewSearch(const Core::CPUThreadGuard& guard, PowerPC::RequestedAddressSpace address_space, bool aligned, const std::function& validator) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return Cheats::SearchErrorCode::DisabledInHardcoreMode; +#endif // USE_RETRO_ACHIEVEMENTS const u32 data_size = sizeof(T); std::vector> results; Cheats::SearchErrorCode error_code = Cheats::SearchErrorCode::Success; @@ -269,6 +274,10 @@ Cheats::NextSearch(const Core::CPUThreadGuard& guard, PowerPC::RequestedAddressSpace address_space, const std::function& validator) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return Cheats::SearchErrorCode::DisabledInHardcoreMode; +#endif // USE_RETRO_ACHIEVEMENTS std::vector> results; Cheats::SearchErrorCode error_code = Cheats::SearchErrorCode::Success; Core::RunAsCPUThread([&] { @@ -444,6 +453,10 @@ MakeCompareFunctionForLastValue(Cheats::CompareType op) template Cheats::SearchErrorCode Cheats::CheatSearchSession::RunSearch(const Core::CPUThreadGuard& guard) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return Cheats::SearchErrorCode::DisabledInHardcoreMode; +#endif // USE_RETRO_ACHIEVEMENTS Common::Result>> result = Cheats::SearchErrorCode::InvalidParameters; if (m_filter_type == FilterType::CompareAgainstSpecificValue) diff --git a/Source/Core/Core/CheatSearch.h b/Source/Core/Core/CheatSearch.h index 5f72a0a9a0..4a3d54a897 100644 --- a/Source/Core/Core/CheatSearch.h +++ b/Source/Core/Core/CheatSearch.h @@ -99,6 +99,11 @@ enum class SearchErrorCode // This is returned if PowerPC::RequestedAddressSpace::Virtual is given but the MSR.DR flag is // currently off in the emulated game. VirtualAddressesCurrentlyNotAccessible, + +#ifdef USE_RETRO_ACHIEVEMENTS + // Cheats and memory reading are disabled in RetroAchievements hardcore mode. + DisabledInHardcoreMode, +#endif // USE_RETRO_ACHIEVEMENTS }; // Returns the corresponding DataType enum for the value currently held by the given SearchValue. diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 7ee58576f0..c9b39b7381 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -18,6 +18,7 @@ #include "Common/MathUtil.h" #include "Common/StringUtil.h" #include "Common/Version.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/DefaultLocale.h" #include "Core/HW/EXI/EXI.h" #include "Core/HW/EXI/EXI_Device.h" @@ -739,6 +740,15 @@ bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot) return Config::Get(GetInfoForGCIPath(slot)).empty(); } +bool AreCheatsEnabled() +{ +#ifdef USE_RETRO_ACHIEVEMENTS + return Config::Get(::Config::MAIN_ENABLE_CHEATS) && !::Config::Get(::Config::RA_HARDCORE_ENABLED); +#else // USE_RETRO_ACHIEVEMENTS + return Config::Get(::Config::MAIN_ENABLE_CHEATS); +#endif // USE_RETRO_ACHIEVEMENTS +} + bool IsDebuggingEnabled() { #ifdef USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index c3e2667a96..5994a9bfd1 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -378,5 +378,6 @@ std::string GetGCIFolderPath(ExpansionInterface::Slot slot, std::optional region); bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot); +bool AreCheatsEnabled(); bool IsDebuggingEnabled(); } // namespace Config diff --git a/Source/Core/Core/GeckoCode.cpp b/Source/Core/Core/GeckoCode.cpp index c28178ae8e..3baf683314 100644 --- a/Source/Core/Core/GeckoCode.cpp +++ b/Source/Core/Core/GeckoCode.cpp @@ -71,7 +71,7 @@ void SetActiveCodes(std::span gcodes) std::lock_guard lk(s_active_codes_lock); s_active_codes.clear(); - if (Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (Config::AreCheatsEnabled()) { s_active_codes.reserve(gcodes.size()); std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes), @@ -103,7 +103,7 @@ std::vector SetAndReturnActiveCodes(std::span gcodes std::lock_guard lk(s_active_codes_lock); s_active_codes.clear(); - if (Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (Config::AreCheatsEnabled()) { s_active_codes.reserve(gcodes.size()); std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes), @@ -238,7 +238,7 @@ void Shutdown() void RunCodeHandler(const Core::CPUThreadGuard& guard) { - if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (!Config::AreCheatsEnabled()) return; // NOTE: Need to release the lock because of GUI deadlocks with PanicAlert in HostWrite_* diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index 6291fd01c9..c25a3232f5 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -90,7 +90,7 @@ void PatchFixedFunctions(Core::System& system) // HLE jump to loader (homebrew). Disabled when Gecko is active as it interferes with the code // handler - if (!Config::Get(Config::MAIN_ENABLE_CHEATS)) + if (!Config::AreCheatsEnabled()) { Patch(system, 0x80001800, "HBReload"); auto& memory = system.GetMemory(); diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 267a710cff..a939a15681 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -1356,7 +1356,7 @@ bool NetPlayServer::SetupNetSettings() // Copy all relevant settings settings.cpu_thread = Config::Get(Config::MAIN_CPU_THREAD); settings.cpu_core = Config::Get(Config::MAIN_CPU_CORE); - settings.enable_cheats = Config::Get(Config::MAIN_ENABLE_CHEATS); + settings.enable_cheats = Config::AreCheatsEnabled(); settings.selected_language = Config::Get(Config::MAIN_GC_LANGUAGE); settings.override_region_settings = Config::Get(Config::MAIN_OVERRIDE_REGION_SETTINGS); settings.dsp_hle = Config::Get(Config::MAIN_DSP_HLE); diff --git a/Source/Core/DolphinQt/CheatsManager.cpp b/Source/Core/DolphinQt/CheatsManager.cpp index 0b80de7304..8f2725b4a9 100644 --- a/Source/Core/DolphinQt/CheatsManager.cpp +++ b/Source/Core/DolphinQt/CheatsManager.cpp @@ -143,6 +143,12 @@ void CheatsManager::RefreshCodeTabs(Core::State state, bool force) connect(m_ar_code, &ARCodeWidget::OpenGeneralSettings, this, &CheatsManager::OpenGeneralSettings); connect(m_gecko_code, &GeckoCodeWidget::OpenGeneralSettings, this, &CheatsManager::OpenGeneralSettings); +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_ar_code, &ARCodeWidget::OpenAchievementSettings, this, + &CheatsManager::OpenAchievementSettings); + connect(m_gecko_code, &GeckoCodeWidget::OpenAchievementSettings, this, + &CheatsManager::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS } void CheatsManager::CreateWidgets() diff --git a/Source/Core/DolphinQt/CheatsManager.h b/Source/Core/DolphinQt/CheatsManager.h index 2692999bb7..33b61a4ccc 100644 --- a/Source/Core/DolphinQt/CheatsManager.h +++ b/Source/Core/DolphinQt/CheatsManager.h @@ -37,6 +37,9 @@ public: signals: void OpenGeneralSettings(); +#ifdef USE_RETRO_ACHIEVEMENTS + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS void ShowMemory(u32 address); void RequestWatch(QString name, u32 address); diff --git a/Source/Core/DolphinQt/Config/ARCodeWidget.cpp b/Source/Core/DolphinQt/Config/ARCodeWidget.cpp index a25d6fe7ab..276318f573 100644 --- a/Source/Core/DolphinQt/Config/ARCodeWidget.cpp +++ b/Source/Core/DolphinQt/Config/ARCodeWidget.cpp @@ -21,6 +21,7 @@ #include "DolphinQt/Config/CheatCodeEditor.h" #include "DolphinQt/Config/CheatWarningWidget.h" +#include "DolphinQt/Config/HardcoreWarningWidget.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/QtUtils/SetWindowDecorations.h" @@ -55,6 +56,9 @@ ARCodeWidget::~ARCodeWidget() = default; void ARCodeWidget::CreateWidgets() { m_warning = new CheatWarningWidget(m_game_id, m_restart_required, this); +#ifdef USE_RETRO_ACHIEVEMENTS + m_hc_warning = new HardcoreWarningWidget(this); +#endif // USE_RETRO_ACHIEVEMENTS m_code_list = new QListWidget; m_code_add = new NonDefaultQPushButton(tr("&Add New Code...")); m_code_edit = new NonDefaultQPushButton(tr("&Edit Code...")); @@ -76,6 +80,9 @@ void ARCodeWidget::CreateWidgets() QVBoxLayout* layout = new QVBoxLayout; layout->addWidget(m_warning); +#ifdef USE_RETRO_ACHIEVEMENTS + layout->addWidget(m_hc_warning); +#endif // USE_RETRO_ACHIEVEMENTS layout->addWidget(m_code_list); layout->addLayout(button_layout); @@ -86,6 +93,10 @@ void ARCodeWidget::ConnectWidgets() { connect(m_warning, &CheatWarningWidget::OpenCheatEnableSettings, this, &ARCodeWidget::OpenGeneralSettings); +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this, + &ARCodeWidget::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS connect(m_code_list, &QListWidget::itemChanged, this, &ARCodeWidget::OnItemChanged); connect(m_code_list, &QListWidget::itemSelectionChanged, this, &ARCodeWidget::OnSelectionChanged); diff --git a/Source/Core/DolphinQt/Config/ARCodeWidget.h b/Source/Core/DolphinQt/Config/ARCodeWidget.h index d24c3fcaf8..e5a96a09f9 100644 --- a/Source/Core/DolphinQt/Config/ARCodeWidget.h +++ b/Source/Core/DolphinQt/Config/ARCodeWidget.h @@ -16,6 +16,9 @@ struct ARCode; } class CheatWarningWidget; +#ifdef USE_RETRO_ACHIEVEMENTS +class HardcoreWarningWidget; +#endif // USE_RETRO_ACHIEVEMENTS class QLabel; class QListWidget; class QListWidgetItem; @@ -32,6 +35,9 @@ public: signals: void OpenGeneralSettings(); +#ifdef USE_RETRO_ACHIEVEMENTS + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS private: void OnSelectionChanged(); @@ -56,6 +62,9 @@ private: u16 m_game_revision; CheatWarningWidget* m_warning; +#ifdef USE_RETRO_ACHIEVEMENTS + HardcoreWarningWidget* m_hc_warning; +#endif // USE_RETRO_ACHIEVEMENTS QListWidget* m_code_list; QPushButton* m_code_add; QPushButton* m_code_edit; diff --git a/Source/Core/DolphinQt/Config/GeckoCodeWidget.cpp b/Source/Core/DolphinQt/Config/GeckoCodeWidget.cpp index 988bcf329c..1aa6afb643 100644 --- a/Source/Core/DolphinQt/Config/GeckoCodeWidget.cpp +++ b/Source/Core/DolphinQt/Config/GeckoCodeWidget.cpp @@ -26,6 +26,7 @@ #include "DolphinQt/Config/CheatCodeEditor.h" #include "DolphinQt/Config/CheatWarningWidget.h" +#include "DolphinQt/Config/HardcoreWarningWidget.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/NonDefaultQPushButton.h" #include "DolphinQt/QtUtils/SetWindowDecorations.h" @@ -61,6 +62,9 @@ GeckoCodeWidget::~GeckoCodeWidget() = default; void GeckoCodeWidget::CreateWidgets() { m_warning = new CheatWarningWidget(m_game_id, m_restart_required, this); +#ifdef USE_RETRO_ACHIEVEMENTS + m_hc_warning = new HardcoreWarningWidget(this); +#endif // USE_RETRO_ACHIEVEMENTS m_code_list = new QListWidget; m_name_label = new QLabel; m_creator_label = new QLabel; @@ -102,6 +106,9 @@ void GeckoCodeWidget::CreateWidgets() auto* layout = new QVBoxLayout; layout->addWidget(m_warning); +#ifdef USE_RETRO_ACHIEVEMENTS + layout->addWidget(m_hc_warning); +#endif // USE_RETRO_ACHIEVEMENTS layout->addWidget(m_code_list); auto* info_layout = new QFormLayout; @@ -150,6 +157,10 @@ void GeckoCodeWidget::ConnectWidgets() connect(m_download_codes, &QPushButton::clicked, this, &GeckoCodeWidget::DownloadCodes); connect(m_warning, &CheatWarningWidget::OpenCheatEnableSettings, this, &GeckoCodeWidget::OpenGeneralSettings); +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this, + &GeckoCodeWidget::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS } void GeckoCodeWidget::OnSelectionChanged() diff --git a/Source/Core/DolphinQt/Config/GeckoCodeWidget.h b/Source/Core/DolphinQt/Config/GeckoCodeWidget.h index a4312f7ec7..bbf13cc253 100644 --- a/Source/Core/DolphinQt/Config/GeckoCodeWidget.h +++ b/Source/Core/DolphinQt/Config/GeckoCodeWidget.h @@ -11,6 +11,9 @@ #include "Common/CommonTypes.h" class CheatWarningWidget; +#ifdef USE_RETRO_ACHIEVEMENTS +class HardcoreWarningWidget; +#endif // USE_RETRO_ACHIEVEMENTS class QLabel; class QListWidget; class QListWidgetItem; @@ -32,6 +35,9 @@ public: signals: void OpenGeneralSettings(); +#ifdef USE_RETRO_ACHIEVEMENTS + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS private: void OnSelectionChanged(); @@ -56,6 +62,9 @@ private: u16 m_game_revision; CheatWarningWidget* m_warning; +#ifdef USE_RETRO_ACHIEVEMENTS + HardcoreWarningWidget* m_hc_warning; +#endif // USE_RETRO_ACHIEVEMENTS QListWidget* m_code_list; QLabel* m_name_label; QLabel* m_creator_label; diff --git a/Source/Core/DolphinQt/Config/PropertiesDialog.cpp b/Source/Core/DolphinQt/Config/PropertiesDialog.cpp index 834c5d68cf..86be3e8c3c 100644 --- a/Source/Core/DolphinQt/Config/PropertiesDialog.cpp +++ b/Source/Core/DolphinQt/Config/PropertiesDialog.cpp @@ -52,6 +52,10 @@ PropertiesDialog::PropertiesDialog(QWidget* parent, const UICommon::GameFile& ga connect(ar, &ARCodeWidget::OpenGeneralSettings, this, &PropertiesDialog::OpenGeneralSettings); #ifdef USE_RETRO_ACHIEVEMENTS + connect(ar, &ARCodeWidget::OpenAchievementSettings, this, + &PropertiesDialog::OpenAchievementSettings); + connect(gecko, &GeckoCodeWidget::OpenAchievementSettings, this, + &PropertiesDialog::OpenAchievementSettings); connect(patches, &PatchesWidget::OpenAchievementSettings, this, &PropertiesDialog::OpenAchievementSettings); #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 881e28549c..bf7e7e776f 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -247,6 +247,8 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters, &MainWindow::ShowGeneralWindow); #ifdef USE_RETRO_ACHIEVEMENTS + connect(m_cheats_manager, &CheatsManager::OpenAchievementSettings, this, + &MainWindow::ShowAchievementSettings); connect(m_game_list, &GameList::OpenAchievementSettings, this, &MainWindow::ShowAchievementSettings); #endif // USE_RETRO_ACHIEVEMENTS @@ -2027,6 +2029,12 @@ void MainWindow::ShowRiivolutionBootWidget(const UICommon::GameFile& game) RiivolutionBootWidget w(disc.volume->GetGameID(), disc.volume->GetRevision(), disc.volume->GetDiscNumber(), game.GetFilePath(), this); SetQWidgetWindowDecorations(&w); + +#ifdef USE_RETRO_ACHIEVEMENTS + connect(&w, &RiivolutionBootWidget::OpenAchievementSettings, this, + &MainWindow::ShowAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS + w.exec(); if (!w.ShouldBoot()) return; diff --git a/Source/Core/DolphinQt/Settings/GeneralPane.cpp b/Source/Core/DolphinQt/Settings/GeneralPane.cpp index 1e54ae533b..3236a72857 100644 --- a/Source/Core/DolphinQt/Settings/GeneralPane.cpp +++ b/Source/Core/DolphinQt/Settings/GeneralPane.cpp @@ -15,6 +15,7 @@ #include #include +#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/UISettings.h" #include "Core/ConfigManager.h" @@ -84,7 +85,12 @@ void GeneralPane::OnEmulationStateChanged(Core::State state) const bool running = state != Core::State::Uninitialized; m_checkbox_dualcore->setEnabled(!running); +#ifdef USE_RETRO_ACHIEVEMENTS + bool hardcore = Config::Get(Config::RA_HARDCORE_ENABLED); + m_checkbox_cheats->setEnabled(!running && !hardcore); +#else // USE_RETRO_ACHIEVEMENTS m_checkbox_cheats->setEnabled(!running); +#endif // USE_RETRO_ACHIEVEMENTS m_checkbox_override_region_settings->setEnabled(!running); #ifdef USE_DISCORD_PRESENCE m_checkbox_discord_presence->setEnabled(!running);