From 1b3c3efcd51a7fc1cb5ae1231600e8e60a4c8918 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 7 Dec 2022 00:46:26 +1000 Subject: [PATCH] Achievements: Add option to disable notifications --- .../Settings/AchievementSettingsWidget.cpp | 38 ++++---- .../Settings/AchievementSettingsWidget.ui | 43 +++++---- pcsx2/Config.h | 1 + pcsx2/Frontend/Achievements.cpp | 92 ++++++++++--------- pcsx2/Frontend/FullscreenUI.cpp | 6 +- pcsx2/Frontend/ImGuiManager.cpp | 2 +- pcsx2/Pcsx2Config.cpp | 2 + 7 files changed, 101 insertions(+), 83 deletions(-) diff --git a/pcsx2-qt/Settings/AchievementSettingsWidget.cpp b/pcsx2-qt/Settings/AchievementSettingsWidget.cpp index a13b566378..c4951e992d 100644 --- a/pcsx2-qt/Settings/AchievementSettingsWidget.cpp +++ b/pcsx2-qt/Settings/AchievementSettingsWidget.cpp @@ -43,38 +43,35 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.challengeMode, "Achievements", "ChallengeMode", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboards, "Achievements", "Leaderboards", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.testMode, "Achievements", "TestMode", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialTestMode, "Achievements", - "UnofficialTestMode", false); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Achievements", - "SoundEffects", true); - SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.primedIndicators, "Achievements", - "PrimedIndicators", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialTestMode, "Achievements", "UnofficialTestMode", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.notifications, "Achievements", "Notifications", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Achievements", "SoundEffects", true); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.primedIndicators, "Achievements", "PrimedIndicators", true); dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"), tr("When enabled and logged in, PCSX2 will scan for achievements on game load.")); dialog->registerWidgetHelp(m_ui.testMode, tr("Enable Test Mode"), tr("Unchecked"), tr("When enabled, PCSX2 will assume all achievements are locked and not send any " "unlock notifications to the server.")); - dialog->registerWidgetHelp( - m_ui.unofficialTestMode, tr("Test Unofficial Achievements"), tr("Unchecked"), + dialog->registerWidgetHelp(m_ui.unofficialTestMode, tr("Test Unofficial Achievements"), tr("Unchecked"), tr("When enabled, PCSX2 will list achievements from unofficial sets. Please note that these achievements are " "not tracked by RetroAchievements, so they unlock every time.")); - dialog->registerWidgetHelp( - m_ui.richPresence, tr("Enable Rich Presence"), tr("Unchecked"), + dialog->registerWidgetHelp(m_ui.richPresence, tr("Enable Rich Presence"), tr("Unchecked"), tr("When enabled, rich presence information will be collected and sent to the server where supported.")); dialog->registerWidgetHelp(m_ui.challengeMode, tr("Enable Hardcore Mode"), tr("Unchecked"), tr("\"Challenge\" mode for achievements, including leaderboard tracking. Disables save state, cheats, and slowdown functions.")); dialog->registerWidgetHelp(m_ui.leaderboards, tr("Enable Leaderboards"), tr("Checked"), tr("Enables tracking and submission of leaderboards in supported games. If leaderboards are disabled, you will still " "be able to view the leaderboard and scores, but no scores will be uploaded.")); - dialog->registerWidgetHelp( - m_ui.soundEffects, tr("Enable Sound Effects"), tr("Checked"), + dialog->registerWidgetHelp(m_ui.notifications, tr("Show Notifications"), tr("Checked"), + tr("Displays popup messages on events such as achievement unlocks and leaderboard submissions.")); + dialog->registerWidgetHelp(m_ui.soundEffects, tr("Enable Sound Effects"), tr("Checked"), tr("Plays sound effects for events such as achievement unlocks and leaderboard submissions.")); - dialog->registerWidgetHelp( - m_ui.primedIndicators, tr("Show Challenge Indicators"), tr("Checked"), + dialog->registerWidgetHelp(m_ui.primedIndicators, tr("Show Challenge Indicators"), tr("Checked"), tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active.")); connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState); + connect(m_ui.notifications, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState); connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState); connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::onChallengeModeStateChanged); @@ -108,12 +105,14 @@ void AchievementSettingsWidget::updateEnableState() { const bool enabled = m_dialog->getEffectiveBoolValue("Achievements", "Enabled", false); const bool challenge = m_dialog->getEffectiveBoolValue("Achievements", "ChallengeMode", false); + const bool notifications = m_dialog->getEffectiveBoolValue("Achievements", "Notifications", true); m_ui.testMode->setEnabled(enabled); m_ui.unofficialTestMode->setEnabled(enabled); m_ui.richPresence->setEnabled(enabled); m_ui.challengeMode->setEnabled(enabled); m_ui.leaderboards->setEnabled(enabled && challenge); - m_ui.soundEffects->setEnabled(enabled); + m_ui.notifications->setEnabled(enabled); + m_ui.soundEffects->setEnabled(enabled && notifications); m_ui.primedIndicators->setEnabled(enabled); } @@ -148,7 +147,8 @@ void AchievementSettingsWidget::updateLoginState() if (logged_in) { - const u64 login_unix_timestamp = StringUtil::FromChars(Host::GetBaseStringSettingValue("Achievements", "LoginTimestamp", "0")).value_or(0); + const u64 login_unix_timestamp = + StringUtil::FromChars(Host::GetBaseStringSettingValue("Achievements", "LoginTimestamp", "0")).value_or(0); const QDateTime login_timestamp(QDateTime::fromSecsSinceEpoch(static_cast(login_unix_timestamp))); m_ui.loginStatus->setText(tr("Username: %1\nLogin token generated on %2.") .arg(QString::fromStdString(username)) @@ -188,13 +188,11 @@ void AchievementSettingsWidget::onViewProfilePressed() return; const QByteArray encoded_username(QUrl::toPercentEncoding(QString::fromStdString(username))); - QtUtils::OpenURL( - QtUtils::GetRootWidget(this), + QtUtils::OpenURL(QtUtils::GetRootWidget(this), QUrl(QStringLiteral("https://retroachievements.org/user/%1").arg(QString::fromUtf8(encoded_username)))); } -void AchievementSettingsWidget::onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, - quint32 points) +void AchievementSettingsWidget::onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points) { m_ui.gameInfo->setText(game_info_string); } diff --git a/pcsx2-qt/Settings/AchievementSettingsWidget.ui b/pcsx2-qt/Settings/AchievementSettingsWidget.ui index a5b6e8ec8d..fd3cd78bb0 100644 --- a/pcsx2-qt/Settings/AchievementSettingsWidget.ui +++ b/pcsx2-qt/Settings/AchievementSettingsWidget.ui @@ -6,8 +6,8 @@ 0 0 - 648 - 470 + 658 + 496 @@ -32,13 +32,6 @@ Global Settings - - - - Enable Leaderboards - - - @@ -46,6 +39,13 @@ + + + + Show Challenge Indicators + + + @@ -60,31 +60,38 @@ - - + + - Enable Sound Effects + Enable Leaderboards - + Test Unofficial Achievements - + Enable Test Mode - - + + - Show Challenge Indicators + Enable Sound Effects + + + + + + + Show Notifications @@ -130,7 +137,7 @@ 0 - 160 + 80 diff --git a/pcsx2/Config.h b/pcsx2/Config.h index d38f14b967..30572f1e0a 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -1011,6 +1011,7 @@ struct Pcsx2Config RichPresence : 1, ChallengeMode : 1, Leaderboards : 1, + Notifications : 1, SoundEffects : 1, PrimedIndicators : 1; BITFIELD_END diff --git a/pcsx2/Frontend/Achievements.cpp b/pcsx2/Frontend/Achievements.cpp index 010eb01946..c203b7fecc 100644 --- a/pcsx2/Frontend/Achievements.cpp +++ b/pcsx2/Frontend/Achievements.cpp @@ -1033,37 +1033,40 @@ void Achievements::DownloadImage(std::string url, std::string cache_filename) void Achievements::DisplayAchievementSummary() { - std::string title = s_game_title; - if (ChallengeModeActive()) - title += " (Hardcore Mode)"; - - std::string summary; - if (GetAchievementCount() > 0) + if (FullscreenUI::IsInitialized() && EmuConfig.Achievements.Notifications) { - summary = StringUtil::StdStringFromFormat("You have earned %u of %u achievements, and %u of %u points.", - GetUnlockedAchiementCount(), GetAchievementCount(), GetCurrentPointsForGame(), GetMaximumPointsForGame()); - } - else - { - summary = "This game has no achievements."; - } - if (GetLeaderboardCount() > 0) - { - summary.push_back('\n'); - if (LeaderboardsActive()) - summary.append("Leaderboard submission is enabled."); - } + std::string title = s_game_title; + if (ChallengeModeActive()) + title += " (Hardcore Mode)"; - ImGuiFullscreen::AddNotification(10.0f, std::move(title), std::move(summary), s_game_icon); + std::string summary; + if (GetAchievementCount() > 0) + { + summary = StringUtil::StdStringFromFormat("You have earned %u of %u achievements, and %u of %u points.", + GetUnlockedAchiementCount(), GetAchievementCount(), GetCurrentPointsForGame(), GetMaximumPointsForGame()); + } + else + { + summary = "This game has no achievements."; + } + if (GetLeaderboardCount() > 0) + { + summary.push_back('\n'); + if (LeaderboardsActive()) + summary.append("Leaderboard submission is enabled."); + } - // Technically not going through the resource API, but since we're passing this to something else, we can't. - if (EmuConfig.Achievements.SoundEffects) - Common::PlaySoundAsync(Path::Combine(EmuFolders::Resources, INFO_SOUND_NAME).c_str()); + ImGuiFullscreen::AddNotification(10.0f, std::move(title), std::move(summary), s_game_icon); + + // Technically not going through the resource API, but since we're passing this to something else, we can't. + if (EmuConfig.Achievements.SoundEffects) + Common::PlaySoundAsync(Path::Combine(EmuFolders::Resources, INFO_SOUND_NAME).c_str()); + } } void Achievements::DisplayMasteredNotification() { - if (!FullscreenUI::IsInitialized()) + if (!FullscreenUI::IsInitialized() || !EmuConfig.Achievements.Notifications) return; std::string title(fmt::format("Mastered {}", s_game_title)); @@ -1468,8 +1471,8 @@ void Achievements::GameChanged(u32 crc) // when we're booting the bios, or shutting down, this will fail if (crc != 0) { - Host::AddKeyedOSDMessage( - "retroachievements_disc_read_failed", "Failed to read executable from disc. Achievements disabled.", Host::OSD_CRITICAL_ERROR_DURATION); + Host::AddKeyedOSDMessage("retroachievements_disc_read_failed", "Failed to read executable from disc. Achievements disabled.", + Host::OSD_CRITICAL_ERROR_DURATION); } s_last_game_crc = 0; @@ -1782,7 +1785,7 @@ void Achievements::SubmitLeaderboardCallback(s32 status_code, const std::string& return; const Leaderboard* lb = GetLeaderboardByID(std::exchange(s_submitting_lboard_id, 0u)); - if (!lb) + if (!lb || !FullscreenUI::IsInitialized() || !EmuConfig.Achievements.Notifications) return; char submitted_score[128]; @@ -1816,24 +1819,27 @@ void Achievements::UnlockAchievement(u32 achievement_id, bool add_notification / Console.WriteLn("Achievement %s (%u) for game %u unlocked", achievement->title.c_str(), achievement_id, s_game_id); - std::string title; - switch (achievement->category) + if (FullscreenUI::IsInitialized() && EmuConfig.Achievements.Notifications) { - case AchievementCategory::Local: - title = fmt::format("{} (Local)", achievement->title); - break; - case AchievementCategory::Unofficial: - title = fmt::format("{} (Unofficial)", achievement->title); - break; - case AchievementCategory::Core: - default: - title = achievement->title; - break; - } + std::string title; + switch (achievement->category) + { + case AchievementCategory::Local: + title = fmt::format("{} (Local)", achievement->title); + break; + case AchievementCategory::Unofficial: + title = fmt::format("{} (Unofficial)", achievement->title); + break; + case AchievementCategory::Core: + default: + title = achievement->title; + break; + } - ImGuiFullscreen::AddNotification(15.0f, std::move(title), achievement->description, GetAchievementBadgePath(*achievement)); - if (EmuConfig.Achievements.SoundEffects) - Common::PlaySoundAsync(Path::Combine(EmuFolders::Resources, UNLOCK_SOUND_NAME).c_str()); + ImGuiFullscreen::AddNotification(15.0f, std::move(title), achievement->description, GetAchievementBadgePath(*achievement)); + if (EmuConfig.Achievements.SoundEffects) + Common::PlaySoundAsync(Path::Combine(EmuFolders::Resources, UNLOCK_SOUND_NAME).c_str()); + } if (IsMastered()) DisplayMasteredNotification(); diff --git a/pcsx2/Frontend/FullscreenUI.cpp b/pcsx2/Frontend/FullscreenUI.cpp index b43500fa7b..58a1369a70 100644 --- a/pcsx2/Frontend/FullscreenUI.cpp +++ b/pcsx2/Frontend/FullscreenUI.cpp @@ -6459,6 +6459,7 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock& se const bool enabled = bsi->GetBoolValue("Achievements", "Enabled", false); const bool challenge = bsi->GetBoolValue("Achievements", "ChallengeMode", false); + const bool notifications = bsi->GetBoolValue("Achievements", "Notifications", true); DrawToggleSetting(bsi, ICON_FA_USER_FRIENDS " Rich Presence", "When enabled, rich presence information will be collected and sent to the server where supported.", "Achievements", "RichPresence", @@ -6468,9 +6469,12 @@ void FullscreenUI::DrawAchievementsSettingsPage(std::unique_lock& se "Achievements", "ChallengeMode", false, enabled); DrawToggleSetting(bsi, ICON_FA_LIST_OL " Leaderboards", "Enables tracking and submission of leaderboards in supported games.", "Achievements", "Leaderboards", true, enabled && challenge); + DrawToggleSetting(bsi, ICON_FA_INBOX " Show Notifications", + "Displays popup messages on events such as achievement unlocks and leaderboard submissions.", "Achievements", "Notifications", true, + enabled); DrawToggleSetting(bsi, ICON_FA_HEADPHONES " Sound Effects", "Plays sound effects for events such as achievement unlocks and leaderboard submissions.", "Achievements", "SoundEffects", true, - enabled); + enabled && notifications); DrawToggleSetting(bsi, ICON_FA_MAGIC " Show Challenge Indicators", "Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active.", "Achievements", "PrimedIndicators", true, enabled); diff --git a/pcsx2/Frontend/ImGuiManager.cpp b/pcsx2/Frontend/ImGuiManager.cpp index 384a4fcb9f..c47227ef34 100644 --- a/pcsx2/Frontend/ImGuiManager.cpp +++ b/pcsx2/Frontend/ImGuiManager.cpp @@ -442,7 +442,7 @@ ImFont* ImGuiManager::AddFixedFont(float size) bool ImGuiManager::AddIconFonts(float size) { // clang-format off - static constexpr ImWchar range_fa[] = { 0xf001,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf028,0xf028,0xf02d,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0a0,0xf0a0,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf121,0xf121,0xf133,0xf133,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf466,0xf466,0xf479,0xf479,0xf500,0xf500,0xf517,0xf517,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0xf8d9,0xf8d9,0x0,0x0 }; + static constexpr ImWchar range_fa[] = { 0xf001,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf01c,0xf01c,0xf021,0xf021,0xf023,0xf023,0xf025,0xf025,0xf028,0xf028,0xf02d,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03d,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf085,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c9,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f1,0xf0f1,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf110,0xf110,0xf119,0xf119,0xf11b,0xf11c,0xf121,0xf121,0xf133,0xf133,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1c9,0xf1c9,0xf1dd,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf242,0xf242,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2d0,0xf2d0,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf466,0xf466,0xf479,0xf479,0xf500,0xf500,0xf517,0xf517,0xf51f,0xf51f,0xf543,0xf543,0xf545,0xf545,0xf547,0xf548,0xf552,0xf552,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf7c2,0xf7c2,0xf807,0xf807,0xf815,0xf815,0xf818,0xf818,0xf84c,0xf84c,0xf8cc,0xf8cc,0xf8d9,0xf8d9,0x0,0x0 }; // clang-format on ImFontConfig cfg; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index b445012166..45bc3f52ea 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -1031,6 +1031,7 @@ Pcsx2Config::AchievementsOptions::AchievementsOptions() RichPresence = true; ChallengeMode = false; Leaderboards = true; + Notifications = true; SoundEffects = true; PrimedIndicators = true; } @@ -1045,6 +1046,7 @@ void Pcsx2Config::AchievementsOptions::LoadSave(SettingsWrapper& wrap) SettingsWrapBitBool(RichPresence); SettingsWrapBitBool(ChallengeMode); SettingsWrapBitBool(Leaderboards); + SettingsWrapBitBool(Notifications); SettingsWrapBitBool(SoundEffects); SettingsWrapBitBool(PrimedIndicators); }