mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-10-24 00:49:18 +00:00
CodeWidgets: Show code approval in Hardcore mode
When Hardcore mode is enabled, show an icon for each code in ARCodeWidget and GeckoCodeWidget indicating whether it's an approved code or not.
This commit is contained in:
parent
2b7faeb920
commit
44f6743a5b
6 changed files with 123 additions and 41 deletions
|
|
@ -460,15 +460,18 @@ void AchievementManager::FilterApprovedIni(std::vector<T>& codes, const std::str
|
||||||
|
|
||||||
for (auto& code : codes)
|
for (auto& code : codes)
|
||||||
{
|
{
|
||||||
if (code.enabled && !CheckApprovedCode(code, game_id, revision))
|
if (code.enabled && !IsApprovedCode(code, game_id, revision))
|
||||||
code.enabled = false;
|
code.enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool AchievementManager::CheckApprovedCode(const T& code, const std::string& game_id,
|
bool AchievementManager::ShouldCodeBeActivated(const T& code, const std::string& game_id,
|
||||||
u16 revision) const
|
u16 revision) const
|
||||||
{
|
{
|
||||||
|
if (!code.enabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!IsHardcoreModeActive())
|
if (!IsHardcoreModeActive())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -478,33 +481,42 @@ bool AchievementManager::CheckApprovedCode(const T& code, const std::string& gam
|
||||||
|
|
||||||
INFO_LOG_FMT(ACHIEVEMENTS, "Verifying code {}", code.name);
|
INFO_LOG_FMT(ACHIEVEMENTS, "Verifying code {}", code.name);
|
||||||
|
|
||||||
bool verified = false;
|
if (IsApprovedCode(code, game_id, revision))
|
||||||
|
return true;
|
||||||
|
|
||||||
auto hash = Common::SHA1::DigestToString(GetCodeHash(code));
|
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);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool AchievementManager::IsApprovedCode(const T& code, const std::string& game_id,
|
||||||
|
u16 revision) const
|
||||||
|
{
|
||||||
|
// Approved codes list failed to hash
|
||||||
|
if (!m_ini_root->is<picojson::value::object>())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const auto hash = Common::SHA1::DigestToString(GetCodeHash(code));
|
||||||
|
|
||||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
||||||
{
|
{
|
||||||
auto config = filename.substr(0, filename.length() - 4);
|
const auto config = filename.substr(0, filename.length() - 4);
|
||||||
if (m_ini_root->contains(config))
|
if (m_ini_root->contains(config))
|
||||||
{
|
{
|
||||||
auto ini_config = m_ini_root->get(config);
|
const auto ini_config = m_ini_root->get(config);
|
||||||
if (ini_config.is<picojson::object>() && ini_config.contains(code.name))
|
if (ini_config.is<picojson::object>() && ini_config.contains(code.name))
|
||||||
{
|
{
|
||||||
auto ini_code = ini_config.get(code.name);
|
const auto ini_code = ini_config.get(code.name);
|
||||||
if (ini_code.template is<std::string>())
|
if (ini_code.template is<std::string>() && ini_code.template get<std::string>() == hash)
|
||||||
verified = (ini_code.template get<std::string>() == hash);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
if (!verified)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
return verified;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::SHA1::Digest AchievementManager::GetCodeHash(const PatchEngine::Patch& patch) const
|
Common::SHA1::Digest AchievementManager::GetCodeHash(const PatchEngine::Patch& patch) const
|
||||||
|
|
@ -564,16 +576,27 @@ void AchievementManager::FilterApprovedARCodes(std::vector<ActionReplay::ARCode>
|
||||||
FilterApprovedIni(codes, game_id, revision);
|
FilterApprovedIni(codes, game_id, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AchievementManager::CheckApprovedGeckoCode(const Gecko::GeckoCode& code,
|
bool AchievementManager::ShouldGeckoCodeBeActivated(const Gecko::GeckoCode& code,
|
||||||
const std::string& game_id, u16 revision) const
|
const std::string& game_id, u16 revision) const
|
||||||
{
|
{
|
||||||
return CheckApprovedCode(code, game_id, revision);
|
return ShouldCodeBeActivated(code, game_id, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AchievementManager::CheckApprovedARCode(const ActionReplay::ARCode& code,
|
bool AchievementManager::ShouldARCodeBeActivated(const ActionReplay::ARCode& code,
|
||||||
|
const std::string& game_id, u16 revision) const
|
||||||
|
{
|
||||||
|
return ShouldCodeBeActivated(code, game_id, revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AchievementManager::IsApprovedGeckoCode(const Gecko::GeckoCode& code,
|
||||||
const std::string& game_id, u16 revision) const
|
const std::string& game_id, u16 revision) const
|
||||||
{
|
{
|
||||||
return CheckApprovedCode(code, game_id, revision);
|
return IsApprovedCode(code, game_id, revision);
|
||||||
|
}
|
||||||
|
bool AchievementManager::IsApprovedARCode(const ActionReplay::ARCode& code,
|
||||||
|
const std::string& game_id, u16 revision) const
|
||||||
|
{
|
||||||
|
return IsApprovedCode(code, game_id, revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AchievementManager::SetSpectatorMode()
|
void AchievementManager::SetSpectatorMode()
|
||||||
|
|
|
||||||
|
|
@ -149,10 +149,14 @@ public:
|
||||||
u16 revision) const;
|
u16 revision) const;
|
||||||
void FilterApprovedARCodes(std::vector<ActionReplay::ARCode>& codes, const std::string& game_id,
|
void FilterApprovedARCodes(std::vector<ActionReplay::ARCode>& codes, const std::string& game_id,
|
||||||
u16 revision) const;
|
u16 revision) const;
|
||||||
bool CheckApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_id,
|
bool ShouldGeckoCodeBeActivated(const Gecko::GeckoCode& code, const std::string& game_id,
|
||||||
u16 revision) const;
|
u16 revision) const;
|
||||||
bool CheckApprovedARCode(const ActionReplay::ARCode& code, const std::string& game_id,
|
bool ShouldARCodeBeActivated(const ActionReplay::ARCode& code, const std::string& game_id,
|
||||||
|
u16 revision) const;
|
||||||
|
bool IsApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_id,
|
||||||
u16 revision) const;
|
u16 revision) const;
|
||||||
|
bool IsApprovedARCode(const ActionReplay::ARCode& code, const std::string& game_id,
|
||||||
|
u16 revision) const;
|
||||||
|
|
||||||
void SetSpectatorMode();
|
void SetSpectatorMode();
|
||||||
std::string_view GetPlayerDisplayName() const;
|
std::string_view GetPlayerDisplayName() const;
|
||||||
|
|
@ -223,7 +227,9 @@ private:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void FilterApprovedIni(std::vector<T>& codes, const std::string& game_id, u16 revision) const;
|
void FilterApprovedIni(std::vector<T>& codes, const std::string& game_id, u16 revision) const;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool CheckApprovedCode(const T& code, const std::string& game_id, u16 revision) const;
|
bool ShouldCodeBeActivated(const T& code, const std::string& game_id, u16 revision) const;
|
||||||
|
template <typename T>
|
||||||
|
bool IsApprovedCode(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 PatchEngine::Patch& patch) const;
|
||||||
Common::SHA1::Digest GetCodeHash(const Gecko::GeckoCode& code) const;
|
Common::SHA1::Digest GetCodeHash(const Gecko::GeckoCode& code) const;
|
||||||
Common::SHA1::Digest GetCodeHash(const ActionReplay::ARCode& code) const;
|
Common::SHA1::Digest GetCodeHash(const ActionReplay::ARCode& code) const;
|
||||||
|
|
@ -338,14 +344,14 @@ public:
|
||||||
|
|
||||||
constexpr bool IsHardcoreModeActive() { return false; }
|
constexpr bool IsHardcoreModeActive() { return false; }
|
||||||
|
|
||||||
constexpr bool CheckApprovedGeckoCode(const Gecko::GeckoCode& code, const std::string& game_id,
|
constexpr bool ShouldGeckoCodeBeActivated(const Gecko::GeckoCode& code,
|
||||||
u16 revision)
|
const std::string& game_id, u16 revision)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool CheckApprovedARCode(const ActionReplay::ARCode& code, const std::string& game_id,
|
constexpr bool ShouldARCodeBeActivated(const ActionReplay::ARCode& code,
|
||||||
u16 revision)
|
const std::string& game_id, u16 revision)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -122,11 +122,11 @@ void ApplyCodes(std::span<const ARCode> codes, const std::string& game_id, u16 r
|
||||||
std::lock_guard guard(s_lock);
|
std::lock_guard guard(s_lock);
|
||||||
s_disable_logging = false;
|
s_disable_logging = false;
|
||||||
s_active_codes.clear();
|
s_active_codes.clear();
|
||||||
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes),
|
|
||||||
[&game_id, &revision](const ARCode& code) {
|
const auto should_be_activated = [&game_id, &revision](const ARCode& code) {
|
||||||
return code.enabled && AchievementManager::GetInstance().CheckApprovedARCode(
|
return AchievementManager::GetInstance().ShouldARCodeBeActivated(code, game_id, revision);
|
||||||
code, game_id, revision);
|
};
|
||||||
});
|
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes), should_be_activated);
|
||||||
s_active_codes.shrink_to_fit();
|
s_active_codes.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,11 +59,11 @@ void SetActiveCodes(std::span<const GeckoCode> gcodes, const std::string& game_i
|
||||||
{
|
{
|
||||||
s_active_codes.reserve(gcodes.size());
|
s_active_codes.reserve(gcodes.size());
|
||||||
|
|
||||||
|
const auto should_be_activated = [&game_id, &revision](const GeckoCode& code) {
|
||||||
|
return AchievementManager::GetInstance().ShouldGeckoCodeBeActivated(code, game_id, revision);
|
||||||
|
};
|
||||||
std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes),
|
std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes),
|
||||||
[&game_id, &revision](const GeckoCode& code) {
|
should_be_activated);
|
||||||
return code.enabled && AchievementManager::GetInstance().CheckApprovedGeckoCode(
|
|
||||||
code, game_id, revision);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
s_active_codes.shrink_to_fit();
|
s_active_codes.shrink_to_fit();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,21 @@
|
||||||
|
|
||||||
#include <QCursor>
|
#include <QCursor>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
#include <QIcon>
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
#include <QStyle>
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
|
|
||||||
|
#include "Core/AchievementManager.h"
|
||||||
#include "Core/ActionReplay.h"
|
#include "Core/ActionReplay.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
|
|
||||||
|
|
@ -23,6 +30,9 @@
|
||||||
#include "DolphinQt/Config/CheatWarningWidget.h"
|
#include "DolphinQt/Config/CheatWarningWidget.h"
|
||||||
#include "DolphinQt/Config/HardcoreWarningWidget.h"
|
#include "DolphinQt/Config/HardcoreWarningWidget.h"
|
||||||
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
#include "DolphinQt/Settings.h"
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
ARCodeWidget::ARCodeWidget(std::string game_id, u16 game_revision, bool restart_required)
|
ARCodeWidget::ARCodeWidget(std::string game_id, u16 game_revision, bool restart_required)
|
||||||
: m_game_id(std::move(game_id)), m_game_revision(game_revision),
|
: m_game_id(std::move(game_id)), m_game_revision(game_revision),
|
||||||
|
|
@ -90,6 +100,7 @@ void ARCodeWidget::ConnectWidgets()
|
||||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this,
|
connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this,
|
||||||
&ARCodeWidget::OpenAchievementSettings);
|
&ARCodeWidget::OpenAchievementSettings);
|
||||||
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, &ARCodeWidget::UpdateList);
|
||||||
#endif // USE_RETRO_ACHIEVEMENTS
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
connect(m_code_list, &QListWidget::itemChanged, this, &ARCodeWidget::OnItemChanged);
|
connect(m_code_list, &QListWidget::itemChanged, this, &ARCodeWidget::OnItemChanged);
|
||||||
|
|
@ -199,6 +210,21 @@ void ARCodeWidget::UpdateList()
|
||||||
item->setCheckState(ar.enabled ? Qt::Checked : Qt::Unchecked);
|
item->setCheckState(ar.enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
item->setData(Qt::UserRole, static_cast<int>(i));
|
item->setData(Qt::UserRole, static_cast<int>(i));
|
||||||
|
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
const AchievementManager& achievement_manager = AchievementManager::GetInstance();
|
||||||
|
|
||||||
|
if (achievement_manager.IsHardcoreModeActive())
|
||||||
|
{
|
||||||
|
const QIcon approved_icon = style()->standardIcon(QStyle::SP_DialogYesButton);
|
||||||
|
const QIcon warning_icon = style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||||
|
|
||||||
|
if (achievement_manager.IsApprovedARCode(ar, m_game_id, m_game_revision))
|
||||||
|
item->setIcon(approved_icon);
|
||||||
|
else
|
||||||
|
item->setIcon(warning_icon);
|
||||||
|
}
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
m_code_list->addItem(item);
|
m_code_list->addItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,16 +10,23 @@
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QFormLayout>
|
#include <QFormLayout>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
#include <QIcon>
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
#include <QStyle>
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
#include <QTextEdit>
|
#include <QTextEdit>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
|
|
||||||
|
#include "Core/AchievementManager.h"
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/GeckoCode.h"
|
#include "Core/GeckoCode.h"
|
||||||
#include "Core/GeckoCodeConfig.h"
|
#include "Core/GeckoCodeConfig.h"
|
||||||
|
|
@ -31,6 +38,9 @@
|
||||||
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
#include "DolphinQt/QtUtils/NonDefaultQPushButton.h"
|
||||||
#include "DolphinQt/QtUtils/QtUtils.h"
|
#include "DolphinQt/QtUtils/QtUtils.h"
|
||||||
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
#include "DolphinQt/QtUtils/WrapInScrollArea.h"
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
#include "DolphinQt/Settings.h"
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
GeckoCodeWidget::GeckoCodeWidget(std::string game_id, std::string gametdb_id, u16 game_revision,
|
GeckoCodeWidget::GeckoCodeWidget(std::string game_id, std::string gametdb_id, u16 game_revision,
|
||||||
bool restart_required)
|
bool restart_required)
|
||||||
|
|
@ -158,6 +168,8 @@ void GeckoCodeWidget::ConnectWidgets()
|
||||||
#ifdef USE_RETRO_ACHIEVEMENTS
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this,
|
connect(m_hc_warning, &HardcoreWarningWidget::OpenAchievementSettings, this,
|
||||||
&GeckoCodeWidget::OpenAchievementSettings);
|
&GeckoCodeWidget::OpenAchievementSettings);
|
||||||
|
connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
|
||||||
|
&GeckoCodeWidget::UpdateList);
|
||||||
#endif // USE_RETRO_ACHIEVEMENTS
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -356,6 +368,21 @@ void GeckoCodeWidget::UpdateList()
|
||||||
item->setCheckState(code.enabled ? Qt::Checked : Qt::Unchecked);
|
item->setCheckState(code.enabled ? Qt::Checked : Qt::Unchecked);
|
||||||
item->setData(Qt::UserRole, static_cast<int>(i));
|
item->setData(Qt::UserRole, static_cast<int>(i));
|
||||||
|
|
||||||
|
#ifdef USE_RETRO_ACHIEVEMENTS
|
||||||
|
const AchievementManager& achievement_manager = AchievementManager::GetInstance();
|
||||||
|
|
||||||
|
if (achievement_manager.IsHardcoreModeActive())
|
||||||
|
{
|
||||||
|
const QIcon approved_icon = style()->standardIcon(QStyle::SP_DialogYesButton);
|
||||||
|
const QIcon warning_icon = style()->standardIcon(QStyle::SP_MessageBoxWarning);
|
||||||
|
|
||||||
|
if (achievement_manager.IsApprovedGeckoCode(code, m_game_id, m_game_revision))
|
||||||
|
item->setIcon(approved_icon);
|
||||||
|
else
|
||||||
|
item->setIcon(warning_icon);
|
||||||
|
}
|
||||||
|
#endif // USE_RETRO_ACHIEVEMENTS
|
||||||
|
|
||||||
m_code_list->addItem(item);
|
m_code_list->addItem(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue