Achievements: Switch to rc_client

This commit is contained in:
Stenzek
2023-09-07 20:13:48 +10:00
parent f8c5e4982c
commit c773c763ef
28 changed files with 3327 additions and 3187 deletions

View File

@ -1,16 +1,29 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "achievementlogindialog.h"
#include "core/achievements.h"
#include "qthost.h"
#include "core/achievements.h"
#include "common/error.h"
#include <QtWidgets/QMessageBox>
AchievementLoginDialog::AchievementLoginDialog(QWidget* parent) : QDialog(parent)
AchievementLoginDialog::AchievementLoginDialog(QWidget* parent, Achievements::LoginRequestReason reason)
: QDialog(parent)
{
m_ui.setupUi(this);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
// Adjust text if needed based on reason.
if (reason == Achievements::LoginRequestReason::TokenInvalid)
{
m_ui.instructionText->setText(tr("<strong>Your RetroAchievements login token is no longer valid.</strong> You must "
"re-enter your credentials for achievements to be tracked. Your password will not "
"be saved in DuckStation, an access token will be generated and used instead."));
}
m_login = m_ui.buttonBox->addButton(tr("&Login"), QDialogButtonBox::AcceptRole);
m_login->setEnabled(false);
connectUi();
@ -28,8 +41,11 @@ void AchievementLoginDialog::loginClicked()
enableUI(false);
Host::RunOnCPUThread([this, username, password]() {
const bool result = Achievements::Login(username.toStdString().c_str(), password.toStdString().c_str());
QMetaObject::invokeMethod(this, "processLoginResult", Qt::QueuedConnection, Q_ARG(bool, result));
Error error;
const bool result = Achievements::Login(username.toUtf8().constData(), password.toUtf8().constData(), &error);
const QString message = QString::fromStdString(error.GetDescription());
QMetaObject::invokeMethod(this, "processLoginResult", Qt::QueuedConnection, Q_ARG(bool, result),
Q_ARG(const QString&, message));
});
}
@ -38,12 +54,13 @@ void AchievementLoginDialog::cancelClicked()
done(1);
}
void AchievementLoginDialog::processLoginResult(bool result)
void AchievementLoginDialog::processLoginResult(bool result, const QString& message)
{
if (!result)
{
QMessageBox::critical(this, tr("Login Error"),
tr("Login failed. Please check your username and password, and try again."));
QMessageBox::critical(
this, tr("Login Error"),
tr("Login failed.\nError: %1\n\nPlease check your username and password, and try again.").arg(message));
m_ui.status->setText(tr("Login failed."));
enableUI(true);
return;

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
@ -6,18 +6,22 @@
#include <QtWidgets/QDialog>
#include <QtWidgets/QPushButton>
namespace Achievements {
enum class LoginRequestReason;
}
class AchievementLoginDialog : public QDialog
{
Q_OBJECT
public:
AchievementLoginDialog(QWidget* parent);
AchievementLoginDialog(QWidget* parent, Achievements::LoginRequestReason reason);
~AchievementLoginDialog();
private Q_SLOTS:
void loginClicked();
void cancelClicked();
void processLoginResult(bool result);
void processLoginResult(bool result, const QString& message);
private:
void connectUi();

View File

@ -64,9 +64,9 @@
</layout>
</item>
<item>
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="instructionText">
<property name="text">
<string>Please enter user name and password for retroachievements.org below. Your password will not be saved in DuckStation, an access token will be generated and used instead.</string>
<string>Please enter your user name and password for retroachievements.org below. Your password will not be saved in DuckStation, an access token will be generated and used instead.</string>
</property>
<property name="wordWrap">
<bool>true</bool>

View File

@ -24,54 +24,64 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
m_ui.setupUi(this);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enable, "Cheevos", "Enabled", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.richPresence, "Cheevos", "RichPresence", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.challengeMode, "Cheevos", "ChallengeMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.testMode, "Cheevos", "TestMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialTestMode, "Cheevos", "UnofficialTestMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hardcoreMode, "Cheevos", "ChallengeMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.achievementNotifications, "Cheevos", "Notifications", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboardNotifications, "Cheevos",
"LeaderboardNotifications", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Cheevos", "SoundEffects", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.overlays, "Cheevos", "Overlays", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.encoreMode, "Cheevos", "EncoreMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.spectatorMode, "Cheevos", "SpectatorMode", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.unofficialAchievements, "Cheevos", "UnofficialTestMode",
false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.useFirstDiscFromPlaylist, "Cheevos",
"UseFirstDiscFromPlaylist", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.leaderboards, "Cheevos", "Leaderboards", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.notifications, "Cheevos", "Notifications", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.soundEffects, "Cheevos", "SoundEffects", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.primedIndicators, "Cheevos", "PrimedIndicators", true);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.achievementNotificationsDuration, "Cheevos",
"NotificationsDuration",
Settings::DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME);
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.leaderboardNotificationsDuration, "Cheevos",
"LeaderboardsDuration",
Settings::DEFAULT_LEADERBOARD_NOTIFICATION_TIME);
dialog->registerWidgetHelp(m_ui.enable, tr("Enable Achievements"), tr("Unchecked"),
tr("When enabled and logged in, DuckStation will scan for achievements on startup."));
dialog->registerWidgetHelp(m_ui.testMode, tr("Enable Test Mode"), tr("Unchecked"),
tr("When enabled, DuckStation will assume all achievements are locked and not send any "
"unlock notifications to the server."));
dialog->registerWidgetHelp(
m_ui.unofficialTestMode, tr("Test Unofficial Achievements"), tr("Unchecked"),
tr("When enabled, DuckStation will list achievements from unofficial sets. Please note that these achievements are "
"not tracked by RetroAchievements, so they unlock every time."));
dialog->registerWidgetHelp(
m_ui.richPresence, tr("Enable Rich Presence"), tr("Unchecked"),
tr("When enabled, rich presence information will be collected and sent to the server where supported."));
dialog->registerWidgetHelp(
m_ui.useFirstDiscFromPlaylist, tr("Use First Disc From Playlist"), tr("Unchecked"),
tr(
"When enabled, the first disc in a playlist will be used for achievements, regardless of which disc is active."));
dialog->registerWidgetHelp(m_ui.challengeMode, tr("Enable Hardcore Mode"), tr("Unchecked"),
dialog->registerWidgetHelp(m_ui.hardcoreMode, tr("Enable Hardcore Mode"), tr("Unchecked"),
tr("\"Challenge\" mode for achievements, including leaderboard tracking. Disables save "
"state, cheats, and slowdown functions."));
dialog->registerWidgetHelp(m_ui.achievementNotifications, tr("Show Achievement Notifications"), tr("Checked"),
tr("Displays popup messages on events such as achievement unlocks and game completion."));
dialog->registerWidgetHelp(
m_ui.notifications, tr("Show Notifications"), tr("Checked"),
tr("Displays popup messages on events such as achievement unlocks and leaderboard submissions."));
m_ui.leaderboardNotifications, tr("Show Leaderboard Notifications"), tr("Checked"),
tr("Displays popup messages when starting, submitting, or failing a leaderboard challenge."));
dialog->registerWidgetHelp(
m_ui.soundEffects, tr("Enable Sound Effects"), tr("Checked"),
tr("Plays sound effects for events such as achievement unlocks and leaderboard submissions."));
dialog->registerWidgetHelp(
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"),
m_ui.overlays, tr("Enable In-Game Overlays"), tr("Checked"),
tr("Shows icons in the lower-right corner of the screen when a challenge/primed achievement is active."));
dialog->registerWidgetHelp(m_ui.encoreMode, tr("Enable Encore Mode"), tr("Unchecked"),
tr("When enabled, each session will behave as if no achievements have been unlocked."));
dialog->registerWidgetHelp(m_ui.spectatorMode, tr("Enable Spectator Mode"), tr("Unchecked"),
tr("When enabled, DuckStation will assume all achievements are locked and not send any "
"unlock notifications to the server."));
dialog->registerWidgetHelp(
m_ui.unofficialAchievements, tr("Test Unofficial Achievements"), tr("Unchecked"),
tr("When enabled, DuckStation will list achievements from unofficial sets. Please note that these achievements are "
"not tracked by RetroAchievements, so they unlock every time."));
dialog->registerWidgetHelp(
m_ui.useFirstDiscFromPlaylist, tr("Use First Disc From Playlist"), tr("Unchecked"),
tr(
"When enabled, the first disc in a playlist will be used for achievements, regardless of which disc is active."));
connect(m_ui.enable, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.notifications, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.challengeMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::onChallengeModeStateChanged);
connect(m_ui.hardcoreMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.hardcoreMode, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::onHardcoreModeStateChanged);
connect(m_ui.achievementNotifications, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.leaderboardNotifications, &QCheckBox::stateChanged, this, &AchievementSettingsWidget::updateEnableState);
connect(m_ui.achievementNotificationsDuration, &QSlider::valueChanged, this,
&AchievementSettingsWidget::onAchievementsNotificationDurationSliderChanged);
connect(m_ui.leaderboardNotificationsDuration, &QSlider::valueChanged, this,
&AchievementSettingsWidget::onLeaderboardsNotificationDurationSliderChanged);
if (!m_dialog->isPerGameSettings())
{
@ -95,6 +105,8 @@ AchievementSettingsWidget::AchievementSettingsWidget(SettingsDialog* dialog, QWi
}
updateEnableState();
onAchievementsNotificationDurationSliderChanged();
onLeaderboardsNotificationDurationSliderChanged();
}
AchievementSettingsWidget::~AchievementSettingsWidget() = default;
@ -102,19 +114,24 @@ AchievementSettingsWidget::~AchievementSettingsWidget() = default;
void AchievementSettingsWidget::updateEnableState()
{
const bool enabled = m_dialog->getEffectiveBoolValue("Cheevos", "Enabled", false);
const bool challenge = m_dialog->getEffectiveBoolValue("Cheevos", "ChallengeMode", false);
m_ui.testMode->setEnabled(enabled);
m_ui.useFirstDiscFromPlaylist->setEnabled(enabled);
m_ui.richPresence->setEnabled(enabled);
m_ui.challengeMode->setEnabled(enabled);
m_ui.leaderboards->setEnabled(enabled && challenge);
m_ui.unofficialTestMode->setEnabled(enabled);
m_ui.notifications->setEnabled(enabled);
const bool notifications = enabled && m_dialog->getEffectiveBoolValue("Cheevos", "Notifications", true);
const bool lb_notifications = enabled && m_dialog->getEffectiveBoolValue("Cheevos", "LeaderboardNotifications", true);
m_ui.hardcoreMode->setEnabled(enabled);
m_ui.achievementNotifications->setEnabled(enabled);
m_ui.leaderboardNotifications->setEnabled(enabled);
m_ui.achievementNotificationsDuration->setEnabled(notifications);
m_ui.achievementNotificationsDurationLabel->setEnabled(notifications);
m_ui.leaderboardNotificationsDuration->setEnabled(lb_notifications);
m_ui.leaderboardNotificationsDurationLabel->setEnabled(lb_notifications);
m_ui.soundEffects->setEnabled(enabled);
m_ui.primedIndicators->setEnabled(enabled);
m_ui.overlays->setEnabled(enabled);
m_ui.encoreMode->setEnabled(enabled);
m_ui.spectatorMode->setEnabled(enabled);
m_ui.unofficialAchievements->setEnabled(enabled);
m_ui.useFirstDiscFromPlaylist->setEnabled(enabled);
}
void AchievementSettingsWidget::onChallengeModeStateChanged()
void AchievementSettingsWidget::onHardcoreModeStateChanged()
{
if (!QtHost::IsSystemValid())
return;
@ -140,6 +157,20 @@ void AchievementSettingsWidget::onChallengeModeStateChanged()
g_emu_thread->resetSystem();
}
void AchievementSettingsWidget::onAchievementsNotificationDurationSliderChanged()
{
const float duration = m_dialog->getEffectiveFloatValue("Cheevos", "NotificationsDuration",
Settings::DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME);
m_ui.achievementNotificationsDurationLabel->setText(tr("%n seconds", nullptr, static_cast<int>(duration)));
}
void AchievementSettingsWidget::onLeaderboardsNotificationDurationSliderChanged()
{
const float duration = m_dialog->getEffectiveFloatValue("Cheevos", "LeaderboardsDuration",
Settings::DEFAULT_ACHIEVEMENT_NOTIFICATION_TIME);
m_ui.leaderboardNotificationsDurationLabel->setText(tr("%n seconds", nullptr, static_cast<int>(duration)));
}
void AchievementSettingsWidget::updateLoginState()
{
const std::string username(Host::GetBaseStringSettingValue("Cheevos", "Username"));
@ -173,7 +204,7 @@ void AchievementSettingsWidget::onLoginLogoutPressed()
return;
}
AchievementLoginDialog login(this);
AchievementLoginDialog login(this, Achievements::LoginRequestReason::UserInitiated);
int res = login.exec();
if (res != 0)
return;
@ -193,8 +224,7 @@ void AchievementSettingsWidget::onViewProfilePressed()
QUrl(QStringLiteral("https://retroachievements.org/user/%1").arg(QString::fromUtf8(encoded_username))));
}
void AchievementSettingsWidget::onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total,
quint32 points)
void AchievementSettingsWidget::onAchievementsRefreshed(quint32 id, const QString& game_info_string)
{
m_ui.gameInfo->setText(game_info_string);
}

View File

@ -17,10 +17,12 @@ public:
private Q_SLOTS:
void updateEnableState();
void onChallengeModeStateChanged();
void onHardcoreModeStateChanged();
void onAchievementsNotificationDurationSliderChanged();
void onLeaderboardsNotificationDurationSliderChanged();
void onLoginLogoutPressed();
void onViewProfilePressed();
void onAchievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
void onAchievementsRefreshed(quint32 id, const QString& game_info_string);
private:
void updateLoginState();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>648</width>
<height>475</height>
<width>674</width>
<height>481</height>
</rect>
</property>
<property name="windowTitle">
@ -29,20 +29,13 @@
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Global Settings</string>
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QCheckBox" name="richPresence">
<property name="text">
<string>Enable Rich Presence</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="leaderboards">
<widget class="QCheckBox" name="spectatorMode">
<property name="text">
<string>Enable Leaderboards</string>
<string>Enable Spectator Mode</string>
</property>
</widget>
</item>
@ -53,52 +46,146 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="unofficialAchievements">
<property name="text">
<string>Test Unofficial Achievements</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="challengeMode">
<widget class="QCheckBox" name="encoreMode">
<property name="text">
<string>Enable Encore Mode</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="hardcoreMode">
<property name="text">
<string>Enable Hardcore Mode</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="primedIndicators">
<property name="text">
<string>Show Challenge Indicators</string>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="2" column="1">
<widget class="QCheckBox" name="useFirstDiscFromPlaylist">
<property name="text">
<string>Use First Disc From Playlist</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="testMode">
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="notificationBox">
<property name="title">
<string>Notifications</string>
</property>
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,1">
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="1,0">
<item>
<widget class="QSlider" name="achievementNotificationsDuration">
<property name="minimum">
<number>3</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="achievementNotificationsDurationLabel">
<property name="text">
<string>5 seconds</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="achievementNotifications">
<property name="text">
<string>Enable Test Mode</string>
<string>Show Achievement Notifications</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="unofficialTestMode">
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,0">
<item>
<widget class="QSlider" name="leaderboardNotificationsDuration">
<property name="minimum">
<number>3</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="invertedAppearance">
<bool>false</bool>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="leaderboardNotificationsDurationLabel">
<property name="text">
<string>5 seconds</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="leaderboardNotifications">
<property name="text">
<string>Test Unofficial Achievements</string>
<string>Show Leaderboard Notifications</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="2" column="0">
<widget class="QCheckBox" name="soundEffects">
<property name="text">
<string>Enable Sound Effects</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="notifications">
<item row="2" column="1">
<widget class="QCheckBox" name="overlays">
<property name="text">
<string>Show Notifications</string>
<string>Enable In-Game Overlays</string>
</property>
</widget>
</item>
@ -113,20 +200,17 @@
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
<item>
<widget class="QLabel" name="loginStatus">
<property name="text">
<string>Username:
Login token generated at:</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QPushButton" name="loginButton">
<property name="text">
<string>Login...</string>
</property>
</widget>
</item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="viewProfile">
<property name="text">
@ -134,6 +218,13 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="loginButton">
<property name="text">
<string>Login...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@ -144,7 +235,7 @@
<property name="minimumSize">
<size>
<width>0</width>
<height>120</height>
<height>75</height>
</size>
</property>
<property name="title">

View File

@ -1,8 +1,9 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "mainwindow.h"
#include "aboutdialog.h"
#include "achievementlogindialog.h"
#include "autoupdaterdialog.h"
#include "cheatmanagerdialog.h"
#include "coverdownloaddialog.h"
@ -507,14 +508,14 @@ void MainWindow::onSystemStarting()
s_system_valid = false;
s_system_paused = false;
updateEmulationActions(true, false, Achievements::ChallengeModeActive());
updateEmulationActions(true, false, Achievements::IsHardcoreModeActive());
}
void MainWindow::onSystemStarted()
{
m_was_disc_change_request = false;
s_system_valid = true;
updateEmulationActions(false, true, Achievements::ChallengeModeActive());
updateEmulationActions(false, true, Achievements::IsHardcoreModeActive());
updateWindowTitle();
updateStatusBarWidgetVisibility();
}
@ -572,7 +573,7 @@ void MainWindow::onSystemDestroyed()
return;
}
updateEmulationActions(false, false, Achievements::ChallengeModeActive());
updateEmulationActions(false, false, Achievements::IsHardcoreModeActive());
if (m_display_widget)
updateDisplayWidgetCursor();
else
@ -724,7 +725,7 @@ void MainWindow::populateGameListContextMenu(const GameList::Entry* entry, QWidg
{
std::vector<SaveStateInfo> available_states(System::GetAvailableSaveStates(entry->serial.c_str()));
const QString timestamp_format = QLocale::system().dateTimeFormat(QLocale::ShortFormat);
const bool challenge_mode = Achievements::ChallengeModeActive();
const bool challenge_mode = Achievements::IsHardcoreModeActive();
for (SaveStateInfo& ssi : available_states)
{
if (ssi.global)
@ -1382,7 +1383,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
g_emu_thread->bootSystem(std::move(boot_params));
});
if (m_ui.menuDebug->menuAction()->isVisible() && !Achievements::ChallengeModeActive())
if (m_ui.menuDebug->menuAction()->isVisible() && !Achievements::IsHardcoreModeActive())
{
connect(menu.addAction(tr("Boot and Debug")), &QAction::triggered, [this, entry]() {
m_open_debugger_on_start = true;
@ -1874,7 +1875,7 @@ void MainWindow::switchToEmulationView()
void MainWindow::connectSignals()
{
updateEmulationActions(false, false, Achievements::ChallengeModeActive());
updateEmulationActions(false, false, Achievements::IsHardcoreModeActive());
connect(qApp, &QGuiApplication::applicationStateChanged, this, &MainWindow::onApplicationStateChanged);
@ -1980,10 +1981,10 @@ void MainWindow::connectSignals()
connect(g_emu_thread, &EmuThread::runningGameChanged, this, &MainWindow::onRunningGameChanged);
connect(g_emu_thread, &EmuThread::mouseModeRequested, this, &MainWindow::onMouseModeRequested);
connect(g_emu_thread, &EmuThread::fullscreenUIStateChange, this, &MainWindow::onFullscreenUIStateChange);
#ifdef WITH_CHEEVOS
connect(g_emu_thread, &EmuThread::achievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested);
connect(g_emu_thread, &EmuThread::achievementsLoginSucceeded, this, &MainWindow::onAchievementsLoginSucceeded);
connect(g_emu_thread, &EmuThread::achievementsChallengeModeChanged, this,
&MainWindow::onAchievementsChallengeModeChanged);
#endif
// These need to be queued connections to stop crashing due to menus opening/closing and switching focus.
connect(m_game_list_widget, &GameListWidget::refreshProgress, this, &MainWindow::onGameListRefreshProgress);
@ -2619,10 +2620,28 @@ void MainWindow::openMemoryCardEditor(const QString& card_a_path, const QString&
}
}
void MainWindow::onAchievementsLoginRequested(Achievements::LoginRequestReason reason)
{
const auto lock = pauseAndLockSystem();
AchievementLoginDialog dlg(lock.getDialogParent(), reason);
dlg.exec();
}
void MainWindow::onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points,
quint32 unread_messages)
{
const QString message = tr("RA: Logged in as %1 (%2, %3 softcore). %4 unread messages.")
.arg(display_name)
.arg(points)
.arg(sc_points)
.arg(unread_messages);
m_ui.statusBar->showMessage(message);
}
void MainWindow::onAchievementsChallengeModeChanged()
{
#ifdef WITH_CHEEVOS
const bool active = Achievements::ChallengeModeActive();
const bool active = Achievements::IsHardcoreModeActive();
if (active)
{
if (m_cheat_manager_dialog)
@ -2641,7 +2660,6 @@ void MainWindow::onAchievementsChallengeModeChanged()
}
updateEmulationActions(false, System::IsValid(), active);
#endif
}
void MainWindow::onToolsMemoryCardEditorTriggered()

View File

@ -33,6 +33,9 @@ class DebuggerWindow;
class MainWindow;
class GPUDevice;
namespace Achievements {
enum class LoginRequestReason;
}
namespace GameList {
struct Entry;
}
@ -128,6 +131,9 @@ private Q_SLOTS:
void onSystemPaused();
void onSystemResumed();
void onRunningGameChanged(const QString& filename, const QString& game_serial, const QString& game_title);
void onAchievementsLoginRequested(Achievements::LoginRequestReason reason);
void onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points,
quint32 unread_messages);
void onAchievementsChallengeModeChanged();
void onApplicationStateChanged(Qt::ApplicationState state);

View File

@ -1204,32 +1204,33 @@ void EmuThread::saveScreenshot()
System::SaveScreenshot(nullptr, true, true);
}
void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason)
{
emit g_emu_thread->achievementsLoginRequested(reason);
}
void Host::OnAchievementsLoginSuccess(const char* username, u32 points, u32 sc_points, u32 unread_messages)
{
emit g_emu_thread->achievementsLoginSucceeded(QString::fromUtf8(username), points, sc_points, unread_messages);
}
void Host::OnAchievementsRefreshed()
{
#ifdef WITH_CHEEVOS
u32 game_id = 0;
u32 achievement_count = 0;
u32 max_points = 0;
QString game_info;
if (Achievements::HasActiveGame())
{
game_id = Achievements::GetGameID();
achievement_count = Achievements::GetAchievementCount();
max_points = Achievements::GetMaximumPointsForGame();
game_info = qApp
->translate("EmuThread", "Game ID: %1\n"
"Game Title: %2\n"
"Achievements: %5 (%6)\n\n")
.arg(game_id)
.arg(QString::fromStdString(Achievements::GetGameTitle()))
.arg(achievement_count)
.arg(qApp->translate("EmuThread", "%n points", "", max_points));
->translate("EmuThread", "Game: %1 (%2)\n")
.arg(QString::fromStdString(Achievements::GetGameTitle()))
.arg(game_id);
const std::string rich_presence_string(Achievements::GetRichPresenceString());
if (!rich_presence_string.empty())
const std::string& rich_presence_string = Achievements::GetRichPresenceString();
if (Achievements::HasRichPresence() && !rich_presence_string.empty())
game_info.append(QString::fromStdString(rich_presence_string));
else
game_info.append(qApp->translate("EmuThread", "Rich presence inactive or unsupported."));
@ -1239,15 +1240,12 @@ void Host::OnAchievementsRefreshed()
game_info = qApp->translate("EmuThread", "Game not loaded or no RetroAchievements available.");
}
emit g_emu_thread->achievementsRefreshed(game_id, game_info, achievement_count, max_points);
#endif
emit g_emu_thread->achievementsRefreshed(game_id, game_info);
}
void Host::OnAchievementsChallengeModeChanged()
void Host::OnAchievementsHardcoreModeChanged()
{
#ifdef WITH_CHEEVOS
emit g_emu_thread->achievementsChallengeModeChanged();
#endif
}
void EmuThread::doBackgroundControllerPoll()

View File

@ -45,14 +45,13 @@ class GPUDevice;
class MainWindow;
class DisplayWidget;
namespace Achievements {
enum class LoginRequestReason;
}
Q_DECLARE_METATYPE(std::optional<bool>);
Q_DECLARE_METATYPE(std::shared_ptr<SystemBootParameters>);
// These cause errors when compiling with gcc, implicitly defined?
// Q_DECLARE_METATYPE(std::function<void()>);
// Q_DECLARE_METATYPE(GPURenderer);
// Q_DECLARE_METATYPE(InputBindingKey);
class EmuThread : public QThread
{
Q_OBJECT
@ -141,7 +140,10 @@ Q_SIGNALS:
void inputProfileLoaded();
void mouseModeRequested(bool relative, bool hide_cursor);
void fullscreenUIStateChange(bool running);
void achievementsRefreshed(quint32 id, const QString& game_info_string, quint32 total, quint32 points);
void achievementsLoginRequested(Achievements::LoginRequestReason reason);
void achievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points,
quint32 unread_messages);
void achievementsRefreshed(quint32 id, const QString& game_info_string);
void achievementsChallengeModeChanged();
void cheatEnabled(quint32 index, bool enabled);

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com>
// SPDX-FileCopyrightText: 2019-2023 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "settingsdialog.h"
@ -7,6 +7,7 @@
#include "biossettingswidget.h"
#include "consolesettingswidget.h"
#include "achievementsettingswidget.h"
#include "displaysettingswidget.h"
#include "emulationsettingswidget.h"
#include "enhancementsettingswidget.h"
@ -19,6 +20,7 @@
#include "postprocessingsettingswidget.h"
#include "qthost.h"
#include "core/achievements.h"
#include "core/host.h"
#include "util/ini_settings_interface.h"
@ -29,11 +31,6 @@
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QTextEdit>
#ifdef WITH_CHEEVOS
#include "achievementsettingswidget.h"
#include "core/achievements.h"
#endif
static QList<SettingsDialog*> s_open_game_properties_dialogs;
SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent)
@ -129,7 +126,6 @@ void SettingsDialog::addPages()
QString help_text(tr("<strong>Achievement Settings</strong><hr>These options control RetroAchievements. Mouse over "
"an option for additional information."));
#ifdef WITH_CHEEVOS
if (!Achievements::IsUsingRAIntegration())
{
addWidget(m_achievement_settings = new AchievementSettingsWidget(this, m_ui.settingsContainer), std::move(title),
@ -144,13 +140,6 @@ void SettingsDialog::addPages()
addWidget(placeholder_label, std::move(title), std::move(icon_text), std::move(help_text));
}
#else
QLabel* placeholder_label =
new QLabel(tr("This DuckStation build was not compiled with RetroAchievements support."), m_ui.settingsContainer);
placeholder_label->setAlignment(Qt::AlignLeft | Qt::AlignTop);
addWidget(placeholder_label, std::move(title), std::move(icon_text), std::move(help_text));
#endif
}
if (!isPerGameSettings())