Skip to content

Commit

Permalink
Achievements: Backports from PCSX2
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Oct 8, 2022
1 parent 6d32e9b commit 550b492
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 38 deletions.
2 changes: 2 additions & 0 deletions src/core/settings.cpp
Expand Up @@ -347,6 +347,7 @@ void Settings::Load(SettingsInterface& si)
achievements_challenge_mode = si.GetBoolValue("Cheevos", "ChallengeMode", false);
achievements_leaderboards = si.GetBoolValue("Cheevos", "Leaderboards", true);
achievements_sound_effects = si.GetBoolValue("Cheevos", "SoundEffects", true);
achievements_primed_indicators = si.GetBoolValue("Cheevos", "PrimedIndicators", true);

log_level = ParseLogLevelName(si.GetStringValue("Logging", "LogLevel", GetLogLevelName(DEFAULT_LOG_LEVEL)).c_str())
.value_or(DEFAULT_LOG_LEVEL);
Expand Down Expand Up @@ -534,6 +535,7 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Cheevos", "ChallengeMode", achievements_challenge_mode);
si.SetBoolValue("Cheevos", "Leaderboards", achievements_leaderboards);
si.SetBoolValue("Cheevos", "SoundEffects", achievements_sound_effects);
si.SetBoolValue("Cheevos", "PrimedIndicators", achievements_primed_indicators);

si.SetStringValue("Logging", "LogLevel", GetLogLevelName(log_level));
si.SetStringValue("Logging", "LogFilter", log_filter.c_str());
Expand Down
1 change: 1 addition & 0 deletions src/core/settings.h
Expand Up @@ -178,6 +178,7 @@ struct Settings
bool achievements_challenge_mode : 1;
bool achievements_leaderboards : 1;
bool achievements_sound_effects : 1;
bool achievements_primed_indicators : 1;
#endif

struct DebugSettings
Expand Down
5 changes: 5 additions & 0 deletions src/duckstation-qt/achievementsettingswidget.cpp
Expand Up @@ -26,6 +26,7 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
"UseFirstDiscFromPlaylist", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboards, "Cheevos", "Leaderboards", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Cheevos", "SoundEffects", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.primedIndicators, "Cheevos", "PrimedIndicators", true);

dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"),
tr("When enabled and logged in, DuckStation will scan for achievements on startup."));
Expand Down Expand Up @@ -53,6 +54,9 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
m_ui.leaderboards, tr("Enable Leaderboards"), tr("Checked"),
tr("Enables tracking and submission of leaderboards in supported games. If leaderboards "
"are disabled, you will still be able to view the leaderboard and scores, but no scores will be uploaded."));
dialog->registerWidgetHelp(
m_ui.primedIndicators, tr("Show Challenge Indicators"), tr("Checked"),
tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."));

connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
Expand Down Expand Up @@ -95,6 +99,7 @@ void AchievementSettingsWidget::updateEnableState()
m_ui.leaderboards->setEnabled(enabled && challenge);
m_ui.unofficialTestMode->setEnabled(enabled);
m_ui.soundEffects->setEnabled(enabled);
m_ui.primedIndicators->setEnabled(enabled);
}

void AchievementSettingsWidget::onChallengeModeStateChanged()
Expand Down
51 changes: 29 additions & 22 deletions src/duckstation-qt/achievementsettingswidget.ui
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>648</width>
<height>456</height>
<height>475</height>
</rect>
</property>
<property name="windowTitle">
Expand All @@ -32,31 +32,45 @@
<string>Global Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="1">
<widget class="QCheckBox" name="unofficialTestMode">
<property name="text">
<string>Test Unofficial Achievements</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="soundEffects">
<property name="text">
<string>Enable Sound Effects</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="enable">
<property name="text">
<string>Enable Achievements</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="unofficialTestMode">
<item row="1" column="1">
<widget class="QCheckBox" name="leaderboards">
<property name="text">
<string>Test Unofficial Achievements</string>
<string>Enable Leaderboards</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="richPresence">
<item row="3" column="0">
<widget class="QCheckBox" name="primedIndicators">
<property name="text">
<string>Enable Rich Presence</string>
<string>Show Challenge Indicators</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="testMode">
<item row="0" column="1">
<widget class="QCheckBox" name="richPresence">
<property name="text">
<string>Enable Test Mode</string>
<string>Enable Rich Presence</string>
</property>
</widget>
</item>
Expand All @@ -67,24 +81,17 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="soundEffects">
<property name="text">
<string>Enable Sound Effects</string>
</property>
</widget>
</item>
<item row="3" column="0">
<item row="4" column="0">
<widget class="QCheckBox" name="useFirstDiscFromPlaylist">
<property name="text">
<string>Use First Disc From Playlist</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="leaderboards">
<item row="3" column="1">
<widget class="QCheckBox" name="testMode">
<property name="text">
<string>Enable Leaderboards</string>
<string>Enable Test Mode</string>
</property>
</widget>
</item>
Expand Down Expand Up @@ -130,7 +137,7 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>160</height>
<height>120</height>
</size>
</property>
<property name="title">
Expand Down
33 changes: 24 additions & 9 deletions src/frontend-common/achievements.cpp
Expand Up @@ -867,7 +867,7 @@ void Achievements::LoginCallback(s32 status_code, std::string content_type, Comm

RAPIResponse<rc_api_login_response_t, rc_api_process_login_response, rc_api_destroy_login_response> response(
status_code, data);
if (!response)
if (!response || !response.username || !response.api_token)
{
FormattedError("Login failed. Please check your user name and password, and try again.");
return;
Expand Down Expand Up @@ -1104,7 +1104,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,

std::unique_lock lock(s_achievements_mutex);
ClearGameInfo();
if (!response)
if (!response || !response.title)
{
DisableChallengeMode();
return;
Expand All @@ -1117,7 +1117,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
s_game_title = response.title;

// try for a icon
if (std::strlen(response.image_name) > 0)
if (response.image_name && std::strlen(response.image_name) > 0)
{
s_game_icon = Path::Combine(s_game_icon_cache_directory, fmt::format("{}.png", s_game_id));
if (!FileSystem::FileExists(s_game_icon.c_str()))
Expand Down Expand Up @@ -1155,6 +1155,12 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
continue;
}

if (!defn.definition || !defn.title || !defn.description || !defn.badge_name)
{
Log_ErrorPrintf("Incomplete achievement %u", defn.id);
continue;
}

Achievement cheevo;
cheevo.id = defn.id;
cheevo.memaddr = defn.definition;
Expand All @@ -1172,6 +1178,11 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
for (u32 i = 0; i < response.num_leaderboards; i++)
{
const rc_api_leaderboard_definition_t& defn = response.leaderboards[i];
if (!defn.title || !defn.description || !defn.definition)
{
Log_ErrorPrintf("Incomplete achievement %u", defn.id);
continue;
}

Leaderboard lboard;
lboard.id = defn.id;
Expand All @@ -1192,7 +1203,7 @@ void Achievements::GetPatchesCallback(s32 status_code, std::string content_type,
}

// parse rich presence
if (std::strlen(response.rich_presence_script) > 0)
if (response.rich_presence_script && std::strlen(response.rich_presence_script) > 0)
{
const int res = rc_runtime_activate_richpresence(&s_rcheevos_runtime, response.rich_presence_script, nullptr, 0);
if (res == RC_OK)
Expand Down Expand Up @@ -1263,6 +1274,8 @@ void Achievements::GetLbInfoCallback(s32 status_code, std::string content_type,
for (u32 i = 0; i < response.num_entries; i++)
{
const rc_api_lboard_info_entry_t& entry = response.entries[i];
if (!entry.username)
continue;

char score[128];
rc_runtime_format_lboard_value(score, sizeof(score), entry.score, leaderboard->format);
Expand Down Expand Up @@ -1903,16 +1916,18 @@ TinyString Achievements::GetAchievementProgressText(const Achievement& achieveme
return buf;
}

const std::string& Achievements::GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing)
const std::string& Achievements::GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing,
bool force_unlocked_icon)
{
std::string& badge_path = achievement.locked ? achievement.locked_badge_path : achievement.unlocked_badge_path;
const bool use_locked = (achievement.locked && !force_unlocked_icon);
std::string& badge_path = use_locked ? achievement.locked_badge_path : achievement.unlocked_badge_path;
if (!badge_path.empty() || achievement.badge_name.empty())
return badge_path;

// well, this comes from the internet.... :)
const std::string clean_name(Path::SanitizeFileName(achievement.badge_name));
badge_path = Path::Combine(s_achievement_icon_cache_directory,
fmt::format("{}{}.png", clean_name, achievement.locked ? "_lock" : ""));
badge_path =
Path::Combine(s_achievement_icon_cache_directory, fmt::format("{}{}.png", clean_name, use_locked ? "_lock" : ""));
if (FileSystem::FileExists(badge_path.c_str()))
return badge_path;

Expand All @@ -1921,7 +1936,7 @@ const std::string& Achievements::GetAchievementBadgePath(const Achievement& achi
{
RAPIRequest<rc_api_fetch_image_request_t, rc_api_init_fetch_image_request> request;
request.image_name = achievement.badge_name.c_str();
request.image_type = achievement.locked ? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED : RC_IMAGE_TYPE_ACHIEVEMENT;
request.image_type = use_locked ? RC_IMAGE_TYPE_ACHIEVEMENT_LOCKED : RC_IMAGE_TYPE_ACHIEVEMENT;
request.DownloadImage(badge_path);
}

Expand Down
3 changes: 2 additions & 1 deletion src/frontend-common/achievements.h
Expand Up @@ -149,7 +149,8 @@ u32 GetPrimedAchievementCount();
const Achievement* GetAchievementByID(u32 id);
std::pair<u32, u32> GetAchievementProgress(const Achievement& achievement);
TinyString GetAchievementProgressText(const Achievement& achievement);
const std::string& GetAchievementBadgePath(const Achievement& achievement, bool download_if_missing = true);
const 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
Expand Down

0 comments on commit 550b492

Please sign in to comment.