Skip to content

Commit

Permalink
Merge pull request #12247 from LillyJadeKatrin/retroachievements-chal…
Browse files Browse the repository at this point in the history
…lenges

RetroAchievements - Challenge Icons
  • Loading branch information
lioncash committed Dec 7, 2023
2 parents 2ece642 + caa729f commit 3a4cf57
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
39 changes: 39 additions & 0 deletions Source/Core/Core/AchievementManager.cpp
Expand Up @@ -710,6 +710,12 @@ void AchievementManager::AchievementEventHandler(const rc_runtime_event_t* runti
case RC_RUNTIME_EVENT_ACHIEVEMENT_PROGRESS_UPDATED:
HandleAchievementProgressUpdatedEvent(runtime_event);
break;
case RC_RUNTIME_EVENT_ACHIEVEMENT_PRIMED:
HandleAchievementPrimedEvent(runtime_event);
break;
case RC_RUNTIME_EVENT_ACHIEVEMENT_UNPRIMED:
HandleAchievementUnprimedEvent(runtime_event);
break;
case RC_RUNTIME_EVENT_LBOARD_STARTED:
HandleLeaderboardStartedEvent(runtime_event);
break;
Expand Down Expand Up @@ -857,6 +863,11 @@ void AchievementManager::SetDisabled(bool disable)
}
};

const AchievementManager::NamedIconMap& AchievementManager::GetChallengeIcons() const
{
return m_active_challenges;
}

void AchievementManager::CloseGame()
{
{
Expand Down Expand Up @@ -1467,6 +1478,34 @@ void AchievementManager::HandleAchievementProgressUpdatedEvent(
nullptr);
}

void AchievementManager::HandleAchievementPrimedEvent(const rc_runtime_event_t* runtime_event)
{
if (!Config::Get(Config::RA_BADGES_ENABLED))
return;
auto it = m_unlock_map.find(runtime_event->id);
if (it == m_unlock_map.end())
{
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid achievement primed event with id {}.", runtime_event->id);
return;
}
m_active_challenges[it->second.unlocked_badge.name] =
DecodeBadgeToOSDIcon(it->second.unlocked_badge.badge);
}

void AchievementManager::HandleAchievementUnprimedEvent(const rc_runtime_event_t* runtime_event)
{
if (!Config::Get(Config::RA_BADGES_ENABLED))
return;
auto it = m_unlock_map.find(runtime_event->id);
if (it == m_unlock_map.end())
{
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid achievement unprimed event with id {}.",
runtime_event->id);
return;
}
m_active_challenges.erase(it->second.unlocked_badge.name);
}

void AchievementManager::HandleLeaderboardStartedEvent(const rc_runtime_event_t* runtime_event)
{
for (u32 ix = 0; ix < m_game_data.num_leaderboards; ix++)
Expand Down
11 changes: 11 additions & 0 deletions Source/Core/Core/AchievementManager.h
Expand Up @@ -7,6 +7,7 @@
#include <array>
#include <ctime>
#include <functional>
#include <map>
#include <mutex>
#include <string>
#include <thread>
Expand All @@ -25,6 +26,11 @@ namespace Core
class System;
}

namespace OSD
{
struct Icon;
}

class AchievementManager
{
public:
Expand Down Expand Up @@ -61,6 +67,7 @@ class AchievementManager
static constexpr size_t RP_SIZE = 256;
using RichPresence = std::array<char, RP_SIZE>;
using Badge = std::vector<u8>;
using NamedIconMap = std::map<std::string, std::unique_ptr<OSD::Icon>, std::less<>>;

struct BadgeStatus
{
Expand Down Expand Up @@ -138,6 +145,7 @@ class AchievementManager
RichPresence GetRichPresence();
bool IsDisabled() const { return m_disabled; };
void SetDisabled(bool disabled);
const NamedIconMap& GetChallengeIcons() const;

void CloseGame();
void Logout();
Expand Down Expand Up @@ -180,6 +188,8 @@ class AchievementManager

void HandleAchievementTriggeredEvent(const rc_runtime_event_t* runtime_event);
void HandleAchievementProgressUpdatedEvent(const rc_runtime_event_t* runtime_event);
void HandleAchievementPrimedEvent(const rc_runtime_event_t* runtime_event);
void HandleAchievementUnprimedEvent(const rc_runtime_event_t* runtime_event);
void HandleLeaderboardStartedEvent(const rc_runtime_event_t* runtime_event);
void HandleLeaderboardCanceledEvent(const rc_runtime_event_t* runtime_event);
void HandleLeaderboardTriggeredEvent(const rc_runtime_event_t* runtime_event);
Expand Down Expand Up @@ -210,6 +220,7 @@ class AchievementManager

std::unordered_map<AchievementId, UnlockStatus> m_unlock_map;
std::unordered_map<AchievementId, LeaderboardStatus> m_leaderboard_map;
NamedIconMap m_active_challenges;

Common::WorkQueueThread<std::function<void()>> m_queue;
Common::WorkQueueThread<std::function<void()>> m_image_queue;
Expand Down
63 changes: 63 additions & 0 deletions Source/Core/VideoCommon/OnScreenUI.cpp
Expand Up @@ -7,6 +7,7 @@
#include "Common/Profiler.h"
#include "Common/Timer.h"

#include "Core/AchievementManager.h"
#include "Core/Config/MainSettings.h"
#include "Core/Config/NetplaySettings.h"
#include "Core/Movie.h"
Expand Down Expand Up @@ -326,13 +327,75 @@ void OnScreenUI::DrawDebugText()
ImGui::TextUnformatted(profile_output.c_str());
}

#ifdef USE_RETRO_ACHIEVEMENTS
void OnScreenUI::DrawChallenges()
{
std::lock_guard lg{*AchievementManager::GetInstance()->GetLock()};
const AchievementManager::NamedIconMap& challenge_icons =
AchievementManager::GetInstance()->GetChallengeIcons();

const std::string window_name = "Challenges";

u32 sum_of_icon_heights = 0;
u32 max_icon_width = 0;
for (const auto& [name, icon] : challenge_icons)
{
// These *should* all be the same square size but you never know.
if (icon->width > max_icon_width)
max_icon_width = icon->width;
sum_of_icon_heights += icon->height;
}
ImGui::SetNextWindowPos(
ImVec2(ImGui::GetIO().DisplaySize.x - 20.f * m_backbuffer_scale - max_icon_width,
ImGui::GetIO().DisplaySize.y - 20.f * m_backbuffer_scale - sum_of_icon_heights));
ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f));
if (ImGui::Begin(window_name.c_str(), nullptr,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing))
{
for (const auto& [name, icon] : challenge_icons)
{
if (m_challenge_texture_map.find(name) != m_challenge_texture_map.end())
continue;
const u32 width = icon->width;
const u32 height = icon->height;
TextureConfig tex_config(width, height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0);
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(),
sizeof(u32) * width * height);
}
for (auto& [name, texture] : m_challenge_texture_map)
{
auto icon_itr = challenge_icons.find(name);
if (icon_itr == challenge_icons.end())
{
m_challenge_texture_map.erase(name);
continue;
}
if (texture)
{
ImGui::Image(texture.get(), ImVec2(static_cast<float>(icon_itr->second->width),
static_cast<float>(icon_itr->second->height)));
}
}
}

ImGui::End();
}
#endif // USE_RETRO_ACHIEVEMENTS

void OnScreenUI::Finalize()
{
auto lock = GetImGuiLock();

g_perf_metrics.DrawImGuiStats(m_backbuffer_scale);
DrawDebugText();
OSD::DrawMessages();
#ifdef USE_RETRO_ACHIEVEMENTS
DrawChallenges();
#endif // USE_RETRO_ACHIEVEMENTS
ImGui::Render();
}

Expand Down
7 changes: 7 additions & 0 deletions Source/Core/VideoCommon/OnScreenUI.h
Expand Up @@ -61,6 +61,9 @@ class OnScreenUI

private:
void DrawDebugText();
#ifdef USE_RETRO_ACHIEVEMENTS
void DrawChallenges();
#endif // USE_RETRO_ACHIEVEMENTS

// ImGui resources.
std::unique_ptr<NativeVertexFormat> m_imgui_vertex_format;
Expand All @@ -74,6 +77,10 @@ class OnScreenUI
u32 m_backbuffer_height = 1;
float m_backbuffer_scale = 1.0;

#ifdef USE_RETRO_ACHIEVEMENTS
std::map<std::string, std::unique_ptr<AbstractTexture>, std::less<>> m_challenge_texture_map;
#endif // USE_RETRO_ACHIEVEMENTS

bool m_ready = false;
};
} // namespace VideoCommon

0 comments on commit 3a4cf57

Please sign in to comment.