mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Switch over to rc-client
This commit is contained in:
parent
0bf0a4a1ef
commit
d0b42705a0
20 changed files with 698 additions and 1922 deletions
|
@ -17,6 +17,14 @@ void OnScreenDisplay::Update() {
|
|||
}
|
||||
}
|
||||
|
||||
for (auto iter = sideEntries_.begin(); iter != sideEntries_.end(); ) {
|
||||
if (now >= iter->endTime) {
|
||||
iter = sideEntries_.erase(iter);
|
||||
} else {
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto iter = bars_.begin(); iter != bars_.end(); ) {
|
||||
if (now >= iter->endTime) {
|
||||
iter = bars_.erase(iter);
|
||||
|
@ -31,6 +39,11 @@ std::vector<OnScreenDisplay::Entry> OnScreenDisplay::Entries() {
|
|||
return entries_; // makes a copy.
|
||||
}
|
||||
|
||||
std::vector<OnScreenDisplay::Entry> OnScreenDisplay::SideEntries() {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return sideEntries_; // makes a copy.
|
||||
}
|
||||
|
||||
std::vector<OnScreenDisplay::ProgressBar> OnScreenDisplay::ProgressBars() {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
return bars_; // makes a copy.
|
||||
|
@ -99,6 +112,28 @@ void OnScreenDisplay::ShowAchievementUnlocked(int achievementID) {
|
|||
entries_.insert(entries_.begin(), msg);
|
||||
}
|
||||
|
||||
void OnScreenDisplay::ShowAchievementProgress(int achievementID, float duration_s) {
|
||||
double now = time_now_d();
|
||||
|
||||
for (auto &entry : sideEntries_) {
|
||||
if (entry.numericID == achievementID && entry.type == OSDType::ACHIEVEMENT_PROGRESS) {
|
||||
// Duplicate, let's just bump the timer.
|
||||
entry.startTime = now;
|
||||
entry.endTime = now + (double)duration_s;
|
||||
// We're done.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// OK, let's make a new side-entry.
|
||||
Entry entry;
|
||||
entry.numericID = achievementID;
|
||||
entry.type = OSDType::ACHIEVEMENT_PROGRESS;
|
||||
entry.startTime = now;
|
||||
entry.endTime = now + (double)duration_s;
|
||||
sideEntries_.insert(sideEntries_.begin(), entry);
|
||||
}
|
||||
|
||||
void OnScreenDisplay::ShowOnOff(const std::string &message, bool on, float duration_s) {
|
||||
// TODO: translate "on" and "off"? Or just get rid of this whole thing?
|
||||
Show(OSDType::MESSAGE_INFO, message + ": " + (on ? "on" : "off"), duration_s);
|
||||
|
|
|
@ -16,6 +16,10 @@ enum class OSDType {
|
|||
|
||||
ACHIEVEMENT_UNLOCKED,
|
||||
|
||||
// Side entries
|
||||
ACHIEVEMENT_PROGRESS,
|
||||
ACHIEVEMENT_CHALLENGE_INDICATOR,
|
||||
|
||||
// PROGRESS_BAR,
|
||||
// PROGRESS_INDETERMINATE,
|
||||
};
|
||||
|
@ -33,6 +37,8 @@ public:
|
|||
void Show(OSDType type, const std::string &text, const std::string &text2, const std::string &icon, float duration_s = 0.0f, const char *id = nullptr);
|
||||
void ShowAchievementUnlocked(int achievementID);
|
||||
|
||||
void ShowAchievementProgress(int achievementID, float duration_s);
|
||||
|
||||
void ShowOnOff(const std::string &message, bool on, float duration_s = 0.0f);
|
||||
|
||||
bool IsEmpty() const { return entries_.empty(); } // Shortcut to skip rendering.
|
||||
|
@ -66,10 +72,12 @@ public:
|
|||
};
|
||||
|
||||
std::vector<Entry> Entries();
|
||||
std::vector<Entry> SideEntries();
|
||||
std::vector<ProgressBar> ProgressBars();
|
||||
|
||||
private:
|
||||
std::vector<Entry> entries_;
|
||||
std::vector<Entry> sideEntries_;
|
||||
std::vector<ProgressBar> bars_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
|
|
@ -266,9 +266,6 @@ static bool DefaultSasThread() {
|
|||
|
||||
static const ConfigSetting achievementSettings[] = {
|
||||
ConfigSetting("AchievementsEnable", &g_Config.bAchievementsEnable, true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsLeaderboards", &g_Config.bAchievementsLeaderboards, false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsTestMode", &g_Config.bAchievementsTestMode, false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsUnofficialTestMode", &g_Config.bAchievementsUnofficialTestMode, false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsRichPresence", &g_Config.bAchievementsRichPresence, true, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsChallengeMode", &g_Config.bAchievementsChallengeMode, false, CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsSoundEffects", &g_Config.bAchievementsSoundEffects, true, CfgFlag::DEFAULT),
|
||||
|
@ -276,10 +273,10 @@ static const ConfigSetting achievementSettings[] = {
|
|||
ConfigSetting("AchievementsLogBadMemReads", &g_Config.bAchievementsLogBadMemReads, false, CfgFlag::DEFAULT),
|
||||
|
||||
// Achievements login info. Note that password is NOT stored, only a login token.
|
||||
// And that login token is stored separately from the ini, see NativeSaveSecret.
|
||||
ConfigSetting("AchievementsUserName", &g_Config.sAchievementsUserName, "", CfgFlag::DEFAULT),
|
||||
// And that login token is stored separately from the ini, see NativeSaveSecret, but it can also be loaded
|
||||
// from the ini if manually entered (useful when testing various builds on Android).
|
||||
ConfigSetting("AchievementsToken", &g_Config.sAchievementsToken, "", CfgFlag::DONT_SAVE),
|
||||
ConfigSetting("AchievementsLoginTimestamp", &g_Config.sAchievementsLoginTimestamp, "", CfgFlag::DEFAULT),
|
||||
ConfigSetting("AchievementsUserName", &g_Config.sAchievementsUserName, "", CfgFlag::DEFAULT),
|
||||
};
|
||||
|
||||
static const ConfigSetting cpuSettings[] = {
|
||||
|
|
|
@ -488,9 +488,6 @@ public:
|
|||
// Retro Achievement settings
|
||||
// Copied from Duckstation, we might want to remove some.
|
||||
bool bAchievementsEnable;
|
||||
bool bAchievementsLeaderboards;
|
||||
bool bAchievementsTestMode;
|
||||
bool bAchievementsUnofficialTestMode;
|
||||
bool bAchievementsRichPresence;
|
||||
bool bAchievementsChallengeMode;
|
||||
bool bAchievementsSoundEffects;
|
||||
|
@ -501,7 +498,6 @@ public:
|
|||
// Still, we may wanna store it more securely than in PPSSPP.ini, especially on Android.
|
||||
std::string sAchievementsUserName;
|
||||
std::string sAchievementsToken; // Not saved, to be used if you want to manually make your RA login persistent. See Native_SaveSecret for the normal case.
|
||||
std::string sAchievementsLoginTimestamp;
|
||||
|
||||
// Various directories. Autoconfigured, not read from ini.
|
||||
Path currentDirectory; // The directory selected in the game browsing window.
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,9 +9,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
@ -19,54 +16,17 @@
|
|||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "ext/rcheevos/include/rc_client.h"
|
||||
|
||||
class Path;
|
||||
class PointerWrap;
|
||||
|
||||
namespace Achievements {
|
||||
|
||||
enum class AchievementCategory : u8
|
||||
{
|
||||
Local = 0,
|
||||
Core = 3,
|
||||
Unofficial = 5
|
||||
};
|
||||
|
||||
struct Achievement
|
||||
{
|
||||
u32 id;
|
||||
std::string title;
|
||||
std::string description;
|
||||
std::string memaddr;
|
||||
std::string badge_name;
|
||||
|
||||
u32 points;
|
||||
AchievementCategory category;
|
||||
bool locked;
|
||||
bool active;
|
||||
bool primed;
|
||||
bool disabled; // due to bad memory access, presumably
|
||||
};
|
||||
|
||||
struct Leaderboard
|
||||
{
|
||||
u32 id;
|
||||
std::string title;
|
||||
std::string description;
|
||||
int format;
|
||||
bool hidden;
|
||||
};
|
||||
|
||||
struct LeaderboardEntry
|
||||
{
|
||||
std::string user;
|
||||
std::string formatted_score;
|
||||
time_t submitted;
|
||||
u32 rank;
|
||||
bool is_self;
|
||||
};
|
||||
|
||||
struct Statistics
|
||||
{
|
||||
struct Statistics {
|
||||
// Debug stats
|
||||
int badMemoryAccessCount;
|
||||
};
|
||||
|
@ -85,101 +45,46 @@ static inline bool IsUsingRAIntegration()
|
|||
|
||||
#endif
|
||||
|
||||
bool IsActive();
|
||||
bool IsLoggedIn();
|
||||
bool ChallengeModeActive();
|
||||
bool LeaderboardsActive();
|
||||
bool IsTestModeActive();
|
||||
bool IsUnofficialTestModeActive();
|
||||
bool IsRichPresenceEnabled();
|
||||
bool HasActiveGame();
|
||||
|
||||
u32 GetGameID();
|
||||
|
||||
/// Acquires the achievements lock. Must be held when accessing any achievement state from another thread.
|
||||
std::unique_lock<std::recursive_mutex> GetLock();
|
||||
|
||||
void Initialize();
|
||||
void UpdateSettings();
|
||||
|
||||
/// Called when the system is being reset. If it returns false, the reset should be aborted.
|
||||
bool ConfirmSystemReset();
|
||||
|
||||
/// Called when the system is being shut down. If Shutdown() returns false, the shutdown should be aborted if possible.
|
||||
bool Shutdown();
|
||||
|
||||
/// Called once a frame at vsync time on the CPU thread.
|
||||
void FrameUpdate();
|
||||
|
||||
/// Called when the system is paused, because FrameUpdate() won't be getting called.
|
||||
void ProcessPendingHTTPRequests();
|
||||
|
||||
/// Saves/loads state.
|
||||
bool DoState(PointerWrap &sw);
|
||||
|
||||
/// Returns true if the current game has any achievements or leaderboards.
|
||||
/// Does not need to have the lock held.
|
||||
bool SafeHasAchievementsOrLeaderboards();
|
||||
|
||||
const std::string &GetUsername();
|
||||
const std::string &GetRichPresenceString();
|
||||
|
||||
bool LoginAsync(const char *username, const char *password);
|
||||
void Logout();
|
||||
|
||||
void GameChanged(const Path &path);
|
||||
void LeftGame();
|
||||
|
||||
/// Re-enables hardcode mode if it is enabled in the settings.
|
||||
bool ResetChallengeMode();
|
||||
|
||||
/// Forces hardcore mode off until next reset.
|
||||
void DisableChallengeMode();
|
||||
|
||||
/// Prompts the user to disable hardcore mode, if they agree, returns true.
|
||||
bool ConfirmChallengeModeDisable(const char *trigger);
|
||||
|
||||
/// Returns true if features such as save states should be disabled.
|
||||
bool ChallengeModeActive();
|
||||
|
||||
const std::string &GetGameTitle();
|
||||
const std::string &GetGameIcon();
|
||||
// The new API is so much nicer that we can use it directly instead of wrapping it. So let's expose the client.
|
||||
// Will of course return nullptr if not active.
|
||||
rc_client_t *GetClient();
|
||||
|
||||
bool EnumerateAchievements(std::function<bool(const Achievement &)> callback);
|
||||
u32 GetGameID();
|
||||
|
||||
// TODO: Make these support multiple games, not just the current games, with cached info.
|
||||
u32 GetUnlockedAchiementCount();
|
||||
u32 GetAchievementCount();
|
||||
u32 GetMaximumPointsForGame();
|
||||
u32 GetCurrentPointsForGame();
|
||||
void Initialize();
|
||||
void UpdateSettings();
|
||||
|
||||
/// Called when the system is being shut down. If Shutdown() returns false, the shutdown should be aborted if possible.
|
||||
bool Shutdown();
|
||||
|
||||
void DownloadImageIfMissing(const std::string &cache_key, std::string &&url);
|
||||
|
||||
/// Called once a frame at vsync time on the CPU thread, during gameplay.
|
||||
void FrameUpdate();
|
||||
|
||||
/// Called every frame to let background processing happen.
|
||||
void Idle();
|
||||
|
||||
/// Saves/loads state.
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
/// Returns true if the current game has any achievements or leaderboards.
|
||||
bool HasAchievementsOrLeaderboards();
|
||||
|
||||
bool LoginAsync(const char *username, const char *password);
|
||||
void Logout();
|
||||
|
||||
void SetGame(const Path &path);
|
||||
void ChangeUMD(const Path &path); // for in-game UMD change
|
||||
void UnloadGame(); // Call when leaving a game.
|
||||
|
||||
Statistics GetStatistics();
|
||||
|
||||
bool EnumerateLeaderboards(std::function<bool(const Leaderboard &)> callback);
|
||||
|
||||
// Unlike most other functions here, this you're supposed to poll until you get a valid std::optional.
|
||||
std::optional<bool> TryEnumerateLeaderboardEntries(u32 id, std::function<bool(const LeaderboardEntry &)> callback);
|
||||
const Leaderboard *GetLeaderboardByID(u32 id);
|
||||
u32 GetLeaderboardCount();
|
||||
bool IsLeaderboardTimeType(const Leaderboard &leaderboard);
|
||||
u32 GetPrimedAchievementCount();
|
||||
|
||||
const Achievement *GetAchievementByID(u32 id);
|
||||
std::pair<u32, u32> GetAchievementProgress(const Achievement &achievement);
|
||||
std::string GetGameAchievementSummary();
|
||||
std::string GetAchievementProgressText(const Achievement &achievement);
|
||||
std::string GetAchievementBadgePath(const Achievement &achievement, bool download_if_missing = true,
|
||||
bool force_unlocked_icon = false);
|
||||
std::string GetAchievementBadgeURL(const Achievement &achievement);
|
||||
|
||||
#ifdef WITH_RAINTEGRATION
|
||||
void SwitchToRAIntegration();
|
||||
|
||||
namespace RAIntegration {
|
||||
void MainWindowChanged(void *new_handle);
|
||||
void GameChanged();
|
||||
std::vector<std::tuple<int, std::string, bool>> GetMenuItems();
|
||||
void ActivateMenuItem(int item);
|
||||
} // namespace RAIntegration
|
||||
#endif
|
||||
} // namespace Achievements
|
||||
|
|
|
@ -348,7 +348,7 @@ void EmuScreen::bootGame(const Path &filename) {
|
|||
g_OSD.Show(OSDType::MESSAGE_WARNING, gr->T("DefaultCPUClockRequired", "Warning: This game requires the CPU clock to be set to default."), 10.0f);
|
||||
}
|
||||
|
||||
Achievements::GameChanged(filename);
|
||||
Achievements::SetGame(filename);
|
||||
|
||||
loadingViewColor_->Divert(0xFFFFFFFF, 0.75f);
|
||||
loadingViewVisible_->Divert(UI::V_VISIBLE, 0.75f);
|
||||
|
@ -405,6 +405,7 @@ void EmuScreen::bootComplete() {
|
|||
EmuScreen::~EmuScreen() {
|
||||
if (!invalid_ || bootPending_) {
|
||||
// If we were invalid, it would already be shutdown.
|
||||
Achievements::UnloadGame();
|
||||
PSP_Shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -1206,7 +1206,8 @@ void NativeUpdate() {
|
|||
|
||||
g_requestManager.ProcessRequests();
|
||||
|
||||
Achievements::ProcessPendingHTTPRequests();
|
||||
// it's ok to call this redundantly with DoFrame from EmuScreen
|
||||
Achievements::Idle();
|
||||
|
||||
g_DownloadManager.Update();
|
||||
g_screenManager->update();
|
||||
|
|
|
@ -53,8 +53,10 @@ static NoticeLevel GetNoticeLevel(OSDType type) {
|
|||
}
|
||||
}
|
||||
|
||||
// Align only matters here for the ASCII-only flag.
|
||||
static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::string &text, const std::string &details, const std::string &iconName, int align, float *width, float *height, float *height1) {
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, text.c_str(), width, height, align);
|
||||
|
||||
*height1 = *height;
|
||||
|
||||
float width2 = 0.0f, height2 = 0.0f;
|
||||
|
@ -85,8 +87,8 @@ static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::str
|
|||
// Align only matters here for the ASCII-only flag.
|
||||
static void MeasureOSDEntry(const UIContext &dc, const OnScreenDisplay::Entry &entry, int align, float *width, float *height, float *height1) {
|
||||
if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) {
|
||||
const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID);
|
||||
MeasureAchievement(dc, *achievement, width, height);
|
||||
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
|
||||
MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, width, height);
|
||||
*width = 550.0f;
|
||||
*height1 = *height;
|
||||
} else {
|
||||
|
@ -141,12 +143,14 @@ static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLeve
|
|||
|
||||
static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, float height1, int align, float alpha) {
|
||||
if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) {
|
||||
const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID);
|
||||
RenderAchievement(dc, *achievement, AchievementRenderStyle::UNLOCKED, bounds, alpha, entry.startTime, time_now_d());
|
||||
const rc_client_achievement_t * achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
|
||||
if (achievement) {
|
||||
RenderAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, bounds, alpha, entry.startTime, time_now_d());
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
RenderNotice(dc, bounds, height1, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, alpha);
|
||||
}
|
||||
|
||||
RenderNotice(dc, bounds, height1, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, alpha);
|
||||
}
|
||||
|
||||
static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::ProgressBar &bar, float *width, float *height) {
|
||||
|
@ -204,11 +208,39 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
|
|||
|
||||
double now = time_now_d();
|
||||
|
||||
float y = 10.0f;
|
||||
|
||||
// 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;
|
||||
AchievementRenderStyle style = AchievementRenderStyle::PROGRESS_INDICATOR;
|
||||
|
||||
switch (entry.type) {
|
||||
case OSDType::ACHIEVEMENT_PROGRESS:
|
||||
{
|
||||
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
|
||||
style = AchievementRenderStyle::PROGRESS_INDICATOR;
|
||||
MeasureAchievement(dc, achievement, style, &tw, &th);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
Bounds b(10.0f, y, tw, th);
|
||||
float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f);
|
||||
// OK, render the thing.
|
||||
y += (b.h + 4.0f) * alpha; // including alpha here gets us smooth animations.
|
||||
|
||||
}
|
||||
|
||||
// Get height
|
||||
float w, h;
|
||||
dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, "Wg", &w, &h);
|
||||
|
||||
float y = 10.0f;
|
||||
y = 10.0f;
|
||||
|
||||
// Then draw them all.
|
||||
const std::vector<OnScreenDisplay::ProgressBar> bars = g_OSD.ProgressBars();
|
||||
for (auto &bar : bars) {
|
||||
|
@ -223,19 +255,34 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
|
|||
}
|
||||
|
||||
const std::vector<OnScreenDisplay::Entry> entries = g_OSD.Entries();
|
||||
for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
|
||||
for (const auto &entry : entries) {
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
// Messages that are wider than the screen are left-aligned instead of centered.
|
||||
|
||||
int align = 0;
|
||||
// If we have newlines, we may be looking at ASCII debug output. But let's verify.
|
||||
if (iter->text.find('\n') != 0) {
|
||||
if (!UTF8StringHasNonASCII(iter->text.c_str()))
|
||||
if (entry.text.find('\n') != 0) {
|
||||
if (!UTF8StringHasNonASCII(entry.text.c_str()))
|
||||
align |= FLAG_DYNAMIC_ASCII;
|
||||
}
|
||||
|
||||
float tw, th, h1;
|
||||
MeasureOSDEntry(dc, *iter, align, &tw, &th, &h1);
|
||||
float tw, th = 0.0f, h1 = 0.0f;
|
||||
|
||||
switch (entry.type) {
|
||||
case OSDType::ACHIEVEMENT_UNLOCKED:
|
||||
{
|
||||
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
|
||||
if (achievement) {
|
||||
MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, &tw, &th);
|
||||
h1 = th;
|
||||
}
|
||||
tw = 550.0f;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MeasureOSDEntry(dc, entry, align, &tw, &th, &h1);
|
||||
break;
|
||||
}
|
||||
|
||||
Bounds b(0.0f, y, tw, th);
|
||||
|
||||
|
@ -257,8 +304,8 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
|
|||
b.h *= scale;
|
||||
}
|
||||
|
||||
float alpha = Clamp((float)(iter->endTime - now) * 4.0f, 0.0f, 1.0f);
|
||||
RenderOSDEntry(dc, *iter, b, h1, align, alpha);
|
||||
float alpha = Clamp((float)(entry.endTime - now) * 4.0f, 0.0f, 1.0f);
|
||||
RenderOSDEntry(dc, entry, b, h1, align, alpha);
|
||||
y += (b.h * scale + 4.0f) * alpha; // including alpha here gets us smooth animations.
|
||||
}
|
||||
|
||||
|
|
|
@ -347,7 +347,7 @@ void GamePauseScreen::CreateViews() {
|
|||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
if (g_Config.bAchievementsEnable && Achievements::SafeHasAchievementsOrLeaderboards()) {
|
||||
if (g_Config.bAchievementsEnable && Achievements::HasAchievementsOrLeaderboards()) {
|
||||
rightColumnItems->Add(new Choice(pa->T("Achievements")))->OnClick.Add([&](UI::EventParams &e) {
|
||||
screenManager()->push(new RetroAchievementsListScreen(gamePath_));
|
||||
return UI::EVENT_DONE;
|
||||
|
|
|
@ -17,11 +17,9 @@ void RetroAchievementsListScreen::CreateTabs() {
|
|||
achievements->SetSpacing(5.0f);
|
||||
CreateAchievementsTab(achievements);
|
||||
|
||||
if (Achievements::GetLeaderboardCount() > 0) {
|
||||
UI::LinearLayout *leaderboards = AddTab("Leaderboards", ac->T("Leaderboards"));
|
||||
leaderboards->SetSpacing(5.0f);
|
||||
CreateLeaderboardsTab(leaderboards);
|
||||
}
|
||||
UI::LinearLayout *leaderboards = AddTab("Leaderboards", ac->T("Leaderboards"));
|
||||
leaderboards->SetSpacing(5.0f);
|
||||
CreateLeaderboardsTab(leaderboards);
|
||||
|
||||
#ifdef _DEBUG
|
||||
CreateStatisticsTab(AddTab("AchievementsStatistics", ac->T("Statistics")));
|
||||
|
@ -34,29 +32,45 @@ void RetroAchievementsListScreen::CreateAchievementsTab(UI::ViewGroup *achieveme
|
|||
|
||||
using namespace UI;
|
||||
|
||||
std::vector<Achievements::Achievement> unlockedAchievements;
|
||||
std::vector<Achievements::Achievement> lockedAchievements;
|
||||
rc_client_achievement_list_t *list = rc_client_create_achievement_list(Achievements::GetClient(),
|
||||
RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE_AND_UNOFFICIAL, RC_CLIENT_ACHIEVEMENT_LIST_GROUPING_LOCK_STATE);
|
||||
|
||||
std::vector<const rc_client_achievement_t *> unlockedAchievements;
|
||||
std::vector<const rc_client_achievement_t *> lockedAchievements;
|
||||
std::vector<const rc_client_achievement_t *> otherAchievements;
|
||||
|
||||
for (uint32_t i = 0; i < list->num_buckets; i++) {
|
||||
const rc_client_achievement_bucket_t &bucket = list->buckets[i];
|
||||
for (uint32_t j = 0; j < bucket.num_achievements; j++) {
|
||||
switch (bucket.bucket_type) {
|
||||
case RC_CLIENT_ACHIEVEMENT_BUCKET_LOCKED:
|
||||
lockedAchievements.push_back(bucket.achievements[j]);
|
||||
break;
|
||||
case RC_CLIENT_ACHIEVEMENT_BUCKET_UNLOCKED:
|
||||
unlockedAchievements.push_back(bucket.achievements[j]);
|
||||
break;
|
||||
default:
|
||||
otherAchievements.push_back(bucket.achievements[j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
achievements->Add(new ItemHeader(ac->T("Achievements")));
|
||||
|
||||
achievements->Add(new GameAchievementSummaryView(Achievements::GetGameID()));
|
||||
|
||||
Achievements::EnumerateAchievements([&](const Achievements::Achievement &achievement) {
|
||||
if (achievement.locked) {
|
||||
lockedAchievements.push_back(achievement);
|
||||
} else {
|
||||
unlockedAchievements.push_back(achievement);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
achievements->Add(new ItemHeader(ac->T("Unlocked achievements")));
|
||||
for (auto &achievement : unlockedAchievements) {
|
||||
achievements->Add(new AchievementView(std::move(achievement)));
|
||||
achievements->Add(new AchievementView(achievement));
|
||||
}
|
||||
achievements->Add(new ItemHeader(ac->T("Locked achievements")));
|
||||
for (auto &achievement : lockedAchievements) {
|
||||
achievements->Add(new AchievementView(std::move(achievement)));
|
||||
achievements->Add(new AchievementView(achievement));
|
||||
}
|
||||
achievements->Add(new ItemHeader(ac->T("Other achievements")));
|
||||
for (auto &achievement : otherAchievements) {
|
||||
achievements->Add(new AchievementView(achievement));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,21 +84,21 @@ void RetroAchievementsListScreen::CreateLeaderboardsTab(UI::ViewGroup *viewGroup
|
|||
|
||||
viewGroup->Add(new ItemHeader(ac->T("Leaderboards")));
|
||||
|
||||
std::vector<Achievements::Leaderboard> leaderboards;
|
||||
|
||||
Achievements::EnumerateLeaderboards([&](const Achievements::Leaderboard &leaderboard) {
|
||||
leaderboards.push_back(leaderboard);
|
||||
return true;
|
||||
});
|
||||
std::vector<rc_client_leaderboard_t *> leaderboards;
|
||||
rc_client_leaderboard_list_t *list = rc_client_create_leaderboard_list(Achievements::GetClient(), RC_CLIENT_LEADERBOARD_LIST_GROUPING_NONE);
|
||||
for (uint32_t i = 0; i < list->num_buckets; i++) {
|
||||
const rc_client_leaderboard_bucket_t &bucket = list->buckets[i];
|
||||
for (uint32_t j = 0; j < bucket.num_leaderboards; j++) {
|
||||
leaderboards.push_back(bucket.leaderboards[j]);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &leaderboard : leaderboards) {
|
||||
if (!leaderboard.hidden) {
|
||||
int leaderboardID = leaderboard.id;
|
||||
viewGroup->Add(new LeaderboardSummaryView(std::move(leaderboard)))->OnClick.Add([=](UI::EventParams &e) -> UI::EventReturn {
|
||||
screenManager()->push(new RetroAchievementsLeaderboardScreen(gamePath_, leaderboardID));
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
int leaderboardID = leaderboard->id;
|
||||
viewGroup->Add(new LeaderboardSummaryView(leaderboard))->OnClick.Add([=](UI::EventParams &e) -> UI::EventReturn {
|
||||
screenManager()->push(new RetroAchievementsLeaderboardScreen(gamePath_, leaderboardID));
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,35 +112,57 @@ void RetroAchievementsListScreen::CreateStatisticsTab(UI::ViewGroup *viewGroup)
|
|||
viewGroup->Add(new InfoItem(ac->T("Bad memory accesses"), StringFromFormat("%d", stats.badMemoryAccessCount)));
|
||||
}
|
||||
|
||||
RetroAchievementsLeaderboardScreen::~RetroAchievementsLeaderboardScreen() {
|
||||
if (pendingAsyncCall_) {
|
||||
rc_client_abort_async(Achievements::GetClient(), pendingAsyncCall_);
|
||||
}
|
||||
Poll(); // Gets rid of pendingEntryList_.
|
||||
if (entryList_) {
|
||||
rc_client_destroy_leaderboard_entry_list(entryList_);
|
||||
}
|
||||
}
|
||||
|
||||
RetroAchievementsLeaderboardScreen::RetroAchievementsLeaderboardScreen(const Path &gamePath, int leaderboardID)
|
||||
: TabbedUIDialogScreenWithGameBackground(gamePath), leaderboardID_(leaderboardID) {
|
||||
rc_client_begin_fetch_leaderboard_entries(Achievements::GetClient(), leaderboardID_, 0, 20, [](int result, const char *error_message, rc_client_leaderboard_entry_list_t *list, rc_client_t *client, void *userdata) {
|
||||
if (result != RC_OK) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, error_message, 10.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
RetroAchievementsLeaderboardScreen *thiz = (RetroAchievementsLeaderboardScreen *)userdata;
|
||||
thiz->pendingEntryList_ = list;
|
||||
thiz->pendingAsyncCall_ = nullptr;
|
||||
}, this);
|
||||
}
|
||||
|
||||
void RetroAchievementsLeaderboardScreen::CreateTabs() {
|
||||
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
|
||||
const Achievements::Leaderboard *leaderboard = Achievements::GetLeaderboardByID(leaderboardID_);
|
||||
const rc_client_leaderboard_t *leaderboard = rc_client_get_leaderboard_info(Achievements::GetClient(), leaderboardID_);
|
||||
|
||||
using namespace UI;
|
||||
|
||||
UI::LinearLayout *layout = AddTab("AchievementsLeaderboard", leaderboard->title.c_str());
|
||||
UI::LinearLayout *layout = AddTab("AchievementsLeaderboard", leaderboard->title);
|
||||
layout->Add(new TextView(leaderboard->description));
|
||||
|
||||
layout->Add(new ItemHeader(ac->T("Leaderboard")));
|
||||
|
||||
Poll();
|
||||
|
||||
// TODO: Make it pretty.
|
||||
for (auto &entry : entries_) {
|
||||
layout->Add(new TextView(StringFromFormat(" %d: %s: %s%s", entry.rank, entry.user.c_str(), entry.formatted_score.c_str(), entry.is_self ? " <<<<< " : "")));
|
||||
if (entryList_) {
|
||||
for (uint32_t i = 0; i < entryList_->num_entries; i++) {
|
||||
bool is_self = (i == entryList_->user_index);
|
||||
// Should highlight somehow.
|
||||
const rc_client_leaderboard_entry_t &entry = entryList_->entries[i];
|
||||
// Can also show entry.submitted, which is a time_t. And maybe highlight recent ones?
|
||||
layout->Add(new TextView(StringFromFormat(" %d: %s: %s%s", entry.rank, entry.user, entry.display, is_self ? " <<<<< " : "")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RetroAchievementsLeaderboardScreen::Poll() {
|
||||
if (done_)
|
||||
return;
|
||||
|
||||
std::optional<bool> result = Achievements::TryEnumerateLeaderboardEntries(leaderboardID_, [&](const Achievements::LeaderboardEntry &entry) -> bool {
|
||||
entries_.push_back(entry);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (result.has_value()) {
|
||||
done_ = true;
|
||||
if (pendingEntryList_) {
|
||||
if (entryList_) {
|
||||
rc_client_destroy_leaderboard_entry_list(entryList_);
|
||||
}
|
||||
entryList_ = pendingEntryList_;
|
||||
pendingEntryList_ = nullptr;
|
||||
RecreateViews();
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +197,14 @@ void RetroAchievementsSettingsScreen::CreateAccountTab(UI::ViewGroup *viewGroup)
|
|||
using namespace UI;
|
||||
|
||||
if (Achievements::IsLoggedIn()) {
|
||||
viewGroup->Add(new InfoItem(ac->T("Username"), Achievements::GetUsername()));
|
||||
const rc_client_user_t *info = rc_client_get_user_info(Achievements::GetClient());
|
||||
|
||||
// In the future, RetroAchievements will support display names. Prepare for that.
|
||||
if (strcmp(info->display_name, info->username) != 0) {
|
||||
viewGroup->Add(new InfoItem(ac->T("Name"), info->display_name));
|
||||
}
|
||||
viewGroup->Add(new InfoItem(ac->T("Username"), info->username));
|
||||
// viewGroup->Add(new InfoItem(ac->T("Unread messages"), info.numUnreadMessages));
|
||||
viewGroup->Add(new Choice(di->T("Log out")))->OnClick.Add([=](UI::EventParams &) -> UI::EventReturn {
|
||||
Achievements::Logout();
|
||||
return UI::EVENT_DONE;
|
||||
|
@ -224,9 +267,16 @@ void RetroAchievementsSettingsScreen::CreateSettingsTab(UI::ViewGroup *viewGroup
|
|||
// viewGroup->Add(new CheckBox(&g_Config.bAchievementsUnofficialTestMode, ac->T("Unofficial Test Mode")));
|
||||
}
|
||||
|
||||
void MeasureAchievement(const UIContext &dc, const Achievements::Achievement &achievement, float *w, float *h) {
|
||||
void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h) {
|
||||
*w = 0.0f;
|
||||
*h = 72.0f;
|
||||
switch (style) {
|
||||
case AchievementRenderStyle::PROGRESS_INDICATOR:
|
||||
*h = 36.0f;
|
||||
break;
|
||||
default:
|
||||
*h = 72.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MeasureGameAchievementSummary(const UIContext &dc, int gameID, float *w, float *h) {
|
||||
|
@ -234,16 +284,18 @@ void MeasureGameAchievementSummary(const UIContext &dc, int gameID, float *w, fl
|
|||
*h = 72.0f;
|
||||
}
|
||||
|
||||
void MeasureLeaderboardSummary(const UIContext &dc, const Achievements::Leaderboard &achievement, float *w, float *h) {
|
||||
void MeasureLeaderboardSummary(const UIContext &dc, const rc_client_leaderboard_t *leaderboard, float *w, float *h) {
|
||||
*w = 0.0f;
|
||||
*h = 72.0f;
|
||||
}
|
||||
|
||||
// Graphical
|
||||
void RenderAchievement(UIContext &dc, const Achievements::Achievement &achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s) {
|
||||
void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s) {
|
||||
using namespace UI;
|
||||
UI::Drawable background = UI::Drawable(dc.theme->backgroundColor);
|
||||
if (achievement.locked) {
|
||||
if (!achievement->unlocked) {
|
||||
// Make the background color gray.
|
||||
// TODO: Different colors in challenge mode, or even in the "re-take achievements" mode when we add that?
|
||||
background.color = 0x706060;
|
||||
}
|
||||
background.color = colorAlpha(background.color, alpha);
|
||||
|
@ -263,13 +315,15 @@ void RenderAchievement(UIContext &dc, const Achievements::Achievement &achieveme
|
|||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
dc.DrawTextRect(achievement.title.c_str(), bounds.Inset(iconSpace + 12.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
dc.DrawTextRect(achievement->title, bounds.Inset(iconSpace + 12.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
|
||||
dc.SetFontScale(0.66f, 0.66f);
|
||||
dc.DrawTextRect(achievement.description.c_str(), bounds.Inset(iconSpace + 12.0f, 39.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
dc.DrawTextRect(achievement->description, bounds.Inset(iconSpace + 12.0f, 39.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
|
||||
char temp[64];
|
||||
snprintf(temp, sizeof(temp), "%d", achievement.points);
|
||||
// TODO: Draw measured_progress / measured_percent in a cute way
|
||||
|
||||
char temp[512];
|
||||
snprintf(temp, sizeof(temp), "%d", achievement->points);
|
||||
|
||||
dc.SetFontScale(1.5f, 1.5f);
|
||||
dc.DrawTextRect(temp, bounds.Expand(-5.0f, -5.0f), fgColor, ALIGN_RIGHT | ALIGN_VCENTER);
|
||||
|
@ -277,9 +331,12 @@ void RenderAchievement(UIContext &dc, const Achievements::Achievement &achieveme
|
|||
dc.SetFontScale(1.0f, 1.0f);
|
||||
dc.Flush();
|
||||
|
||||
std::string name = Achievements::GetAchievementBadgePath(achievement);
|
||||
if (g_iconCache.BindIconTexture(&dc, name)) {
|
||||
dc.Draw()->DrawTexRect(Bounds(bounds.x + 4.0f, bounds.y + 4.0f, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
|
||||
// Download and display the image.
|
||||
if (RC_OK == rc_client_achievement_get_image_url(achievement, achievement->state, temp, sizeof(temp))) {
|
||||
Achievements::DownloadImageIfMissing(achievement->badge_name, std::move(std::string(temp)));
|
||||
if (g_iconCache.BindIconTexture(&dc, achievement->badge_name)) {
|
||||
dc.Draw()->DrawTexRect(Bounds(bounds.x + 4.0f, bounds.y + 4.0f, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
|
||||
}
|
||||
}
|
||||
|
||||
dc.Flush();
|
||||
|
@ -301,11 +358,12 @@ void RenderGameAchievementSummary(UIContext &dc, int gameID, const Bounds &bound
|
|||
|
||||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
|
||||
const rc_client_game_t *gameInfo = rc_client_get_game_info(Achievements::GetClient());
|
||||
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
dc.DrawTextRect(Achievements::GetGameTitle().c_str(), bounds.Inset(iconSpace + 5.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
dc.DrawTextRect(gameInfo->title, bounds.Inset(iconSpace + 5.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
|
||||
std::string description = Achievements::GetGameAchievementSummary();
|
||||
std::string icon = Achievements::GetGameIcon();
|
||||
|
||||
dc.SetFontScale(0.66f, 0.66f);
|
||||
dc.DrawTextRect(description.c_str(), bounds.Inset(iconSpace + 5.0f, 38.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
|
@ -313,16 +371,19 @@ void RenderGameAchievementSummary(UIContext &dc, int gameID, const Bounds &bound
|
|||
dc.SetFontScale(1.0f, 1.0f);
|
||||
dc.Flush();
|
||||
|
||||
std::string name = icon;
|
||||
if (g_iconCache.BindIconTexture(&dc, name)) {
|
||||
dc.Draw()->DrawTexRect(Bounds(bounds.x, bounds.y, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
|
||||
char temp[512];
|
||||
if (RC_OK == rc_client_game_get_image_url(gameInfo, temp, sizeof(temp))) {
|
||||
Achievements::DownloadImageIfMissing(gameInfo->badge_name, std::move(std::string(temp)));
|
||||
if (g_iconCache.BindIconTexture(&dc, gameInfo->badge_name)) {
|
||||
dc.Draw()->DrawTexRect(Bounds(bounds.x, bounds.y, iconSpace, iconSpace), 0.0f, 0.0f, 1.0f, 1.0f, whiteAlpha(alpha));
|
||||
}
|
||||
}
|
||||
|
||||
dc.Flush();
|
||||
dc.RebindTexture();
|
||||
}
|
||||
|
||||
void RenderLeaderboardSummary(UIContext &dc, const Achievements::Leaderboard &leaderboard, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s) {
|
||||
void RenderLeaderboardSummary(UIContext &dc, const rc_client_leaderboard_t *leaderboard, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s) {
|
||||
using namespace UI;
|
||||
UI::Drawable background = UI::Drawable(dc.theme->backgroundColor);
|
||||
background.color = colorAlpha(background.color, alpha);
|
||||
|
@ -333,7 +394,6 @@ void RenderLeaderboardSummary(UIContext &dc, const Achievements::Leaderboard &le
|
|||
background.color = colorBlend(0xFFE0FFFF, background.color, mixWhite);
|
||||
}
|
||||
|
||||
float iconSpace = 64.0f;
|
||||
dc.Flush();
|
||||
|
||||
dc.Begin();
|
||||
|
@ -342,10 +402,10 @@ void RenderLeaderboardSummary(UIContext &dc, const Achievements::Leaderboard &le
|
|||
dc.SetFontStyle(dc.theme->uiFont);
|
||||
|
||||
dc.SetFontScale(1.0f, 1.0f);
|
||||
dc.DrawTextRect(leaderboard.title.c_str(), bounds.Inset(iconSpace + 12.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
dc.DrawTextRect(leaderboard->title, bounds.Inset(12.0f, 2.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
|
||||
dc.SetFontScale(0.66f, 0.66f);
|
||||
dc.DrawTextRect(leaderboard.description.c_str(), bounds.Inset(iconSpace + 12.0f, 39.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
dc.DrawTextRect(leaderboard->description, bounds.Inset(12.0f, 39.0f, 5.0f, 5.0f), fgColor, ALIGN_TOPLEFT);
|
||||
|
||||
/*
|
||||
char temp[64];
|
||||
|
@ -367,13 +427,13 @@ void AchievementView::Draw(UIContext &dc) {
|
|||
}
|
||||
|
||||
void AchievementView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
MeasureAchievement(dc, achievement_, &w, &h);
|
||||
MeasureAchievement(dc, achievement_, AchievementRenderStyle::LISTED, &w, &h);
|
||||
}
|
||||
|
||||
void AchievementView::Click() {
|
||||
// In debug builds, clicking achievements will show them being unlocked (which may be a lie).
|
||||
#ifdef _DEBUG
|
||||
g_OSD.ShowAchievementUnlocked(achievement_.id);
|
||||
g_OSD.ShowAchievementUnlocked(achievement_->id);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "Common/File/Path.h"
|
||||
#include "Common/UI/View.h"
|
||||
#include "Common/UI/UIScreen.h"
|
||||
|
@ -47,20 +49,29 @@ private:
|
|||
|
||||
class RetroAchievementsLeaderboardScreen : public TabbedUIDialogScreenWithGameBackground {
|
||||
public:
|
||||
RetroAchievementsLeaderboardScreen(const Path &gamePath, int leaderboardID) : TabbedUIDialogScreenWithGameBackground(gamePath), leaderboardID_(leaderboardID) {}
|
||||
RetroAchievementsLeaderboardScreen(const Path &gamePath, int leaderboardID);
|
||||
~RetroAchievementsLeaderboardScreen();
|
||||
|
||||
const char *tag() const override { return "RetroAchievementsLeaderboardScreen"; }
|
||||
|
||||
void CreateTabs() override;
|
||||
|
||||
void update() override;
|
||||
|
||||
protected:
|
||||
bool ShowSearchControls() const override { return false; }
|
||||
|
||||
private:
|
||||
void Poll();
|
||||
|
||||
int leaderboardID_;
|
||||
bool done_ = false;
|
||||
std::vector<Achievements::LeaderboardEntry> entries_;
|
||||
|
||||
// Keep the fetched list alive and destroy in destructor.
|
||||
rc_client_leaderboard_entry_list_t *entryList_ = nullptr;
|
||||
|
||||
rc_client_leaderboard_entry_list_t *pendingEntryList_ = nullptr;
|
||||
|
||||
rc_client_async_handle_t *pendingAsyncCall_ = nullptr;
|
||||
};
|
||||
|
||||
class UIContext;
|
||||
|
@ -68,33 +79,35 @@ class UIContext;
|
|||
enum class AchievementRenderStyle {
|
||||
LISTED,
|
||||
UNLOCKED,
|
||||
PROGRESS_INDICATOR,
|
||||
};
|
||||
|
||||
void MeasureAchievement(const UIContext &dc, const Achievements::Achievement &achievement, float *w, float *h);
|
||||
void RenderAchievement(UIContext &dc, const Achievements::Achievement &achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s);
|
||||
void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h);
|
||||
void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, const Bounds &bounds, float alpha, float startTime, float time_s);
|
||||
|
||||
void MeasureGameAchievementSummary(const UIContext &dc, int gameID, float *w, float *h);
|
||||
void RenderGameAchievementSummary(UIContext &dc, int gameID, const Bounds &bounds, float alpha);
|
||||
|
||||
class AchievementView : public UI::ClickableItem {
|
||||
public:
|
||||
AchievementView(const Achievements::Achievement &&achievement, UI::LayoutParams *layoutParams = nullptr) : UI::ClickableItem(layoutParams), achievement_(achievement) {}
|
||||
AchievementView(const rc_client_achievement_t *achievement, UI::LayoutParams *layoutParams = nullptr) : UI::ClickableItem(layoutParams), achievement_(achievement) {}
|
||||
|
||||
void Click() override;
|
||||
void Draw(UIContext &dc) override;
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
private:
|
||||
Achievements::Achievement achievement_;
|
||||
const rc_client_achievement_t *achievement_;
|
||||
};
|
||||
|
||||
class LeaderboardSummaryView : public UI::ClickableItem {
|
||||
public:
|
||||
LeaderboardSummaryView(const Achievements::Leaderboard &&leaderboard, UI::LayoutParams *layoutParams = nullptr) : UI::ClickableItem(layoutParams), leaderboard_(leaderboard) {}
|
||||
LeaderboardSummaryView(const rc_client_leaderboard_t *leaderboard, UI::LayoutParams *layoutParams = nullptr) : UI::ClickableItem(layoutParams), leaderboard_(leaderboard) {}
|
||||
|
||||
void Draw(UIContext &dc) override;
|
||||
void GetContentDimensions(const UIContext &dc, float &w, float &h) const override;
|
||||
|
||||
private:
|
||||
Achievements::Leaderboard leaderboard_;
|
||||
const rc_client_leaderboard_t *leaderboard_;
|
||||
};
|
||||
|
||||
class GameAchievementSummaryView : public UI::Item {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
<ClInclude Include="..\..\ext\rcheevos\include\rc_api_request.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_api_runtime.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_api_user.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_client.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_consoles.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_error.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_hash.h" />
|
||||
|
@ -48,6 +49,7 @@
|
|||
<ClInclude Include="..\..\ext\rcheevos\include\rc_runtime_types.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_url.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\src\rapi\rc_api_common.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\src\rcheevos\rc_client_internal.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\src\rcheevos\rc_compat.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\src\rcheevos\rc_internal.h" />
|
||||
<ClInclude Include="..\..\ext\rcheevos\src\rcheevos\rc_validate.h" />
|
||||
|
@ -69,6 +71,7 @@
|
|||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\lboard.c" />
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\memref.c" />
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\operand.c" />
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\rc_client.c" />
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\rc_validate.c" />
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\richpresence.c" />
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\runtime.c" />
|
||||
|
@ -103,8 +106,10 @@
|
|||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings"></ImportGroup>
|
||||
<ImportGroup Label="Shared"></ImportGroup>
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
|
|
|
@ -55,6 +55,12 @@
|
|||
<ClInclude Include="..\..\ext\rcheevos\src\rhash\md5.h">
|
||||
<Filter>rhash</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\ext\rcheevos\src\rcheevos\rc_client_internal.h">
|
||||
<Filter>rcheevos</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\ext\rcheevos\include\rc_client.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="include">
|
||||
|
@ -140,5 +146,8 @@
|
|||
<ClCompile Include="..\..\ext\rcheevos\src\rhash\md5.c">
|
||||
<Filter>rhash</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\ext\rcheevos\src\rcheevos\rc_client.c">
|
||||
<Filter>rcheevos</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -95,6 +95,7 @@ RCHEEVOS_FILES := \
|
|||
${SRC}/ext/rcheevos/src/rcheevos/lboard.c \
|
||||
${SRC}/ext/rcheevos/src/rcheevos/memref.c \
|
||||
${SRC}/ext/rcheevos/src/rcheevos/operand.c \
|
||||
${SRC}/ext/rcheevos/src/rcheevos/rc_client.c \
|
||||
${SRC}/ext/rcheevos/src/rcheevos/rc_validate.c \
|
||||
${SRC}/ext/rcheevos/src/rcheevos/richpresence.c \
|
||||
${SRC}/ext/rcheevos/src/rcheevos/runtime.c \
|
||||
|
@ -103,8 +104,7 @@ RCHEEVOS_FILES := \
|
|||
${SRC}/ext/rcheevos/src/rcheevos/value.c \
|
||||
${SRC}/ext/rcheevos/src/rhash/cdreader.c \
|
||||
${SRC}/ext/rcheevos/src/rhash/hash.c \
|
||||
${SRC}/ext/rcheevos/src/rhash/md5.c \
|
||||
${SRC}/ext/rcheevos/src/rurl/url.c
|
||||
${SRC}/ext/rcheevos/src/rhash/md5.c
|
||||
|
||||
VR_FILES := \
|
||||
$(SRC)/Common/VR/OpenXRLoader.cpp \
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d176b4bcb42488da84f55991fd10f8ff36183384
|
||||
Subproject commit 223df0761313c5c9d9f4d4dc4b5897cf41e7e036
|
|
@ -23,6 +23,8 @@ set(ALL_SOURCE_FILES
|
|||
${SRC_DIR}/rcheevos/memref.c
|
||||
${SRC_DIR}/rcheevos/operand.c
|
||||
${SRC_DIR}/rcheevos/rc_compat.h
|
||||
${SRC_DIR}/rcheevos/rc_client.c
|
||||
${SRC_DIR}/rcheevos/rc_client_internal.h
|
||||
${SRC_DIR}/rcheevos/rc_internal.h
|
||||
${SRC_DIR}/rcheevos/rc_validate.h
|
||||
${SRC_DIR}/rcheevos/rc_validate.c
|
||||
|
@ -37,8 +39,6 @@ set(ALL_SOURCE_FILES
|
|||
${SRC_DIR}/rhash/hash.c
|
||||
${SRC_DIR}/rhash/md5.c
|
||||
${SRC_DIR}/rhash/md5.h
|
||||
# rurl
|
||||
${SRC_DIR}/rurl/url.c
|
||||
)
|
||||
|
||||
add_library(rcheevos STATIC ${ALL_SOURCE_FILES})
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
<ClCompile Include="..\rcheevos\src\rcheevos\lboard.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\memref.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\operand.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\rc_client.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\rc_validate.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\richpresence.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\runtime.c" />
|
||||
|
@ -58,7 +59,6 @@
|
|||
<ClCompile Include="..\rcheevos\src\rhash\cdreader.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rhash\hash.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rhash\md5.c" />
|
||||
<ClCompile Include="..\rcheevos\src\rurl\url.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\rcheevos\include\rcheevos.h" />
|
||||
|
@ -67,6 +67,7 @@
|
|||
<ClInclude Include="..\rcheevos\include\rc_api_request.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_api_runtime.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_api_user.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_client.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_consoles.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_error.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_hash.h" />
|
||||
|
@ -74,6 +75,7 @@
|
|||
<ClInclude Include="..\rcheevos\include\rc_runtime_types.h" />
|
||||
<ClInclude Include="..\rcheevos\include\rc_url.h" />
|
||||
<ClInclude Include="..\rcheevos\src\rapi\rc_api_common.h" />
|
||||
<ClInclude Include="..\rcheevos\src\rcheevos\rc_client_internal.h" />
|
||||
<ClInclude Include="..\rcheevos\src\rcheevos\rc_compat.h" />
|
||||
<ClInclude Include="..\rcheevos\src\rcheevos\rc_internal.h" />
|
||||
<ClInclude Include="..\rcheevos\src\rcheevos\rc_validate.h" />
|
||||
|
|
|
@ -10,9 +10,6 @@
|
|||
<Filter Include="rhash">
|
||||
<UniqueIdentifier>{55ec06aa-6d34-4edf-8b0b-f93f93a064b4}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="rurl">
|
||||
<UniqueIdentifier>{990047ac-f0d4-44f5-8463-54f898557d02}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{9e049d1f-4b83-4aa5-89f3-01a42e1773e2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
|
@ -87,8 +84,8 @@
|
|||
<ClCompile Include="..\rcheevos\src\rhash\md5.c">
|
||||
<Filter>rhash</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\rcheevos\src\rurl\url.c">
|
||||
<Filter>rurl</Filter>
|
||||
<ClCompile Include="..\rcheevos\src\rcheevos\rc_client.c">
|
||||
<Filter>rcheevos</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -146,5 +143,11 @@
|
|||
<ClInclude Include="..\rcheevos\src\rhash\md5.h">
|
||||
<Filter>rhash</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\rcheevos\include\rc_client.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\rcheevos\src\rcheevos\rc_client_internal.h">
|
||||
<Filter>rcheevos</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -212,6 +212,7 @@ SOURCES_C += \
|
|||
$(EXTDIR)/rcheevos/src/rcheevos/lboard.c \
|
||||
$(EXTDIR)/rcheevos/src/rcheevos/memref.c \
|
||||
$(EXTDIR)/rcheevos/src/rcheevos/operand.c \
|
||||
$(EXTDIR)/rcheevos/src/rcheevos/rc_client.c \
|
||||
$(EXTDIR)/rcheevos/src/rcheevos/rc_validate.c \
|
||||
$(EXTDIR)/rcheevos/src/rcheevos/richpresence.c \
|
||||
$(EXTDIR)/rcheevos/src/rcheevos/runtime.c \
|
||||
|
|
Loading…
Add table
Reference in a new issue