From 138e68ef9f7a7cb2bc8640c876ffc800a4d05baf Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 15 Nov 2023 10:46:42 -0500 Subject: [PATCH 01/11] Added Hardcore flag to Achievement Settings Hardcore Mode is a RetroAchievements feature for enabling as close to original hardware as possible, to keep a fair, challenging, and competitive playing field for achievements (which get tallied differently and emphasized more in hardcore) and leaderboards (where it is mandatory) at the cost of several common emulator features that provide advantages, such as state loading and slower emulation speeds. This commit just adds the flag to the AchievementSettings, with more to come. --- Source/Core/Core/AchievementManager.cpp | 12 ++++++++++++ Source/Core/Core/AchievementManager.h | 3 ++- Source/Core/Core/Config/AchievementSettings.cpp | 5 +++++ Source/Core/Core/Config/AchievementSettings.h | 4 ++++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 54671a1388..6fab056c79 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -633,6 +633,18 @@ std::recursive_mutex* AchievementManager::GetLock() return &m_lock; } +bool AchievementManager::IsHardcoreModeActive() const +{ + std::lock_guard lg{m_lock}; + if (!Config::Get(Config::RA_HARDCORE_ENABLED)) + return false; + if (!Core::IsRunning()) + return true; + if (!IsGameLoaded()) + return false; + return (m_runtime.trigger_count + m_runtime.lboard_count > 0); +} + std::string AchievementManager::GetPlayerDisplayName() const { return IsLoggedIn() ? m_display_name : ""; diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index be2469dc9e..e790e0bc1c 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -119,6 +119,7 @@ public: void AchievementEventHandler(const rc_runtime_event_t* runtime_event); std::recursive_mutex* GetLock(); + bool IsHardcoreModeActive() const; std::string GetPlayerDisplayName() const; u32 GetPlayerScore() const; const BadgeStatus& GetPlayerBadge() const; @@ -190,7 +191,7 @@ private: Common::WorkQueueThread> m_queue; Common::WorkQueueThread> m_image_queue; - std::recursive_mutex m_lock; + mutable std::recursive_mutex m_lock; }; // class AchievementManager #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/Config/AchievementSettings.cpp b/Source/Core/Core/Config/AchievementSettings.cpp index a425605f8c..5edaa6a54c 100644 --- a/Source/Core/Core/Config/AchievementSettings.cpp +++ b/Source/Core/Core/Config/AchievementSettings.cpp @@ -1,6 +1,7 @@ // Copyright 2023 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#ifdef USE_RETRO_ACHIEVEMENTS #include "Core/Config/AchievementSettings.h" #include @@ -19,6 +20,8 @@ const Info RA_LEADERBOARDS_ENABLED{ {System::Achievements, "Achievements", "LeaderboardsEnabled"}, false}; const Info RA_RICH_PRESENCE_ENABLED{ {System::Achievements, "Achievements", "RichPresenceEnabled"}, false}; +const Info RA_HARDCORE_ENABLED{{System::Achievements, "Achievements", "HardcoreEnabled"}, + false}; const Info RA_PROGRESS_ENABLED{{System::Achievements, "Achievements", "ProgressEnabled"}, false}; const Info RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false}; @@ -26,3 +29,5 @@ const Info RA_UNOFFICIAL_ENABLED{{System::Achievements, "Achievements", "U false}; const Info RA_ENCORE_ENABLED{{System::Achievements, "Achievements", "EncoreEnabled"}, false}; } // namespace Config + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/Config/AchievementSettings.h b/Source/Core/Core/Config/AchievementSettings.h index b17d00c65f..15277ca043 100644 --- a/Source/Core/Core/Config/AchievementSettings.h +++ b/Source/Core/Core/Config/AchievementSettings.h @@ -1,6 +1,7 @@ // Copyright 2023 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#ifdef USE_RETRO_ACHIEVEMENTS #pragma once #include "Common/Config/Config.h" @@ -14,8 +15,11 @@ extern const Info RA_API_TOKEN; extern const Info RA_ACHIEVEMENTS_ENABLED; extern const Info RA_LEADERBOARDS_ENABLED; extern const Info RA_RICH_PRESENCE_ENABLED; +extern const Info RA_HARDCORE_ENABLED; extern const Info RA_PROGRESS_ENABLED; extern const Info RA_BADGES_ENABLED; extern const Info RA_UNOFFICIAL_ENABLED; extern const Info RA_ENCORE_ENABLED; } // namespace Config + +#endif // USE_RETRO_ACHIEVEMENTS From 71f3039f9682df901d2554370293b2aaee1a1c27 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 15 Nov 2023 10:56:15 -0500 Subject: [PATCH 02/11] Added Hardcore Warning Widget This widget will be used in several places to notify the player that a feature has been disabled because hardcore mode is on. It includes a button to open the Achievement Settings so that Hardcore Mode may be turned off. Also included is the framework required to open AchievementsWindow specifically on the Settings tab. --- .../Achievements/AchievementsWindow.cpp | 5 ++ .../Achievements/AchievementsWindow.h | 1 + Source/Core/DolphinQt/CMakeLists.txt | 2 + .../Config/HardcoreWarningWidget.cpp | 62 +++++++++++++++++++ .../DolphinQt/Config/HardcoreWarningWidget.h | 30 +++++++++ Source/Core/DolphinQt/DolphinQt.vcxproj | 6 +- Source/Core/DolphinQt/MainWindow.cpp | 6 ++ Source/Core/DolphinQt/MainWindow.h | 1 + 8 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 Source/Core/DolphinQt/Config/HardcoreWarningWidget.cpp create mode 100644 Source/Core/DolphinQt/Config/HardcoreWarningWidget.h diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index 8d01663c87..4a278c3649 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -81,4 +81,9 @@ void AchievementsWindow::UpdateData() update(); } +void AchievementsWindow::ForceSettingsTab() +{ + m_tab_widget->setCurrentIndex(0); +} + #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index 6fd7165e1f..381a0aafb5 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -22,6 +22,7 @@ class AchievementsWindow : public QDialog public: explicit AchievementsWindow(QWidget* parent); void UpdateData(); + void ForceSettingsTab(); private: void CreateMainLayout(); diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 391b1f1afb..a7eac856d0 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -102,6 +102,8 @@ add_executable(dolphin-emu Config/GraphicsModListWidget.h Config/GraphicsModWarningWidget.cpp Config/GraphicsModWarningWidget.h + Config/HardcoreWarningWidget.cpp + Config/HardcoreWarningWidget.h Config/InfoWidget.cpp Config/InfoWidget.h Config/LogConfigWidget.cpp diff --git a/Source/Core/DolphinQt/Config/HardcoreWarningWidget.cpp b/Source/Core/DolphinQt/Config/HardcoreWarningWidget.cpp new file mode 100644 index 0000000000..c2db01d077 --- /dev/null +++ b/Source/Core/DolphinQt/Config/HardcoreWarningWidget.cpp @@ -0,0 +1,62 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef USE_RETRO_ACHIEVEMENTS +#include "DolphinQt/Config/HardcoreWarningWidget.h" + +#include +#include +#include +#include +#include + +#include "Core/Config/AchievementSettings.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" + +#include "DolphinQt/Settings.h" + +HardcoreWarningWidget::HardcoreWarningWidget(QWidget* parent) : QWidget(parent) +{ + CreateWidgets(); + ConnectWidgets(); + + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, [this] { Update(); }); + + Update(); +} + +void HardcoreWarningWidget::CreateWidgets() +{ + const auto size = 1.5 * QFontMetrics(font()).height(); + + QPixmap warning_icon = style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(size, size); + + auto* icon = new QLabel; + icon->setPixmap(warning_icon); + + m_text = new QLabel(tr("This feature is disabled in hardcore mode.")); + m_settings_button = new QPushButton(tr("Achievement Settings")); + + auto* layout = new QHBoxLayout; + + layout->addWidget(icon); + layout->addWidget(m_text, 1); + layout->addWidget(m_settings_button); + + layout->setContentsMargins(0, 0, 0, 0); + + setLayout(layout); +} + +void HardcoreWarningWidget::ConnectWidgets() +{ + connect(m_settings_button, &QPushButton::clicked, this, + &HardcoreWarningWidget::OpenAchievementSettings); +} + +void HardcoreWarningWidget::Update() +{ + setHidden(!Config::Get(Config::RA_HARDCORE_ENABLED)); +} +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Config/HardcoreWarningWidget.h b/Source/Core/DolphinQt/Config/HardcoreWarningWidget.h new file mode 100644 index 0000000000..c4a20eba96 --- /dev/null +++ b/Source/Core/DolphinQt/Config/HardcoreWarningWidget.h @@ -0,0 +1,30 @@ +// Copyright 2023 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef USE_RETRO_ACHIEVEMENTS +#include + +class QLabel; +class QPushButton; + +class HardcoreWarningWidget : public QWidget +{ + Q_OBJECT +public: + explicit HardcoreWarningWidget(QWidget* parent); + +signals: + void OpenAchievementSettings(); + +private: + void CreateWidgets(); + void ConnectWidgets(); + + void Update(); + + QLabel* m_text; + QPushButton* m_settings_button; +}; +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index 36e4b44d31..9ad07befec 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -31,10 +31,8 @@ $(ProjectDir)Settings;%(AdditionalIncludeDirectories) $(ProjectDir)TAS;%(AdditionalIncludeDirectories) $(ProjectDir)VideoInterface;%(AdditionalIncludeDirectories) - _SILENCE_CXX23_ALIGNED_STORAGE_DEPRECATION_WARNING;%(PreprocessorDefinitions) - $(SourceDir)PCH;%(AdditionalIncludeDirectories) Use @@ -87,6 +85,7 @@ + @@ -239,7 +238,7 @@ - + @@ -298,6 +297,7 @@ + diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index d9eda82bb1..6cf6ac57bd 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1971,6 +1971,12 @@ void MainWindow::ShowAchievementsWindow() m_achievements_window->raise(); m_achievements_window->activateWindow(); } + +void MainWindow::ShowAchievementSettings() +{ + ShowAchievementsWindow(); + m_achievements_window->ForceSettingsTab(); +} #endif // USE_RETRO_ACHIEVEMENTS void MainWindow::ShowMemcardManager() diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index ce6beb1578..1f53d5e1ff 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -175,6 +175,7 @@ private: #ifdef USE_RETRO_ACHIEVEMENTS void ShowAchievementsWindow(); + void ShowAchievementSettings(); #endif // USE_RETRO_ACHIEVEMENTS void NetPlayInit(); From 2c40d6ba31a46de30d7e2be7bffb3c0003651830 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 21:37:13 -0400 Subject: [PATCH 03/11] Disable loading state in hardcore mode While saving states is allowed (especially for the purpose of debugging), RetroAchievements does not allow loading saved states when hardcore mode is on. --- Source/Core/Core/State.cpp | 18 ++++++++++++++++++ Source/Core/DolphinQt/MenuBar.cpp | 10 +++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 7879b84dda..afad78986c 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -31,6 +31,8 @@ #include "Common/Version.h" #include "Common/WorkQueueThread.h" +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" @@ -204,6 +206,14 @@ void LoadFromBuffer(std::vector& buffer) return; } +#ifdef USE_RETRO_ACHIEVEMENTS + if (AchievementManager::GetInstance()->IsHardcoreModeActive()) + { + OSD::AddMessage("Loading savestates is disabled in RetroAchievements hardcore mode"); + return; + } +#endif // USE_RETRO_ACHIEVEMENTS + Core::RunOnCPUThread( [&] { u8* ptr = buffer.data(); @@ -842,6 +852,14 @@ void LoadAs(const std::string& filename) return; } +#ifdef USE_RETRO_ACHIEVEMENTS + if (AchievementManager::GetInstance()->IsHardcoreModeActive()) + { + OSD::AddMessage("Loading savestates is disabled in RetroAchievements hardcore mode"); + return; + } +#endif // USE_RETRO_ACHIEVEMENTS + std::unique_lock lk(s_load_or_save_in_progress_mutex, std::try_to_lock); if (!lk) return; diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 2b68cf640d..8bf96d7acb 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -20,6 +20,7 @@ #include "Common/FileUtil.h" #include "Common/StringUtil.h" +#include "Core/AchievementManager.h" #include "Core/Boot/Boot.h" #include "Core/CommonTitles.h" #include "Core/Config/AchievementSettings.h" @@ -122,9 +123,16 @@ void MenuBar::OnEmulationStateChanged(Core::State state) m_fullscreen_action->setEnabled(running); m_frame_advance_action->setEnabled(running); m_screenshot_action->setEnabled(running); - m_state_load_menu->setEnabled(running); m_state_save_menu->setEnabled(running); +#ifdef USE_RETRO_ACHIEVEMENTS + bool hardcore = AchievementManager::GetInstance()->IsHardcoreModeActive(); + m_state_load_menu->setEnabled(running && !hardcore); +#else // USE_RETRO_ACHIEVEMENTS + m_state_load_menu->setEnabled(running); + +#endif // USE_RETRO_ACHIEVEMENTS + // Movie m_recording_read_only->setEnabled(running); if (!running) From 45105822f3ed5c86694f3bddfc0c43555b1b2499 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 21:46:49 -0400 Subject: [PATCH 04/11] Disable frame advance in hardcore mode Frame advancing is easily exploitable for slowing down a game and artificially improving reaction times and is not allowed in RetroAchievements hardcore mode. --- Source/Core/Core/Core.cpp | 8 ++++++++ Source/Core/DolphinQt/MenuBar.cpp | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 536244869a..8390bd44b6 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -42,6 +42,7 @@ #include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/CPUThreadConfigCallback.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" @@ -1081,6 +1082,13 @@ void HostDispatchJobs() // NOTE: Host Thread void DoFrameStep() { +#ifdef USE_RETRO_ACHIEVEMENTS + if (AchievementManager::GetInstance()->IsHardcoreModeActive()) + { + OSD::AddMessage("Frame stepping is disabled in RetroAchievements hardcore mode"); + return; + } +#endif // USE_RETRO_ACHIEVEMENTS if (GetState() == State::Paused) { // if already paused, frame advance for 1 frame diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 8bf96d7acb..0a0b52e1fc 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -121,16 +121,16 @@ void MenuBar::OnEmulationStateChanged(Core::State state) m_stop_action->setVisible(running); m_reset_action->setEnabled(running); m_fullscreen_action->setEnabled(running); - m_frame_advance_action->setEnabled(running); m_screenshot_action->setEnabled(running); m_state_save_menu->setEnabled(running); #ifdef USE_RETRO_ACHIEVEMENTS bool hardcore = AchievementManager::GetInstance()->IsHardcoreModeActive(); m_state_load_menu->setEnabled(running && !hardcore); + m_frame_advance_action->setEnabled(running && !hardcore); #else // USE_RETRO_ACHIEVEMENTS m_state_load_menu->setEnabled(running); - + m_frame_advance_action->setEnabled(running); #endif // USE_RETRO_ACHIEVEMENTS // Movie From c20258d782ada6ce2a628bdf4070b1ad8f8d97b0 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 22:16:39 -0400 Subject: [PATCH 05/11] Disable slowdown in hardcore mode Slowing down the emulator would artificially improve reaction times and is therefore disallowed in hardcore mode. Speeds faster than 1x are allowed, but any speed below 1x is scaled back up to 1x. --- Source/Core/Core/CoreTiming.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 2e6f6a0968..ae0a7bd2bf 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -16,13 +16,16 @@ #include "Common/Logging/Log.h" #include "Common/SPSCQueue.h" +#include "Core/AchievementManager.h" #include "Core/CPUThreadConfigCallback.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Core.h" #include "Core/PowerPC/PowerPC.h" #include "Core/System.h" #include "VideoCommon/Fifo.h" +#include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/PerformanceMetrics.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoConfig.h" @@ -135,6 +138,17 @@ void CoreTimingManager::RefreshConfig() m_max_variance = std::chrono::duration_cast
(DT_ms(Config::Get(Config::MAIN_TIMING_VARIANCE))); +#ifdef USE_RETRO_ACHIEVEMENTS + if (AchievementManager::GetInstance()->IsHardcoreModeActive() && + Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f && + Config::Get(Config::MAIN_EMULATION_SPEED) > 0.0f) + { + Config::SetCurrent(Config::MAIN_EMULATION_SPEED, 1.0f); + m_emulation_speed = 1.0f; + OSD::AddMessage("Minimum speed is 100% in Hardcore Mode"); + } +#endif // USE_RETRO_ACHIEVEMENTS + m_emulation_speed = Config::Get(Config::MAIN_EMULATION_SPEED); } From cb2fa9a1f2873edf2704729cfcef4c317206acbd Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 21:54:49 -0400 Subject: [PATCH 06/11] Disable Debug Mode in hardcore mode Debug Mode gives players direct read and write access to memory, which could be used to completely manipulate RetroAchievements logic and therefore is not allowed in hardcore mode. --- Source/Core/Core/Config/MainSettings.cpp | 11 ++++++++++ Source/Core/Core/Config/MainSettings.h | 1 + Source/Core/Core/HLE/HLE.cpp | 2 +- .../Core/PowerPC/Interpreter/Interpreter.cpp | 2 +- Source/Core/Core/PowerPC/Jit64/JitAsm.cpp | 2 +- Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp | 2 +- Source/Core/DolphinQt/Debugger/JITWidget.cpp | 2 +- Source/Core/DolphinQt/HotkeyScheduler.cpp | 2 +- Source/Core/DolphinQt/Settings.cpp | 5 +++++ .../Core/DolphinQt/Settings/InterfacePane.cpp | 22 ++++++++++++++++++- .../Core/DolphinQt/Settings/InterfacePane.h | 4 +++- 11 files changed, 47 insertions(+), 8 deletions(-) diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 4a7470ada8..7ee58576f0 100644 --- a/Source/Core/Core/Config/MainSettings.cpp +++ b/Source/Core/Core/Config/MainSettings.cpp @@ -738,4 +738,15 @@ bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot) { return Config::Get(GetInfoForGCIPath(slot)).empty(); } + +bool IsDebuggingEnabled() +{ +#ifdef USE_RETRO_ACHIEVEMENTS + return Config::Get(::Config::MAIN_ENABLE_DEBUGGING) && + !::Config::Get(::Config::RA_HARDCORE_ENABLED); +#else // USE_RETRO_ACHIEVEMENTS + return Config::Get(::Config::MAIN_ENABLE_DEBUGGING); +#endif // USE_RETRO_ACHIEVEMENTS +} + } // namespace Config diff --git a/Source/Core/Core/Config/MainSettings.h b/Source/Core/Core/Config/MainSettings.h index b591a00de4..c3e2667a96 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -378,4 +378,5 @@ std::string GetGCIFolderPath(ExpansionInterface::Slot slot, std::optional region); bool IsDefaultGCIFolderPathConfigured(ExpansionInterface::Slot slot); +bool IsDebuggingEnabled(); } // namespace Config diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index 2d4f3313f2..6291fd01c9 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -219,7 +219,7 @@ TryReplaceFunctionResult TryReplaceFunction(u32 address) bool IsEnabled(HookFlag flag) { - return flag != HLE::HookFlag::Debug || Config::Get(Config::MAIN_ENABLE_DEBUGGING) || + return flag != HLE::HookFlag::Debug || Config::IsDebuggingEnabled() || Core::System::GetInstance().GetPowerPC().GetMode() == PowerPC::CoreMode::Interpreter; } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index f3d3619f1b..6b475e1204 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -236,7 +236,7 @@ void Interpreter::Run() core_timing.Advance(); // we have to check exceptions at branches apparently (or maybe just rfi?) - if (Config::Get(Config::MAIN_ENABLE_DEBUGGING)) + if (Config::IsDebuggingEnabled()) { #ifdef SHOW_HISTORY s_pc_block_vec.push_back(m_ppc_state.pc); diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index f77afc563c..a5d89cd315 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -44,7 +44,7 @@ void Jit64AsmRoutineManager::Regenerate() void Jit64AsmRoutineManager::Generate() { - const bool enable_debugging = Config::Get(Config::MAIN_ENABLE_DEBUGGING); + const bool enable_debugging = Config::IsDebuggingEnabled(); enter_code = AlignCode16(); // We need to own the beginning of RSP, so we do an extra stack adjustment diff --git a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp index cc3f7cc298..350edc2ba4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp @@ -30,7 +30,7 @@ void JitArm64::GenerateAsm() { const Common::ScopedJITPageWriteAndNoExecute enable_jit_page_writes; - const bool enable_debugging = Config::Get(Config::MAIN_ENABLE_DEBUGGING); + const bool enable_debugging = Config::IsDebuggingEnabled(); // This value is all of the callee saved registers that we are required to save. // According to the AACPS64 we need to save R19 ~ R30 and Q8 ~ Q15. diff --git a/Source/Core/DolphinQt/Debugger/JITWidget.cpp b/Source/Core/DolphinQt/Debugger/JITWidget.cpp index 771f72473c..6148528891 100644 --- a/Source/Core/DolphinQt/Debugger/JITWidget.cpp +++ b/Source/Core/DolphinQt/Debugger/JITWidget.cpp @@ -160,7 +160,7 @@ void JITWidget::Update() PPCAnalyst::BlockRegStats fpa; PPCAnalyst::CodeBlock code_block; PPCAnalyst::PPCAnalyzer analyzer; - analyzer.SetDebuggingEnabled(Config::Get(Config::MAIN_ENABLE_DEBUGGING)); + analyzer.SetDebuggingEnabled(Config::IsDebuggingEnabled()); analyzer.SetBranchFollowingEnabled(Config::Get(Config::MAIN_JIT_FOLLOW_BRANCH)); analyzer.SetFloatExceptionsEnabled(Config::Get(Config::MAIN_FLOAT_EXCEPTIONS)); analyzer.SetDivByZeroExceptionsEnabled(Config::Get(Config::MAIN_DIVIDE_BY_ZERO_EXCEPTIONS)); diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index 05b38a367f..b527e96c6c 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -257,7 +257,7 @@ void HotkeyScheduler::Run() if (auto bt = WiiUtils::GetBluetoothRealDevice()) bt->UpdateSyncButtonState(IsHotkey(HK_TRIGGER_SYNC_BUTTON, true)); - if (Config::Get(Config::MAIN_ENABLE_DEBUGGING)) + if (Config::IsDebuggingEnabled()) { CheckDebuggingHotkeys(); } diff --git a/Source/Core/DolphinQt/Settings.cpp b/Source/Core/DolphinQt/Settings.cpp index 2e21835b6f..e3bb288c7b 100644 --- a/Source/Core/DolphinQt/Settings.cpp +++ b/Source/Core/DolphinQt/Settings.cpp @@ -33,6 +33,7 @@ #include "Common/FileUtil.h" #include "Common/StringUtil.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" @@ -563,6 +564,10 @@ void Settings::SetCheatsEnabled(bool enabled) void Settings::SetDebugModeEnabled(bool enabled) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + enabled = false; +#endif // USE_RETRO_ACHIEVEMENTS if (IsDebugModeEnabled() != enabled) { Config::SetBaseOrCurrent(Config::MAIN_ENABLE_DEBUGGING, enabled); diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.cpp b/Source/Core/DolphinQt/Settings/InterfacePane.cpp index 81a0453c7e..39c11733c0 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.cpp +++ b/Source/Core/DolphinQt/Settings/InterfacePane.cpp @@ -19,9 +19,11 @@ #include "Common/MsgHandler.h" #include "Common/StringUtil.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/UISettings.h" +#include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" #include "DolphinQt/QtUtils/SignalBlocking.h" #include "DolphinQt/Settings.h" @@ -84,6 +86,9 @@ InterfacePane::InterfacePane(QWidget* parent) : QWidget(parent) CreateLayout(); LoadConfig(); ConnectLayout(); + + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, + &InterfacePane::LoadConfig); } void InterfacePane::CreateLayout() @@ -151,7 +156,7 @@ void InterfacePane::CreateUI() m_checkbox_use_builtin_title_database = new QCheckBox(tr("Use Built-In Database of Game Names")); m_checkbox_use_covers = new QCheckBox(tr("Download Game Covers from GameTDB.com for Use in Grid Mode")); - m_checkbox_show_debugging_ui = new QCheckBox(tr("Enable Debugging UI")); + m_checkbox_show_debugging_ui = new ToolTipCheckBox(tr("Enable Debugging UI")); m_checkbox_focused_hotkeys = new QCheckBox(tr("Hotkeys Require Window Focus")); m_checkbox_disable_screensaver = new QCheckBox(tr("Inhibit Screensaver During Emulation")); @@ -249,6 +254,21 @@ void InterfacePane::LoadConfig() ->setChecked(Config::Get(Config::MAIN_USE_BUILT_IN_TITLE_DATABASE)); SignalBlocking(m_checkbox_show_debugging_ui) ->setChecked(Settings::Instance().IsDebugModeEnabled()); + +#ifdef USE_RETRO_ACHIEVEMENTS + bool hardcore = Config::Get(Config::RA_HARDCORE_ENABLED); + SignalBlocking(m_checkbox_show_debugging_ui)->setEnabled(!hardcore); + if (hardcore) + { + m_checkbox_show_debugging_ui->SetDescription( + tr("Disabled in Hardcore Mode.")); + } + else + { + m_checkbox_show_debugging_ui->SetDescription({}); + } +#endif // USE_RETRO_ACHIEVEMENTS + SignalBlocking(m_combobox_language) ->setCurrentIndex(m_combobox_language->findData( QString::fromStdString(Config::Get(Config::MAIN_INTERFACE_LANGUAGE)))); diff --git a/Source/Core/DolphinQt/Settings/InterfacePane.h b/Source/Core/DolphinQt/Settings/InterfacePane.h index ffa09c3f72..22c1a2b4f3 100644 --- a/Source/Core/DolphinQt/Settings/InterfacePane.h +++ b/Source/Core/DolphinQt/Settings/InterfacePane.h @@ -10,6 +10,7 @@ class QComboBox; class QLabel; class QRadioButton; class QVBoxLayout; +class ToolTipCheckBox; class InterfacePane final : public QWidget { @@ -36,7 +37,8 @@ private: QLabel* m_label_userstyle; QCheckBox* m_checkbox_top_window; QCheckBox* m_checkbox_use_builtin_title_database; - QCheckBox* m_checkbox_show_debugging_ui; + QCheckBox* m_checkbox_use_userstyle; + ToolTipCheckBox* m_checkbox_show_debugging_ui; QCheckBox* m_checkbox_focused_hotkeys; QCheckBox* m_checkbox_use_covers; QCheckBox* m_checkbox_disable_screensaver; From 1a19a9294342828630a6d0c02ba80a1010c87315 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 15 Nov 2023 12:03:21 -0500 Subject: [PATCH 07/11] Disable memory patches in hardcore mode Memory patches would be an easy way to manipulate the memory needed to calculate achievement logic, so they must be disabled. Riivolution patches that do not affect memory are allowed, as they will be hashed with the game file. --- .../Core/Core/Debugger/PPCDebugInterface.cpp | 5 ++++ Source/Core/Core/PatchEngine.cpp | 9 +++++++ Source/Core/DiscIO/RiivolutionPatcher.cpp | 6 +++++ .../Core/DolphinQt/Config/PatchesWidget.cpp | 26 +++++++++++++++---- Source/Core/DolphinQt/Config/PatchesWidget.h | 18 +++++++++---- .../DolphinQt/Config/PropertiesDialog.cpp | 4 +++ .../Core/DolphinQt/Config/PropertiesDialog.h | 3 +++ Source/Core/DolphinQt/GameList/GameList.cpp | 4 +++ Source/Core/DolphinQt/GameList/GameList.h | 3 +++ Source/Core/DolphinQt/MainWindow.cpp | 5 ++++ .../Core/DolphinQt/RiivolutionBootWidget.cpp | 18 +++++++++++++ Source/Core/DolphinQt/RiivolutionBootWidget.h | 12 +++++++++ 12 files changed, 103 insertions(+), 10 deletions(-) diff --git a/Source/Core/Core/Debugger/PPCDebugInterface.cpp b/Source/Core/Core/Debugger/PPCDebugInterface.cpp index 5f8d04d79a..7ab64c9310 100644 --- a/Source/Core/Core/Debugger/PPCDebugInterface.cpp +++ b/Source/Core/Core/Debugger/PPCDebugInterface.cpp @@ -16,6 +16,7 @@ #include "Common/GekkoDisassembler.h" #include "Common/StringUtil.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Core.h" #include "Core/Debugger/OSThread.h" @@ -29,6 +30,10 @@ void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, Common::Debug::MemoryPatch& patch, bool store_existing_value) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return; +#endif // USE_RETRO_ACHIEVEMENTS if (patch.value.empty()) return; diff --git a/Source/Core/Core/PatchEngine.cpp b/Source/Core/Core/PatchEngine.cpp index 069d8565c0..456c2b008c 100644 --- a/Source/Core/Core/PatchEngine.cpp +++ b/Source/Core/Core/PatchEngine.cpp @@ -26,6 +26,7 @@ #include "Core/ActionReplay.h" #include "Core/CheatCodes.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/SessionSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -232,6 +233,10 @@ void LoadPatches() static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector& patches) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return; +#endif // USE_RETRO_ACHIEVEMENTS for (const Patch& patch : patches) { if (patch.enabled) @@ -273,6 +278,10 @@ static void ApplyPatches(const Core::CPUThreadGuard& guard, const std::vector memory_patch_indices) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return; +#endif // USE_RETRO_ACHIEVEMENTS std::lock_guard lock(s_on_frame_memory_mutex); for (std::size_t index : memory_patch_indices) { diff --git a/Source/Core/DiscIO/RiivolutionPatcher.cpp b/Source/Core/DiscIO/RiivolutionPatcher.cpp index 9362a3930a..175ee18f17 100644 --- a/Source/Core/DiscIO/RiivolutionPatcher.cpp +++ b/Source/Core/DiscIO/RiivolutionPatcher.cpp @@ -14,6 +14,7 @@ #include "Common/FileUtil.h" #include "Common/IOFile.h" #include "Common/StringUtil.h" +#include "Core/Config/AchievementSettings.h" #include "Core/HLE/HLE.h" #include "Core/HW/Memmap.h" #include "Core/IOS/FS/FileSystem.h" @@ -522,6 +523,11 @@ static bool MemoryMatchesAt(const Core::CPUThreadGuard& guard, u32 offset, static void ApplyMemoryPatch(const Core::CPUThreadGuard& guard, u32 offset, const std::vector& value, const std::vector& original) { +#ifdef USE_RETRO_ACHIEVEMENTS + if (::Config::Get(::Config::RA_HARDCORE_ENABLED)) + return; +#endif // USE_RETRO_ACHIEVEMENTS + if (value.empty()) return; diff --git a/Source/Core/DolphinQt/Config/PatchesWidget.cpp b/Source/Core/DolphinQt/Config/PatchesWidget.cpp index e1fd12f913..0aa216ad82 100644 --- a/Source/Core/DolphinQt/Config/PatchesWidget.cpp +++ b/Source/Core/DolphinQt/Config/PatchesWidget.cpp @@ -14,6 +14,7 @@ #include "Core/ConfigManager.h" #include "Core/PatchEngine.h" +#include "DolphinQt/Config/HardcoreWarningWidget.h" #include "DolphinQt/Config/NewPatchDialog.h" #include "DolphinQt/QtUtils/SetWindowDecorations.h" @@ -40,23 +41,38 @@ PatchesWidget::PatchesWidget(const UICommon::GameFile& game) void PatchesWidget::CreateWidgets() { +#ifdef USE_RETRO_ACHIEVEMENTS + m_hc_warning = new HardcoreWarningWidget(this); +#endif // USE_RETRO_ACHIEVEMENTS m_list = new QListWidget; m_add_button = new QPushButton(tr("&Add...")); m_edit_button = new QPushButton(); m_remove_button = new QPushButton(tr("&Remove")); - auto* layout = new QGridLayout; + auto* grid_layout = new QGridLayout; - layout->addWidget(m_list, 0, 0, 1, -1); - layout->addWidget(m_add_button, 1, 0); - layout->addWidget(m_edit_button, 1, 2); - layout->addWidget(m_remove_button, 1, 1); + grid_layout->addWidget(m_list, 0, 0, 1, -1); + grid_layout->addWidget(m_add_button, 1, 0); + grid_layout->addWidget(m_edit_button, 1, 2); + grid_layout->addWidget(m_remove_button, 1, 1); + + auto* layout = new QVBoxLayout; + +#ifdef USE_RETRO_ACHIEVEMENTS + layout->addWidget(m_hc_warning); +#endif // USE_RETRO_ACHIEVEMENTS + layout->addLayout(grid_layout); setLayout(layout); } void PatchesWidget::ConnectWidgets() { +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this, + &PatchesWidget::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS + connect(m_list, &QListWidget::itemSelectionChanged, this, &PatchesWidget::UpdateActions); connect(m_list, &QListWidget::itemChanged, this, &PatchesWidget::OnItemChanged); connect(m_remove_button, &QPushButton::clicked, this, &PatchesWidget::OnRemove); diff --git a/Source/Core/DolphinQt/Config/PatchesWidget.h b/Source/Core/DolphinQt/Config/PatchesWidget.h index bb84519bbb..9c324ce49a 100644 --- a/Source/Core/DolphinQt/Config/PatchesWidget.h +++ b/Source/Core/DolphinQt/Config/PatchesWidget.h @@ -9,12 +9,11 @@ #include #include "Common/CommonTypes.h" +#include "Core/PatchEngine.h" -namespace PatchEngine -{ -struct Patch; -} - +#ifdef USE_RETRO_ACHIEVEMENTS +class HardcoreWarningWidget; +#endif // USE_RETRO_ACHIEVEMENTS class QListWidget; class QListWidgetItem; class QPushButton; @@ -26,9 +25,15 @@ class GameFile; class PatchesWidget : public QWidget { + Q_OBJECT public: explicit PatchesWidget(const UICommon::GameFile& game); +#ifdef USE_RETRO_ACHIEVEMENTS +signals: + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS + private: void CreateWidgets(); void ConnectWidgets(); @@ -41,6 +46,9 @@ private: void OnRemove(); void OnEdit(); +#ifdef USE_RETRO_ACHIEVEMENTS + HardcoreWarningWidget* m_hc_warning; +#endif // USE_RETRO_ACHIEVEMENTS QListWidget* m_list; QPushButton* m_add_button; QPushButton* m_edit_button; diff --git a/Source/Core/DolphinQt/Config/PropertiesDialog.cpp b/Source/Core/DolphinQt/Config/PropertiesDialog.cpp index b72e950862..834c5d68cf 100644 --- a/Source/Core/DolphinQt/Config/PropertiesDialog.cpp +++ b/Source/Core/DolphinQt/Config/PropertiesDialog.cpp @@ -51,6 +51,10 @@ PropertiesDialog::PropertiesDialog(QWidget* parent, const UICommon::GameFile& ga &PropertiesDialog::OpenGeneralSettings); connect(ar, &ARCodeWidget::OpenGeneralSettings, this, &PropertiesDialog::OpenGeneralSettings); +#ifdef USE_RETRO_ACHIEVEMENTS + connect(patches, &PatchesWidget::OpenAchievementSettings, this, + &PropertiesDialog::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS connect(graphics_mod_list, &GraphicsModListWidget::OpenGraphicsSettings, this, &PropertiesDialog::OpenGraphicsSettings); diff --git a/Source/Core/DolphinQt/Config/PropertiesDialog.h b/Source/Core/DolphinQt/Config/PropertiesDialog.h index 2135be8948..29d282a6e8 100644 --- a/Source/Core/DolphinQt/Config/PropertiesDialog.h +++ b/Source/Core/DolphinQt/Config/PropertiesDialog.h @@ -19,4 +19,7 @@ public: signals: void OpenGeneralSettings(); void OpenGraphicsSettings(); +#ifdef USE_RETRO_ACHIEVEMENTS + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS }; diff --git a/Source/Core/DolphinQt/GameList/GameList.cpp b/Source/Core/DolphinQt/GameList/GameList.cpp index 242466af35..1b621222b2 100644 --- a/Source/Core/DolphinQt/GameList/GameList.cpp +++ b/Source/Core/DolphinQt/GameList/GameList.cpp @@ -552,6 +552,10 @@ void GameList::OpenProperties() connect(properties, &PropertiesDialog::OpenGeneralSettings, this, &GameList::OpenGeneralSettings); connect(properties, &PropertiesDialog::OpenGraphicsSettings, this, &GameList::OpenGraphicsSettings); +#ifdef USE_RETRO_ACHIEVEMENTS + connect(properties, &PropertiesDialog::OpenAchievementSettings, this, + &GameList::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS SetQWidgetWindowDecorations(properties); properties->show(); diff --git a/Source/Core/DolphinQt/GameList/GameList.h b/Source/Core/DolphinQt/GameList/GameList.h index ebe2ec7152..54ca50ab15 100644 --- a/Source/Core/DolphinQt/GameList/GameList.h +++ b/Source/Core/DolphinQt/GameList/GameList.h @@ -56,6 +56,9 @@ signals: void SelectionChanged(std::shared_ptr game_file); void OpenGeneralSettings(); void OpenGraphicsSettings(); +#ifdef USE_RETRO_ACHIEVEMENTS + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS private: void ShowHeaderContextMenu(const QPoint& pos); diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 6cf6ac57bd..e3b96c6390 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -246,6 +246,11 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters, connect(m_cheats_manager, &CheatsManager::OpenGeneralSettings, this, &MainWindow::ShowGeneralWindow); +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_game_list, &GameList::OpenAchievementSettings, this, + &MainWindow::ShowAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS + InitCoreCallbacks(); NetPlayInit(); diff --git a/Source/Core/DolphinQt/RiivolutionBootWidget.cpp b/Source/Core/DolphinQt/RiivolutionBootWidget.cpp index 178fef2367..29b5af0a1f 100644 --- a/Source/Core/DolphinQt/RiivolutionBootWidget.cpp +++ b/Source/Core/DolphinQt/RiivolutionBootWidget.cpp @@ -26,6 +26,7 @@ #include "DiscIO/GameModDescriptor.h" #include "DiscIO/RiivolutionParser.h" #include "DiscIO/RiivolutionPatcher.h" +#include "DolphinQt/Config/HardcoreWarningWidget.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" struct GuiRiivolutionPatchIndex @@ -48,6 +49,7 @@ RiivolutionBootWidget::RiivolutionBootWidget(std::string game_id, std::optional< setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); CreateWidgets(); + ConnectWidgets(); LoadMatchingXMLs(); resize(QSize(400, 600)); @@ -57,6 +59,9 @@ RiivolutionBootWidget::~RiivolutionBootWidget() = default; void RiivolutionBootWidget::CreateWidgets() { +#ifdef USE_RETRO_ACHIEVEMENTS + m_hc_warning = new HardcoreWarningWidget(this); +#endif // USE_RETRO_ACHIEVEMENTS auto* open_xml_button = new QPushButton(tr("Open Riivolution XML...")); auto* boot_game_button = new QPushButton(tr("Start")); boot_game_button->setDefault(true); @@ -79,6 +84,9 @@ void RiivolutionBootWidget::CreateWidgets() button_layout->addWidget(boot_game_button, 0, Qt::AlignRight); auto* layout = new QVBoxLayout(); +#ifdef USE_RETRO_ACHIEVEMENTS + layout->addWidget(m_hc_warning); +#endif // USE_RETRO_ACHIEVEMENTS layout->addWidget(scroll_area); layout->addLayout(button_layout); setLayout(layout); @@ -88,6 +96,16 @@ void RiivolutionBootWidget::CreateWidgets() connect(save_preset_button, &QPushButton::clicked, this, &RiivolutionBootWidget::SaveAsPreset); } +void RiivolutionBootWidget::ConnectWidgets() +{ +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this, + &RiivolutionBootWidget::OpenAchievementSettings); + connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this, + &RiivolutionBootWidget::reject); +#endif // USE_RETRO_ACHIEVEMENTS +} + void RiivolutionBootWidget::LoadMatchingXMLs() { const std::string& riivolution_dir = File::GetUserPath(D_RIIVOLUTION_IDX); diff --git a/Source/Core/DolphinQt/RiivolutionBootWidget.h b/Source/Core/DolphinQt/RiivolutionBootWidget.h index 1318241a11..2455001928 100644 --- a/Source/Core/DolphinQt/RiivolutionBootWidget.h +++ b/Source/Core/DolphinQt/RiivolutionBootWidget.h @@ -11,6 +11,9 @@ #include "Common/CommonTypes.h" #include "DiscIO/RiivolutionParser.h" +#ifdef USE_RETRO_ACHIEVEMENTS +class HardcoreWarningWidget; +#endif // USE_RETRO_ACHIEVEMENTS class QPushButton; class QVBoxLayout; @@ -26,8 +29,14 @@ public: bool ShouldBoot() const { return m_should_boot; } std::vector& GetPatches() { return m_patches; } +#ifdef USE_RETRO_ACHIEVEMENTS +signals: + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS + private: void CreateWidgets(); + void ConnectWidgets(); void LoadMatchingXMLs(); void OpenXML(); @@ -38,6 +47,9 @@ private: void BootGame(); void SaveAsPreset(); +#ifdef USE_RETRO_ACHIEVEMENTS + HardcoreWarningWidget* m_hc_warning; +#endif // USE_RETRO_ACHIEVEMENTS std::string m_game_id; std::optional m_revision; std::optional m_disc_number; From 0abfa94bc83b99bfe02b9f310c6cd3ddcb7e11ec Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 22:14:54 -0400 Subject: [PATCH 08/11] Disable Freelook in hardcore mode The player getting a better view of their surroundings than the game would normally allow could possibly give the player an advantage over the original hardware, so Freelook is disabled in hardcore mode. To do this, I disable the config flag for Freelook when it is accessed, to make sure that it is disabled whether it was enabled before or after hardcore mode was enabled. --- Source/Core/Core/FreeLookConfig.cpp | 7 +++++++ Source/Core/DolphinQt/Config/FreeLookWidget.cpp | 10 ++++++++++ Source/Core/DolphinQt/Config/FreeLookWindow.cpp | 17 +++++++++++++++++ Source/Core/DolphinQt/Config/FreeLookWindow.h | 12 ++++++++++++ Source/Core/DolphinQt/HotkeyScheduler.cpp | 10 ++++++++++ Source/Core/DolphinQt/MainWindow.cpp | 5 +++++ 6 files changed, 61 insertions(+) diff --git a/Source/Core/Core/FreeLookConfig.cpp b/Source/Core/Core/FreeLookConfig.cpp index 31a673ce85..c0c58ce2c1 100644 --- a/Source/Core/Core/FreeLookConfig.cpp +++ b/Source/Core/Core/FreeLookConfig.cpp @@ -3,7 +3,9 @@ #include "Core/FreeLookConfig.h" +#include "Core/AchievementManager.h" #include "Core/CPUThreadConfigCallback.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/FreeLookSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -44,6 +46,11 @@ void Config::Refresh() } camera_config.control_type = ::Config::Get(::Config::FL1_CONTROL_TYPE); +#ifdef USE_RETRO_ACHIEVEMENTS + enabled = ::Config::Get(::Config::FREE_LOOK_ENABLED) && + !AchievementManager::GetInstance()->IsHardcoreModeActive(); +#else // USE_RETRO_ACHIEVEMENTS enabled = ::Config::Get(::Config::FREE_LOOK_ENABLED); +#endif // USE_RETRO_ACHIEVEMENTS } } // namespace FreeLook diff --git a/Source/Core/DolphinQt/Config/FreeLookWidget.cpp b/Source/Core/DolphinQt/Config/FreeLookWidget.cpp index 5fe1ecd66d..430dce883d 100644 --- a/Source/Core/DolphinQt/Config/FreeLookWidget.cpp +++ b/Source/Core/DolphinQt/Config/FreeLookWidget.cpp @@ -9,6 +9,8 @@ #include #include +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/FreeLookSettings.h" #include "Core/ConfigManager.h" #include "Core/Core.h" @@ -36,6 +38,10 @@ void FreeLookWidget::CreateLayout() m_enable_freelook->SetDescription( tr("Allows manipulation of the in-game camera.

If unsure, " "leave this unchecked.")); +#ifdef USE_RETRO_ACHIEVEMENTS + bool hardcore = AchievementManager::GetInstance()->IsHardcoreModeActive(); + m_enable_freelook->setEnabled(!hardcore); +#endif // USE_RETRO_ACHIEVEMENTS m_freelook_controller_configure_button = new NonDefaultQPushButton(tr("Configure Controller")); m_freelook_control_type = new ConfigChoice({tr("Six Axis"), tr("First Person"), tr("Orbital")}, @@ -106,6 +112,10 @@ void FreeLookWidget::LoadSettings() { const bool checked = Config::Get(Config::FREE_LOOK_ENABLED); m_enable_freelook->setChecked(checked); +#ifdef USE_RETRO_ACHIEVEMENTS + bool hardcore = AchievementManager::GetInstance()->IsHardcoreModeActive(); + m_enable_freelook->setEnabled(!hardcore); +#endif // USE_RETRO_ACHIEVEMENTS m_freelook_control_type->setEnabled(checked); m_freelook_controller_configure_button->setEnabled(checked); m_freelook_background_input->setEnabled(checked); diff --git a/Source/Core/DolphinQt/Config/FreeLookWindow.cpp b/Source/Core/DolphinQt/Config/FreeLookWindow.cpp index 86b78ae39c..d2c57be8a6 100644 --- a/Source/Core/DolphinQt/Config/FreeLookWindow.cpp +++ b/Source/Core/DolphinQt/Config/FreeLookWindow.cpp @@ -9,10 +9,12 @@ #include #include "DolphinQt/Config/FreeLookWidget.h" +#include "DolphinQt/Config/HardcoreWarningWidget.h" FreeLookWindow::FreeLookWindow(QWidget* parent) : QDialog(parent) { CreateMainLayout(); + ConnectWidgets(); setWindowTitle(tr("Free Look Settings")); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -20,11 +22,26 @@ FreeLookWindow::FreeLookWindow(QWidget* parent) : QDialog(parent) void FreeLookWindow::CreateMainLayout() { +#ifdef USE_RETRO_ACHIEVEMENTS + m_hc_warning = new HardcoreWarningWidget(this); +#endif // USE_RETRO_ACHIEVEMENTS m_button_box = new QDialogButtonBox(QDialogButtonBox::Close); connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject); auto* main_layout = new QVBoxLayout(); + +#ifdef USE_RETRO_ACHIEVEMENTS + main_layout->addWidget(m_hc_warning); +#endif // USE_RETRO_ACHIEVEMENTS main_layout->addWidget(new FreeLookWidget(this)); main_layout->addWidget(m_button_box); setLayout(main_layout); } + +void FreeLookWindow::ConnectWidgets() +{ +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this, + &FreeLookWindow::OpenAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS +} diff --git a/Source/Core/DolphinQt/Config/FreeLookWindow.h b/Source/Core/DolphinQt/Config/FreeLookWindow.h index 3a7b6c17fd..0ffd4472ee 100644 --- a/Source/Core/DolphinQt/Config/FreeLookWindow.h +++ b/Source/Core/DolphinQt/Config/FreeLookWindow.h @@ -5,6 +5,9 @@ #include +#ifdef USE_RETRO_ACHIEVEMENTS +class HardcoreWarningWidget; +#endif // USE_RETRO_ACHIEVEMENTS class QDialogButtonBox; class FreeLookWindow final : public QDialog @@ -13,8 +16,17 @@ class FreeLookWindow final : public QDialog public: explicit FreeLookWindow(QWidget* parent); +#ifdef USE_RETRO_ACHIEVEMENTS +signals: + void OpenAchievementSettings(); +#endif // USE_RETRO_ACHIEVEMENTS + private: void CreateMainLayout(); + void ConnectWidgets(); +#ifdef USE_RETRO_ACHIEVEMENTS + HardcoreWarningWidget* m_hc_warning; +#endif // USE_RETRO_ACHIEVEMENTS QDialogButtonBox* m_button_box; }; diff --git a/Source/Core/DolphinQt/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index b527e96c6c..6ccd09b0f5 100644 --- a/Source/Core/DolphinQt/HotkeyScheduler.cpp +++ b/Source/Core/DolphinQt/HotkeyScheduler.cpp @@ -17,6 +17,8 @@ #include "Common/Config/Config.h" #include "Common/Thread.h" +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/FreeLookSettings.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" @@ -579,7 +581,15 @@ void HotkeyScheduler::Run() { const bool new_value = !Config::Get(Config::FREE_LOOK_ENABLED); Config::SetCurrent(Config::FREE_LOOK_ENABLED, new_value); +#ifdef USE_RETRO_ACHIEVEMENTS + bool hardcore = AchievementManager::GetInstance()->IsHardcoreModeActive(); + if (hardcore) + OSD::AddMessage("Free Look is Disabled in Hardcore Mode"); + else + OSD::AddMessage(fmt::format("Free Look: {}", new_value ? "Enabled" : "Disabled")); +#else // USE_RETRO_ACHIEVEMENTS OSD::AddMessage(fmt::format("Free Look: {}", new_value ? "Enabled" : "Disabled")); +#endif // USE_RETRO_ACHIEVEMENTS } // Savestates diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index e3b96c6390..881e28549c 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1244,6 +1244,11 @@ void MainWindow::ShowFreeLookWindow() { m_freelook_window = new FreeLookWindow(this); InstallHotkeyFilter(m_freelook_window); + +#ifdef USE_RETRO_ACHIEVEMENTS + connect(m_freelook_window, &FreeLookWindow::OpenAchievementSettings, this, + &MainWindow::ShowAchievementSettings); +#endif // USE_RETRO_ACHIEVEMENTS } SetQWidgetWindowDecorations(m_freelook_window); From 3aebbbb3e74f24b6da7537052f8b78c6b600eefa Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 21:53:38 -0400 Subject: [PATCH 09/11] Disable cheats in hardcore mode RetroAchievements does not allow cheats such as Action Replay or Gecko in hardcore mode, for fairness. --- Source/Core/Core/ActionReplay.cpp | 8 ++++---- Source/Core/Core/CheatSearch.cpp | 13 +++++++++++++ Source/Core/Core/CheatSearch.h | 5 +++++ Source/Core/Core/Config/MainSettings.cpp | 10 ++++++++++ Source/Core/Core/Config/MainSettings.h | 1 + Source/Core/Core/GeckoCode.cpp | 6 +++--- Source/Core/Core/HLE/HLE.cpp | 2 +- Source/Core/Core/NetPlayServer.cpp | 2 +- Source/Core/DolphinQt/CheatsManager.cpp | 6 ++++++ Source/Core/DolphinQt/CheatsManager.h | 3 +++ Source/Core/DolphinQt/Config/ARCodeWidget.cpp | 11 +++++++++++ Source/Core/DolphinQt/Config/ARCodeWidget.h | 9 +++++++++ Source/Core/DolphinQt/Config/GeckoCodeWidget.cpp | 11 +++++++++++ Source/Core/DolphinQt/Config/GeckoCodeWidget.h | 9 +++++++++ Source/Core/DolphinQt/Config/PropertiesDialog.cpp | 4 ++++ Source/Core/DolphinQt/MainWindow.cpp | 8 ++++++++ Source/Core/DolphinQt/Settings/GeneralPane.cpp | 6 ++++++ 17 files changed, 105 insertions(+), 9 deletions(-) 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); From 6f7e02e2012fa889fb5f8e7a20e58c8538cc1a05 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Thu, 20 Jul 2023 17:55:25 -0400 Subject: [PATCH 10/11] Disable TAS recording playback in hardcore mode Play Input Recording would potentially unlock achievements without any player input and needs to be disabled. If a recording is already playing, hardcore mode cannot be enabled. --- Source/Core/Core/Movie.cpp | 13 +++++++++++++ Source/Core/DolphinQt/MenuBar.cpp | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 5b66b707ea..f8b202ab48 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -34,6 +34,7 @@ #include "Common/Version.h" #include "Core/Boot/Boot.h" +#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/SYSCONFSettings.h" #include "Core/Config/WiimoteSettings.h" @@ -974,6 +975,12 @@ bool PlayInput(const std::string& movie_path, std::optional* savest } ReadHeader(); + +#ifdef USE_RETRO_ACHIEVEMENTS + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + return false; +#endif // USE_RETRO_ACHIEVEMENTS + s_totalFrames = tmpHeader.frameCount; s_totalLagCount = tmpHeader.lagCount; s_totalInputCount = tmpHeader.inputCount; @@ -1010,6 +1017,12 @@ bool PlayInput(const std::string& movie_path, std::optional* savest } s_bRecordingFromSaveState = true; + +#ifdef USE_RETRO_ACHIEVEMENTS + // On the chance someone tries to re-enable before the TAS can start + Config::SetBase(Config::RA_HARDCORE_ENABLED, false); +#endif // USE_RETRO_ACHIEVEMENTS + Movie::LoadInput(movie_path); } diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 0a0b52e1fc..9b400e7c2a 100644 --- a/Source/Core/DolphinQt/MenuBar.cpp +++ b/Source/Core/DolphinQt/MenuBar.cpp @@ -141,6 +141,11 @@ void MenuBar::OnEmulationStateChanged(Core::State state) m_recording_export->setEnabled(false); } m_recording_play->setEnabled(m_game_selected && !running); +#ifdef USE_RETRO_ACHIEVEMENTS + m_recording_play->setEnabled(m_game_selected && !running && !hardcore); +#else // USE_RETRO_ACHIEVEMENTS + m_recording_play->setEnabled(m_game_selected && !running); +#endif // USE_RETRO_ACHIEVEMENTS m_recording_start->setEnabled((m_game_selected || running) && !Movie::IsPlayingInput()); // JIT From 2cb14edafa4dfcb6c6502142fff736a436186a9f Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 7 Jun 2023 22:23:10 -0400 Subject: [PATCH 11/11] Add Hardcore switch to Achievement Settings dialog This adds the actual switch to turn on Hardcore Mode to the settings tab of the Achievements dialog. It is accompanied by a large tooltip warning explaining what it does and when it can be enabled. The switch is only enabled to be turned on when no game is running, so that games are started in hardcore mode and can only be loaded via the console's memory card, as in the original hardware. Hardcore may be turned off while a game is running, but cannot be turned back on until the game is disabled. The toggle trigger for hardcore mode also automatically disables the settings that are not allowed during hardcore mode. Finally, the original flag in AchievementSettingsWidget to set whether things are enabled in hardcore mode (primarily Leaderboards) is replaced with the actual Hardcore Mode setting. --- .../AchievementSettingsWidget.cpp | 61 ++++++++++++++++--- .../Achievements/AchievementSettingsWidget.h | 7 +-- .../Achievements/AchievementsWindow.cpp | 10 +-- .../Achievements/AchievementsWindow.h | 2 + 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp index dbfb13f7a6..fb843d7ea0 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp @@ -13,10 +13,11 @@ #include "Core/AchievementManager.h" #include "Core/Config/AchievementSettings.h" +#include "Core/Config/FreeLookSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Core.h" +#include "Core/Movie.h" -#include "DolphinQt/Achievements/AchievementsWindow.h" #include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h" #include "DolphinQt/Config/ToolTipControls/ToolTipCheckBox.h" #include "DolphinQt/QtUtils/ModalMessageBox.h" @@ -24,11 +25,7 @@ #include "DolphinQt/QtUtils/SignalBlocking.h" #include "DolphinQt/Settings.h" -static constexpr bool hardcore_mode_enabled = false; - -AchievementSettingsWidget::AchievementSettingsWidget(QWidget* parent, - AchievementsWindow* parent_window) - : QWidget(parent), parent_window(parent_window) +AchievementSettingsWidget::AchievementSettingsWidget(QWidget* parent) : QWidget(parent) { CreateLayout(); LoadSettings(); @@ -36,6 +33,15 @@ AchievementSettingsWidget::AchievementSettingsWidget(QWidget* parent, connect(&Settings::Instance(), &Settings::ConfigChanged, this, &AchievementSettingsWidget::LoadSettings); + + // If hardcore is enabled when the emulator starts, make sure it turns off what it needs to + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + ToggleHardcore(); +} + +void AchievementSettingsWidget::UpdateData() +{ + LoadSettings(); } void AchievementSettingsWidget::CreateLayout() @@ -75,6 +81,20 @@ void AchievementSettingsWidget::CreateLayout() "achievements.

Unofficial achievements may be optional or unfinished achievements " "that have not been deemed official by RetroAchievements and may be useful for testing or " "simply for fun.")); + m_common_hardcore_enabled_input = new ToolTipCheckBox(tr("Enable Hardcore Mode")); + m_common_hardcore_enabled_input->SetDescription( + tr("Enable Hardcore Mode on RetroAchievements.

Hardcore Mode is intended to provide " + "an experience as close to gaming on the original hardware as possible. RetroAchievements " + "rankings are primarily oriented towards Hardcore points (Softcore points are tracked but " + "not as heavily emphasized) and leaderboards require Hardcore Mode to be on.

To " + "ensure this experience, the following features will be disabled, as they give emulator " + "players an advantage over console players:
- Loading states
-- Saving states is " + "allowed
- Emulator speeds below 100%
-- Frame advance is disabled
-- Turbo is " + "allowed
- Cheats
- Memory patches
-- File patches are allowed
- Debug " + "UI
- Freelook

This cannot be turned on while a game is " + "playing.
Close your current game before enabling.
Be aware that " + "turning Hardcore Mode off while a game is running requires the game to be closed before " + "re-enabling.")); m_common_progress_enabled_input = new ToolTipCheckBox(tr("Enable Progress Notifications")); m_common_progress_enabled_input->SetDescription( tr("Enable progress notifications on achievements.

Displays a brief popup message " @@ -102,6 +122,7 @@ void AchievementSettingsWidget::CreateLayout() m_common_layout->addWidget(m_common_achievements_enabled_input); m_common_layout->addWidget(m_common_leaderboards_enabled_input); m_common_layout->addWidget(m_common_rich_presence_enabled_input); + m_common_layout->addWidget(m_common_hardcore_enabled_input); m_common_layout->addWidget(m_common_progress_enabled_input); m_common_layout->addWidget(m_common_badges_enabled_input); m_common_layout->addWidget(m_common_unofficial_enabled_input); @@ -123,6 +144,8 @@ void AchievementSettingsWidget::ConnectWidgets() &AchievementSettingsWidget::ToggleLeaderboards); connect(m_common_rich_presence_enabled_input, &QCheckBox::toggled, this, &AchievementSettingsWidget::ToggleRichPresence); + connect(m_common_hardcore_enabled_input, &QCheckBox::toggled, this, + &AchievementSettingsWidget::ToggleHardcore); connect(m_common_progress_enabled_input, &QCheckBox::toggled, this, &AchievementSettingsWidget::ToggleProgress); connect(m_common_badges_enabled_input, &QCheckBox::toggled, this, @@ -145,6 +168,7 @@ void AchievementSettingsWidget::LoadSettings() { bool enabled = Config::Get(Config::RA_ENABLED); bool achievements_enabled = Config::Get(Config::RA_ACHIEVEMENTS_ENABLED); + bool hardcore_enabled = Config::Get(Config::RA_HARDCORE_ENABLED); bool logged_out = Config::Get(Config::RA_API_TOKEN).empty(); std::string username = Config::Get(Config::RA_USERNAME); @@ -167,12 +191,19 @@ void AchievementSettingsWidget::LoadSettings() SignalBlocking(m_common_leaderboards_enabled_input) ->setChecked(Config::Get(Config::RA_LEADERBOARDS_ENABLED)); - SignalBlocking(m_common_leaderboards_enabled_input)->setEnabled(enabled && hardcore_mode_enabled); + SignalBlocking(m_common_leaderboards_enabled_input)->setEnabled(enabled && hardcore_enabled); SignalBlocking(m_common_rich_presence_enabled_input) ->setChecked(Config::Get(Config::RA_RICH_PRESENCE_ENABLED)); SignalBlocking(m_common_rich_presence_enabled_input)->setEnabled(enabled); + SignalBlocking(m_common_hardcore_enabled_input) + ->setChecked(Config::Get(Config::RA_HARDCORE_ENABLED)); + SignalBlocking(m_common_hardcore_enabled_input) + ->setEnabled(enabled && + (hardcore_enabled || + (Core::GetState() == Core::State::Uninitialized && !Movie::IsPlayingInput()))); + SignalBlocking(m_common_progress_enabled_input) ->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED)); SignalBlocking(m_common_progress_enabled_input)->setEnabled(enabled && achievements_enabled); @@ -199,6 +230,8 @@ void AchievementSettingsWidget::SaveSettings() m_common_leaderboards_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_RICH_PRESENCE_ENABLED, m_common_rich_presence_enabled_input->isChecked()); + Config::SetBaseOrCurrent(Config::RA_HARDCORE_ENABLED, + m_common_hardcore_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_PROGRESS_ENABLED, m_common_unofficial_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_enabled_input->isChecked()); @@ -250,6 +283,20 @@ void AchievementSettingsWidget::ToggleRichPresence() AchievementManager::GetInstance()->ActivateDeactivateRichPresence(); } +void AchievementSettingsWidget::ToggleHardcore() +{ + SaveSettings(); + if (Config::Get(Config::RA_HARDCORE_ENABLED)) + { + if (Config::Get(Config::MAIN_EMULATION_SPEED) < 1.0f) + Config::SetBaseOrCurrent(Config::MAIN_EMULATION_SPEED, 1.0f); + Config::SetBaseOrCurrent(Config::FREE_LOOK_ENABLED, false); + Settings::Instance().SetCheatsEnabled(false); + Settings::Instance().SetDebugModeEnabled(false); + } + emit Settings::Instance().EmulationStateChanged(Core::GetState()); +} + void AchievementSettingsWidget::ToggleProgress() { SaveSettings(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h index edf22b7350..eb3f237389 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h @@ -6,7 +6,6 @@ #ifdef USE_RETRO_ACHIEVEMENTS #include -class AchievementsWindow; class QGroupBox; class QVBoxLayout; class QLabel; @@ -18,7 +17,8 @@ class AchievementSettingsWidget final : public QWidget { Q_OBJECT public: - explicit AchievementSettingsWidget(QWidget* parent, AchievementsWindow* parent_window); + explicit AchievementSettingsWidget(QWidget* parent); + void UpdateData(); private: void OnControllerInterfaceConfigure(); @@ -41,8 +41,6 @@ private: void ToggleUnofficial(); void ToggleEncore(); - AchievementsWindow* parent_window; - QGroupBox* m_common_box; QVBoxLayout* m_common_layout; ToolTipCheckBox* m_common_integration_enabled_input; @@ -56,6 +54,7 @@ private: ToolTipCheckBox* m_common_achievements_enabled_input; ToolTipCheckBox* m_common_leaderboards_enabled_input; ToolTipCheckBox* m_common_rich_presence_enabled_input; + ToolTipCheckBox* m_common_hardcore_enabled_input; ToolTipCheckBox* m_common_progress_enabled_input; ToolTipCheckBox* m_common_badges_enabled_input; ToolTipCheckBox* m_common_unofficial_enabled_input; diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index 4a278c3649..6665fdd871 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -16,6 +16,7 @@ #include "DolphinQt/Achievements/AchievementSettingsWidget.h" #include "DolphinQt/QtUtils/QueueOnObject.h" #include "DolphinQt/QtUtils/WrapInScrollArea.h" +#include "DolphinQt/Settings.h" AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent) { @@ -26,6 +27,8 @@ AchievementsWindow::AchievementsWindow(QWidget* parent) : QDialog(parent) ConnectWidgets(); AchievementManager::GetInstance()->SetUpdateCallback( [this] { QueueOnObject(this, &AchievementsWindow::UpdateData); }); + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, + &AchievementsWindow::UpdateData); UpdateData(); } @@ -42,11 +45,10 @@ void AchievementsWindow::CreateMainLayout() m_header_widget = new AchievementHeaderWidget(this); m_tab_widget = new QTabWidget(); + m_settings_widget = new AchievementSettingsWidget(m_tab_widget); m_progress_widget = new AchievementProgressWidget(m_tab_widget); m_leaderboard_widget = new AchievementLeaderboardWidget(m_tab_widget); - m_tab_widget->addTab( - GetWrappedWidget(new AchievementSettingsWidget(m_tab_widget, this), this, 125, 100), - tr("Settings")); + m_tab_widget->addTab(GetWrappedWidget(m_settings_widget, this, 125, 100), tr("Settings")); m_tab_widget->addTab(GetWrappedWidget(m_progress_widget, this, 125, 100), tr("Progress")); m_tab_widget->setTabVisible(1, AchievementManager::GetInstance()->IsGameLoaded()); m_tab_widget->addTab(GetWrappedWidget(m_leaderboard_widget, this, 125, 100), tr("Leaderboards")); @@ -72,7 +74,7 @@ void AchievementsWindow::UpdateData() std::lock_guard lg{*AchievementManager::GetInstance()->GetLock()}; m_header_widget->UpdateData(); m_header_widget->setVisible(AchievementManager::GetInstance()->IsLoggedIn()); - // Settings tab handles its own updates ... indeed, that calls this + m_settings_widget->UpdateData(); m_progress_widget->UpdateData(); m_tab_widget->setTabVisible(1, AchievementManager::GetInstance()->IsGameLoaded()); m_leaderboard_widget->UpdateData(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h index 381a0aafb5..4559159a64 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.h +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.h @@ -11,6 +11,7 @@ class AchievementHeaderWidget; class AchievementLeaderboardWidget; +class AchievementSettingsWidget; class AchievementProgressWidget; class QDialogButtonBox; class QTabWidget; @@ -31,6 +32,7 @@ private: AchievementHeaderWidget* m_header_widget; QTabWidget* m_tab_widget; + AchievementSettingsWidget* m_settings_widget; AchievementProgressWidget* m_progress_widget; AchievementLeaderboardWidget* m_leaderboard_widget; QDialogButtonBox* m_button_box;