2424#include " Common/ScopeGuard.h"
2525#include " Common/Version.h"
2626#include " Common/WorkQueueThread.h"
27+ #include " Core/ActionReplay.h"
2728#include " Core/Config/AchievementSettings.h"
2829#include " Core/Config/FreeLookSettings.h"
2930#include " Core/Config/MainSettings.h"
3031#include " Core/Core.h"
32+ #include " Core/GeckoCode.h"
3133#include " Core/HW/Memmap.h"
3234#include " Core/HW/VideoInterface.h"
3335#include " Core/PatchEngine.h"
@@ -370,7 +372,6 @@ void AchievementManager::SetHardcoreMode()
370372 if (Config::Get (Config::MAIN_EMULATION_SPEED) < 1 .0f )
371373 Config::SetBaseOrCurrent (Config::MAIN_EMULATION_SPEED, 1 .0f );
372374 Config::SetBaseOrCurrent (Config::FREE_LOOK_ENABLED, false );
373- Config::SetBaseOrCurrent (Config::MAIN_ENABLE_CHEATS, false );
374375 }
375376}
376377
@@ -384,10 +385,11 @@ bool AchievementManager::IsHardcoreModeActive() const
384385 return rc_client_is_processing_required (m_client);
385386}
386387
387- void AchievementManager::FilterApprovedPatches (std::vector<PatchEngine::Patch>& patches,
388- const std::string& game_ini_id) const
388+ template <typename T>
389+ void AchievementManager::FilterApprovedIni (std::vector<T>& codes,
390+ const std::string& game_ini_id) const
389391{
390- if (patches .empty ())
392+ if (codes .empty ())
391393 {
392394 // There's nothing to verify, so let's save ourselves some work
393395 return ;
@@ -398,46 +400,120 @@ void AchievementManager::FilterApprovedPatches(std::vector<PatchEngine::Patch>&
398400 if (!IsHardcoreModeActive ())
399401 return ;
400402
403+ // Approved codes list failed to hash
404+ if (!m_ini_root->is <picojson::value::object>())
405+ {
406+ codes.clear ();
407+ return ;
408+ }
409+
410+ for (auto & code : codes)
411+ {
412+ if (code.enabled && !CheckApprovedCode (code, game_ini_id))
413+ code.enabled = false ;
414+ }
415+ }
416+
417+ template <typename T>
418+ bool AchievementManager::CheckApprovedCode (const T& code, const std::string& game_ini_id) const
419+ {
420+ if (!IsHardcoreModeActive ())
421+ return true ;
422+
423+ // Approved codes list failed to hash
424+ if (!m_ini_root->is <picojson::value::object>())
425+ return false ;
426+
401427 const bool known_id = m_ini_root->contains (game_ini_id);
402428
403- auto patch_itr = patches.begin ();
404- while (patch_itr != patches.end ())
429+ INFO_LOG_FMT (ACHIEVEMENTS, " Verifying code {}" , code.name );
430+
431+ bool verified = false ;
432+
433+ if (known_id)
405434 {
406- INFO_LOG_FMT (ACHIEVEMENTS, " Verifying patch {} " , patch_itr-> name );
435+ auto digest = GetCodeHash (code );
407436
408- bool verified = false ;
437+ verified = m_ini_root->get (game_ini_id).contains (Common::SHA1::DigestToString (digest));
438+ }
409439
410- if (known_id)
411- {
412- auto context = Common::SHA1::CreateContext ();
413- context->Update (Common::BitCastToArray<u8 >(static_cast <u64 >(patch_itr->entries .size ())));
414- for (const auto & entry : patch_itr->entries )
415- {
416- context->Update (Common::BitCastToArray<u8 >(entry.type ));
417- context->Update (Common::BitCastToArray<u8 >(entry.address ));
418- context->Update (Common::BitCastToArray<u8 >(entry.value ));
419- context->Update (Common::BitCastToArray<u8 >(entry.comparand ));
420- context->Update (Common::BitCastToArray<u8 >(entry.conditional ));
421- }
422- auto digest = context->Finish ();
440+ if (!verified)
441+ {
442+ OSD::AddMessage (fmt::format (" Failed to verify code {} from file {}." , code.name , game_ini_id),
443+ OSD::Duration::VERY_LONG, OSD::Color::RED);
444+ OSD::AddMessage (" Disable hardcore mode to enable this code." , OSD::Duration::VERY_LONG,
445+ OSD::Color::RED);
446+ }
447+ return verified;
448+ }
423449
424- verified = m_ini_root->get (game_ini_id).contains (Common::SHA1::DigestToString (digest));
425- }
450+ Common::SHA1::Digest AchievementManager::GetCodeHash (const PatchEngine::Patch& patch) const
451+ {
452+ auto context = Common::SHA1::CreateContext ();
453+ context->Update (Common::BitCastToArray<u8 >(static_cast <u64 >(patch.entries .size ())));
454+ for (const auto & entry : patch.entries )
455+ {
456+ context->Update (Common::BitCastToArray<u8 >(entry.type ));
457+ context->Update (Common::BitCastToArray<u8 >(entry.address ));
458+ context->Update (Common::BitCastToArray<u8 >(entry.value ));
459+ context->Update (Common::BitCastToArray<u8 >(entry.comparand ));
460+ context->Update (Common::BitCastToArray<u8 >(entry.conditional ));
461+ }
462+ return context->Finish ();
463+ }
426464
427- if (!verified)
428- {
429- patch_itr = patches.erase (patch_itr);
430- OSD::AddMessage (
431- fmt::format (" Failed to verify patch {} from file {}." , patch_itr->name , game_ini_id),
432- OSD::Duration::VERY_LONG, OSD::Color::RED);
433- OSD::AddMessage (" Disable hardcore mode to enable this patch." , OSD::Duration::VERY_LONG,
434- OSD::Color::RED);
435- }
436- else
437- {
438- patch_itr++;
439- }
465+ Common::SHA1::Digest AchievementManager::GetCodeHash (const Gecko::GeckoCode& code) const
466+ {
467+ auto context = Common::SHA1::CreateContext ();
468+ context->Update (Common::BitCastToArray<u8 >(static_cast <u64 >(code.codes .size ())));
469+ for (const auto & entry : code.codes )
470+ {
471+ context->Update (Common::BitCastToArray<u8 >(entry.address ));
472+ context->Update (Common::BitCastToArray<u8 >(entry.data ));
440473 }
474+ return context->Finish ();
475+ }
476+
477+ Common::SHA1::Digest AchievementManager::GetCodeHash (const ActionReplay::ARCode& code) const
478+ {
479+ auto context = Common::SHA1::CreateContext ();
480+ context->Update (Common::BitCastToArray<u8 >(static_cast <u64 >(code.ops .size ())));
481+ for (const auto & entry : code.ops )
482+ {
483+ context->Update (Common::BitCastToArray<u8 >(entry.cmd_addr ));
484+ context->Update (Common::BitCastToArray<u8 >(entry.value ));
485+ }
486+ return context->Finish ();
487+ }
488+
489+ void AchievementManager::FilterApprovedPatches (std::vector<PatchEngine::Patch>& patches,
490+ const std::string& game_ini_id) const
491+ {
492+ FilterApprovedIni (patches, game_ini_id);
493+ }
494+
495+ void AchievementManager::FilterApprovedGeckoCodes (std::vector<Gecko::GeckoCode>& codes,
496+ const std::string& game_ini_id) const
497+ {
498+ FilterApprovedIni (codes, game_ini_id);
499+ }
500+
501+ void AchievementManager::FilterApprovedARCodes (std::vector<ActionReplay::ARCode>& codes,
502+ const std::string& game_ini_id) const
503+ {
504+ FilterApprovedIni (codes, game_ini_id);
505+ }
506+
507+ bool AchievementManager::CheckApprovedGeckoCode (const Gecko::GeckoCode& code,
508+ const std::string& game_ini_id) const
509+ {
510+ return CheckApprovedCode (code, game_ini_id);
511+ }
512+
513+ bool AchievementManager::CheckApprovedARCode (const ActionReplay::ARCode& code,
514+ const std::string& game_ini_id) const
515+ {
516+ return CheckApprovedCode (code, game_ini_id);
441517}
442518
443519void AchievementManager::SetSpectatorMode ()
0 commit comments