From 75c2360aeacefddddd83cb585f69f9a822a614e7 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 19 Jun 2024 22:12:30 -0400 Subject: [PATCH 1/3] Split AchievementBox UpdateData AchievementBox now has UpdateData and UpdateProgress, which is called from UpdateData, but may be called elsewhere to update just the progress measurement of the achievement. --- Source/Core/DolphinQt/Achievements/AchievementBox.cpp | 5 +++++ Source/Core/DolphinQt/Achievements/AchievementBox.h | 1 + 2 files changed, 6 insertions(+) diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index a14936171d..d4d92e9965 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -87,6 +87,11 @@ void AchievementBox::UpdateData() m_status->setText(tr("Locked")); } + UpdateProgress(); +} + +void AchievementBox::UpdateProgress() +{ if (m_achievement->measured_percent > 0.000) { m_progress_bar->setRange(0, 100); diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.h b/Source/Core/DolphinQt/Achievements/AchievementBox.h index 596893b148..92b1e75878 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.h +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.h @@ -20,6 +20,7 @@ class AchievementBox final : public QGroupBox public: explicit AchievementBox(QWidget* parent, rc_client_achievement_t* achievement); void UpdateData(); + void UpdateProgress(); private: QLabel* m_badge; From 9b9e6c4582446181effebd9d391b1d409a96dde6 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Wed, 19 Jun 2024 22:54:24 -0400 Subject: [PATCH 2/3] Refactored AchievementProgress UpdateData to Re-Sort When AchievementProgress::UpdateData(false) is called, it will now empty itself and reinsert all existing boxes, re-sorted into their current buckets, and call UpdateProgress on them all. --- .../DolphinQt/Achievements/AchievementBox.cpp | 8 +++ .../AchievementProgressWidget.cpp | 56 ++++++++++++------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index d4d92e9965..edfcf6fdf9 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -62,6 +62,9 @@ AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achieve void AchievementBox::UpdateData() { std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; + // rc_client guarantees m_achievement will be valid as long as the game is loaded + if (!AchievementManager::GetInstance().IsGameLoaded()) + return; const auto& badge = AchievementManager::GetInstance().GetAchievementBadge( m_achievement->id, m_achievement->state != RC_CLIENT_ACHIEVEMENT_STATE_UNLOCKED); @@ -92,6 +95,11 @@ void AchievementBox::UpdateData() void AchievementBox::UpdateProgress() { + std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; + // rc_client guarantees m_achievement will be valid as long as the game is loaded + if (!AchievementManager::GetInstance().IsGameLoaded()) + return; + if (m_achievement->measured_percent > 0.000) { m_progress_bar->setRange(0, 100); diff --git a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp index 741cb61227..352645c5db 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp @@ -42,33 +42,47 @@ void AchievementProgressWidget::UpdateData(bool clean_all) { m_achievement_boxes.clear(); ClearLayoutRecursively(m_common_layout); - - auto& instance = AchievementManager::GetInstance(); - if (!instance.IsGameLoaded()) - return; - 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_PROGRESS); - for (u32 ix = 0; ix < achievement_list->num_buckets; ix++) - { - m_common_layout->addWidget(new QLabel(tr(achievement_list->buckets[ix].label))); - for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++) - { - auto* achievement = achievement_list->buckets[ix].achievements[jx]; - m_achievement_boxes[achievement->id] = std::make_shared(this, achievement); - m_common_layout->addWidget(m_achievement_boxes[achievement->id].get()); - } - } - rc_client_destroy_achievement_list(achievement_list); } else { - for (auto box : m_achievement_boxes) + while (auto* item = m_common_layout->takeAt(0)) { - box.second->UpdateData(); + auto* widget = item->widget(); + m_common_layout->removeWidget(widget); + if (std::strcmp(widget->metaObject()->className(), "QLabel") == 0) + { + delete widget; + delete item; + } } } + + auto& instance = AchievementManager::GetInstance(); + if (!instance.IsGameLoaded()) + return; + 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_PROGRESS); + for (u32 ix = 0; ix < achievement_list->num_buckets; ix++) + { + m_common_layout->addWidget(new QLabel(tr(achievement_list->buckets[ix].label))); + for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++) + { + auto* achievement = achievement_list->buckets[ix].achievements[jx]; + auto box_itr = m_achievement_boxes.find(achievement->id); + if (box_itr == m_achievement_boxes.end()) + { + m_achievement_boxes[achievement->id] = std::make_shared(this, achievement); + } + else + { + box_itr->second->UpdateProgress(); + } + m_common_layout->addWidget(m_achievement_boxes[achievement->id].get()); + } + } + rc_client_destroy_achievement_list(achievement_list); } void AchievementProgressWidget::UpdateData( From 1a33e2845271b9a46d986f09e051fac88e6e50d7 Mon Sep 17 00:00:00 2001 From: LillyJadeKatrin Date: Thu, 20 Jun 2024 00:35:46 -0400 Subject: [PATCH 3/3] Update Achievement Sort and Progress on RP Whenever a request to update the Rich Presence comes in, typically every ten seconds, the Achievement Progress Widget will update the sort order of the achievements and all of their measured values. --- .../DolphinQt/Achievements/AchievementBox.cpp | 55 ++++++++++--------- .../AchievementProgressWidget.cpp | 16 ++++-- .../Achievements/AchievementsWindow.cpp | 2 +- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp index edfcf6fdf9..987b92a6a0 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementBox.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementBox.cpp @@ -61,33 +61,36 @@ AchievementBox::AchievementBox(QWidget* parent, rc_client_achievement_t* achieve void AchievementBox::UpdateData() { - std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; - // rc_client guarantees m_achievement will be valid as long as the game is loaded - if (!AchievementManager::GetInstance().IsGameLoaded()) - return; - - 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; - 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) { - m_status->setText( - tr("Unlocked at %1") - .arg(QDateTime::fromSecsSinceEpoch(m_achievement->unlock_time).toString())); - } - else - { - m_status->setText(tr("Locked")); + std::lock_guard lg{AchievementManager::GetInstance().GetLock()}; + // rc_client guarantees m_achievement will be valid as long as the game is loaded + if (!AchievementManager::GetInstance().IsGameLoaded()) + return; + + 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; + 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) + { + m_status->setText( + tr("Unlocked at %1") + .arg(QDateTime::fromSecsSinceEpoch(m_achievement->unlock_time).toString())); + } + else + { + m_status->setText(tr("Locked")); + } } UpdateProgress(); diff --git a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp index 352645c5db..235f37a5d8 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementProgressWidget.cpp @@ -51,7 +51,7 @@ void AchievementProgressWidget::UpdateData(bool clean_all) m_common_layout->removeWidget(widget); if (std::strcmp(widget->metaObject()->className(), "QLabel") == 0) { - delete widget; + widget->deleteLater(); delete item; } } @@ -64,22 +64,26 @@ void AchievementProgressWidget::UpdateData(bool clean_all) auto* achievement_list = rc_client_create_achievement_list(client, RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL, RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_PROGRESS); + if (!achievement_list) + return; for (u32 ix = 0; ix < achievement_list->num_buckets; ix++) { m_common_layout->addWidget(new QLabel(tr(achievement_list->buckets[ix].label))); for (u32 jx = 0; jx < achievement_list->buckets[ix].num_achievements; jx++) { auto* achievement = achievement_list->buckets[ix].achievements[jx]; - auto box_itr = m_achievement_boxes.find(achievement->id); - if (box_itr == m_achievement_boxes.end()) + auto box_itr = m_achievement_boxes.lower_bound(achievement->id); + if (box_itr != m_achievement_boxes.end() && box_itr->first == achievement->id) { - m_achievement_boxes[achievement->id] = std::make_shared(this, achievement); + box_itr->second->UpdateProgress(); + m_common_layout->addWidget(box_itr->second.get()); } else { - box_itr->second->UpdateProgress(); + const auto new_box_itr = m_achievement_boxes.try_emplace( + box_itr, achievement->id, std::make_shared(this, achievement)); + m_common_layout->addWidget(new_box_itr->second.get()); } - m_common_layout->addWidget(m_achievement_boxes[achievement->id].get()); } } rc_client_destroy_achievement_list(achievement_list); diff --git a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp index b796b9dc3e..eb79896de2 100644 --- a/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp +++ b/Source/Core/DolphinQt/Achievements/AchievementsWindow.cpp @@ -89,7 +89,7 @@ void AchievementsWindow::UpdateData(AchievementManager::UpdatedItems updated_ite { m_header_widget->UpdateData(); } - if (updated_items.all_achievements) + if (updated_items.all_achievements || updated_items.rich_presence) m_progress_widget->UpdateData(false); else if (updated_items.achievements.size() > 0) m_progress_widget->UpdateData(updated_items.achievements);