diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 1126411228..e5a6d6c32c 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -24,6 +24,7 @@ #include "Common/ScopeGuard.h" #include "Common/Version.h" #include "Common/WorkQueueThread.h" +#include "Core/ActionReplay.h" #include "Core/Config/AchievementSettings.h" #include "Core/Config/FreeLookSettings.h" #include "Core/Config/MainSettings.h" @@ -474,6 +475,18 @@ Common::SHA1::Digest AchievementManager::GetCodeHash(const Gecko::GeckoCode& cod return context->Finish(); } +Common::SHA1::Digest AchievementManager::GetCodeHash(const ActionReplay::ARCode& code) const +{ + auto context = Common::SHA1::CreateContext(); + context->Update(Common::BitCastToArray(static_cast(code.ops.size()))); + for (const auto& entry : code.ops) + { + context->Update(Common::BitCastToArray(entry.cmd_addr)); + context->Update(Common::BitCastToArray(entry.value)); + } + return context->Finish(); +} + void AchievementManager::FilterApprovedPatches(std::vector& patches, const std::string& game_ini_id) const { @@ -486,12 +499,24 @@ void AchievementManager::FilterApprovedGeckoCodes(std::vector& FilterApprovedIni(codes, game_ini_id); } +void AchievementManager::FilterApprovedARCodes(std::vector& codes, + const std::string& game_ini_id) const +{ + FilterApprovedIni(codes, game_ini_id); +} + bool AchievementManager::CheckApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_ini_id) const { return CheckApprovedCode(code, game_ini_id); } +bool AchievementManager::CheckApprovedARCode(const ActionReplay::ARCode& code, + const std::string& game_ini_id) const +{ + return CheckApprovedCode(code, game_ini_id); +} + void AchievementManager::SetSpectatorMode() { rc_client_set_spectator_mode_enabled(m_client, Config::Get(Config::RA_SPECTATOR_ENABLED)); diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 5160d23327..2cacc2a6fc 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -50,6 +50,11 @@ namespace Gecko class GeckoCode; } // namespace Gecko +namespace ActionReplay +{ +struct ARCode; +} // namespace ActionReplay + class AchievementManager { public: @@ -135,7 +140,10 @@ public: const std::string& game_ini_id) const; void FilterApprovedGeckoCodes(std::vector& codes, const std::string& game_ini_id) const; + void FilterApprovedARCodes(std::vector& codes, + const std::string& game_ini_id) const; bool CheckApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_ini_id) const; + bool CheckApprovedARCode(const ActionReplay::ARCode& code, const std::string& game_ini_id) const; void SetSpectatorMode(); std::string_view GetPlayerDisplayName() const; @@ -197,6 +205,7 @@ private: bool CheckApprovedCode(const T& code, const std::string& game_ini_id) const; Common::SHA1::Digest GetCodeHash(const PatchEngine::Patch& patch) const; Common::SHA1::Digest GetCodeHash(const Gecko::GeckoCode& code) const; + Common::SHA1::Digest GetCodeHash(const ActionReplay::ARCode& code) const; static void LeaderboardEntriesCallback(int result, const char* error_message, rc_client_leaderboard_entry_list_t* list, @@ -288,6 +297,12 @@ public: return true; }; + constexpr bool CheckApprovedARCode(const ActionReplay::ARCode& code, + const std::string& game_ini_id) + { + return true; + }; + constexpr void LoadGame(const std::string&, const DiscIO::Volume*) {} constexpr void SetBackgroundExecutionAllowed(bool allowed) {} diff --git a/Source/Core/Core/ActionReplay.cpp b/Source/Core/Core/ActionReplay.cpp index 3052f06dec..d3171cdd25 100644 --- a/Source/Core/Core/ActionReplay.cpp +++ b/Source/Core/Core/ActionReplay.cpp @@ -39,6 +39,7 @@ #include "Common/MsgHandler.h" #include "Core/ARDecrypt.h" +#include "Core/AchievementManager.h" #include "Core/CheatCodes.h" #include "Core/Config/MainSettings.h" #include "Core/PowerPC/MMU.h" @@ -112,7 +113,7 @@ struct ARAddr // ---------------------- // AR Remote Functions -void ApplyCodes(std::span codes) +void ApplyCodes(std::span codes, const std::string& game_id) { if (!Config::AreCheatsEnabled()) return; @@ -121,7 +122,10 @@ void ApplyCodes(std::span codes) s_disable_logging = false; s_active_codes.clear(); std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), - [](const ARCode& code) { return code.enabled; }); + [&game_id](const ARCode& code) { + return code.enabled && + AchievementManager::GetInstance().CheckApprovedARCode(code, game_id); + }); s_active_codes.shrink_to_fit(); } @@ -169,9 +173,10 @@ void AddCode(ARCode code) } } -void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini) +void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini, + const std::string& game_id) { - ApplyCodes(LoadCodes(global_ini, local_ini)); + ApplyCodes(LoadCodes(global_ini, local_ini), game_id); } // Parses the Action Replay section of a game ini file. diff --git a/Source/Core/Core/ActionReplay.h b/Source/Core/Core/ActionReplay.h index ee2cb8b485..1cfbb0a1fe 100644 --- a/Source/Core/Core/ActionReplay.h +++ b/Source/Core/Core/ActionReplay.h @@ -45,12 +45,13 @@ struct ARCode void RunAllActive(const Core::CPUThreadGuard& cpu_guard); -void ApplyCodes(std::span codes); +void ApplyCodes(std::span codes, const std::string& game_id); void SetSyncedCodesAsActive(); void UpdateSyncedCodes(std::span codes); std::vector ApplyAndReturnCodes(std::span codes); void AddCode(ARCode new_code); -void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini); +void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini, + const std::string& game_id); std::vector LoadCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini); void SaveCodes(Common::IniFile* local_ini, std::span codes); diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index 3578893672..ae88ba3d82 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -2125,13 +2125,16 @@ bool NetPlayServer::SyncCodes() // Sync AR Codes { + std::vector codes = ActionReplay::LoadCodes(globalIni, localIni); +#ifdef USE_RETRO_ACHIEVEMENTS + AchievementManager::GetInstance().FilterApprovedARCodes(codes, game_id); +#endif // USE_RETRO_ACHIEVEMENTS // Create an AR Code Vector with just the active codes - std::vector s_active_codes = - ActionReplay::ApplyAndReturnCodes(ActionReplay::LoadCodes(globalIni, localIni)); + std::vector active_codes = ActionReplay::ApplyAndReturnCodes(codes); // Determine Codelist Size u16 codelines = 0; - for (const ActionReplay::ARCode& active_code : s_active_codes) + for (const ActionReplay::ARCode& active_code : active_codes) { INFO_LOG_FMT(NETPLAY, "Indexing {}", active_code.name); for (const ActionReplay::AREntry& op : active_code.ops) @@ -2159,7 +2162,7 @@ bool NetPlayServer::SyncCodes() pac << MessageID::SyncCodes; pac << SyncCodeID::ARData; // Iterate through the active code vector and send each codeline - for (const ActionReplay::ARCode& active_code : s_active_codes) + for (const ActionReplay::ARCode& active_code : active_codes) { INFO_LOG_FMT(NETPLAY, "Sending {}", active_code.name); for (const ActionReplay::AREntry& op : active_code.ops) diff --git a/Source/Core/Core/PatchEngine.cpp b/Source/Core/Core/PatchEngine.cpp index 4dc58a6761..c601b6b39c 100644 --- a/Source/Core/Core/PatchEngine.cpp +++ b/Source/Core/Core/PatchEngine.cpp @@ -198,7 +198,7 @@ void LoadPatches() else { Gecko::SetActiveCodes(Gecko::LoadCodes(globalIni, localIni), sconfig.GetGameID()); - ActionReplay::LoadAndApplyCodes(globalIni, localIni); + ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID()); } } @@ -335,7 +335,7 @@ bool ApplyFramePatches(Core::System& system) void Shutdown() { s_on_frame.clear(); - ActionReplay::ApplyCodes({}); + ActionReplay::ApplyCodes({}, ""); Gecko::Shutdown(); } diff --git a/Source/Core/DolphinQt/Config/ARCodeWidget.cpp b/Source/Core/DolphinQt/Config/ARCodeWidget.cpp index e7d44b8fe6..5089e98806 100644 --- a/Source/Core/DolphinQt/Config/ARCodeWidget.cpp +++ b/Source/Core/DolphinQt/Config/ARCodeWidget.cpp @@ -115,7 +115,7 @@ void ARCodeWidget::OnItemChanged(QListWidgetItem* item) m_ar_codes[m_code_list->row(item)].enabled = (item->checkState() == Qt::Checked); if (!m_restart_required) - ActionReplay::ApplyCodes(m_ar_codes); + ActionReplay::ApplyCodes(m_ar_codes, m_game_id); UpdateList(); SaveCodes();