From 4d139943f2407144d5f8e3dc5a673f24850d43d0 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Sun, 16 Sep 2018 20:05:51 +0200 Subject: Port web_service from Citra --- src/yuzu/CMakeLists.txt | 16 +++ src/yuzu/compatdb.cpp | 61 ++++++++ src/yuzu/compatdb.h | 27 ++++ src/yuzu/compatdb.ui | 215 ++++++++++++++++++++++++++++ src/yuzu/configuration/config.cpp | 18 +++ src/yuzu/configuration/configure.ui | 11 ++ src/yuzu/configuration/configure_dialog.cpp | 1 + src/yuzu/configuration/configure_web.cpp | 121 ++++++++++++++++ src/yuzu/configuration/configure_web.h | 38 +++++ src/yuzu/configuration/configure_web.ui | 206 ++++++++++++++++++++++++++ src/yuzu/discord.h | 25 ++++ src/yuzu/discord_impl.cpp | 52 +++++++ src/yuzu/discord_impl.h | 20 +++ src/yuzu/main.cpp | 82 +++++++++-- src/yuzu/main.h | 10 +- src/yuzu/main.ui | 16 ++- src/yuzu/ui_settings.h | 3 + 17 files changed, 906 insertions(+), 16 deletions(-) create mode 100644 src/yuzu/compatdb.cpp create mode 100644 src/yuzu/compatdb.h create mode 100644 src/yuzu/compatdb.ui create mode 100644 src/yuzu/configuration/configure_web.cpp create mode 100644 src/yuzu/configuration/configure_web.h create mode 100644 src/yuzu/configuration/configure_web.ui create mode 100644 src/yuzu/discord.h create mode 100644 src/yuzu/discord_impl.cpp create mode 100644 src/yuzu/discord_impl.h (limited to 'src/yuzu') diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f48b69809..f93ba2569 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -29,6 +29,8 @@ add_executable(yuzu configuration/configure_input.h configuration/configure_system.cpp configuration/configure_system.h + configuration/configure_web.cpp + configuration/configure_web.h debugger/graphics/graphics_breakpoint_observer.cpp debugger/graphics/graphics_breakpoint_observer.h debugger/graphics/graphics_breakpoints.cpp @@ -42,6 +44,7 @@ add_executable(yuzu debugger/profiler.h debugger/wait_tree.cpp debugger/wait_tree.h + discord.h game_list.cpp game_list.h game_list_p.h @@ -57,6 +60,8 @@ add_executable(yuzu util/spinbox.h util/util.cpp util/util.h + compatdb.cpp + compatdb.h yuzu.rc ) @@ -70,8 +75,10 @@ set(UIS configuration/configure_graphics.ui configuration/configure_input.ui configuration/configure_system.ui + configuration/configure_web.ui hotkeys.ui main.ui + compatdb.ui ) file(GLOB COMPAT_LIST @@ -113,6 +120,15 @@ target_link_libraries(yuzu PRIVATE common core input_common video_core) target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) +if (USE_DISCORD_PRESENCE) + target_sources(yuzu PUBLIC + discord_impl.cpp + discord_impl.h + ) + target_link_libraries(yuzu PRIVATE discord-rpc) + target_compile_definitions(yuzu PRIVATE -DUSE_DISCORD_PRESENCE) +endif() + if(UNIX AND NOT APPLE) install(TARGETS yuzu RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") endif() diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp new file mode 100644 index 000000000..45f8b4461 --- /dev/null +++ b/src/yuzu/compatdb.cpp @@ -0,0 +1,61 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include "common/logging/log.h" +#include "common/telemetry.h" +#include "core/core.h" +#include "core/telemetry_session.h" +#include "ui_compatdb.h" +#include "yuzu/compatdb.h" + +CompatDB::CompatDB(QWidget* parent) + : QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), + ui{std::make_unique()} { + ui->setupUi(this); + connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Okay, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_Bad, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext); + connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit); +} + +CompatDB::~CompatDB() = default; + +enum class CompatDBPage { Intro = 0, Selection = 1, Final = 2 }; + +void CompatDB::Submit() { + QButtonGroup* compatibility = new QButtonGroup(this); + compatibility->addButton(ui->radioButton_Perfect, 0); + compatibility->addButton(ui->radioButton_Great, 1); + compatibility->addButton(ui->radioButton_Okay, 2); + compatibility->addButton(ui->radioButton_Bad, 3); + compatibility->addButton(ui->radioButton_IntroMenu, 4); + compatibility->addButton(ui->radioButton_WontBoot, 5); + switch ((static_cast(currentId()))) { + case CompatDBPage::Selection: + if (compatibility->checkedId() == -1) { + button(NextButton)->setEnabled(false); + } + break; + case CompatDBPage::Final: + LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); + Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility", + compatibility->checkedId()); + // older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a + // workaround + button(QWizard::CancelButton)->setVisible(false); + break; + default: + LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); + } +} + +void CompatDB::EnableNext() { + button(NextButton)->setEnabled(true); +} diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h new file mode 100644 index 000000000..0a0f27cca --- /dev/null +++ b/src/yuzu/compatdb.h @@ -0,0 +1,27 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +namespace Ui { +class CompatDB; +} + +class CompatDB : public QWizard { + Q_OBJECT + +public: + explicit CompatDB(QWidget* parent = nullptr); + ~CompatDB(); + +private: + std::unique_ptr ui; + +private slots: + void Submit(); + void EnableNext(); +}; diff --git a/src/yuzu/compatdb.ui b/src/yuzu/compatdb.ui new file mode 100644 index 000000000..fed402176 --- /dev/null +++ b/src/yuzu/compatdb.ui @@ -0,0 +1,215 @@ + + + CompatDB + + + + 0 + 0 + 600 + 482 + + + + + 500 + 410 + + + + Report Compatibility + + + QWizard::DisabledBackButtonOnLastPage|QWizard::HelpButtonOnRight|QWizard::NoBackButtonOnStartPage + + + + Report Game Compatibility + + + 0 + + + + + + <html><head/><body><p><span style=" font-size:10pt;">Should you choose to submit a test case to the </span><a href="https://yuzu-emu.org/game/"><span style=" font-size:10pt; text-decoration: underline; color:#0000ff;">yuzu Compatibility List</span></a><span style=" font-size:10pt;">, The following information will be collected and displayed on the site:</span></p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hardware Information (CPU / GPU / Operating System)</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Which version of yuzu you are running</li><li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The connected yuzu account</li></ul></body></html> + + + true + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + Report Game Compatibility + + + 1 + + + + + + Perfect + + + + + + + <html><head/><body><p>Game functions flawlessly with no audio or graphical glitches.</p></body></html> + + + true + + + + + + + Great + + + + + + + <html><head/><body><p>Game functions with minor graphical or audio glitches and is playable from start to finish. May require some workarounds.</p></body></html> + + + true + + + + + + + Okay + + + + + + + <html><head/><body><p>Game functions with major graphical or audio glitches, but game is playable from start to finish with workarounds.</p></body></html> + + + true + + + + + + + Bad + + + + + + + <html><head/><body><p>Game functions, but with major graphical or audio glitches. Unable to progress in specific areas due to glitches even with workarounds.</p></body></html> + + + true + + + + + + + Intro/Menu + + + + + + + <html><head/><body><p>Game is completely unplayable due to major graphical or audio glitches. Unable to progress past the Start Screen.</p></body></html> + + + true + + + + + + + Won't Boot + + + true + + + false + + + + + + + <html><head/><body><p>The game crashes when attempting to startup.</p></body></html> + + + + + + + + 10 + + + + <html><head/><body><p>Independent of speed or performance, how well does this game play from start to finish on this version of yuzu?</p></body></html> + + + true + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + Thank you for your submission! + + + 2 + + + + + + diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index d229225b4..650dd03c0 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -136,8 +136,18 @@ void Config::ReadValues() { Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); qt_config->endGroup(); + qt_config->beginGroup("WebService"); + Settings::values.enable_telemetry = qt_config->value("enable_telemetry", true).toBool(); + Settings::values.web_api_url = + qt_config->value("web_api_url", "https://api.yuzu-emu.org").toString().toStdString(); + Settings::values.yuzu_username = qt_config->value("yuzu_username").toString().toStdString(); + Settings::values.yuzu_token = qt_config->value("yuzu_token").toString().toStdString(); + qt_config->endGroup(); + qt_config->beginGroup("UI"); UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); + UISettings::values.enable_discord_presence = + qt_config->value("enable_discord_presence", true).toBool(); qt_config->beginGroup("UIGameList"); UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); @@ -261,8 +271,16 @@ void Config::SaveValues() { qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); qt_config->endGroup(); + qt_config->beginGroup("WebService"); + qt_config->setValue("enable_telemetry", Settings::values.enable_telemetry); + qt_config->setValue("web_api_url", QString::fromStdString(Settings::values.web_api_url)); + qt_config->setValue("yuzu_username", QString::fromStdString(Settings::values.yuzu_username)); + qt_config->setValue("yuzu_token", QString::fromStdString(Settings::values.yuzu_token)); + qt_config->endGroup(); + qt_config->beginGroup("UI"); qt_config->setValue("theme", UISettings::values.theme); + qt_config->setValue("enable_discord_presence", UISettings::values.enable_discord_presence); qt_config->beginGroup("UIGameList"); qt_config->setValue("show_unknown", UISettings::values.show_unknown); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 20f120134..9b297df28 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -54,6 +54,11 @@ Debug + + + Web + + @@ -108,6 +113,12 @@
configuration/configure_graphics.h
1 + + ConfigureWeb + QWidget +
configuration/configure_web.h
+ 1 +
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index daa4cc0d9..3905423e9 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -27,5 +27,6 @@ void ConfigureDialog::applyConfiguration() { ui->graphicsTab->applyConfiguration(); ui->audioTab->applyConfiguration(); ui->debugTab->applyConfiguration(); + ui->webTab->applyConfiguration(); Settings::Apply(); } diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp new file mode 100644 index 000000000..cfca08014 --- /dev/null +++ b/src/yuzu/configuration/configure_web.cpp @@ -0,0 +1,121 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include "core/settings.h" +#include "core/telemetry_session.h" +#include "ui_configure_web.h" +#include "yuzu/configuration/configure_web.h" +#include "yuzu/ui_settings.h" + +ConfigureWeb::ConfigureWeb(QWidget* parent) + : QWidget(parent), ui(std::make_unique()) { + ui->setupUi(this); + connect(ui->button_regenerate_telemetry_id, &QPushButton::clicked, this, + &ConfigureWeb::RefreshTelemetryID); + connect(ui->button_verify_login, &QPushButton::clicked, this, &ConfigureWeb::VerifyLogin); + connect(&verify_watcher, &QFutureWatcher::finished, this, &ConfigureWeb::OnLoginVerified); + +#ifndef USE_DISCORD_PRESENCE + ui->discord_group->setVisible(false); +#endif + this->setConfiguration(); +} + +ConfigureWeb::~ConfigureWeb() {} + +void ConfigureWeb::setConfiguration() { + ui->web_credentials_disclaimer->setWordWrap(true); + ui->telemetry_learn_more->setOpenExternalLinks(true); + ui->telemetry_learn_more->setText(tr("Learn more")); + + ui->web_signup_link->setOpenExternalLinks(true); + ui->web_signup_link->setText( + tr("Sign up")); + ui->web_token_info_link->setOpenExternalLinks(true); + ui->web_token_info_link->setText( + tr("What is my token?")); + + ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry); + ui->edit_username->setText(QString::fromStdString(Settings::values.yuzu_username)); + ui->edit_token->setText(QString::fromStdString(Settings::values.yuzu_token)); + // Connect after setting the values, to avoid calling OnLoginChanged now + connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged); + connect(ui->edit_username, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged); + ui->label_telemetry_id->setText( + tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper())); + user_verified = true; + + ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence); +} + +void ConfigureWeb::applyConfiguration() { + Settings::values.enable_telemetry = ui->toggle_telemetry->isChecked(); + UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked(); + if (user_verified) { + Settings::values.yuzu_username = ui->edit_username->text().toStdString(); + Settings::values.yuzu_token = ui->edit_token->text().toStdString(); + } else { + QMessageBox::warning(this, tr("Username and token not verified"), + tr("Username and token were not verified. The changes to your " + "username and/or token have not been saved.")); + } +} + +void ConfigureWeb::RefreshTelemetryID() { + const u64 new_telemetry_id{Core::RegenerateTelemetryId()}; + ui->label_telemetry_id->setText( + tr("Telemetry ID: 0x%1").arg(QString::number(new_telemetry_id, 16).toUpper())); +} + +void ConfigureWeb::OnLoginChanged() { + if (ui->edit_username->text().isEmpty() && ui->edit_token->text().isEmpty()) { + user_verified = true; + ui->label_username_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16)); + ui->label_token_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16)); + } else { + user_verified = false; + ui->label_username_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16)); + ui->label_token_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16)); + } +} + +void ConfigureWeb::VerifyLogin() { + ui->button_verify_login->setDisabled(true); + ui->button_verify_login->setText(tr("Verifying")); + verify_watcher.setFuture( + QtConcurrent::run([this, username = ui->edit_username->text().toStdString(), + token = ui->edit_token->text().toStdString()]() { + return Core::VerifyLogin(username, token); + })); +} + +void ConfigureWeb::OnLoginVerified() { + ui->button_verify_login->setEnabled(true); + ui->button_verify_login->setText(tr("Verify")); + if (verify_watcher.result()) { + user_verified = true; + ui->label_username_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16)); + ui->label_token_verified->setPixmap(QIcon::fromTheme("checked").pixmap(16)); + } else { + ui->label_username_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16)); + ui->label_token_verified->setPixmap(QIcon::fromTheme("failed").pixmap(16)); + QMessageBox::critical( + this, tr("Verification failed"), + tr("Verification failed. Check that you have entered your username and token " + "correctly, and that your internet connection is working.")); + } +} + +void ConfigureWeb::retranslateUi() { + ui->retranslateUi(this); +} diff --git a/src/yuzu/configuration/configure_web.h b/src/yuzu/configuration/configure_web.h new file mode 100644 index 000000000..7741ab95d --- /dev/null +++ b/src/yuzu/configuration/configure_web.h @@ -0,0 +1,38 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +namespace Ui { +class ConfigureWeb; +} + +class ConfigureWeb : public QWidget { + Q_OBJECT + +public: + explicit ConfigureWeb(QWidget* parent = nullptr); + ~ConfigureWeb(); + + void applyConfiguration(); + void retranslateUi(); + +public slots: + void RefreshTelemetryID(); + void OnLoginChanged(); + void VerifyLogin(); + void OnLoginVerified(); + +private: + void setConfiguration(); + + bool user_verified = true; + QFutureWatcher verify_watcher; + + std::unique_ptr ui; +}; diff --git a/src/yuzu/configuration/configure_web.ui b/src/yuzu/configuration/configure_web.ui new file mode 100644 index 000000000..2f4b9dd73 --- /dev/null +++ b/src/yuzu/configuration/configure_web.ui @@ -0,0 +1,206 @@ + + + ConfigureWeb + + + + 0 + 0 + 926 + 561 + + + + Form + + + + + + + + yuzu Web Service + + + + + + By providing your username and token, you agree to allow yuzu to collect additional usage data, which may include user identifying information. + + + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + Verify + + + + + + + Sign up + + + + + + + 36 + + + + + + + Token: + + + + + + + + + + + Username: + + + + + + + + + + + 36 + + + QLineEdit::Password + + + + + + + What is my token? + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Telemetry + + + + + + Share anonymous usage data with the yuzu team + + + + + + + Learn more + + + + + + + + + Telemetry ID: + + + + + + + + 0 + 0 + + + + Qt::RightToLeft + + + Regenerate + + + + + + + + + + + + + + Discord Presence + + + + + + Show Current Game in your Discord Status + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/yuzu/discord.h b/src/yuzu/discord.h new file mode 100644 index 000000000..a867cc4d6 --- /dev/null +++ b/src/yuzu/discord.h @@ -0,0 +1,25 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace DiscordRPC { + +class DiscordInterface { +public: + virtual ~DiscordInterface() = default; + + virtual void Pause() = 0; + virtual void Update() = 0; +}; + +class NullImpl : public DiscordInterface { +public: + ~NullImpl() = default; + + void Pause() override {} + void Update() override {} +}; + +} // namespace DiscordRPC diff --git a/src/yuzu/discord_impl.cpp b/src/yuzu/discord_impl.cpp new file mode 100644 index 000000000..9d87a41eb --- /dev/null +++ b/src/yuzu/discord_impl.cpp @@ -0,0 +1,52 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include "common/common_types.h" +#include "core/core.h" +#include "core/loader/loader.h" +#include "yuzu/discord_impl.h" +#include "yuzu/ui_settings.h" + +namespace DiscordRPC { + +DiscordImpl::DiscordImpl() { + DiscordEventHandlers handlers{}; + + // The number is the client ID for yuzu, it's used for images and the + // application name + Discord_Initialize("471872241299226636", &handlers, 1, nullptr); +} + +DiscordImpl::~DiscordImpl() { + Discord_ClearPresence(); + Discord_Shutdown(); +} + +void DiscordImpl::Pause() { + Discord_ClearPresence(); +} + +void DiscordImpl::Update() { + s64 start_time = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); + std::string title; + if (Core::System::GetInstance().IsPoweredOn()) + Core::System::GetInstance().GetAppLoader().ReadTitle(title); + DiscordRichPresence presence{}; + presence.largeImageKey = "yuzu_logo"; + presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; + if (Core::System::GetInstance().IsPoweredOn()) { + presence.state = title.c_str(); + presence.details = "Currently in game"; + } else { + presence.details = "Not in game"; + } + presence.startTimestamp = start_time; + Discord_UpdatePresence(&presence); +} +} // namespace DiscordRPC diff --git a/src/yuzu/discord_impl.h b/src/yuzu/discord_impl.h new file mode 100644 index 000000000..d71428c10 --- /dev/null +++ b/src/yuzu/discord_impl.h @@ -0,0 +1,20 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "yuzu/discord.h" + +namespace DiscordRPC { + +class DiscordImpl : public DiscordInterface { +public: + DiscordImpl(); + ~DiscordImpl(); + + void Pause() override; + void Update() override; +}; + +} // namespace DiscordRPC diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 27015d02c..2d6e0d4fc 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -35,6 +35,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include #include #include "common/common_paths.h" +#include "common/detached_tasks.h" #include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/filter.h" @@ -65,6 +66,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "video_core/debug_utils/debug_utils.h" #include "yuzu/about_dialog.h" #include "yuzu/bootmanager.h" +#include "yuzu/compatdb.h" #include "yuzu/compatibility_list.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" @@ -73,12 +75,17 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/debugger/graphics/graphics_surface.h" #include "yuzu/debugger/profiler.h" #include "yuzu/debugger/wait_tree.h" +#include "yuzu/discord.h" #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/hotkeys.h" #include "yuzu/main.h" #include "yuzu/ui_settings.h" +#ifdef USE_DISCORD_PRESENCE +#include "yuzu/discord_impl.h" +#endif + #ifdef QT_STATICPLUGIN Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #endif @@ -102,23 +109,22 @@ enum class CalloutFlag : uint32_t { DRDDeprecation = 0x2, }; -static void ShowCalloutMessage(const QString& message, CalloutFlag flag) { - if (UISettings::values.callout_flags & static_cast(flag)) { +void GMainWindow::ShowTelemetryCallout() { + if (UISettings::values.callout_flags & static_cast(CalloutFlag::Telemetry)) { return; } - UISettings::values.callout_flags |= static_cast(flag); - - QMessageBox msg; - msg.setText(message); - msg.setStandardButtons(QMessageBox::Ok); - msg.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - msg.setStyleSheet("QLabel{min-width: 900px;}"); - msg.exec(); + UISettings::values.callout_flags |= static_cast(CalloutFlag::Telemetry); + static const QString telemetry_message = + tr("Anonymous " + "data is collected to help improve yuzu. " + "

Would you like to share your usage data with us?"); + if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { + Settings::values.enable_telemetry = false; + Settings::Apply(); + } } -void GMainWindow::ShowCallouts() {} - const int GMainWindow::max_recent_files_item; static void InitializeLogging() { @@ -145,6 +151,9 @@ GMainWindow::GMainWindow() default_theme_paths = QIcon::themeSearchPaths(); UpdateUITheme(); + SetDiscordEnabled(UISettings::values.enable_discord_presence); + discord_rpc->Update(); + InitializeWidgets(); InitializeDebugWidgets(); InitializeRecentFileMenuActions(); @@ -168,7 +177,7 @@ GMainWindow::GMainWindow() game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); // Show one-time "callout" messages to the user - ShowCallouts(); + ShowTelemetryCallout(); QStringList args = QApplication::arguments(); if (args.length() >= 2) { @@ -183,6 +192,9 @@ GMainWindow::~GMainWindow() { } void GMainWindow::InitializeWidgets() { +#ifdef YUZU_ENABLE_COMPATIBILITY_REPORTING + ui.action_Report_Compatibility->setVisible(true); +#endif render_window = new GRenderWindow(this, emu_thread.get()); render_window->hide(); @@ -411,6 +423,8 @@ void GMainWindow::ConnectMenuEvents() { connect(ui.action_Start, &QAction::triggered, this, &GMainWindow::OnStartGame); connect(ui.action_Pause, &QAction::triggered, this, &GMainWindow::OnPauseGame); connect(ui.action_Stop, &QAction::triggered, this, &GMainWindow::OnStopGame); + connect(ui.action_Report_Compatibility, &QAction::triggered, this, + &GMainWindow::OnMenuReportCompatibility); connect(ui.action_Restart, &QAction::triggered, this, [this] { BootGame(QString(game_path)); }); connect(ui.action_Configure, &QAction::triggered, this, &GMainWindow::OnConfigure); @@ -647,6 +661,7 @@ void GMainWindow::BootGame(const QString& filename) { } void GMainWindow::ShutdownGame() { + discord_rpc->Pause(); emu_thread->RequestStop(); emit EmulationStopping(); @@ -655,6 +670,8 @@ void GMainWindow::ShutdownGame() { emu_thread->wait(); emu_thread = nullptr; + discord_rpc->Update(); + // The emulation is stopped, so closing the window or not does not matter anymore disconnect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); @@ -664,6 +681,7 @@ void GMainWindow::ShutdownGame() { ui.action_Pause->setEnabled(false); ui.action_Stop->setEnabled(false); ui.action_Restart->setEnabled(false); + ui.action_Report_Compatibility->setEnabled(false); render_window->hide(); game_list->show(); game_list->setFilterFocus(); @@ -1147,6 +1165,9 @@ void GMainWindow::OnStartGame() { ui.action_Pause->setEnabled(true); ui.action_Stop->setEnabled(true); ui.action_Restart->setEnabled(true); + ui.action_Report_Compatibility->setEnabled(true); + + discord_rpc->Update(); } void GMainWindow::OnPauseGame() { @@ -1161,6 +1182,20 @@ void GMainWindow::OnStopGame() { ShutdownGame(); } +void GMainWindow::OnMenuReportCompatibility() { + if (!Settings::values.yuzu_token.empty() && !Settings::values.yuzu_username.empty()) { + CompatDB compatdb{this}; + compatdb.exec(); + } else { + QMessageBox::critical( + this, tr("Missing yuzu Account"), + tr("In order to submit a game compatibility test case, you must link your yuzu " + "account.

To link your yuzu account, go to Emulation > Configuration " + "> " + "Web.")); + } +} + void GMainWindow::ToggleFullscreen() { if (!emulation_running) { return; @@ -1224,11 +1259,14 @@ void GMainWindow::ToggleWindowMode() { void GMainWindow::OnConfigure() { ConfigureDialog configureDialog(this, hotkey_registry); auto old_theme = UISettings::values.theme; + const bool old_discord_presence = UISettings::values.enable_discord_presence; auto result = configureDialog.exec(); if (result == QDialog::Accepted) { configureDialog.applyConfiguration(); if (UISettings::values.theme != old_theme) UpdateUITheme(); + if (UISettings::values.enable_discord_presence != old_discord_presence) + SetDiscordEnabled(UISettings::values.enable_discord_presence); game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); config->Save(); } @@ -1443,11 +1481,25 @@ void GMainWindow::UpdateUITheme() { emit UpdateThemedIcons(); } +void GMainWindow::SetDiscordEnabled(bool state) { +#ifdef USE_DISCORD_PRESENCE + if (state) { + discord_rpc = std::make_unique(); + } else { + discord_rpc = std::make_unique(); + } +#else + discord_rpc = std::make_unique(); +#endif + discord_rpc->Update(); +} + #ifdef main #undef main #endif int main(int argc, char* argv[]) { + Common::DetachedTasks detached_tasks; MicroProfileOnThreadCreate("Frontend"); SCOPE_EXIT({ MicroProfileShutdown(); }); @@ -1465,5 +1517,7 @@ int main(int argc, char* argv[]) { GMainWindow main_window; // After settings have been loaded by GMainWindow, apply the filter main_window.show(); - return app.exec(); + int result = app.exec(); + detached_tasks.WaitForAllTasks(); + return result; } diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 8ee9242b1..fe0e9a50a 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -41,6 +41,10 @@ enum class EmulatedDirectoryTarget { SDMC, }; +namespace DiscordRPC { +class DiscordInterface; +} + class GMainWindow : public QMainWindow { Q_OBJECT @@ -61,6 +65,8 @@ public: GMainWindow(); ~GMainWindow() override; + std::unique_ptr discord_rpc; + signals: /** @@ -99,7 +105,8 @@ private: void BootGame(const QString& filename); void ShutdownGame(); - void ShowCallouts(); + void ShowTelemetryCallout(); + void SetDiscordEnabled(bool state); /** * Stores the filename in the recently loaded files list. @@ -135,6 +142,7 @@ private slots: void OnStartGame(); void OnPauseGame(); void OnStopGame(); + void OnMenuReportCompatibility(); /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path); void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target); diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 3879d4813..cb1664b21 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -45,7 +45,7 @@ 0 0 1081 - 19 + 21 @@ -101,6 +101,8 @@ &Help + + @@ -239,6 +241,18 @@ Restart + + + false + + + Report Compatibility + + + false + + + diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 051494bc5..89d9140f3 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h @@ -39,6 +39,9 @@ struct Values { bool confirm_before_closing; bool first_start; + // Discord RPC + bool enable_discord_presence; + QString roms_path; QString symbols_path; QString gamedir; -- cgit v1.2.3 From b4ace6ec6f86079b3bd297f95dfe133240b53e15 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Mon, 17 Sep 2018 17:16:01 +0200 Subject: Address a bunch of review comments --- src/yuzu/compatdb.cpp | 6 +++++- src/yuzu/compatdb.h | 1 - src/yuzu/configuration/configure_web.cpp | 2 +- src/yuzu/discord_impl.h | 2 +- src/yuzu/main.cpp | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) (limited to 'src/yuzu') diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp index 45f8b4461..91e754274 100644 --- a/src/yuzu/compatdb.cpp +++ b/src/yuzu/compatdb.cpp @@ -27,7 +27,11 @@ CompatDB::CompatDB(QWidget* parent) CompatDB::~CompatDB() = default; -enum class CompatDBPage { Intro = 0, Selection = 1, Final = 2 }; +enum class CompatDBPage { + Intro = 0, + Selection = 1, + Final = 2, +}; void CompatDB::Submit() { QButtonGroup* compatibility = new QButtonGroup(this); diff --git a/src/yuzu/compatdb.h b/src/yuzu/compatdb.h index 0a0f27cca..ca0dd11d6 100644 --- a/src/yuzu/compatdb.h +++ b/src/yuzu/compatdb.h @@ -21,7 +21,6 @@ public: private: std::unique_ptr ui; -private slots: void Submit(); void EnableNext(); }; diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index cfca08014..4b5c39e26 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -25,7 +25,7 @@ ConfigureWeb::ConfigureWeb(QWidget* parent) this->setConfiguration(); } -ConfigureWeb::~ConfigureWeb() {} +ConfigureWeb::~ConfigureWeb() = default; void ConfigureWeb::setConfiguration() { ui->web_credentials_disclaimer->setWordWrap(true); diff --git a/src/yuzu/discord_impl.h b/src/yuzu/discord_impl.h index d71428c10..4bfda8cdf 100644 --- a/src/yuzu/discord_impl.h +++ b/src/yuzu/discord_impl.h @@ -11,7 +11,7 @@ namespace DiscordRPC { class DiscordImpl : public DiscordInterface { public: DiscordImpl(); - ~DiscordImpl(); + ~DiscordImpl() override; void Pause() override; void Update() override; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2d6e0d4fc..f236c63c5 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -115,7 +115,7 @@ void GMainWindow::ShowTelemetryCallout() { } UISettings::values.callout_flags |= static_cast(CalloutFlag::Telemetry); - static const QString telemetry_message = + const QString telemetry_message = tr("Anonymous " "data is collected to help improve yuzu. " "

Would you like to share your usage data with us?"); -- cgit v1.2.3 From aa484688623db59df3ef334a63eff98d98e362f3 Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Wed, 19 Sep 2018 20:04:45 +0200 Subject: Review comments - part 3 --- src/yuzu/configuration/configure_web.cpp | 6 +++--- src/yuzu/main.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/yuzu') diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index 4b5c39e26..d6bd3d309 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -31,18 +31,18 @@ void ConfigureWeb::setConfiguration() { ui->web_credentials_disclaimer->setWordWrap(true); ui->telemetry_learn_more->setOpenExternalLinks(true); ui->telemetry_learn_more->setText(tr("Learn more")); ui->web_signup_link->setOpenExternalLinks(true); ui->web_signup_link->setText( - tr("Sign up")); ui->web_token_info_link->setOpenExternalLinks(true); ui->web_token_info_link->setText( - tr("What is my token?")); ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f236c63c5..52743aefd 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -116,7 +116,7 @@ void GMainWindow::ShowTelemetryCallout() { UISettings::values.callout_flags |= static_cast(CalloutFlag::Telemetry); const QString telemetry_message = - tr("Anonymous " + tr("Anonymous " "data is collected to help improve yuzu. " "

Would you like to share your usage data with us?"); if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { -- cgit v1.2.3 From ac06105dfe9c7e5306e1f4cac0ee12dc5f72f14e Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Sat, 29 Sep 2018 02:51:28 +0200 Subject: Review comments -part 4 --- src/yuzu/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/yuzu') diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f93ba2569..04464ad5e 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -120,6 +120,10 @@ target_link_libraries(yuzu PRIVATE common core input_common video_core) target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets) target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) +if (YUZU_ENABLE_COMPATIBILITY_REPORTING) + add_definitions(-DYUZU_ENABLE_COMPATIBILITY_REPORTING) +endif() + if (USE_DISCORD_PRESENCE) target_sources(yuzu PUBLIC discord_impl.cpp -- cgit v1.2.3 From e4daf4bee522c046e5e01eeed2c5b12bd91f489e Mon Sep 17 00:00:00 2001 From: fearlessTobi Date: Tue, 2 Oct 2018 16:04:10 +0200 Subject: Review comments - part 5 --- src/yuzu/configuration/configure_web.cpp | 8 +++----- src/yuzu/main.cpp | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/yuzu') diff --git a/src/yuzu/configuration/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index d6bd3d309..5fb9251db 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp @@ -30,11 +30,9 @@ ConfigureWeb::~ConfigureWeb() = default; void ConfigureWeb::setConfiguration() { ui->web_credentials_disclaimer->setWordWrap(true); ui->telemetry_learn_more->setOpenExternalLinks(true); - ui->telemetry_learn_more->setText(tr("Learn more")); + ui->telemetry_learn_more->setText( + tr("Learn more")); ui->web_signup_link->setOpenExternalLinks(true); ui->web_signup_link->setText( diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 52743aefd..147e7fcad 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -116,7 +116,7 @@ void GMainWindow::ShowTelemetryCallout() { UISettings::values.callout_flags |= static_cast(CalloutFlag::Telemetry); const QString telemetry_message = - tr("Anonymous " + tr("Anonymous " "data is collected to help improve yuzu. " "

Would you like to share your usage data with us?"); if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) != QMessageBox::Yes) { -- cgit v1.2.3