RetroAchievements: Show active challenge achievements on pause screen.

This commit is contained in:
Henrik Rydgård 2023-07-10 10:39:44 +02:00
parent 591b9ebbba
commit cd45125085
8 changed files with 91 additions and 52 deletions

View file

@ -53,6 +53,10 @@ public:
void SetProgressBar(std::string id, std::string &&message, int minValue, int maxValue, int progress);
void RemoveProgressBar(std::string id);
// Show stuff on the side or now, like the challenge indicators etc.
void SetShowSidebar(bool show) { showSidebar_ = show; }
bool ShowSidebar() const { return showSidebar_; }
struct Entry {
OSDType type;
std::string text;
@ -84,6 +88,8 @@ private:
std::vector<Entry> sideEntries_;
std::vector<ProgressBar> bars_;
std::mutex mutex_;
bool showSidebar_ = true;
};
extern OnScreenDisplay g_OSD;

View file

@ -10,6 +10,7 @@
#include <cstdlib>
#include <ctime>
#include <functional>
#include <set>
#include <string>
#include <vector>
#include <mutex>
@ -82,6 +83,7 @@ const std::string g_iconCachePrefix = "badge:";
Path s_game_path;
std::string s_game_hash;
std::set<uint32_t> g_activeChallenges;
bool g_isIdentifying = false;
// rc_client implementation
@ -285,12 +287,14 @@ static void event_handler_callback(const rc_client_event_t *event, rc_client_t *
case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW:
NOTICE_LOG(ACHIEVEMENTS, "Challenge indicator show: %s", event->achievement->title);
g_OSD.ShowChallengeIndicator(event->achievement->id, true);
g_activeChallenges.insert(event->achievement->id);
// A challenge achievement has become active. The handler should show a small version of the achievement icon
// to indicate the challenge is active.
break;
case RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE:
NOTICE_LOG(ACHIEVEMENTS, "Challenge indicator hide: %s", event->achievement->title);
g_OSD.ShowChallengeIndicator(event->achievement->id, false);
g_activeChallenges.erase(event->achievement->id);
// The handler should hide the small version of the achievement icon that was shown by the corresponding RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_SHOW event.
break;
case RC_CLIENT_EVENT_ACHIEVEMENT_PROGRESS_INDICATOR_SHOW:
@ -395,6 +399,7 @@ void Logout() {
g_Config.sAchievementsUserName.clear();
NativeSaveSecret(RA_TOKEN_SECRET_NAME, "");
g_Config.Save("Achievements logout");
g_activeChallenges.clear();
}
void UpdateSettings() {
@ -411,6 +416,7 @@ void UpdateSettings() {
}
bool Shutdown() {
g_activeChallenges.clear();
rc_client_destroy(g_rcClient);
g_rcClient = nullptr;
return true;
@ -419,6 +425,7 @@ bool Shutdown() {
void ResetRuntime() {
INFO_LOG(ACHIEVEMENTS, "Resetting rcheevos state...");
rc_client_reset(g_rcClient);
g_activeChallenges.clear();
}
void FrameUpdate() {
@ -635,4 +642,8 @@ void ChangeUMD(const Path &path) {
g_isIdentifying = true;
}
std::set<uint32_t> GetActiveChallengeIDs() {
return g_activeChallenges;
}
} // namespace Achievements

View file

@ -14,6 +14,7 @@
#include <string>
#include <utility>
#include <vector>
#include <set>
#include <mutex>
#include "Common/StringUtils.h"
@ -105,4 +106,6 @@ Statistics GetStatistics();
std::string GetGameAchievementSummary();
std::set<uint32_t> GetActiveChallengeIDs();
} // namespace Achievements

View file

@ -197,6 +197,7 @@ EmuScreen::EmuScreen(const Path &filename)
// Usually, we don't want focus movement enabled on this screen, so disable on start.
// Only if you open chat or dev tools do we want it to start working.
UI::EnableFocusMovement(false);
g_OSD.SetShowSidebar(true);
}
bool EmuScreen::bootAllowStorage(const Path &filename) {

View file

@ -226,61 +226,63 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
const float fadeoutCoef = 1.0f / OnScreenDisplay::FadeoutTime();
// Draw side entries. Top entries should apply on top of them if there's a collision, so drawing
// these first makes sense.
const std::vector<OnScreenDisplay::Entry> sideEntries = g_OSD.SideEntries();
for (auto &entry : sideEntries) {
float tw, th;
if (g_OSD.ShowSidebar()) {
// Draw side entries. Top entries should apply on top of them if there's a collision, so drawing
// these first makes sense.
const std::vector<OnScreenDisplay::Entry> sideEntries = g_OSD.SideEntries();
for (auto &entry : sideEntries) {
float tw, th;
const rc_client_achievement_t *achievement = nullptr;
AchievementRenderStyle style;
const rc_client_achievement_t *achievement = nullptr;
AchievementRenderStyle style;
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
style = AchievementRenderStyle::PROGRESS_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
continue;
style = AchievementRenderStyle::CHALLENGE_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::LEADERBOARD_TRACKER:
{
MeasureLeaderboardTracker(dc, entry.text, &tw, &th);
break;
}
default:
continue;
style = AchievementRenderStyle::PROGRESS_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
if (!achievement)
}
Bounds b(10.0f, y, tw, th);
float alpha = Clamp((float)(entry.endTime - now) * fadeoutCoef, 0.0f, 1.0f);
// OK, render the thing.
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
RenderAchievement(dc, achievement, style, b, alpha, entry.startTime, now);
break;
}
case OSDType::LEADERBOARD_TRACKER:
RenderLeaderboardTracker(dc, b, entry.text, alpha);
break;
default:
continue;
style = AchievementRenderStyle::CHALLENGE_INDICATOR;
MeasureAchievement(dc, achievement, style, &tw, &th);
break;
}
case OSDType::LEADERBOARD_TRACKER:
{
MeasureLeaderboardTracker(dc, entry.text, &tw, &th);
break;
}
default:
continue;
}
Bounds b(10.0f, y, tw, th);
float alpha = Clamp((float)(entry.endTime - now) * fadeoutCoef, 0.0f, 1.0f);
// OK, render the thing.
}
switch (entry.type) {
case OSDType::ACHIEVEMENT_PROGRESS:
case OSDType::ACHIEVEMENT_CHALLENGE_INDICATOR:
{
RenderAchievement(dc, achievement, style, b, alpha, entry.startTime, now);
break;
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
}
case OSDType::LEADERBOARD_TRACKER:
RenderLeaderboardTracker(dc, b, entry.text, alpha);
break;
default:
continue;
}
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
}
// Get height

View file

@ -261,8 +261,14 @@ void GamePauseScreen::update() {
SetVRAppMode(VRAppMode::VR_MENU_MODE);
}
GamePauseScreen::GamePauseScreen(const Path &filename)
: UIDialogScreenWithGameBackground(filename) {
g_OSD.SetShowSidebar(false);
}
GamePauseScreen::~GamePauseScreen() {
__DisplaySetWasPaused();
g_OSD.SetShowSidebar(true);
}
void GamePauseScreen::CreateSavestateControls(UI::LinearLayout *leftColumnItems, bool vertical) {
@ -326,6 +332,18 @@ void GamePauseScreen::CreateViews() {
if (!Achievements::ChallengeModeActive()) {
CreateSavestateControls(leftColumnItems, vertical);
} else {
// Let's show the active challenges.
std::set<uint32_t> ids = Achievements::GetActiveChallengeIDs();
if (!ids.empty()) {
leftColumnItems->Add(new ItemHeader(ac->T("Active Challenges")));
for (auto id : ids) {
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), id);
if (!achievement)
continue;
leftColumnItems->Add(new AchievementView(achievement));
}
}
}
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(vertical ? 200 : 300, FILL_PARENT, actionMenuMargins));

View file

@ -32,7 +32,7 @@ enum class PauseScreenMode {
class GamePauseScreen : public UIDialogScreenWithGameBackground {
public:
GamePauseScreen(const Path &filename) : UIDialogScreenWithGameBackground(filename), gamePath_(filename) {}
GamePauseScreen(const Path &filename);
~GamePauseScreen();
void dialogFinished(const Screen *dialog, DialogResult dr) override;
@ -65,6 +65,5 @@ private:
// hack
bool finishNextFrame_ = false;
Path gamePath_;
PauseScreenMode mode_ = PauseScreenMode::MAIN;
};

View file

@ -595,4 +595,3 @@ void LeaderboardEntryView::Draw(UIContext &dc) {
void LeaderboardEntryView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
MeasureLeaderboardEntry(dc, entry_, &w, &h);
}