Fixed Multi Config Code Approvals

Refactors the AR/Gecko/Patch code approval process to verify from every possible game ini, not just the base game ID. This fixes codes on specific revisions or codes general to any region.
This commit is contained in:
LillyJadeKatrin 2025-03-14 23:53:54 -04:00
parent fd2766f5df
commit 0615ade725
10 changed files with 61 additions and 58 deletions

View File

@ -28,6 +28,7 @@
#include "Core/Config/AchievementSettings.h"
#include "Core/Config/FreeLookSettings.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigLoaders/GameConfigLoader.h"
#include "Core/Core.h"
#include "Core/GeckoCode.h"
#include "Core/HW/Memmap.h"
@ -386,8 +387,8 @@ bool AchievementManager::IsHardcoreModeActive() const
}
template <typename T>
void AchievementManager::FilterApprovedIni(std::vector<T>& codes,
const std::string& game_ini_id) const
void AchievementManager::FilterApprovedIni(std::vector<T>& codes, const std::string& game_id,
u16 revision) const
{
if (codes.empty())
{
@ -409,13 +410,14 @@ void AchievementManager::FilterApprovedIni(std::vector<T>& codes,
for (auto& code : codes)
{
if (code.enabled && !CheckApprovedCode(code, game_ini_id))
if (code.enabled && !CheckApprovedCode(code, game_id, revision))
code.enabled = false;
}
}
template <typename T>
bool AchievementManager::CheckApprovedCode(const T& code, const std::string& game_ini_id) const
bool AchievementManager::CheckApprovedCode(const T& code, const std::string& game_id,
u16 revision) const
{
if (!IsHardcoreModeActive())
return true;
@ -424,22 +426,22 @@ bool AchievementManager::CheckApprovedCode(const T& code, const std::string& gam
if (!m_ini_root->is<picojson::value::object>())
return false;
const bool known_id = m_ini_root->contains(game_ini_id);
INFO_LOG_FMT(ACHIEVEMENTS, "Verifying code {}", code.name);
bool verified = false;
if (known_id)
{
auto digest = GetCodeHash(code);
auto hash = Common::SHA1::DigestToString(GetCodeHash(code));
verified = m_ini_root->get(game_ini_id).contains(Common::SHA1::DigestToString(digest));
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
{
auto config = filename.substr(0, filename.length() - 4);
if (m_ini_root->contains(config) && m_ini_root->get(config).contains(hash))
verified = true;
}
if (!verified)
{
OSD::AddMessage(fmt::format("Failed to verify code {} from file {}.", code.name, game_ini_id),
OSD::AddMessage(fmt::format("Failed to verify code {} for game ID {}.", code.name, game_id),
OSD::Duration::VERY_LONG, OSD::Color::RED);
OSD::AddMessage("Disable hardcore mode to enable this code.", OSD::Duration::VERY_LONG,
OSD::Color::RED);
@ -487,33 +489,33 @@ Common::SHA1::Digest AchievementManager::GetCodeHash(const ActionReplay::ARCode&
}
void AchievementManager::FilterApprovedPatches(std::vector<PatchEngine::Patch>& patches,
const std::string& game_ini_id) const
const std::string& game_id, u16 revision) const
{
FilterApprovedIni(patches, game_ini_id);
FilterApprovedIni(patches, game_id, revision);
}
void AchievementManager::FilterApprovedGeckoCodes(std::vector<Gecko::GeckoCode>& codes,
const std::string& game_ini_id) const
const std::string& game_id, u16 revision) const
{
FilterApprovedIni(codes, game_ini_id);
FilterApprovedIni(codes, game_id, revision);
}
void AchievementManager::FilterApprovedARCodes(std::vector<ActionReplay::ARCode>& codes,
const std::string& game_ini_id) const
const std::string& game_id, u16 revision) const
{
FilterApprovedIni(codes, game_ini_id);
FilterApprovedIni(codes, game_id, revision);
}
bool AchievementManager::CheckApprovedGeckoCode(const Gecko::GeckoCode& code,
const std::string& game_ini_id) const
const std::string& game_id, u16 revision) const
{
return CheckApprovedCode(code, game_ini_id);
return CheckApprovedCode(code, game_id, revision);
}
bool AchievementManager::CheckApprovedARCode(const ActionReplay::ARCode& code,
const std::string& game_ini_id) const
const std::string& game_id, u16 revision) const
{
return CheckApprovedCode(code, game_ini_id);
return CheckApprovedCode(code, game_id, revision);
}
void AchievementManager::SetSpectatorMode()

View File

@ -133,16 +133,17 @@ public:
std::recursive_mutex& GetLock();
bool IsHardcoreModeActive() const;
void SetGameIniId(const std::string& game_ini_id) { m_game_ini_id = game_ini_id; }
void FilterApprovedPatches(std::vector<PatchEngine::Patch>& patches,
const std::string& game_ini_id) const;
void FilterApprovedGeckoCodes(std::vector<Gecko::GeckoCode>& codes,
const std::string& game_ini_id) const;
void FilterApprovedARCodes(std::vector<ActionReplay::ARCode>& 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 FilterApprovedPatches(std::vector<PatchEngine::Patch>& patches, const std::string& game_id,
u16 revision) const;
void FilterApprovedGeckoCodes(std::vector<Gecko::GeckoCode>& codes, const std::string& game_id,
u16 revision) const;
void FilterApprovedARCodes(std::vector<ActionReplay::ARCode>& codes, const std::string& game_id,
u16 revision) const;
bool CheckApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_id,
u16 revision) const;
bool CheckApprovedARCode(const ActionReplay::ARCode& code, const std::string& game_id,
u16 revision) const;
void SetSpectatorMode();
std::string_view GetPlayerDisplayName() const;
@ -201,9 +202,9 @@ private:
void SetHardcoreMode();
template <typename T>
void FilterApprovedIni(std::vector<T>& codes, const std::string& game_ini_id) const;
void FilterApprovedIni(std::vector<T>& codes, const std::string& game_id, u16 revision) const;
template <typename T>
bool CheckApprovedCode(const T& code, const std::string& game_ini_id) const;
bool CheckApprovedCode(const T& code, const std::string& game_id, u16 revision) 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;
@ -259,7 +260,6 @@ private:
std::chrono::steady_clock::time_point m_last_progress_message = std::chrono::steady_clock::now();
Common::Lazy<picojson::value> m_ini_root{LoadApprovedList};
std::string m_game_ini_id;
std::unordered_map<AchievementId, LeaderboardStatus> m_leaderboard_map;
bool m_challenges_updated = false;
@ -302,14 +302,12 @@ public:
constexpr bool IsHardcoreModeActive() { return false; }
constexpr bool CheckApprovedGeckoCode(const Gecko::GeckoCode& code,
const std::string& game_ini_id)
constexpr bool CheckApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_id)
{
return true;
};
constexpr bool CheckApprovedARCode(const ActionReplay::ARCode& code,
const std::string& game_ini_id)
constexpr bool CheckApprovedARCode(const ActionReplay::ARCode& code, const std::string& game_id)
{
return true;
};

View File

@ -113,7 +113,7 @@ struct ARAddr
// ----------------------
// AR Remote Functions
void ApplyCodes(std::span<const ARCode> codes, const std::string& game_id)
void ApplyCodes(std::span<const ARCode> codes, const std::string& game_id, u16 revision)
{
if (!Config::AreCheatsEnabled())
return;
@ -122,9 +122,9 @@ void ApplyCodes(std::span<const ARCode> codes, const std::string& game_id)
s_disable_logging = false;
s_active_codes.clear();
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes),
[&game_id](const ARCode& code) {
return code.enabled &&
AchievementManager::GetInstance().CheckApprovedARCode(code, game_id);
[&game_id, &revision](const ARCode& code) {
return code.enabled && AchievementManager::GetInstance().CheckApprovedARCode(
code, game_id, revision);
});
s_active_codes.shrink_to_fit();
}
@ -174,9 +174,9 @@ void AddCode(ARCode code)
}
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
const std::string& game_id)
const std::string& game_id, u16 revision)
{
ApplyCodes(LoadCodes(global_ini, local_ini), game_id);
ApplyCodes(LoadCodes(global_ini, local_ini), game_id, revision);
}
// Parses the Action Replay section of a game ini file.

View File

@ -45,13 +45,13 @@ struct ARCode
void RunAllActive(const Core::CPUThreadGuard& cpu_guard);
void ApplyCodes(std::span<const ARCode> codes, const std::string& game_id);
void ApplyCodes(std::span<const ARCode> codes, const std::string& game_id, u16 revision);
void SetSyncedCodesAsActive();
void UpdateSyncedCodes(std::span<const ARCode> codes);
std::vector<ARCode> ApplyAndReturnCodes(std::span<const ARCode> codes);
void AddCode(ARCode new_code);
void LoadAndApplyCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini,
const std::string& game_id);
const std::string& game_id, u16 revision);
std::vector<ARCode> LoadCodes(const Common::IniFile& global_ini, const Common::IniFile& local_ini);
void SaveCodes(Common::IniFile* local_ini, std::span<const ARCode> codes);

View File

@ -50,7 +50,7 @@ static std::vector<GeckoCode> s_active_codes;
static std::vector<GeckoCode> s_synced_codes;
static std::mutex s_active_codes_lock;
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id)
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision)
{
std::lock_guard lk(s_active_codes_lock);
@ -60,9 +60,9 @@ void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_i
s_active_codes.reserve(gcodes.size());
std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes),
[&game_id](const GeckoCode& code) {
return code.enabled &&
AchievementManager::GetInstance().CheckApprovedGeckoCode(code, game_id);
[&game_id, &revision](const GeckoCode& code) {
return code.enabled && AchievementManager::GetInstance().CheckApprovedGeckoCode(
code, game_id, revision);
});
}
s_active_codes.shrink_to_fit();

View File

@ -60,7 +60,7 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
// preserve the emulation performance.
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id);
void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_id, u16 revision);
void SetSyncedCodesAsActive();
void UpdateSyncedCodes(std::span<const GeckoCode> gcodes);
std::vector<GeckoCode> SetAndReturnActiveCodes(std::span<const GeckoCode> gcodes);

View File

@ -2075,7 +2075,7 @@ bool NetPlayServer::SyncCodes()
std::vector<Gecko::GeckoCode> codes = Gecko::LoadCodes(globalIni, localIni);
#ifdef USE_RETRO_ACHIEVEMENTS
AchievementManager::GetInstance().FilterApprovedGeckoCodes(codes, game_id);
AchievementManager::GetInstance().FilterApprovedGeckoCodes(codes, game_id, revision);
#endif // USE_RETRO_ACHIEVEMENTS
// Create a Gecko Code Vector with just the active codes
@ -2129,7 +2129,7 @@ bool NetPlayServer::SyncCodes()
{
std::vector<ActionReplay::ARCode> codes = ActionReplay::LoadCodes(globalIni, localIni);
#ifdef USE_RETRO_ACHIEVEMENTS
AchievementManager::GetInstance().FilterApprovedARCodes(codes, game_id);
AchievementManager::GetInstance().FilterApprovedARCodes(codes, game_id, revision);
#endif // USE_RETRO_ACHIEVEMENTS
// Create an AR Code Vector with just the active codes
std::vector<ActionReplay::ARCode> active_codes = ActionReplay::ApplyAndReturnCodes(codes);

View File

@ -183,7 +183,8 @@ void LoadPatches()
LoadPatchSection("OnFrame", &s_on_frame, globalIni, localIni);
#ifdef USE_RETRO_ACHIEVEMENTS
AchievementManager::GetInstance().FilterApprovedPatches(s_on_frame, sconfig.GetGameID());
AchievementManager::GetInstance().FilterApprovedPatches(s_on_frame, sconfig.GetGameID(),
sconfig.GetRevision());
#endif // USE_RETRO_ACHIEVEMENTS
// Check if I'm syncing Codes
@ -194,8 +195,10 @@ void LoadPatches()
}
else
{
Gecko::SetActiveCodes(Gecko::LoadCodes(globalIni, localIni), sconfig.GetGameID());
ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID());
Gecko::SetActiveCodes(Gecko::LoadCodes(globalIni, localIni), sconfig.GetGameID(),
sconfig.GetRevision());
ActionReplay::LoadAndApplyCodes(globalIni, localIni, sconfig.GetGameID(),
sconfig.GetRevision());
}
}
@ -340,7 +343,7 @@ bool ApplyFramePatches(Core::System& system)
void Shutdown()
{
s_on_frame.clear();
ActionReplay::ApplyCodes({}, "");
ActionReplay::ApplyCodes({}, "", 0);
Gecko::Shutdown();
}

View File

@ -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, m_game_id);
ActionReplay::ApplyCodes(m_ar_codes, m_game_id, m_game_revision);
UpdateList();
SaveCodes();

View File

@ -202,7 +202,7 @@ void GeckoCodeWidget::OnItemChanged(QListWidgetItem* item)
m_gecko_codes[index].enabled = (item->checkState() == Qt::Checked);
if (!m_restart_required)
Gecko::SetActiveCodes(m_gecko_codes, m_game_id);
Gecko::SetActiveCodes(m_gecko_codes, m_game_id, m_game_revision);
SaveCodes();
}