Merge pull request #12778 from LillyJadeKatrin/retroachievements-default-badges-v2
RetroAchievements - Default Badges
This commit is contained in:
commit
f991610052
Binary file not shown.
After Width: | Height: | Size: 460 B |
Binary file not shown.
After Width: | Height: | Size: 235 B |
Binary file not shown.
After Width: | Height: | Size: 335 B |
Binary file not shown.
After Width: | Height: | Size: 235 B |
|
@ -13,6 +13,8 @@
|
|||
#include <rcheevos/include/rc_api_info.h>
|
||||
#include <rcheevos/include/rc_hash.h>
|
||||
|
||||
#include "Common/CommonPaths.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/Image.h"
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Common/ScopeGuard.h"
|
||||
|
@ -23,11 +25,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<OSD::Icon> DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge);
|
||||
|
||||
AchievementManager& AchievementManager::GetInstance()
|
||||
{
|
||||
static AchievementManager s_instance;
|
||||
|
@ -36,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);
|
||||
|
@ -278,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;
|
||||
}
|
||||
|
@ -298,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_locked_badges;
|
||||
auto& badge_list = locked ? m_locked_badges : m_unlocked_badges;
|
||||
auto itr = badge_list.find(id);
|
||||
return (itr == badge_list.end()) ? m_default_badge : itr->second;
|
||||
return (itr != badge_list.end() && itr->second.data.size() > 0) ?
|
||||
itr->second :
|
||||
(locked ? m_default_locked_badge : m_default_unlocked_badge);
|
||||
}
|
||||
|
||||
const AchievementManager::LeaderboardStatus*
|
||||
|
@ -330,7 +334,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;
|
||||
}
|
||||
|
@ -393,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();
|
||||
|
@ -415,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, "");
|
||||
}
|
||||
|
||||
|
@ -500,6 +508,55 @@ void AchievementManager::FilereaderClose(void* file_handle)
|
|||
delete static_cast<FilereaderState*>(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 = 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 = 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)
|
||||
{
|
||||
|
@ -637,11 +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 (Config::Get(Config::RA_BADGES_ENABLED) && !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);
|
||||
auto info = rc_client_get_game_info(m_client);
|
||||
if (!info)
|
||||
{
|
||||
|
@ -671,17 +725,13 @@ void AchievementManager::DisplayWelcomeMessage()
|
|||
|
||||
void AchievementManager::HandleAchievementTriggeredEvent(const rc_client_event_t* client_event)
|
||||
{
|
||||
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(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);
|
||||
(rc_client_get_hardcore_enabled(instance.m_client)) ? OSD::Color::YELLOW :
|
||||
OSD::Color::CYAN,
|
||||
&instance.GetAchievementBadge(client_event->achievement->id, false));
|
||||
}
|
||||
|
||||
void AchievementManager::HandleLeaderboardStartedEvent(const rc_client_event_t* client_event)
|
||||
|
@ -738,16 +788,9 @@ 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())
|
||||
{
|
||||
AchievementManager::GetInstance().m_active_challenges[client_event->achievement->badge_name] =
|
||||
DecodeBadgeToOSDIcon(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);
|
||||
}
|
||||
|
||||
void AchievementManager::HandleAchievementChallengeIndicatorHideEvent(
|
||||
|
@ -760,14 +803,11 @@ void AchievementManager::HandleAchievementChallengeIndicatorHideEvent(
|
|||
void AchievementManager::HandleAchievementProgressIndicatorShowEvent(
|
||||
const rc_client_event_t* client_event)
|
||||
{
|
||||
const auto& instance = AchievementManager::GetInstance();
|
||||
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);
|
||||
&instance.GetAchievementBadge(client_event->achievement->id, false));
|
||||
}
|
||||
|
||||
void AchievementManager::HandleGameCompletedEvent(const rc_client_event_t* client_event,
|
||||
|
@ -784,9 +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,
|
||||
(Config::Get(Config::RA_BADGES_ENABLED)) ?
|
||||
DecodeBadgeToOSDIcon(AchievementManager::GetInstance().m_game_badge.badge) :
|
||||
nullptr);
|
||||
&AchievementManager::GetInstance().m_game_badge);
|
||||
}
|
||||
|
||||
void AchievementManager::HandleResetEvent(const rc_client_event_t* client_event)
|
||||
|
@ -801,20 +839,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<OSD::Icon> DecodeBadgeToOSDIcon(const AchievementManager::Badge& badge)
|
||||
{
|
||||
if (badge.empty())
|
||||
return nullptr;
|
||||
|
||||
auto icon = std::make_unique<OSD::Icon>();
|
||||
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)
|
||||
|
@ -876,11 +900,11 @@ 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)
|
||||
{
|
||||
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)
|
||||
|
@ -923,7 +947,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};
|
||||
|
@ -932,8 +955,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);
|
||||
badge->name = std::move(name_to_fetch);
|
||||
|
||||
if (!LoadPNGTexture(badge, *http_response))
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Default game badge '{}' failed to load",
|
||||
DEFAULT_GAME_BADGE_FILENAME);
|
||||
}
|
||||
|
||||
m_update_callback(callback_data);
|
||||
});
|
||||
|
|
|
@ -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,16 +43,14 @@ public:
|
|||
using LeaderboardRank = u32;
|
||||
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<>>;
|
||||
using Badge = VideoCommon::CustomTextureData::ArraySlice::Level;
|
||||
using NamedBadgeMap = std::unordered_map<std::string, const Badge*>;
|
||||
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";
|
||||
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";
|
||||
|
@ -108,15 +102,15 @@ 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 NamedIconMap& GetChallengeIcons() const;
|
||||
const NamedBadgeMap& GetChallengeIcons() const;
|
||||
std::vector<std::string> GetActiveLeaderboards() const;
|
||||
|
||||
void DoState(PointerWrap& p);
|
||||
|
@ -134,8 +128,6 @@ private:
|
|||
std::unique_ptr<DiscIO::Volume> 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);
|
||||
|
@ -143,6 +135,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);
|
||||
|
||||
|
@ -177,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);
|
||||
|
||||
|
@ -187,20 +180,24 @@ private:
|
|||
bool m_is_runtime_initialized = false;
|
||||
UpdateCallback m_update_callback = [](const UpdatedItems&) {};
|
||||
std::unique_ptr<DiscIO::Volume> m_loading_volume;
|
||||
BadgeStatus m_player_badge;
|
||||
Badge m_default_player_badge;
|
||||
Badge m_default_game_badge;
|
||||
Badge m_default_unlocked_badge;
|
||||
Badge m_default_locked_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<AchievementId, BadgeStatus> m_unlocked_badges;
|
||||
std::unordered_map<AchievementId, BadgeStatus> m_locked_badges;
|
||||
std::unordered_map<AchievementId, Badge> m_unlocked_badges;
|
||||
std::unordered_map<AchievementId, Badge> m_locked_badges;
|
||||
RichPresence m_rich_presence;
|
||||
std::chrono::steady_clock::time_point m_last_rp_time = std::chrono::steady_clock::now();
|
||||
|
||||
std::unordered_map<AchievementId, LeaderboardStatus> m_leaderboard_map;
|
||||
NamedIconMap m_active_challenges;
|
||||
NamedBadgeMap m_active_challenges;
|
||||
std::vector<rc_client_leaderboard_tracker_t> m_active_leaderboards;
|
||||
|
||||
Common::WorkQueueThread<std::function<void()>> m_queue;
|
||||
|
|
|
@ -26,7 +26,6 @@ const Info<bool> RA_DISCORD_PRESENCE_ENABLED{
|
|||
{System::Achievements, "Achievements", "DiscordPresenceEnabled"}, false};
|
||||
const Info<bool> RA_PROGRESS_ENABLED{{System::Achievements, "Achievements", "ProgressEnabled"},
|
||||
false};
|
||||
const Info<bool> RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false};
|
||||
} // namespace Config
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -20,7 +20,6 @@ extern const Info<bool> RA_ENCORE_ENABLED;
|
|||
extern const Info<bool> RA_SPECTATOR_ENABLED;
|
||||
extern const Info<bool> RA_DISCORD_PRESENCE_ENABLED;
|
||||
extern const Info<bool> RA_PROGRESS_ENABLED;
|
||||
extern const Info<bool> RA_BADGES_ENABLED;
|
||||
} // namespace Config
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -61,22 +61,11 @@ 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 != "")
|
||||
{
|
||||
QImage i_badge{};
|
||||
if (i_badge.loadFromData(&badge.badge.front(), static_cast<int>(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({});
|
||||
}
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -68,24 +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 (Config::Get(Config::RA_BADGES_ENABLED) && !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.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({});
|
||||
|
@ -94,26 +90,19 @@ 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())
|
||||
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{};
|
||||
if (i_game_icon.loadFromData(&game_badge.badge.front(), (int)game_badge.badge.size()))
|
||||
{
|
||||
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")
|
||||
|
|
|
@ -105,11 +105,6 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
tr("Enable progress notifications on achievements.<br><br>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.<br><br>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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -574,6 +574,14 @@ bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::stri
|
|||
std::vector<u8> buffer(file.GetSize());
|
||||
file.ReadBytes(buffer.data(), file.GetSize());
|
||||
|
||||
return LoadPNGTexture(level, buffer);
|
||||
}
|
||||
|
||||
bool LoadPNGTexture(CustomTextureData::ArraySlice::Level* level, const std::vector<u8>& buffer)
|
||||
{
|
||||
if (!level) [[unlikely]]
|
||||
return false;
|
||||
|
||||
if (!Common::LoadPNG(buffer, &level->data, &level->width, &level->height))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -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<u8>& buffer);
|
||||
} // namespace VideoCommon
|
||||
|
|
|
@ -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<int> s_obscured_pixels_top = 0;
|
|||
struct Message
|
||||
{
|
||||
Message() = default;
|
||||
Message(std::string text_, u32 duration_, u32 color_, std::unique_ptr<Icon> 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> icon;
|
||||
const VideoCommon::CustomTextureData::ArraySlice::Level* icon;
|
||||
std::unique_ptr<AbstractTexture> texture;
|
||||
};
|
||||
static std::multimap<MessageType, Message> 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> 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> 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)));
|
||||
|
|
|
@ -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<u8> 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> 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> 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();
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue