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/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/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 diff --git a/Source/Core/Core/Config/MainSettings.cpp b/Source/Core/Core/Config/MainSettings.cpp index 4a7470ada8..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" @@ -738,4 +739,24 @@ 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 + 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..5994a9bfd1 100644 --- a/Source/Core/Core/Config/MainSettings.h +++ b/Source/Core/Core/Config/MainSettings.h @@ -378,4 +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/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/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); } 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/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/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 2d4f3313f2..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(); @@ -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/Movie.cpp b/Source/Core/Core/Movie.cpp index 6d9f3b4c8d..fb96379748 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/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/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/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/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/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/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 8d01663c87..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(); @@ -81,4 +83,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..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; @@ -22,6 +23,7 @@ class AchievementsWindow : public QDialog public: explicit AchievementsWindow(QWidget* parent); void UpdateData(); + void ForceSettingsTab(); private: void CreateMainLayout(); @@ -30,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; 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/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/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/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/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/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..86be3e8c3c 100644 --- a/Source/Core/DolphinQt/Config/PropertiesDialog.cpp +++ b/Source/Core/DolphinQt/Config/PropertiesDialog.cpp @@ -51,6 +51,14 @@ PropertiesDialog::PropertiesDialog(QWidget* parent, const UICommon::GameFile& ga &PropertiesDialog::OpenGeneralSettings); 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 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/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/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/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/HotkeyScheduler.cpp b/Source/Core/DolphinQt/HotkeyScheduler.cpp index 05b38a367f..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" @@ -257,7 +259,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(); } @@ -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 d9eda82bb1..bf7e7e776f 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -246,6 +246,13 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters, connect(m_cheats_manager, &CheatsManager::OpenGeneralSettings, this, &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 + InitCoreCallbacks(); NetPlayInit(); @@ -1239,6 +1246,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); @@ -1971,6 +1983,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() @@ -2011,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/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(); diff --git a/Source/Core/DolphinQt/MenuBar.cpp b/Source/Core/DolphinQt/MenuBar.cpp index 2b68cf640d..9b400e7c2a 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" @@ -120,11 +121,18 @@ 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_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); + 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 m_recording_read_only->setEnabled(running); if (!running) @@ -133,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 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; 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/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); 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;