From 75465f00ccf8694bbae37fccb106a7aaf233e3ac Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 8 May 2024 07:28:28 -0400 Subject: [PATCH 1/4] Remove Badges Enabled option from Achievements Was informed by the RetroAchievements team that this isn't an option in most emulators, and as the next commits will be to enable default icons, there will always be something to display. --- Source/Core/Core/AchievementManager.cpp | 37 +++++++------------ .../Core/Core/Config/AchievementSettings.cpp | 1 - Source/Core/Core/Config/AchievementSettings.h | 1 - .../DolphinQt/Achievements/AchievementBox.cpp | 2 +- .../Achievements/AchievementHeaderWidget.cpp | 4 +- .../AchievementSettingsWidget.cpp | 19 ---------- .../Achievements/AchievementSettingsWidget.h | 2 - 7 files changed, 17 insertions(+), 49 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index b1b63726b3..f9ae5fadb5 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -637,7 +637,7 @@ void AchievementManager::DisplayWelcomeMessage() m_display_welcome_message = false; const u32 color = rc_client_get_hardcore_enabled(m_client) ? OSD::Color::YELLOW : OSD::Color::CYAN; - if (Config::Get(Config::RA_BADGES_ENABLED) && !m_game_badge.name.empty()) + if (!m_game_badge.name.empty()) { OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, DecodeBadgeToOSDIcon(m_game_badge.badge)); @@ -677,11 +677,9 @@ void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t (rc_client_get_hardcore_enabled(AchievementManager::GetInstance().m_client)) ? OSD::Color::YELLOW : OSD::Color::CYAN, - (Config::Get(Config::RA_BADGES_ENABLED)) ? - DecodeBadgeToOSDIcon(AchievementManager::GetInstance() - .m_unlocked_badges[client_event->achievement->id] - .badge) : - nullptr); + DecodeBadgeToOSDIcon(AchievementManager::GetInstance() + .m_unlocked_badges[client_event->achievement->id] + .badge)); } void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event) @@ -738,15 +736,12 @@ void AchievementManager::HandleLeaderboardTrackerHideEvent(const rc_client_event void AchievementManager::HandleAchievementChallengeIndicatorShowEvent( const rc_client_event_t* client_event) { - if (Config::Get(Config::RA_BADGES_ENABLED)) + auto& unlocked_badges = AchievementManager::GetInstance().m_unlocked_badges; + if (const auto unlocked_iter = unlocked_badges.find(client_event->achievement->id); + unlocked_iter != unlocked_badges.end()) { - auto& unlocked_badges = AchievementManager::GetInstance().m_unlocked_badges; - if (const auto unlocked_iter = unlocked_badges.find(client_event->achievement->id); - unlocked_iter != unlocked_badges.end()) - { - AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] = - DecodeBadgeToOSDIcon(unlocked_iter->second.badge); - } + AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] = + DecodeBadgeToOSDIcon(unlocked_iter->second.badge); } } @@ -763,11 +758,9 @@ void AchievementManager::HandleAchievementProgressIndicatorShowEvent( OSD::AddMessage(fmt::format("{} {}", client_event->achievement->title, client_event->achievement->measured_progress), OSD::Duration::SHORT, OSD::Color::GREEN, - (Config::Get(Config::RA_BADGES_ENABLED)) ? - DecodeBadgeToOSDIcon(AchievementManager::GetInstance() - .m_unlocked_badges[client_event->achievement->id] - .badge) : - nullptr); + DecodeBadgeToOSDIcon(AchievementManager::GetInstance() + .m_unlocked_badges[client_event->achievement->id] + .badge)); } void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event, @@ -784,9 +777,7 @@ void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* clien OSD::AddMessage(fmt::format("Congratulations! {} has {} {}", user_info->display_name, hardcore ? "mastered" : "completed", game_info->title), OSD::Duration::VERY_LONG, hardcore ? OSD::Color::YELLOW : OSD::Color::CYAN, - (Config::Get(Config::RA_BADGES_ENABLED)) ? - DecodeBadgeToOSDIcon(AchievementManager::GetInstance().m_game_badge.badge) : - nullptr); + DecodeBadgeToOSDIcon(AchievementManager::GetInstance().m_game_badge.badge)); } void AchievementManager::HandleResetEvent(const rc_client_event_t* client_event) @@ -880,7 +871,7 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 const AchievementManager::BadgeNameFunction function, const UpdatedItems callback_data) { - if (!m_client || !HasAPIToken() || !Config::Get(Config::RA_BADGES_ENABLED)) + if (!m_client || !HasAPIToken()) { m_update_callback(callback_data); if (m_display_welcome_message && badge_type == RC_IMAGE_TYPE_GAME) diff --git a/Source/Core/Core/Config/AchievementSettings.cpp b/Source/Core/Core/Config/AchievementSettings.cpp index 1e20729bdd..63945777cb 100644 --- a/Source/Core/Core/Config/AchievementSettings.cpp +++ b/Source/Core/Core/Config/AchievementSettings.cpp @@ -26,7 +26,6 @@ const Info RA_DISCORD_PRESENCE_ENABLED{ {System::Achievements, "Achievements", "DiscordPresenceEnabled"}, false}; const Info RA_PROGRESS_ENABLED{{System::Achievements, "Achievements", "ProgressEnabled"}, false}; -const Info RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false}; } // namespace Config #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/Core/Config/AchievementSettings.h b/Source/Core/Core/Config/AchievementSettings.h index ae2ecbc8b6..f1552ec59c 100644 --- a/Source/Core/Core/Config/AchievementSettings.h +++ b/Source/Core/Core/Config/AchievementSettings.h @@ -20,7 +20,6 @@ extern const Info RA_ENCORE_ENABLED; extern const Info RA_SPECTATOR_ENABLED; extern const Info RA_DISCORD_PRESENCE_ENABLED; extern const Info RA_PROGRESS_ENABLED; -extern const Info RA_BADGES_ENABLED; } // namespace Config #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index 534b965d78..f563f9cfc9 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -61,7 +61,7 @@ void AchievementBox::UpdateData() color = AchievementManager::GOLD; else if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE) color = AchievementManager::BLUE; - if (Config::Get(Config::RA_BADGES_ENABLED) && badge.name != "") + if (badge.name != "") { QImage i_badge{}; if (i_badge.loadFromData(&badge.badge.front(), static_cast(badge.badge.size()))) diff --git a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp index c148714171..e2fc6addbc 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp @@ -74,7 +74,7 @@ void AchievementHeaderWidget::UpdateData() m_user_icon->setVisible(false); m_user_icon->clear(); m_user_icon->setText({}); - if (Config::Get(Config::RA_BADGES_ENABLED) && !player_badge.name.empty()) + if (!player_badge.name.empty()) { QImage i_user_icon{}; if (i_user_icon.loadFromData(&player_badge.badge.front(), (int)player_badge.badge.size())) @@ -95,7 +95,7 @@ void AchievementHeaderWidget::UpdateData() rc_client_user_game_summary_t game_summary; rc_client_get_user_game_summary(instance.GetClient(), &game_summary); - if (Config::Get(Config::RA_BADGES_ENABLED) && !game_badge.name.empty()) + if (!game_badge.name.empty()) { QImage i_game_icon{}; if (i_game_icon.loadFromData(&game_badge.badge.front(), (int)game_badge.badge.size())) diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp index 62f6a1e0cb..5b8a07d24f 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.cpp @@ -105,11 +105,6 @@ void AchievementSettingsWidget::CreateLayout() tr("Enable progress notifications on achievements.

Displays a brief popup message " "whenever the player makes progress on an achievement that tracks an accumulated value, " "such as 60 out of 120 stars.")); - m_common_badges_enabled_input = new ToolTipCheckBox(tr("Enable Achievement Badges")); - m_common_badges_enabled_input->SetDescription( - tr("Enable achievement badges.

Displays icons for the player, game, and achievements. " - "Simple visual option, but will require a small amount of extra memory and time to " - "download the images.")); m_common_layout->addWidget(m_common_integration_enabled_input); m_common_layout->addWidget(m_common_username_label); @@ -129,7 +124,6 @@ void AchievementSettingsWidget::CreateLayout() m_common_layout->addWidget(m_common_discord_presence_enabled_input); #endif // USE_DISCORD_PRESENCE m_common_layout->addWidget(m_common_progress_enabled_input); - m_common_layout->addWidget(m_common_badges_enabled_input); m_common_layout->setAlignment(Qt::AlignTop); setLayout(m_common_layout); @@ -153,8 +147,6 @@ void AchievementSettingsWidget::ConnectWidgets() &AchievementSettingsWidget::ToggleDiscordPresence); connect(m_common_progress_enabled_input, &QCheckBox::toggled, this, &AchievementSettingsWidget::ToggleProgress); - connect(m_common_badges_enabled_input, &QCheckBox::toggled, this, - &AchievementSettingsWidget::ToggleBadges); } void AchievementSettingsWidget::OnControllerInterfaceConfigure() @@ -214,9 +206,6 @@ void AchievementSettingsWidget::LoadSettings() SignalBlocking(m_common_progress_enabled_input) ->setChecked(Config::Get(Config::RA_PROGRESS_ENABLED)); SignalBlocking(m_common_progress_enabled_input)->setEnabled(enabled); - - SignalBlocking(m_common_badges_enabled_input)->setChecked(Config::Get(Config::RA_BADGES_ENABLED)); - SignalBlocking(m_common_badges_enabled_input)->setEnabled(enabled); } void AchievementSettingsWidget::SaveSettings() @@ -235,7 +224,6 @@ void AchievementSettingsWidget::SaveSettings() m_common_discord_presence_enabled_input->isChecked()); Config::SetBaseOrCurrent(Config::RA_PROGRESS_ENABLED, m_common_progress_enabled_input->isChecked()); - Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_enabled_input->isChecked()); Config::Save(); } @@ -308,11 +296,4 @@ void AchievementSettingsWidget::ToggleProgress() SaveSettings(); } -void AchievementSettingsWidget::ToggleBadges() -{ - SaveSettings(); - AchievementManager::GetInstance().FetchPlayerBadge(); - AchievementManager::GetInstance().FetchGameBadges(); -} - #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h index b8e848c2d1..8d4aa03c2a 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h +++ b/Source/Core/DolphinQt/Achievements/AchievementSettingsWidget.h @@ -38,7 +38,6 @@ private: void ToggleSpectator(); void ToggleDiscordPresence(); void ToggleProgress(); - void ToggleBadges(); QGroupBox* m_common_box; QVBoxLayout* m_common_layout; @@ -56,7 +55,6 @@ private: ToolTipCheckBox* m_common_spectator_enabled_input; ToolTipCheckBox* m_common_discord_presence_enabled_input; ToolTipCheckBox* m_common_progress_enabled_input; - ToolTipCheckBox* m_common_badges_enabled_input; }; #endif // USE_RETRO_ACHIEVEMENTS From dc8f3f6eaea51d054be6007713959426763b611d Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Mon, 13 May 2024 00:15:21 -0400 Subject: [PATCH 2/4] Refactored Achievement Badges into Texture Layers Achievement badges/icons are refactored into the type CustomTextureData::ArraySlice::Level as that is the data type images loaded from the filesystem will be. This includes everything that uses the badges in the Qt UI and OnScreenDisplay, and similarly removes the OSD::Icon type because Level already contains that information. --- Source/Core/Core/AchievementManager.cpp | 68 ++++++++----------- Source/Core/Core/AchievementManager.h | 16 ++--- .../DolphinQt/Achievements/AchievementBox.cpp | 16 ++--- .../Achievements/AchievementHeaderWidget.cpp | 42 ++++++------ .../VideoCommon/Assets/CustomTextureData.cpp | 8 +++ .../VideoCommon/Assets/CustomTextureData.h | 1 + Source/Core/VideoCommon/OnScreenDisplay.cpp | 17 +++-- Source/Core/VideoCommon/OnScreenDisplay.h | 14 ++-- Source/Core/VideoCommon/OnScreenUI.cpp | 2 +- 9 files changed, 83 insertions(+), 101 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index f9ae5fadb5..dd81a6e871 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -23,11 +23,10 @@ #include "Core/System.h" #include "DiscIO/Blob.h" #include "UICommon/DiscordPresence.h" +#include "VideoCommon/Assets/CustomTextureData.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoEvents.h" -static std::unique_ptr DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge); - AchievementManager& AchievementManager::GetInstance() { static AchievementManager s_instance; @@ -306,9 +305,9 @@ const AchievementManager::BadgeStatus& AchievementManager::GetGameBadge() const const AchievementManager::BadgeStatus& AchievementManager::GetAchievementBadge(AchievementId id, bool locked) const { - auto& badge_list = locked ? m_locked_badges : m_locked_badges; - auto itr = badge_list.find(id); - return (itr == badge_list.end()) ? m_default_badge : itr->second; + auto& badge_list = locked ? m_locked_badges : m_unlocked_badges; + // Brief regression - difficult to return a default BadgeStatus, will be fixed in later commit + return badge_list.find(id)->second; } const AchievementManager::LeaderboardStatus* @@ -330,7 +329,7 @@ AchievementManager::RichPresence AchievementManager::GetRichPresence() const return m_rich_presence; } -const AchievementManager::NamedIconMap& AchievementManager::GetChallengeIcons() const +const AchievementManager::NamedBadgeMap& AchievementManager::GetChallengeIcons() const { return m_active_challenges; } @@ -639,8 +638,7 @@ void AchievementManager::DisplayWelcomeMessage() rc_client_get_hardcore_enabled(m_client) ? OSD::Color::YELLOW : OSD::Color::CYAN; if (!m_game_badge.name.empty()) { - OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, - DecodeBadgeToOSDIcon(m_game_badge.badge)); + OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, &m_game_badge.badge); } auto info = rc_client_get_game_info(m_client); if (!info) @@ -671,15 +669,14 @@ void AchievementManager::DisplayWelcomeMessage() void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t* client_event) { - OSD::AddMessage(fmt::format("Unlocked: {} ({})", client_event->achievement->title, - client_event->achievement->points), - OSD::Duration::VERY_LONG, - (rc_client_get_hardcore_enabled(AchievementManager::GetInstance().m_client)) ? - OSD::Color::YELLOW : - OSD::Color::CYAN, - DecodeBadgeToOSDIcon(AchievementManager::GetInstance() - .m_unlocked_badges[client_event->achievement->id] - .badge)); + OSD::AddMessage( + fmt::format("Unlocked: {} ({})", client_event->achievement->title, + client_event->achievement->points), + OSD::Duration::VERY_LONG, + (rc_client_get_hardcore_enabled(AchievementManager::GetInstance().m_client)) ? + OSD::Color::YELLOW : + OSD::Color::CYAN, + &AchievementManager::GetInstance().m_unlocked_badges[client_event->achievement->id].badge); } void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event) @@ -741,7 +738,7 @@ void AchievementManager::HandleAchievementChallengeIndicatorShowEvent( unlocked_iter != unlocked_badges.end()) { AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] = - DecodeBadgeToOSDIcon(unlocked_iter->second.badge); + &unlocked_iter->second.badge; } } @@ -755,12 +752,11 @@ void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( void AchievementManager::HandleAchievementProgressIndicatorShowEvent( const rc_client_event_t* client_event) { - OSD::AddMessage(fmt::format("{} {}", client_event->achievement->title, - client_event->achievement->measured_progress), - OSD::Duration::SHORT, OSD::Color::GREEN, - DecodeBadgeToOSDIcon(AchievementManager::GetInstance() - .m_unlocked_badges[client_event->achievement->id] - .badge)); + OSD::AddMessage( + fmt::format("{} {}", client_event->achievement->title, + client_event->achievement->measured_progress), + OSD::Duration::SHORT, OSD::Color::GREEN, + &AchievementManager::GetInstance().m_unlocked_badges[client_event->achievement->id].badge); } void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event, @@ -777,7 +773,7 @@ void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* clien OSD::AddMessage(fmt::format("Congratulations! {} has {} {}", user_info->display_name, hardcore ? "mastered" : "completed", game_info->title), OSD::Duration::VERY_LONG, hardcore ? OSD::Color::YELLOW : OSD::Color::CYAN, - DecodeBadgeToOSDIcon(AchievementManager::GetInstance().m_game_badge.badge)); + &AchievementManager::GetInstance().m_game_badge.badge); } void AchievementManager::HandleResetEvent(const rc_client_event_t* client_event) @@ -792,20 +788,6 @@ void AchievementManager::HandleServerErrorEvent(const rc_client_event_t* client_ client_event->server_error->api, client_event->server_error->error_message); } -static std::unique_ptr DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge) -{ - if (badge.empty()) - return nullptr; - - auto icon = std::make_unique(); - if (!Common::LoadPNG(badge, &icon->rgba_data, &icon->width, &icon->height)) - { - ERROR_LOG_FMT(ACHIEVEMENTS, "Error decoding badge."); - return nullptr; - } - return icon; -} - void AchievementManager::Request(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client) @@ -914,7 +896,6 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 } rc_api_destroy_request(&api_request); - fetched_badge = std::move(*http_response); INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded badge id {}.", name_to_fetch); std::lock_guard lg{m_lock}; @@ -923,7 +904,12 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 INFO_LOG_FMT(ACHIEVEMENTS, "Requested outdated badge id {}.", name_to_fetch); return; } - badge->badge = std::move(fetched_badge); + + if (!LoadPNGTexture(&badge->badge, *http_response)) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load", + DEFAULT_GAME_BADGE_FILENAME); + } badge->name = std::move(name_to_fetch); m_update_callback(callback_data); diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 5d133e023f..e7aaa672e3 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -22,6 +22,7 @@ #include "Common/HttpRequest.h" #include "Common/WorkQueueThread.h" #include "DiscIO/Volume.h" +#include "VideoCommon/Assets/CustomTextureData.h" namespace Core { @@ -29,11 +30,6 @@ class CPUThreadGuard; class System; } // namespace Core -namespace OSD -{ -struct Icon; -} - class AchievementManager { public: @@ -47,8 +43,8 @@ public: using LeaderboardRank = u32; static constexpr size_t RP_SIZE = 256; using RichPresence = std::array; - using Badge = std::vector; - using NamedIconMap = std::map, std::less<>>; + using Badge = VideoCommon::CustomTextureData::ArraySlice::Level; + using NamedBadgeMap = std::unordered_map; static constexpr size_t MAX_DISPLAYED_LBOARDS = 4; struct BadgeStatus @@ -116,7 +112,7 @@ public: const BadgeStatus& GetAchievementBadge(AchievementId id, bool locked) const; const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id); RichPresence GetRichPresence() const; - const NamedIconMap& GetChallengeIcons() const; + const NamedBadgeMap& GetChallengeIcons() const; std::vector GetActiveLeaderboards() const; void DoState(PointerWrap& p); @@ -134,8 +130,6 @@ private: std::unique_ptr volume; }; - const BadgeStatus m_default_badge; - static void* FilereaderOpenByFilepath(const char* path_utf8); static void* FilereaderOpenByVolume(const char* path_utf8); static void FilereaderSeek(void* file_handle, int64_t offset, int origin); @@ -200,7 +194,7 @@ private: std::chrono::steady_clock::time_point m_last_rp_time = std::chrono::steady_clock::now(); std::unordered_map m_leaderboard_map; - NamedIconMap m_active_challenges; + NamedBadgeMap m_active_challenges; std::vector m_active_leaderboards; Common::WorkQueueThread> m_queue; diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index f563f9cfc9..8b4bccbf31 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -63,15 +63,13 @@ void AchievementBox::UpdateData() color = AchievementManager::BLUE; if (badge.name != "") { - QImage i_badge{}; - if (i_badge.loadFromData(&badge.badge.front(), static_cast(badge.badge.size()))) - { - m_badge->setPixmap(QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, - Qt::SmoothTransformation)); - m_badge->adjustSize(); - m_badge->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); - } + QImage i_badge(&badge.badge.data.front(), badge.badge.width, badge.badge.height, + QImage::Format_RGBA8888); + m_badge->setPixmap( + QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_badge->adjustSize(); + m_badge->setStyleSheet( + QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); } else { diff --git a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp index e2fc6addbc..ffa0bf35e0 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp @@ -76,15 +76,13 @@ void AchievementHeaderWidget::UpdateData() m_user_icon->setText({}); if (!player_badge.name.empty()) { - QImage i_user_icon{}; - if (i_user_icon.loadFromData(&player_badge.badge.front(), (int)player_badge.badge.size())) - { - m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon) - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_user_icon->adjustSize(); - m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent")); - m_user_icon->setVisible(true); - } + QImage i_user_icon(&player_badge.badge.data.front(), player_badge.badge.width, + player_badge.badge.height, QImage::Format_RGBA8888); + m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon) + .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_user_icon->adjustSize(); + m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent")); + m_user_icon->setVisible(true); } m_game_icon->setVisible(false); m_game_icon->clear(); @@ -97,22 +95,20 @@ void AchievementHeaderWidget::UpdateData() if (!game_badge.name.empty()) { - QImage i_game_icon{}; - if (i_game_icon.loadFromData(&game_badge.badge.front(), (int)game_badge.badge.size())) + QImage i_game_icon(&game_badge.badge.data.front(), game_badge.badge.width, + game_badge.badge.height, QImage::Format_RGBA8888); + m_game_icon->setPixmap(QPixmap::fromImage(i_game_icon) + .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_game_icon->adjustSize(); + std::string_view color = AchievementManager::GRAY; + if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements) { - m_game_icon->setPixmap(QPixmap::fromImage(i_game_icon) - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_game_icon->adjustSize(); - std::string_view color = AchievementManager::GRAY; - if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements) - { - color = - instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE; - } - m_game_icon->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); - m_game_icon->setVisible(true); + color = + instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE; } + m_game_icon->setStyleSheet( + QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); + m_game_icon->setVisible(true); } m_name->setText(tr("%1 is playing %2").arg(user_name).arg(game_name)); diff --git a/Source/Core/VideoCommon/Assets/CustomTextureData.cpp b/Source/Core/VideoCommon/Assets/CustomTextureData.cpp index 23af429d11..d30532142a 100644 --- a/Source/Core/VideoCommon/Assets/CustomTextureData.cpp +++ b/Source/Core/VideoCommon/Assets/CustomTextureData.cpp @@ -574,6 +574,14 @@ bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::stri std::vector buffer(file.GetSize()); file.ReadBytes(buffer.data(), file.GetSize()); + return LoadPNGTexture(level, buffer); +} + +bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector& buffer) +{ + if (!level) [[unlikely]] + return false; + if (!Common::LoadPNG(buffer, &level->data, &level->width, &level->height)) return false; diff --git a/Source/Core/VideoCommon/Assets/CustomTextureData.h b/Source/Core/VideoCommon/Assets/CustomTextureData.h index fe15c05eaa..32607f4e88 100644 --- a/Source/Core/VideoCommon/Assets/CustomTextureData.h +++ b/Source/Core/VideoCommon/Assets/CustomTextureData.h @@ -33,4 +33,5 @@ bool LoadDDSTexture(CustomTextureData* texture, const std::string& filename); bool LoadDDSTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename, u32 mip_level); bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::string& filename); +bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector& buffer); } // namespace VideoCommon diff --git a/Source/Core/VideoCommon/OnScreenDisplay.cpp b/Source/Core/VideoCommon/OnScreenDisplay.cpp index bfa8bc5321..c24fee6538 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/OnScreenDisplay.cpp @@ -20,6 +20,7 @@ #include "VideoCommon/AbstractGfx.h" #include "VideoCommon/AbstractTexture.h" +#include "VideoCommon/Assets/CustomTextureData.h" #include "VideoCommon/TextureConfig.h" namespace OSD @@ -36,8 +37,9 @@ static std::atomic s_obscured_pixels_top = 0; struct Message { Message() = default; - Message(std::string text_, u32 duration_, u32 color_, std::unique_ptr icon_ = nullptr) - : text(std::move(text_)), duration(duration_), color(color_), icon(std::move(icon_)) + Message(std::string text_, u32 duration_, u32 color_, + const VideoCommon::CustomTextureData::ArraySlice::Level* icon_ = nullptr) + : text(std::move(text_)), duration(duration_), color(color_), icon(icon_) { timer.Start(); } @@ -48,7 +50,7 @@ struct Message bool ever_drawn = false; bool should_discard = false; u32 color = 0; - std::unique_ptr icon; + const VideoCommon::CustomTextureData::ArraySlice::Level* icon; std::unique_ptr texture; }; static std::multimap s_messages; @@ -95,13 +97,13 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti msg.texture = g_gfx->CreateTexture(tex_config); if (msg.texture) { - msg.texture->Load(0, width, height, width, msg.icon->rgba_data.data(), + msg.texture->Load(0, width, height, width, msg.icon->data.data(), sizeof(u32) * width * height); } else { // don't try again next time - msg.icon.reset(); + msg.icon = nullptr; } } @@ -127,7 +129,7 @@ static float DrawMessage(int index, Message& msg, const ImVec2& position, int ti } void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb, - std::unique_ptr icon) + const VideoCommon::CustomTextureData::ArraySlice::Level* icon) { std::lock_guard lock{s_messages_mutex}; @@ -141,7 +143,8 @@ void AddTypedMessage(MessageType type, std::string message, u32 ms, u32 argb, s_messages.emplace(type, Message(std::move(message), ms, argb, std::move(icon))); } -void AddMessage(std::string message, u32 ms, u32 argb, std::unique_ptr icon) +void AddMessage(std::string message, u32 ms, u32 argb, + const VideoCommon::CustomTextureData::ArraySlice::Level* icon) { std::lock_guard lock{s_messages_mutex}; s_messages.emplace(MessageType::Typeless, Message(std::move(message), ms, argb, std::move(icon))); diff --git a/Source/Core/VideoCommon/OnScreenDisplay.h b/Source/Core/VideoCommon/OnScreenDisplay.h index f566eb0bf1..33d8662744 100644 --- a/Source/Core/VideoCommon/OnScreenDisplay.h +++ b/Source/Core/VideoCommon/OnScreenDisplay.h @@ -10,6 +10,8 @@ #include "Common/CommonTypes.h" +#include "VideoCommon/Assets/CustomTextureData.h" + namespace OSD { enum class MessageType @@ -37,18 +39,12 @@ constexpr u32 NORMAL = 5000; constexpr u32 VERY_LONG = 10000; }; // namespace Duration -struct Icon -{ - std::vector rgba_data; - u32 width = 0; - u32 height = 0; -}; // struct Icon - // On-screen message display (colored yellow by default) void AddMessage(std::string message, u32 ms = Duration::SHORT, u32 argb = Color::YELLOW, - std::unique_ptr icon = nullptr); + const VideoCommon::CustomTextureData::ArraySlice::Level* icon = nullptr); void AddTypedMessage(MessageType type, std::string message, u32 ms = Duration::SHORT, - u32 argb = Color::YELLOW, std::unique_ptr icon = nullptr); + u32 argb = Color::YELLOW, + const VideoCommon::CustomTextureData::ArraySlice::Level* icon = nullptr); // Draw the current messages on the screen. Only call once per frame. void DrawMessages(); diff --git a/Source/Core/VideoCommon/OnScreenUI.cpp b/Source/Core/VideoCommon/OnScreenUI.cpp index 8f85db85b0..1231851c9a 100644 --- a/Source/Core/VideoCommon/OnScreenUI.cpp +++ b/Source/Core/VideoCommon/OnScreenUI.cpp @@ -358,7 +358,7 @@ void OnScreenUI::DrawChallengesAndLeaderboards() TextureConfig tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0, AbstractTextureType::Texture_2DArray); auto res = m_challenge_texture_map.insert_or_assign(name, g_gfx->CreateTexture(tex_config)); - res.first->second->Load(0, width, height, width, icon->rgba_data.data(), + res.first->second->Load(0, width, height, width, icon->data.data(), sizeof(u32) * width * height); } for (auto& [name, texture] : m_challenge_texture_map) From 3b61b6d81690a715327c4cf7329538424b0df023 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Mon, 13 May 2024 18:53:06 -0400 Subject: [PATCH 3/4] Add Default Achievement Badges The defaults get loaded in by Dolphin at emulator start, and are used if the badge that would normally be displayed has not for whatever reason been downloaded yet. Badges attached to this PR are placeholders (MayIMilae is designing permanent badges) and reside in Sys\Load\RetroAchievements. --- Data/Sys/Resources/achievements_game.png | Bin 0 -> 460 bytes Data/Sys/Resources/achievements_locked.png | Bin 0 -> 235 bytes Data/Sys/Resources/achievements_player.png | Bin 0 -> 335 bytes Data/Sys/Resources/achievements_unlocked.png | Bin 0 -> 235 bytes Source/Core/Core/AchievementManager.cpp | 89 ++++++++++++++----- Source/Core/Core/AchievementManager.h | 9 ++ 6 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 Data/Sys/Resources/achievements_game.png create mode 100644 Data/Sys/Resources/achievements_locked.png create mode 100644 Data/Sys/Resources/achievements_player.png create mode 100644 Data/Sys/Resources/achievements_unlocked.png diff --git a/Data/Sys/Resources/achievements_game.png b/Data/Sys/Resources/achievements_game.png new file mode 100644 index 0000000000000000000000000000000000000000..624c3a917d1b8bcb726ec283180320fc0bb1bf91 GIT binary patch literal 460 zcmV;-0W2G`Ja7*`Nz~k$(%p{e;@%EMFTov9IF`g?@Ff)n8vj|o z2)J?BJqW60WGBdyoqr;vz(6C|IeBl}K$o)%M)}`~(Ii;6ITBFNYzc(wM&#ldlBT%I zD3T_7bPP$8LSy7OvV2)Wn)$6!ph3ZHM6ULxD6TlhT@aFg5Two$_m~J$TIC!H>I!~L zR7c@nBQ!2Lo8t1@MB0i^3V_eZpNaPdB?5XX)8v4r1_9DN7ptIq&VHhL^m|ayJwrV4 zvh@qh748D(`x(vke#vu!yUyT3xi;>DR=pse*k!l~R(il+adZczD@WfZj3Q~{`8@QI zJmIE~k&pR}@#uMaj-gP50U4L-2dY0tjEZKUBAjE{Wh}K)8Q8uJ?9W5KjQ_G2<+?J< zGPSXz@p%E))s&^R6U#a;i@v-9_&R@Jd2Q(VU;F@Bos3MQ{Y%^c0000@jRu?6^qxB}__|Nk$&IsYz@wZPNG zF+?MH>&1<{hZO`^FZ63@NHzva@VX_7xGh-X5c7k*Ge@&E_({vs_FDBHMo&cQoR6;h zAd;P;G08(+N-)3U5c{2vx;IWRp7@~Tx^70;kr%Z+Rg9TAPXgvH`c$xpG0?DK$qWN^ zzpv~z-_B>`UnvOq<5*U-|Hg(JFZ7nrJv4oV#>Ss>O-i?KK7G!P_qx;eKf4Z`GcEfm i-ufZ_<4eo0Ec&9_UAYAgp)-JPW$<+Mb6Mw<&;$U4bYYVK literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/achievements_player.png b/Data/Sys/Resources/achievements_player.png new file mode 100644 index 0000000000000000000000000000000000000000..d99412b839e7c00a51d8fa97ae88ad1dfdac2eec GIT binary patch literal 335 zcmV-V0kHmwP)^d;cJilmOLqP-!lc-LVG9nq1thOm?ELwG2r;R|?- z4`6LLulpL@NK0;=MBb<1qnlQ8RBS|TMGiz+DI#eHQM7a7 z7b+|#GPSf8&Ma5q<<6k%(Ij&oeQYhC>Wv0z^p>TC1`gSQC^vBXRW;mygpUcgNz%j3oLM-#@^TM$;M1!{t-V*zM4oB97BB1RwFHkE8q5*=b2o^}|1qbAY9qN}C h`~dJxoAf$=h+l#F>W9OIztI2y002ovPDHLkV1lzal9&Jh literal 0 HcmV?d00001 diff --git a/Data/Sys/Resources/achievements_unlocked.png b/Data/Sys/Resources/achievements_unlocked.png new file mode 100644 index 0000000000000000000000000000000000000000..e95e60558a1c7f8de88eeac45c61a3abf8700b06 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRu?6^qxc)!M_y7NY*W)KUfFcV# zT^vI+g127W$a`2pfb~MZhK6Kgpaid5vWVM)B@Qt^*gJDHTZ5mpEN!n<|6%k*q|W*1 zst+RBDH@YJ)TIRTI}Wkm`KWv21mlShO0Mf>gdKTN+f&7une!xI?xIfxix>k98bfIoG6g`{vWh jpW>|_;y=E${K}#)s@;`a;1D_k=vD?#S3j3^P6 #include +#include "Common/CommonPaths.h" +#include "Common/FileUtil.h" #include "Common/Image.h" #include "Common/Logging/Log.h" #include "Common/ScopeGuard.h" @@ -35,6 +37,7 @@ AchievementManager& AchievementManager::GetInstance() void AchievementManager::Init() { + LoadDefaultBadges(); if (!m_client && Config::Get(Config::RA_ENABLED)) { m_client = rc_client_create(MemoryPeeker, Request); @@ -499,6 +502,55 @@ void AchievementManager::FilereaderClose(void* file_handle) delete static_cast(file_handle); } +void AchievementManager::LoadDefaultBadges() +{ + std::lock_guard lg{m_lock}; + + std::string directory = File::GetSysDirectory() + DIR_SEP + RESOURCES_DIR + DIR_SEP; + + if (m_default_player_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_player_badge, + fmt::format("{}{}", directory, DEFAULT_PLAYER_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default player badge '{}' failed to load", + DEFAULT_PLAYER_BADGE_FILENAME); + } + } + m_player_badge.badge = m_default_player_badge; + + if (m_default_game_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_game_badge, + fmt::format("{}{}", directory, DEFAULT_GAME_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load", + DEFAULT_GAME_BADGE_FILENAME); + } + } + m_game_badge.badge = m_default_game_badge; + + if (m_default_unlocked_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_unlocked_badge, + fmt::format("{}{}", directory, DEFAULT_UNLOCKED_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default unlocked achievement badge '{}' failed to load", + DEFAULT_UNLOCKED_BADGE_FILENAME); + } + } + + if (m_default_locked_badge.data.empty()) + { + if (!LoadPNGTexture(&m_default_locked_badge, + fmt::format("{}{}", directory, DEFAULT_LOCKED_BADGE_FILENAME))) + { + ERROR_LOG_FMT(ACHIEVEMENTS, "Default locked achievement badge '{}' failed to load", + DEFAULT_LOCKED_BADGE_FILENAME); + } + } +} + void AchievementManager::LoginCallback(int result, const char* error_message, rc_client_t* client, void* userdata) { @@ -669,14 +721,13 @@ void AchievementManager::DisplayWelcomeMessage() void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t* client_event) { - OSD::AddMessage( - fmt::format("Unlocked: {} ({})", client_event->achievement->title, - client_event->achievement->points), - OSD::Duration::VERY_LONG, - (rc_client_get_hardcore_enabled(AchievementManager::GetInstance().m_client)) ? - OSD::Color::YELLOW : - OSD::Color::CYAN, - &AchievementManager::GetInstance().m_unlocked_badges[client_event->achievement->id].badge); + const auto& instance = AchievementManager::GetInstance(); + OSD::AddMessage(fmt::format("Unlocked: {} ({})", client_event->achievement->title, + client_event->achievement->points), + OSD::Duration::VERY_LONG, + (rc_client_get_hardcore_enabled(instance.m_client)) ? OSD::Color::YELLOW : + OSD::Color::CYAN, + &instance.GetAchievementBadge(client_event->achievement->id, false).badge); } void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event) @@ -733,13 +784,11 @@ void AchievementManager::HandleLeaderboardTrackerHideEvent(const rc_client_event void AchievementManager::HandleAchievementChallengeIndicatorShowEvent( const rc_client_event_t* client_event) { - auto& unlocked_badges = AchievementManager::GetInstance().m_unlocked_badges; - if (const auto unlocked_iter = unlocked_badges.find(client_event->achievement->id); - unlocked_iter != unlocked_badges.end()) - { - AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] = - &unlocked_iter->second.badge; - } + auto& instance = AchievementManager::GetInstance(); + instance.m_active_challenges[client_event->achievement->badge_name] = + &AchievementManager::GetInstance() + .GetAchievementBadge(client_event->achievement->id, false) + .badge; } void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( @@ -752,11 +801,11 @@ void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( void AchievementManager::HandleAchievementProgressIndicatorShowEvent( const rc_client_event_t* client_event) { - OSD::AddMessage( - fmt::format("{} {}", client_event->achievement->title, - client_event->achievement->measured_progress), - OSD::Duration::SHORT, OSD::Color::GREEN, - &AchievementManager::GetInstance().m_unlocked_badges[client_event->achievement->id].badge); + const auto& instance = AchievementManager::GetInstance(); + OSD::AddMessage(fmt::format("{} {}", client_event->achievement->title, + client_event->achievement->measured_progress), + OSD::Duration::SHORT, OSD::Color::GREEN, + &instance.GetAchievementBadge(client_event->achievement->id, false).badge); } void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event, diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index e7aaa672e3..17abceeaa8 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -53,6 +53,10 @@ public: Badge badge{}; }; + static constexpr std::string_view DEFAULT_PLAYER_BADGE_FILENAME = "achievements_player.png"; + static constexpr std::string_view DEFAULT_GAME_BADGE_FILENAME = "achievements_game.png"; + static constexpr std::string_view DEFAULT_LOCKED_BADGE_FILENAME = "achievements_locked.png"; + static constexpr std::string_view DEFAULT_UNLOCKED_BADGE_FILENAME = "achievements_unlocked.png"; static constexpr std::string_view GRAY = "transparent"; static constexpr std::string_view GOLD = "#FFD700"; static constexpr std::string_view BLUE = "#0B71C1"; @@ -137,6 +141,7 @@ private: static size_t FilereaderRead(void* file_handle, void* buffer, size_t requested_bytes); static void FilereaderClose(void* file_handle); + void LoadDefaultBadges(); static void LoginCallback(int result, const char* error_message, rc_client_t* client, void* userdata); @@ -181,6 +186,10 @@ private: bool m_is_runtime_initialized = false; UpdateCallback m_update_callback = [](const UpdatedItems&) {}; std::unique_ptr m_loading_volume; + Badge m_default_player_badge; + Badge m_default_game_badge; + Badge m_default_unlocked_badge; + Badge m_default_locked_badge; BadgeStatus m_player_badge; Hash m_game_hash{}; u32 m_game_id = 0; From 1e9e0cd2d7cf1e28fcbc038e3d26a02ece549ec0 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Mon, 13 May 2024 19:21:55 -0400 Subject: [PATCH 4/4] Remove names from badge objects The names attached to the BadgeStatus object are obsolete and unneeded and are removed from everything that uses them. All BadgeStatus references are updated to just Badge. --- Source/Core/Core/AchievementManager.cpp | 47 +++++++++--------- Source/Core/Core/AchievementManager.h | 22 +++------ .../DolphinQt/Achievements/AchievementBox.cpp | 19 ++----- .../Achievements/AchievementHeaderWidget.cpp | 49 ++++++++----------- 4 files changed, 58 insertions(+), 79 deletions(-) diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index dec365b290..360a332eb0 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -280,7 +280,7 @@ u32 AchievementManager::GetPlayerScore() const return user->score; } -const AchievementManager::BadgeStatus& AchievementManager::GetPlayerBadge() const +const AchievementManager::Badge& AchievementManager::GetPlayerBadge() const { return m_player_badge; } @@ -300,17 +300,19 @@ rc_api_fetch_game_data_response_t* AchievementManager::GetGameData() return &m_game_data; } -const AchievementManager::BadgeStatus& AchievementManager::GetGameBadge() const +const AchievementManager::Badge& AchievementManager::GetGameBadge() const { return m_game_badge; } -const AchievementManager::BadgeStatus& AchievementManager::GetAchievementBadge(AchievementId id, - bool locked) const +const AchievementManager::Badge& AchievementManager::GetAchievementBadge(AchievementId id, + bool locked) const { auto& badge_list = locked ? m_locked_badges : m_unlocked_badges; - // Brief regression - difficult to return a default BadgeStatus, will be fixed in later commit - return badge_list.find(id)->second; + auto itr = badge_list.find(id); + return (itr != badge_list.end() && itr->second.data.size() > 0) ? + itr->second : + (locked ? m_default_locked_badge : m_default_unlocked_badge); } const AchievementManager::LeaderboardStatus* @@ -395,7 +397,9 @@ void AchievementManager::CloseGame() { m_active_challenges.clear(); m_active_leaderboards.clear(); - m_game_badge.name.clear(); + m_game_badge.width = 0; + m_game_badge.height = 0; + m_game_badge.data.clear(); m_unlocked_badges.clear(); m_locked_badges.clear(); m_leaderboard_map.clear(); @@ -417,7 +421,9 @@ void AchievementManager::Logout() { std::lock_guard lg{m_lock}; CloseGame(); - m_player_badge.name.clear(); + m_player_badge.width = 0; + m_player_badge.height = 0; + m_player_badge.data.clear(); Config::SetBaseOrCurrent(Config::RA_API_TOKEN, ""); } @@ -517,7 +523,7 @@ void AchievementManager::LoadDefaultBadges() DEFAULT_PLAYER_BADGE_FILENAME); } } - m_player_badge.badge = m_default_player_badge; + m_player_badge = m_default_player_badge; if (m_default_game_badge.data.empty()) { @@ -528,7 +534,7 @@ void AchievementManager::LoadDefaultBadges() DEFAULT_GAME_BADGE_FILENAME); } } - m_game_badge.badge = m_default_game_badge; + m_game_badge = m_default_game_badge; if (m_default_unlocked_badge.data.empty()) { @@ -688,10 +694,8 @@ void AchievementManager::DisplayWelcomeMessage() m_display_welcome_message = false; const u32 color = rc_client_get_hardcore_enabled(m_client) ? OSD::Color::YELLOW : OSD::Color::CYAN; - if (!m_game_badge.name.empty()) - { - OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, &m_game_badge.badge); - } + + OSD::AddMessage("", OSD::Duration::VERY_LONG, OSD::Color::GREEN, &m_game_badge); auto info = rc_client_get_game_info(m_client); if (!info) { @@ -727,7 +731,7 @@ void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t OSD::Duration::VERY_LONG, (rc_client_get_hardcore_enabled(instance.m_client)) ? OSD::Color::YELLOW : OSD::Color::CYAN, - &instance.GetAchievementBadge(client_event->achievement->id, false).badge); + &instance.GetAchievementBadge(client_event->achievement->id, false)); } void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event) @@ -786,9 +790,7 @@ void AchievementManager::HandleAchievementChallengeIndicatorShowEvent( { auto& instance = AchievementManager::GetInstance(); instance.m_active_challenges[client_event->achievement->badge_name] = - &AchievementManager::GetInstance() - .GetAchievementBadge(client_event->achievement->id, false) - .badge; + &AchievementManager::GetInstance().GetAchievementBadge(client_event->achievement->id, false); } void AchievementManager::HandleAchievementChallengeIndicatorHideEvent( @@ -805,7 +807,7 @@ void AchievementManager::HandleAchievementProgressIndicatorShowEvent( OSD::AddMessage(fmt::format("{} {}", client_event->achievement->title, client_event->achievement->measured_progress), OSD::Duration::SHORT, OSD::Color::GREEN, - &instance.GetAchievementBadge(client_event->achievement->id, false).badge); + &instance.GetAchievementBadge(client_event->achievement->id, false)); } void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event, @@ -822,7 +824,7 @@ void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* clien OSD::AddMessage(fmt::format("Congratulations! {} has {} {}", user_info->display_name, hardcore ? "mastered" : "completed", game_info->title), OSD::Duration::VERY_LONG, hardcore ? OSD::Color::YELLOW : OSD::Color::CYAN, - &AchievementManager::GetInstance().m_game_badge.badge); + &AchievementManager::GetInstance().m_game_badge); } void AchievementManager::HandleResetEvent(const rc_client_event_t* client_event) @@ -898,7 +900,7 @@ u32 AchievementManager::MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_ return num_bytes; } -void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 badge_type, +void AchievementManager::FetchBadge(AchievementManager::Badge* badge, u32 badge_type, const AchievementManager::BadgeNameFunction function, const UpdatedItems callback_data) { @@ -954,12 +956,11 @@ void AchievementManager::FetchBadge(AchievementManager::BadgeStatus* badge, u32 return; } - if (!LoadPNGTexture(&badge->badge, *http_response)) + if (!LoadPNGTexture(badge, *http_response)) { ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load", DEFAULT_GAME_BADGE_FILENAME); } - badge->name = std::move(name_to_fetch); m_update_callback(callback_data); }); diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index 17abceeaa8..3fdb5b2591 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -47,12 +47,6 @@ public: using NamedBadgeMap = std::unordered_map; static constexpr size_t MAX_DISPLAYED_LBOARDS = 4; - struct BadgeStatus - { - std::string name = ""; - Badge badge{}; - }; - static constexpr std::string_view DEFAULT_PLAYER_BADGE_FILENAME = "achievements_player.png"; static constexpr std::string_view DEFAULT_GAME_BADGE_FILENAME = "achievements_game.png"; static constexpr std::string_view DEFAULT_LOCKED_BADGE_FILENAME = "achievements_locked.png"; @@ -108,12 +102,12 @@ public: void SetSpectatorMode(); std::string_view GetPlayerDisplayName() const; u32 GetPlayerScore() const; - const BadgeStatus& GetPlayerBadge() const; + const Badge& GetPlayerBadge() const; std::string_view GetGameDisplayName() const; rc_client_t* GetClient(); rc_api_fetch_game_data_response_t* GetGameData(); - const BadgeStatus& GetGameBadge() const; - const BadgeStatus& GetAchievementBadge(AchievementId id, bool locked) const; + const Badge& GetGameBadge() const; + const Badge& GetAchievementBadge(AchievementId id, bool locked) const; const LeaderboardStatus* GetLeaderboardInfo(AchievementId leaderboard_id); RichPresence GetRichPresence() const; const NamedBadgeMap& GetChallengeIcons() const; @@ -176,7 +170,7 @@ private: static void Request(const rc_api_request_t* request, rc_client_server_callback_t callback, void* callback_data, rc_client_t* client); static u32 MemoryPeeker(u32 address, u8* buffer, u32 num_bytes, rc_client_t* client); - void FetchBadge(BadgeStatus* badge, u32 badge_type, const BadgeNameFunction function, + void FetchBadge(Badge* badge, u32 badge_type, const BadgeNameFunction function, const UpdatedItems callback_data); static void EventHandler(const rc_client_event_t* event, rc_client_t* client); @@ -190,15 +184,15 @@ private: Badge m_default_game_badge; Badge m_default_unlocked_badge; Badge m_default_locked_badge; - BadgeStatus m_player_badge; + Badge m_player_badge; Hash m_game_hash{}; u32 m_game_id = 0; rc_api_fetch_game_data_response_t m_game_data{}; bool m_is_game_loaded = false; - BadgeStatus m_game_badge; + Badge m_game_badge; bool m_display_welcome_message = false; - std::unordered_map m_unlocked_badges; - std::unordered_map m_locked_badges; + std::unordered_map m_unlocked_badges; + std::unordered_map m_locked_badges; RichPresence m_rich_presence; std::chrono::steady_clock::time_point m_last_rp_time = std::chrono::steady_clock::now(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index 8b4bccbf31..4b54851b39 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -61,20 +61,11 @@ void AchievementBox::UpdateData() color = AchievementManager::GOLD; else if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_SOFTCORE) color = AchievementManager::BLUE; - if (badge.name != "") - { - QImage i_badge(&badge.badge.data.front(), badge.badge.width, badge.badge.height, - QImage::Format_RGBA8888); - m_badge->setPixmap( - QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_badge->adjustSize(); - m_badge->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); - } - else - { - m_badge->setText({}); - } + QImage i_badge(&badge.data.front(), badge.width, badge.height, QImage::Format_RGBA8888); + m_badge->setPixmap( + QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_badge->adjustSize(); + m_badge->setStyleSheet(QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); if (m_achievement->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED) { diff --git a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp index ffa0bf35e0..c1976e2752 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementHeaderWidget.cpp @@ -68,22 +68,20 @@ void AchievementHeaderWidget::UpdateData() QString user_name = QtUtils::FromStdString(instance.GetPlayerDisplayName()); QString game_name = QtUtils::FromStdString(instance.GetGameDisplayName()); - AchievementManager::BadgeStatus player_badge = instance.GetPlayerBadge(); - AchievementManager::BadgeStatus game_badge = instance.GetGameBadge(); + const AchievementManager::Badge& player_badge = instance.GetPlayerBadge(); + const AchievementManager::Badge& game_badge = instance.GetGameBadge(); m_user_icon->setVisible(false); m_user_icon->clear(); m_user_icon->setText({}); - if (!player_badge.name.empty()) - { - QImage i_user_icon(&player_badge.badge.data.front(), player_badge.badge.width, - player_badge.badge.height, QImage::Format_RGBA8888); - m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon) - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_user_icon->adjustSize(); - m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent")); - m_user_icon->setVisible(true); - } + QImage i_user_icon(&player_badge.data.front(), player_badge.width, player_badge.height, + QImage::Format_RGBA8888); + m_user_icon->setPixmap(QPixmap::fromImage(i_user_icon) + .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_user_icon->adjustSize(); + m_user_icon->setStyleSheet(QStringLiteral("border: 4px solid transparent")); + m_user_icon->setVisible(true); + m_game_icon->setVisible(false); m_game_icon->clear(); m_game_icon->setText({}); @@ -92,24 +90,19 @@ void AchievementHeaderWidget::UpdateData() { rc_client_user_game_summary_t game_summary; rc_client_get_user_game_summary(instance.GetClient(), &game_summary); - - if (!game_badge.name.empty()) + QImage i_game_icon(&game_badge.data.front(), game_badge.width, game_badge.height, + QImage::Format_RGBA8888); + m_game_icon->setPixmap(QPixmap::fromImage(i_game_icon) + .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + m_game_icon->adjustSize(); + std::string_view color = AchievementManager::GRAY; + if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements) { - QImage i_game_icon(&game_badge.badge.data.front(), game_badge.badge.width, - game_badge.badge.height, QImage::Format_RGBA8888); - m_game_icon->setPixmap(QPixmap::fromImage(i_game_icon) - .scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - m_game_icon->adjustSize(); - std::string_view color = AchievementManager::GRAY; - if (game_summary.num_core_achievements == game_summary.num_unlocked_achievements) - { - color = - instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE; - } - m_game_icon->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); - m_game_icon->setVisible(true); + color = instance.IsHardcoreModeActive() ? AchievementManager::GOLD : AchievementManager::BLUE; } + m_game_icon->setStyleSheet( + QStringLiteral("border: 4px solid %1").arg(QtUtils::FromStdString(color))); + m_game_icon->setVisible(true); m_name->setText(tr("%1 is playing %2").arg(user_name).arg(game_name)); m_points->setText(tr("%1 has unlocked %2/%3 achievements worth %4/%5 points")