diff --git a/Source/Core/Core/AchievementManager.cpp b/Source/Core/Core/AchievementManager.cpp index 4d4700e857..a40df12104 100644 --- a/Source/Core/Core/AchievementManager.cpp +++ b/Source/Core/Core/AchievementManager.cpp @@ -306,6 +306,11 @@ AchievementManager::PointSpread AchievementManager::TallyScore() const return spread; } +rc_client_t* AchievementManager::GetClient() +{ + return m_client; +} + rc_api_fetch_game_data_response_t* AchievementManager::GetGameData() { return &m_game_data; @@ -316,10 +321,20 @@ const AchievementManager::BadgeStatus& AchievementManager::GetGameBadge() const return m_game_badge; } -const AchievementManager::UnlockStatus& +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; +} + +const AchievementManager::UnlockStatus* AchievementManager::GetUnlockStatus(AchievementId achievement_id) const { - return m_unlock_map.at(achievement_id); + if (m_unlock_map.count(achievement_id) < 1) + return nullptr; + return &m_unlock_map.at(achievement_id); } AchievementManager::ResponseType diff --git a/Source/Core/Core/AchievementManager.h b/Source/Core/Core/AchievementManager.h index eb1cb3d740..6cd7d39a90 100644 --- a/Source/Core/Core/AchievementManager.h +++ b/Source/Core/Core/AchievementManager.h @@ -136,9 +136,11 @@ public: const BadgeStatus& GetPlayerBadge() const; std::string_view GetGameDisplayName() const; PointSpread TallyScore() const; + rc_client_t* GetClient(); rc_api_fetch_game_data_response_t* GetGameData(); const BadgeStatus& GetGameBadge() const; - const UnlockStatus& GetUnlockStatus(AchievementId achievement_id) const; + const BadgeStatus& GetAchievementBadge(AchievementId id, bool locked) const; + const UnlockStatus* GetUnlockStatus(AchievementId achievement_id) const; AchievementManager::ResponseType GetAchievementProgress(AchievementId achievement_id, u32* value, u32* target); const std::unordered_map& GetLeaderboardsInfo() const; @@ -163,6 +165,8 @@ 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); diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp new file mode 100644 index 0000000000..534b965d78 --- /dev/null +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -0,0 +1,104 @@ +// Copyright 2024 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifdef USE_RETRO_ACHIEVEMENTS +#include "DolphinQt/Achievements/AchievementBox.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "Core/AchievementManager.h" +#include "Core/Config/AchievementSettings.h" + +#include "DolphinQt/QtUtils/FromStdString.h" + +AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achievement) + : QGroupBox(parent), m_achievement(achievement) +{ + const auto& instance = AchievementManager::GetInstance(); + if (!instance.IsGameLoaded()) + return; + + m_badge = new QLabel(); + QLabel* title = new QLabel(QString::fromUtf8(achievement->title, strlen(achievement->title))); + QLabel* description = + new QLabel(QString::fromUtf8(achievement->description, strlen(achievement->description))); + QLabel* points = new QLabel(tr("%1 points").arg(achievement->points)); + m_status = new QLabel(); + m_progress_bar = new QProgressBar(); + QSizePolicy sp_retain = m_progress_bar->sizePolicy(); + sp_retain.setRetainSizeWhenHidden(true); + m_progress_bar->setSizePolicy(sp_retain); + + QVBoxLayout* a_col_right = new QVBoxLayout(); + a_col_right->addWidget(title); + a_col_right->addWidget(description); + a_col_right->addWidget(points); + a_col_right->addWidget(m_status); + a_col_right->addWidget(m_progress_bar); + QHBoxLayout* a_total = new QHBoxLayout(); + a_total->addWidget(m_badge); + a_total->addLayout(a_col_right); + setLayout(a_total); + + UpdateData(); +} + +void AchievementBox::UpdateData() +{ + std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; + + const auto& badge = AchievementManager::GetInstance().GetAchievementBadge( + m_achievement->id, m_achievement->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED); + std::string_view color = AchievementManager::GRAY; + if (m_achievement->unlocked & RC_CLIENT_ACHIEVEMENT_UNLOCKED_HARDCORE) + 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 != "") + { + 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))); + } + } + else + { + m_badge->setText({}); + } + + if (m_achievement->state == RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED) + { + m_status->setText( + tr("Unlocked at %1") + .arg(QDateTime::fromSecsSinceEpoch(m_achievement->unlock_time).toString())); + } + else + { + m_status->setText(tr("Locked")); + } + + if (m_achievement->measured_percent > 0.000) + { + m_progress_bar->setRange(0, 100); + m_progress_bar->setValue(m_achievement->measured_percent); + m_progress_bar->setVisible(true); + } + else + { + m_progress_bar->setVisible(false); + } +} + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.h b/Source/Core/DolphinQt/Achievements/AchievementBox.h new file mode 100644 index 0000000000..1bb7ce56ad --- /dev/null +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.h @@ -0,0 +1,32 @@ +// Copyright 2024 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef USE_RETRO_ACHIEVEMENTS +#include + +#include "Core/AchievementManager.h" + +class QLabel; +class QProgressBar; +class QWidget; + +struct rc_api_achievement_definition_t; + +class AchievementBox final : public QGroupBox +{ + Q_OBJECT +public: + explicit AchievementBox(QWidget* parent, rc_client_achievement_t* achievement); + void UpdateData(); + +private: + QLabel* m_badge; + QLabel* m_status; + QProgressBar* m_progress_bar; + + rc_client_achievement_t* m_achievement; +}; + +#endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp index 39cc36948c..bfa008db5a 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp @@ -18,11 +18,10 @@ #include "Core/Config/MainSettings.h" #include "Core/Core.h" +#include "DolphinQt/Achievements/AchievementBox.h" #include "DolphinQt/QtUtils/ClearLayoutRecursively.h" #include "DolphinQt/Settings.h" -static constexpr bool hardcore_mode_enabled = false; - AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget(parent) { m_common_box = new QGroupBox(); @@ -42,88 +41,6 @@ AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget( setLayout(layout); } -QGroupBox* -AchievementProgressWidget::CreateAchievementBox(const rc_api_achievement_definition_t* achievement) -{ - const auto& instance = AchievementManager::GetInstance(); - if (!instance.IsGameLoaded()) - return new QGroupBox(); - - QLabel* a_badge = new QLabel(); - const auto unlock_status = instance.GetUnlockStatus(achievement->id); - const AchievementManager::BadgeStatus* badge = &unlock_status.locked_badge; - std::string_view color = AchievementManager::GRAY; - if (unlock_status.remote_unlock_status == AchievementManager::UnlockStatus::UnlockType::HARDCORE) - { - badge = &unlock_status.unlocked_badge; - color = AchievementManager::GOLD; - } - else if (hardcore_mode_enabled && unlock_status.session_unlock_count > 1) - { - badge = &unlock_status.unlocked_badge; - color = AchievementManager::GOLD; - } - else if (unlock_status.remote_unlock_status == - AchievementManager::UnlockStatus::UnlockType::SOFTCORE) - { - badge = &unlock_status.unlocked_badge; - color = AchievementManager::BLUE; - } - else if (unlock_status.session_unlock_count > 1) - { - badge = &unlock_status.unlocked_badge; - color = AchievementManager::BLUE; - } - if (Config::Get(Config::RA_BADGES_ENABLED) && badge->name != "") - { - QImage i_badge{}; - if (i_badge.loadFromData(&badge->badge.front(), (int)badge->badge.size())) - { - a_badge->setPixmap(QPixmap::fromImage(i_badge).scaled(64, 64, Qt::KeepAspectRatio, - Qt::SmoothTransformation)); - a_badge->adjustSize(); - a_badge->setStyleSheet( - QStringLiteral("border: 4px solid %1").arg(QString::fromStdString(std::string(color)))); - } - } - - QLabel* a_title = new QLabel(QString::fromUtf8(achievement->title, strlen(achievement->title))); - QLabel* a_description = - new QLabel(QString::fromUtf8(achievement->description, strlen(achievement->description))); - QLabel* a_points = new QLabel(tr("%1 points").arg(achievement->points)); - QLabel* a_status = new QLabel(GetStatusString(achievement->id)); - QProgressBar* a_progress_bar = new QProgressBar(); - QSizePolicy sp_retain = a_progress_bar->sizePolicy(); - sp_retain.setRetainSizeWhenHidden(true); - a_progress_bar->setSizePolicy(sp_retain); - unsigned int value = 0; - unsigned int target = 0; - if (AchievementManager::GetInstance().GetAchievementProgress(achievement->id, &value, &target) == - AchievementManager::ResponseType::SUCCESS && - target > 0) - { - a_progress_bar->setRange(0, target); - a_progress_bar->setValue(value); - } - else - { - a_progress_bar->setVisible(false); - } - - QVBoxLayout* a_col_right = new QVBoxLayout(); - a_col_right->addWidget(a_title); - a_col_right->addWidget(a_description); - a_col_right->addWidget(a_points); - a_col_right->addWidget(a_status); - a_col_right->addWidget(a_progress_bar); - QHBoxLayout* a_total = new QHBoxLayout(); - a_total->addWidget(a_badge); - a_total->addLayout(a_col_right); - QGroupBox* a_group_box = new QGroupBox(); - a_group_box->setLayout(a_total); - return a_group_box; -} - void AchievementProgressWidget::UpdateData() { ClearLayoutRecursively(m_common_layout); @@ -132,34 +49,18 @@ void AchievementProgressWidget::UpdateData() if (!instance.IsGameLoaded()) return; - const auto* game_data = instance.GetGameData(); - for (u32 ix = 0; ix < game_data->num_achievements; ix++) + auto* client = instance.GetClient(); + auto* achievement_list = + rc_client_create_achievement_list(client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL, + RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_LOCK_STATE); + for (u32 ix = 0; ix < achievement_list->num_buckets; ix++) { - m_common_layout->addWidget(CreateAchievementBox(game_data->achievements + ix)); - } -} - -QString AchievementProgressWidget::GetStatusString(u32 achievement_id) const -{ - const auto unlock_status = AchievementManager::GetInstance().GetUnlockStatus(achievement_id); - if (unlock_status.session_unlock_count > 0) - { - if (Config::Get(Config::RA_ENCORE_ENABLED)) + for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++) { - return tr("Unlocked %1 times this session").arg(unlock_status.session_unlock_count); + m_common_layout->addWidget( + new AchievementBox(this, achievement_list->buckets[ix].achievements[jx])); } - return tr("Unlocked this session"); } - switch (unlock_status.remote_unlock_status) - { - case AchievementManager::UnlockStatus::UnlockType::LOCKED: - return tr("Locked"); - case AchievementManager::UnlockStatus::UnlockType::SOFTCORE: - return tr("Unlocked (Casual)"); - case AchievementManager::UnlockStatus::UnlockType::HARDCORE: - return tr("Unlocked"); - } - return {}; } #endif // USE_RETRO_ACHIEVEMENTS diff --git a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.h b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.h index b1e09e40d8..32d2754fd3 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.h +++ b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.h @@ -24,9 +24,6 @@ public: void UpdateData(); private: - QGroupBox* CreateAchievementBox(const rc_api_achievement_definition_t* achievement); - QString GetStatusString(u32 achievement_id) const; - QGroupBox* m_common_box; QVBoxLayout* m_common_layout; }; diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt index 87bd9883d5..dc946b5b50 100644 --- a/Source/Core/DolphinQt/CMakeLists.txt +++ b/Source/Core/DolphinQt/CMakeLists.txt @@ -28,6 +28,8 @@ add_executable(dolphin-emu CheatSearchWidget.h CheatsManager.cpp CheatsManager.h + Achievements/AchievementBox.cpp + Achievements/AchievementBox.h Achievements/AchievementHeaderWidget.cpp Achievements/AchievementHeaderWidget.h Achievements/AchievementLeaderboardWidget.cpp diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj index cbcd07bfad..9dd72e3622 100644 --- a/Source/Core/DolphinQt/DolphinQt.vcxproj +++ b/Source/Core/DolphinQt/DolphinQt.vcxproj @@ -48,6 +48,7 @@ + @@ -267,6 +268,7 @@ +