Merge pull request #12025 from LillyJadeKatrin/retroachievements-badges
RetroAchievements - Badges
This commit is contained in:
commit
404a47af77
|
@ -35,6 +35,8 @@ void AchievementManager::Init()
|
|||
rc_runtime_init(&m_runtime);
|
||||
m_is_runtime_initialized = true;
|
||||
m_queue.Reset("AchievementManagerQueue", [](const std::function<void()>& func) { func(); });
|
||||
m_image_queue.Reset("AchievementManagerImageQueue",
|
||||
[](const std::function<void()>& func) { func(); });
|
||||
LoginAsync("", [](ResponseType r_type) {});
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Achievement Manager Initialized");
|
||||
}
|
||||
|
@ -55,6 +57,7 @@ AchievementManager::ResponseType AchievementManager::Login(const std::string& pa
|
|||
return AchievementManager::ResponseType::MANAGER_NOT_INITIALIZED;
|
||||
}
|
||||
AchievementManager::ResponseType r_type = VerifyCredentials(password);
|
||||
FetchBadges();
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
return r_type;
|
||||
|
@ -71,6 +74,7 @@ void AchievementManager::LoginAsync(const std::string& password, const ResponseC
|
|||
}
|
||||
m_queue.EmplaceItem([this, password, callback] {
|
||||
callback(VerifyCredentials(password));
|
||||
FetchBadges();
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
});
|
||||
|
@ -207,6 +211,7 @@ void AchievementManager::LoadGameByFilenameAsync(const std::string& iso_path,
|
|||
}
|
||||
ActivateDeactivateLeaderboards();
|
||||
ActivateDeactivateRichPresence();
|
||||
FetchBadges();
|
||||
// Reset this to zero so that RP immediately triggers on the first frame
|
||||
m_last_ping_time = 0;
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "RetroAchievements successfully loaded for {}.", m_game_data.title);
|
||||
|
@ -286,6 +291,256 @@ void AchievementManager::ActivateDeactivateRichPresence()
|
|||
INFO_LOG_FMT(ACHIEVEMENTS, "Rich presence (de)activated.");
|
||||
}
|
||||
|
||||
void AchievementManager::FetchBadges()
|
||||
{
|
||||
if (!m_is_runtime_initialized || !IsLoggedIn() || !Config::Get(Config::RA_BADGES_ENABLED))
|
||||
{
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
return;
|
||||
}
|
||||
m_image_queue.Cancel();
|
||||
|
||||
if (m_player_badge.name != m_display_name)
|
||||
{
|
||||
m_image_queue.EmplaceItem([this] {
|
||||
std::string name_to_fetch;
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
if (m_display_name == m_player_badge.name)
|
||||
return;
|
||||
name_to_fetch = m_display_name;
|
||||
}
|
||||
rc_api_fetch_image_request_t icon_request = {.image_name = name_to_fetch.c_str(),
|
||||
.image_type = RC_IMAGE_TYPE_USER};
|
||||
Badge fetched_badge;
|
||||
if (RequestImage(icon_request, &fetched_badge) == ResponseType::SUCCESS)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded player badge id {}.", name_to_fetch);
|
||||
std::lock_guard lg{m_lock};
|
||||
if (name_to_fetch != m_display_name)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Requested outdated badge id {} for player id {}.",
|
||||
name_to_fetch, m_display_name);
|
||||
return;
|
||||
}
|
||||
m_player_badge.badge = std::move(fetched_badge);
|
||||
m_player_badge.name = std::move(name_to_fetch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to download player badge id {}.", name_to_fetch);
|
||||
}
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
});
|
||||
}
|
||||
|
||||
if (!IsGameLoaded())
|
||||
{
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
return;
|
||||
}
|
||||
|
||||
int badgematch = 0;
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
badgematch = m_game_badge.name.compare(m_game_data.image_name);
|
||||
}
|
||||
if (badgematch != 0)
|
||||
{
|
||||
m_image_queue.EmplaceItem([this] {
|
||||
std::string name_to_fetch;
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
if (m_game_badge.name.compare(m_game_data.image_name) == 0)
|
||||
return;
|
||||
name_to_fetch.assign(m_game_data.image_name);
|
||||
}
|
||||
rc_api_fetch_image_request_t icon_request = {.image_name = name_to_fetch.c_str(),
|
||||
.image_type = RC_IMAGE_TYPE_GAME};
|
||||
Badge fetched_badge;
|
||||
if (RequestImage(icon_request, &fetched_badge) == ResponseType::SUCCESS)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded game badge id {}.", name_to_fetch);
|
||||
std::lock_guard lg{m_lock};
|
||||
if (name_to_fetch.compare(m_game_data.image_name) != 0)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Requested outdated badge id {} for game id {}.",
|
||||
name_to_fetch, m_game_data.image_name);
|
||||
return;
|
||||
}
|
||||
m_game_badge.badge = std::move(fetched_badge);
|
||||
m_game_badge.name = std::move(name_to_fetch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to download game badge id {}.", name_to_fetch);
|
||||
}
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
});
|
||||
}
|
||||
|
||||
unsigned num_achievements = m_game_data.num_achievements;
|
||||
for (size_t index = 0; index < num_achievements; index++)
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
// In case the number of achievements changes since the loop started; I just don't want
|
||||
// to lock for the ENTIRE loop so instead I reclaim the lock each cycle
|
||||
if (num_achievements != m_game_data.num_achievements)
|
||||
break;
|
||||
rc_api_achievement_definition_t& achievement = m_game_data.achievements[index];
|
||||
std::string name_to_fetch(achievement.badge_name);
|
||||
const UnlockStatus& unlock_status = m_unlock_map[achievement.id];
|
||||
if (unlock_status.unlocked_badge.name != name_to_fetch)
|
||||
{
|
||||
m_image_queue.EmplaceItem([this, index] {
|
||||
std::string current_name, name_to_fetch;
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
if (m_game_data.num_achievements <= index)
|
||||
{
|
||||
INFO_LOG_FMT(
|
||||
ACHIEVEMENTS,
|
||||
"Attempted to fetch unlocked badge for index {} after achievement list cleared.",
|
||||
index);
|
||||
return;
|
||||
}
|
||||
rc_api_achievement_definition_t& achievement = m_game_data.achievements[index];
|
||||
auto unlock_itr = m_unlock_map.find(achievement.id);
|
||||
if (unlock_itr == m_unlock_map.end())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
ACHIEVEMENTS,
|
||||
"Attempted to fetch unlocked badge for achievement id {} not in unlock map.",
|
||||
index);
|
||||
return;
|
||||
}
|
||||
name_to_fetch.assign(achievement.badge_name);
|
||||
current_name = unlock_itr->second.unlocked_badge.name;
|
||||
}
|
||||
if (current_name == name_to_fetch)
|
||||
return;
|
||||
rc_api_fetch_image_request_t icon_request = {.image_name = name_to_fetch.c_str(),
|
||||
.image_type = RC_IMAGE_TYPE_ACHIEVEMENT};
|
||||
Badge fetched_badge;
|
||||
if (RequestImage(icon_request, &fetched_badge) == ResponseType::SUCCESS)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded unlocked achievement badge id {}.",
|
||||
name_to_fetch);
|
||||
std::lock_guard lg{m_lock};
|
||||
if (m_game_data.num_achievements <= index)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS,
|
||||
"Fetched unlocked badge for index {} after achievement list cleared.",
|
||||
index);
|
||||
return;
|
||||
}
|
||||
rc_api_achievement_definition_t& achievement = m_game_data.achievements[index];
|
||||
auto unlock_itr = m_unlock_map.find(achievement.id);
|
||||
if (unlock_itr == m_unlock_map.end())
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS,
|
||||
"Fetched unlocked badge for achievement id {} not in unlock map.", index);
|
||||
return;
|
||||
}
|
||||
if (name_to_fetch.compare(achievement.badge_name) != 0)
|
||||
{
|
||||
INFO_LOG_FMT(
|
||||
ACHIEVEMENTS,
|
||||
"Requested outdated unlocked achievement badge id {} for achievement id {}.",
|
||||
name_to_fetch, current_name);
|
||||
return;
|
||||
}
|
||||
unlock_itr->second.unlocked_badge.badge = std::move(fetched_badge);
|
||||
unlock_itr->second.unlocked_badge.name = std::move(name_to_fetch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to download unlocked achievement badge id {}.",
|
||||
name_to_fetch);
|
||||
}
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
});
|
||||
}
|
||||
if (unlock_status.locked_badge.name != name_to_fetch)
|
||||
{
|
||||
m_image_queue.EmplaceItem([this, index] {
|
||||
std::string current_name, name_to_fetch;
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
if (m_game_data.num_achievements <= index)
|
||||
{
|
||||
INFO_LOG_FMT(
|
||||
ACHIEVEMENTS,
|
||||
"Attempted to fetch locked badge for index {} after achievement list cleared.",
|
||||
index);
|
||||
return;
|
||||
}
|
||||
rc_api_achievement_definition_t& achievement = m_game_data.achievements[index];
|
||||
auto unlock_itr = m_unlock_map.find(achievement.id);
|
||||
if (unlock_itr == m_unlock_map.end())
|
||||
{
|
||||
ERROR_LOG_FMT(
|
||||
ACHIEVEMENTS,
|
||||
"Attempted to fetch locked badge for achievement id {} not in unlock map.", index);
|
||||
return;
|
||||
}
|
||||
name_to_fetch.assign(achievement.badge_name);
|
||||
current_name = unlock_itr->second.locked_badge.name;
|
||||
}
|
||||
if (current_name == name_to_fetch)
|
||||
return;
|
||||
rc_api_fetch_image_request_t icon_request = {
|
||||
.image_name = name_to_fetch.c_str(), .image_type = RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED};
|
||||
Badge fetched_badge;
|
||||
if (RequestImage(icon_request, &fetched_badge) == ResponseType::SUCCESS)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Successfully downloaded locked achievement badge id {}.",
|
||||
name_to_fetch);
|
||||
std::lock_guard lg{m_lock};
|
||||
if (m_game_data.num_achievements <= index)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS,
|
||||
"Fetched locked badge for index {} after achievement list cleared.",
|
||||
index);
|
||||
return;
|
||||
}
|
||||
rc_api_achievement_definition_t& achievement = m_game_data.achievements[index];
|
||||
auto unlock_itr = m_unlock_map.find(achievement.id);
|
||||
if (unlock_itr == m_unlock_map.end())
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS,
|
||||
"Fetched locked badge for achievement id {} not in unlock map.", index);
|
||||
return;
|
||||
}
|
||||
if (name_to_fetch.compare(achievement.badge_name) != 0)
|
||||
{
|
||||
INFO_LOG_FMT(ACHIEVEMENTS,
|
||||
"Requested outdated locked achievement badge id {} for achievement id {}.",
|
||||
name_to_fetch, current_name);
|
||||
return;
|
||||
}
|
||||
unlock_itr->second.locked_badge.badge = std::move(fetched_badge);
|
||||
unlock_itr->second.locked_badge.name = std::move(name_to_fetch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "Failed to download locked achievement badge id {}.",
|
||||
name_to_fetch);
|
||||
}
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
}
|
||||
|
||||
void AchievementManager::DoFrame()
|
||||
{
|
||||
if (!m_is_game_loaded)
|
||||
|
@ -381,6 +636,11 @@ u32 AchievementManager::GetPlayerScore() const
|
|||
return IsLoggedIn() ? m_player_score : 0;
|
||||
}
|
||||
|
||||
const AchievementManager::BadgeStatus& AchievementManager::GetPlayerBadge() const
|
||||
{
|
||||
return m_player_badge;
|
||||
}
|
||||
|
||||
std::string AchievementManager::GetGameDisplayName() const
|
||||
{
|
||||
return IsGameLoaded() ? m_game_data.title : "";
|
||||
|
@ -417,7 +677,12 @@ rc_api_fetch_game_data_response_t* AchievementManager::GetGameData()
|
|||
return &m_game_data;
|
||||
}
|
||||
|
||||
AchievementManager::UnlockStatus
|
||||
const AchievementManager::BadgeStatus& AchievementManager::GetGameBadge() const
|
||||
{
|
||||
return m_game_badge;
|
||||
}
|
||||
|
||||
const AchievementManager::UnlockStatus&
|
||||
AchievementManager::GetUnlockStatus(AchievementId achievement_id) const
|
||||
{
|
||||
return m_unlock_map.at(achievement_id);
|
||||
|
@ -426,6 +691,8 @@ AchievementManager::GetUnlockStatus(AchievementId achievement_id) const
|
|||
void AchievementManager::GetAchievementProgress(AchievementId achievement_id, u32* value,
|
||||
u32* target)
|
||||
{
|
||||
if (!IsGameLoaded())
|
||||
return;
|
||||
rc_runtime_get_achievement_measured(&m_runtime, achievement_id, value, target);
|
||||
}
|
||||
|
||||
|
@ -447,10 +714,12 @@ void AchievementManager::CloseGame()
|
|||
ActivateDeactivateLeaderboards();
|
||||
ActivateDeactivateRichPresence();
|
||||
m_game_id = 0;
|
||||
m_game_badge.name = "";
|
||||
m_unlock_map.clear();
|
||||
rc_api_destroy_fetch_game_data_response(&m_game_data);
|
||||
std::memset(&m_game_data, 0, sizeof(m_game_data));
|
||||
m_queue.Cancel();
|
||||
m_image_queue.Cancel();
|
||||
m_system = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -461,8 +730,12 @@ void AchievementManager::CloseGame()
|
|||
|
||||
void AchievementManager::Logout()
|
||||
{
|
||||
CloseGame();
|
||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
|
||||
{
|
||||
std::lock_guard lg{m_lock};
|
||||
CloseGame();
|
||||
m_player_badge.name = "";
|
||||
Config::SetBaseOrCurrent(Config::RA_API_TOKEN, "");
|
||||
}
|
||||
if (m_update_callback)
|
||||
m_update_callback();
|
||||
INFO_LOG_FMT(ACHIEVEMENTS, "Logged out from server.");
|
||||
|
@ -944,4 +1217,30 @@ AchievementManager::ResponseType AchievementManager::Request(
|
|||
}
|
||||
}
|
||||
|
||||
AchievementManager::ResponseType
|
||||
AchievementManager::RequestImage(rc_api_fetch_image_request_t rc_request, Badge* rc_response)
|
||||
{
|
||||
rc_api_request_t api_request;
|
||||
Common::HttpRequest http_request;
|
||||
if (rc_api_init_fetch_image_request(&api_request, &rc_request) != RC_OK)
|
||||
{
|
||||
ERROR_LOG_FMT(ACHIEVEMENTS, "Invalid request for image.");
|
||||
return ResponseType::INVALID_REQUEST;
|
||||
}
|
||||
auto http_response = http_request.Get(api_request.url);
|
||||
if (http_response.has_value() && http_response->size() > 0)
|
||||
{
|
||||
rc_api_destroy_request(&api_request);
|
||||
*rc_response = std::move(*http_response);
|
||||
return ResponseType::SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG_FMT(ACHIEVEMENTS, "RetroAchievements connection failed on image request.\n URL: {}",
|
||||
api_request.url);
|
||||
rc_api_destroy_request(&api_request);
|
||||
return ResponseType::CONNECTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -56,6 +56,13 @@ public:
|
|||
using FormattedValue = std::array<char, FORMAT_SIZE>;
|
||||
static constexpr size_t RP_SIZE = 256;
|
||||
using RichPresence = std::array<char, RP_SIZE>;
|
||||
using Badge = std::vector<u8>;
|
||||
|
||||
struct BadgeStatus
|
||||
{
|
||||
std::string name = "";
|
||||
Badge badge{};
|
||||
};
|
||||
|
||||
struct UnlockStatus
|
||||
{
|
||||
|
@ -68,8 +75,14 @@ public:
|
|||
} remote_unlock_status = UnlockType::LOCKED;
|
||||
u32 session_unlock_count = 0;
|
||||
u32 points = 0;
|
||||
BadgeStatus locked_badge;
|
||||
BadgeStatus unlocked_badge;
|
||||
};
|
||||
|
||||
static constexpr std::string_view GRAY = "transparent";
|
||||
static constexpr std::string_view GOLD = "#FFD700";
|
||||
static constexpr std::string_view BLUE = "#0B71C1";
|
||||
|
||||
static AchievementManager* GetInstance();
|
||||
void Init();
|
||||
void SetUpdateCallback(UpdateCallback callback);
|
||||
|
@ -83,6 +96,7 @@ public:
|
|||
void ActivateDeactivateAchievements();
|
||||
void ActivateDeactivateLeaderboards();
|
||||
void ActivateDeactivateRichPresence();
|
||||
void FetchBadges();
|
||||
|
||||
void DoFrame();
|
||||
u32 MemoryPeeker(u32 address, u32 num_bytes, void* ud);
|
||||
|
@ -91,10 +105,12 @@ public:
|
|||
std::recursive_mutex* GetLock();
|
||||
std::string GetPlayerDisplayName() const;
|
||||
u32 GetPlayerScore() const;
|
||||
const BadgeStatus& GetPlayerBadge() const;
|
||||
std::string GetGameDisplayName() const;
|
||||
PointSpread TallyScore() const;
|
||||
rc_api_fetch_game_data_response_t* GetGameData();
|
||||
UnlockStatus GetUnlockStatus(AchievementId achievement_id) const;
|
||||
const BadgeStatus& GetGameBadge() const;
|
||||
const UnlockStatus& GetUnlockStatus(AchievementId achievement_id) const;
|
||||
void GetAchievementProgress(AchievementId achievement_id, u32* value, u32* target);
|
||||
RichPresence GetRichPresence();
|
||||
|
||||
|
@ -129,6 +145,7 @@ private:
|
|||
ResponseType Request(RcRequest rc_request, RcResponse* rc_response,
|
||||
const std::function<int(rc_api_request_t*, const RcRequest*)>& init_request,
|
||||
const std::function<int(RcResponse*, const char*)>& process_response);
|
||||
ResponseType RequestImage(rc_api_fetch_image_request_t rc_request, Badge* rc_response);
|
||||
|
||||
rc_runtime_t m_runtime{};
|
||||
Core::System* m_system{};
|
||||
|
@ -136,16 +153,19 @@ private:
|
|||
UpdateCallback m_update_callback;
|
||||
std::string m_display_name;
|
||||
u32 m_player_score = 0;
|
||||
BadgeStatus m_player_badge;
|
||||
std::array<char, HASH_LENGTH> 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;
|
||||
RichPresence m_rich_presence;
|
||||
time_t m_last_ping_time = 0;
|
||||
|
||||
std::unordered_map<AchievementId, UnlockStatus> m_unlock_map;
|
||||
|
||||
Common::WorkQueueThread<std::function<void()>> m_queue;
|
||||
Common::WorkQueueThread<std::function<void()>> m_image_queue;
|
||||
std::recursive_mutex m_lock;
|
||||
}; // class AchievementManager
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ const Info<bool> RA_LEADERBOARDS_ENABLED{
|
|||
{System::Achievements, "Achievements", "LeaderboardsEnabled"}, false};
|
||||
const Info<bool> RA_RICH_PRESENCE_ENABLED{
|
||||
{System::Achievements, "Achievements", "RichPresenceEnabled"}, false};
|
||||
const Info<bool> RA_BADGES_ENABLED{{System::Achievements, "Achievements", "BadgesEnabled"}, false};
|
||||
const Info<bool> RA_UNOFFICIAL_ENABLED{{System::Achievements, "Achievements", "UnofficialEnabled"},
|
||||
false};
|
||||
const Info<bool> RA_ENCORE_ENABLED{{System::Achievements, "Achievements", "EncoreEnabled"}, false};
|
||||
|
|
|
@ -14,6 +14,7 @@ extern const Info<std::string> RA_API_TOKEN;
|
|||
extern const Info<bool> RA_ACHIEVEMENTS_ENABLED;
|
||||
extern const Info<bool> RA_LEADERBOARDS_ENABLED;
|
||||
extern const Info<bool> RA_RICH_PRESENCE_ENABLED;
|
||||
extern const Info<bool> RA_BADGES_ENABLED;
|
||||
extern const Info<bool> RA_UNOFFICIAL_ENABLED;
|
||||
extern const Info<bool> RA_ENCORE_ENABLED;
|
||||
} // namespace Config
|
||||
|
|
|
@ -47,6 +47,7 @@ bool IsSettingSaveable(const Config::Location& config_location)
|
|||
&Config::RA_ACHIEVEMENTS_ENABLED.GetLocation(),
|
||||
&Config::RA_LEADERBOARDS_ENABLED.GetLocation(),
|
||||
&Config::RA_RICH_PRESENCE_ENABLED.GetLocation(),
|
||||
&Config::RA_BADGES_ENABLED.GetLocation(),
|
||||
&Config::RA_UNOFFICIAL_ENABLED.GetLocation(),
|
||||
&Config::RA_ENCORE_ENABLED.GetLocation(),
|
||||
};
|
||||
|
|
|
@ -30,45 +30,44 @@
|
|||
|
||||
AchievementHeaderWidget::AchievementHeaderWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
m_user_name = new QLabel();
|
||||
m_user_points = new QLabel();
|
||||
m_game_name = new QLabel();
|
||||
m_game_points = new QLabel();
|
||||
m_user_icon = new QLabel();
|
||||
m_game_icon = new QLabel();
|
||||
m_name = new QLabel();
|
||||
m_points = new QLabel();
|
||||
m_game_progress_hard = new QProgressBar();
|
||||
m_game_progress_soft = new QProgressBar();
|
||||
m_rich_presence = new QLabel();
|
||||
|
||||
QVBoxLayout* m_user_right_col = new QVBoxLayout();
|
||||
m_user_right_col->addWidget(m_user_name);
|
||||
m_user_right_col->addWidget(m_user_points);
|
||||
QHBoxLayout* m_user_layout = new QHBoxLayout();
|
||||
// TODO: player badge goes here
|
||||
m_user_layout->addLayout(m_user_right_col);
|
||||
m_user_box = new QGroupBox();
|
||||
m_user_box->setLayout(m_user_layout);
|
||||
QSizePolicy sp_retain = m_game_progress_hard->sizePolicy();
|
||||
sp_retain.setRetainSizeWhenHidden(true);
|
||||
m_game_progress_hard->setSizePolicy(sp_retain);
|
||||
sp_retain = m_game_progress_soft->sizePolicy();
|
||||
sp_retain.setRetainSizeWhenHidden(true);
|
||||
m_game_progress_soft->setSizePolicy(sp_retain);
|
||||
|
||||
QVBoxLayout* m_game_right_col = new QVBoxLayout();
|
||||
m_game_right_col->addWidget(m_game_name);
|
||||
m_game_right_col->addWidget(m_game_points);
|
||||
m_game_right_col->addWidget(m_game_progress_hard);
|
||||
m_game_right_col->addWidget(m_game_progress_soft);
|
||||
QHBoxLayout* m_game_upper_row = new QHBoxLayout();
|
||||
// TODO: player badge and game badge go here
|
||||
m_game_upper_row->addLayout(m_game_right_col);
|
||||
QVBoxLayout* m_game_layout = new QVBoxLayout();
|
||||
m_game_layout->addLayout(m_game_upper_row);
|
||||
m_game_layout->addWidget(m_rich_presence);
|
||||
m_game_box = new QGroupBox();
|
||||
m_game_box->setLayout(m_game_layout);
|
||||
QVBoxLayout* icon_col = new QVBoxLayout();
|
||||
icon_col->addWidget(m_user_icon);
|
||||
icon_col->addWidget(m_game_icon);
|
||||
QVBoxLayout* text_col = new QVBoxLayout();
|
||||
text_col->addWidget(m_name);
|
||||
text_col->addWidget(m_points);
|
||||
text_col->addWidget(m_game_progress_hard);
|
||||
text_col->addWidget(m_game_progress_soft);
|
||||
text_col->addWidget(m_rich_presence);
|
||||
QHBoxLayout* header_layout = new QHBoxLayout();
|
||||
header_layout->addLayout(icon_col);
|
||||
header_layout->addLayout(text_col);
|
||||
m_header_box = new QGroupBox();
|
||||
m_header_box->setLayout(header_layout);
|
||||
|
||||
QVBoxLayout* m_total = new QVBoxLayout();
|
||||
m_total->addWidget(m_user_box);
|
||||
m_total->addWidget(m_game_box);
|
||||
m_total->addWidget(m_header_box);
|
||||
|
||||
m_total->setContentsMargins(0, 0, 0, 0);
|
||||
m_total->setAlignment(Qt::AlignTop);
|
||||
setLayout(m_total);
|
||||
|
||||
std::lock_guard lg{*AchievementManager::GetInstance()->GetLock()};
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
|
@ -76,38 +75,89 @@ void AchievementHeaderWidget::UpdateData()
|
|||
{
|
||||
if (!AchievementManager::GetInstance()->IsLoggedIn())
|
||||
{
|
||||
m_user_box->setVisible(false);
|
||||
m_game_box->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
QString user_name =
|
||||
QString::fromStdString(AchievementManager::GetInstance()->GetPlayerDisplayName());
|
||||
m_user_name->setText(user_name);
|
||||
m_user_points->setText(tr("%1 points").arg(AchievementManager::GetInstance()->GetPlayerScore()));
|
||||
|
||||
if (!AchievementManager::GetInstance()->IsGameLoaded())
|
||||
{
|
||||
m_user_box->setVisible(true);
|
||||
m_game_box->setVisible(false);
|
||||
m_header_box->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
AchievementManager::PointSpread point_spread = AchievementManager::GetInstance()->TallyScore();
|
||||
m_game_name->setText(
|
||||
QString::fromStdString(AchievementManager::GetInstance()->GetGameDisplayName()));
|
||||
m_game_points->setText(GetPointsString(user_name, point_spread));
|
||||
m_game_progress_hard = new QProgressBar();
|
||||
m_game_progress_hard->setRange(0, point_spread.total_count);
|
||||
m_game_progress_soft->setValue(point_spread.hard_unlocks);
|
||||
m_game_progress_soft->setRange(0, point_spread.total_count);
|
||||
m_game_progress_soft->setValue(point_spread.hard_unlocks + point_spread.soft_unlocks);
|
||||
m_rich_presence->setText(
|
||||
QString::fromUtf8(AchievementManager::GetInstance()->GetRichPresence().data()));
|
||||
m_rich_presence->setVisible(Config::Get(Config::RA_RICH_PRESENCE_ENABLED));
|
||||
QString user_name =
|
||||
QString::fromStdString(AchievementManager::GetInstance()->GetPlayerDisplayName());
|
||||
QString game_name =
|
||||
QString::fromStdString(AchievementManager::GetInstance()->GetGameDisplayName());
|
||||
AchievementManager::BadgeStatus player_badge =
|
||||
AchievementManager::GetInstance()->GetPlayerBadge();
|
||||
AchievementManager::BadgeStatus game_badge = AchievementManager::GetInstance()->GetGameBadge();
|
||||
|
||||
m_user_box->setVisible(false);
|
||||
m_game_box->setVisible(true);
|
||||
m_user_icon->setVisible(false);
|
||||
m_user_icon->clear();
|
||||
m_user_icon->setText({});
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED))
|
||||
{
|
||||
if (player_badge.name != "")
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_game_icon->setVisible(false);
|
||||
m_game_icon->clear();
|
||||
m_game_icon->setText({});
|
||||
if (Config::Get(Config::RA_BADGES_ENABLED))
|
||||
{
|
||||
if (game_badge.name != "")
|
||||
{
|
||||
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 (point_spread.hard_unlocks == point_spread.total_count)
|
||||
color = AchievementManager::GOLD;
|
||||
else if (point_spread.hard_unlocks + point_spread.soft_unlocks == point_spread.total_count)
|
||||
color = AchievementManager::BLUE;
|
||||
m_game_icon->setStyleSheet(
|
||||
QStringLiteral("border: 4px solid %1").arg(QString::fromStdString(std::string(color))));
|
||||
m_game_icon->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!game_name.isEmpty())
|
||||
{
|
||||
m_name->setText(tr("%1 is playing %2").arg(user_name).arg(game_name));
|
||||
m_points->setText(GetPointsString(user_name, point_spread));
|
||||
|
||||
m_game_progress_hard->setRange(0, point_spread.total_count);
|
||||
if (!m_game_progress_hard->isVisible())
|
||||
m_game_progress_hard->setVisible(true);
|
||||
m_game_progress_soft->setValue(point_spread.hard_unlocks);
|
||||
m_game_progress_soft->setRange(0, point_spread.total_count);
|
||||
m_game_progress_soft->setValue(point_spread.hard_unlocks + point_spread.soft_unlocks);
|
||||
if (!m_game_progress_soft->isVisible())
|
||||
m_game_progress_soft->setVisible(true);
|
||||
m_rich_presence->setText(
|
||||
QString::fromUtf8(AchievementManager::GetInstance()->GetRichPresence().data()));
|
||||
if (!m_rich_presence->isVisible())
|
||||
m_rich_presence->setVisible(Config::Get(Config::RA_RICH_PRESENCE_ENABLED));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_name->setText(user_name);
|
||||
m_points->setText(tr("%1 points").arg(AchievementManager::GetInstance()->GetPlayerScore()));
|
||||
|
||||
m_game_progress_hard->setVisible(false);
|
||||
m_game_progress_soft->setVisible(false);
|
||||
m_rich_presence->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
QString
|
||||
|
|
|
@ -27,16 +27,14 @@ private:
|
|||
QGroupBox* m_common_box;
|
||||
QVBoxLayout* m_common_layout;
|
||||
|
||||
QLabel* m_user_name;
|
||||
QLabel* m_user_points;
|
||||
QLabel* m_game_name;
|
||||
QLabel* m_game_points;
|
||||
QLabel* m_user_icon;
|
||||
QLabel* m_game_icon;
|
||||
QLabel* m_name;
|
||||
QLabel* m_points;
|
||||
QProgressBar* m_game_progress_hard;
|
||||
QProgressBar* m_game_progress_soft;
|
||||
QLabel* m_rich_presence;
|
||||
|
||||
QGroupBox* m_user_box;
|
||||
QGroupBox* m_game_box;
|
||||
QGroupBox* m_header_box;
|
||||
};
|
||||
|
||||
#endif // USE_RETRO_ACHIEVEMENTS
|
||||
|
|
|
@ -30,12 +30,17 @@
|
|||
#include "DolphinQt/QtUtils/SignalBlocking.h"
|
||||
#include "DolphinQt/Settings.h"
|
||||
|
||||
static constexpr bool hardcore_mode_enabled = false;
|
||||
|
||||
AchievementProgressWidget::AchievementProgressWidget(QWidget* parent) : QWidget(parent)
|
||||
{
|
||||
m_common_box = new QGroupBox();
|
||||
m_common_layout = new QVBoxLayout();
|
||||
|
||||
UpdateData();
|
||||
{
|
||||
std::lock_guard lg{*AchievementManager::GetInstance()->GetLock()};
|
||||
UpdateData();
|
||||
}
|
||||
|
||||
m_common_box->setLayout(m_common_layout);
|
||||
|
||||
|
@ -51,12 +56,53 @@ AchievementProgressWidget::CreateAchievementBox(const rc_api_achievement_definit
|
|||
{
|
||||
if (!AchievementManager::GetInstance()->IsGameLoaded())
|
||||
return new QGroupBox();
|
||||
QLabel* a_badge = new QLabel();
|
||||
const auto unlock_status = AchievementManager::GetInstance()->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;
|
||||
AchievementManager::GetInstance()->GetAchievementProgress(achievement->id, &value, &target);
|
||||
|
@ -77,7 +123,7 @@ AchievementProgressWidget::CreateAchievementBox(const rc_api_achievement_definit
|
|||
a_col_right->addWidget(a_status);
|
||||
a_col_right->addWidget(a_progress_bar);
|
||||
QHBoxLayout* a_total = new QHBoxLayout();
|
||||
// TODO: achievement badge goes here
|
||||
a_total->addWidget(a_badge);
|
||||
a_total->addLayout(a_col_right);
|
||||
QGroupBox* a_group_box = new QGroupBox();
|
||||
a_group_box->setLayout(a_total);
|
||||
|
|
|
@ -75,6 +75,11 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
"achievements.<br><br>Unofficial achievements may be optional or unfinished achievements "
|
||||
"that have not been deemed official by RetroAchievements and may be useful for testing or "
|
||||
"simply for fun."));
|
||||
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_encore_enabled_input = new ToolTipCheckBox(tr("Enable Encore Achievements"));
|
||||
m_common_encore_enabled_input->SetDescription(tr(
|
||||
"Enable unlocking achievements in Encore Mode.<br><br>Encore Mode re-enables achievements "
|
||||
|
@ -92,6 +97,7 @@ void AchievementSettingsWidget::CreateLayout()
|
|||
m_common_layout->addWidget(m_common_achievements_enabled_input);
|
||||
m_common_layout->addWidget(m_common_leaderboards_enabled_input);
|
||||
m_common_layout->addWidget(m_common_rich_presence_enabled_input);
|
||||
m_common_layout->addWidget(m_common_badges_enabled_input);
|
||||
m_common_layout->addWidget(m_common_unofficial_enabled_input);
|
||||
m_common_layout->addWidget(m_common_encore_enabled_input);
|
||||
|
||||
|
@ -111,6 +117,8 @@ void AchievementSettingsWidget::ConnectWidgets()
|
|||
&AchievementSettingsWidget::ToggleLeaderboards);
|
||||
connect(m_common_rich_presence_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleRichPresence);
|
||||
connect(m_common_badges_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleBadges);
|
||||
connect(m_common_unofficial_enabled_input, &QCheckBox::toggled, this,
|
||||
&AchievementSettingsWidget::ToggleUnofficial);
|
||||
connect(m_common_encore_enabled_input, &QCheckBox::toggled, this,
|
||||
|
@ -157,6 +165,9 @@ void AchievementSettingsWidget::LoadSettings()
|
|||
->setChecked(Config::Get(Config::RA_RICH_PRESENCE_ENABLED));
|
||||
SignalBlocking(m_common_rich_presence_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);
|
||||
|
||||
SignalBlocking(m_common_unofficial_enabled_input)
|
||||
->setChecked(Config::Get(Config::RA_UNOFFICIAL_ENABLED));
|
||||
SignalBlocking(m_common_unofficial_enabled_input)->setEnabled(enabled && achievements_enabled);
|
||||
|
@ -176,6 +187,7 @@ void AchievementSettingsWidget::SaveSettings()
|
|||
m_common_leaderboards_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_RICH_PRESENCE_ENABLED,
|
||||
m_common_rich_presence_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_BADGES_ENABLED, m_common_badges_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_UNOFFICIAL_ENABLED,
|
||||
m_common_unofficial_enabled_input->isChecked());
|
||||
Config::SetBaseOrCurrent(Config::RA_ENCORE_ENABLED, m_common_encore_enabled_input->isChecked());
|
||||
|
@ -224,6 +236,12 @@ void AchievementSettingsWidget::ToggleRichPresence()
|
|||
AchievementManager::GetInstance()->ActivateDeactivateRichPresence();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleBadges()
|
||||
{
|
||||
SaveSettings();
|
||||
AchievementManager::GetInstance()->FetchBadges();
|
||||
}
|
||||
|
||||
void AchievementSettingsWidget::ToggleUnofficial()
|
||||
{
|
||||
SaveSettings();
|
||||
|
|
|
@ -36,7 +36,7 @@ private:
|
|||
void ToggleLeaderboards();
|
||||
void ToggleRichPresence();
|
||||
void ToggleHardcore();
|
||||
void ToggleBadgeIcons();
|
||||
void ToggleBadges();
|
||||
void ToggleUnofficial();
|
||||
void ToggleEncore();
|
||||
|
||||
|
@ -55,6 +55,7 @@ private:
|
|||
ToolTipCheckBox* m_common_achievements_enabled_input;
|
||||
ToolTipCheckBox* m_common_leaderboards_enabled_input;
|
||||
ToolTipCheckBox* m_common_rich_presence_enabled_input;
|
||||
ToolTipCheckBox* m_common_badges_enabled_input;
|
||||
ToolTipCheckBox* m_common_unofficial_enabled_input;
|
||||
ToolTipCheckBox* m_common_encore_enabled_input;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue