Add option to configure to download system files from Nintendo Update Service (#6269)

Co-authored-by: B3n30 <benediktthomas@gmail.com>
This commit is contained in:
Steveice10
2023-02-09 11:58:08 -08:00
committed by GitHub
parent 691cb43871
commit 6bef34852c
16 changed files with 1076 additions and 10 deletions

View File

@@ -266,7 +266,7 @@ endif()
create_target_directory_groups(citra-qt)
target_link_libraries(citra-qt PRIVATE audio_core common core input_common network video_core)
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia)
target_link_libraries(citra-qt PRIVATE Boost::boost glad nihstro-headers Qt5::Widgets Qt5::Multimedia Qt5::Concurrent)
target_link_libraries(citra-qt PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
target_compile_definitions(citra-qt PRIVATE

View File

@@ -3,14 +3,22 @@
// Refer to the license.txt file included.
#include <cstring>
#include <QFutureWatcher>
#include <QMessageBox>
#include <QProgressDialog>
#include <QtConcurrent/QtConcurrentMap>
#include "citra_qt/configuration/configuration_shared.h"
#include "citra_qt/configuration/configure_system.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/ptm/ptm.h"
#include "core/hw/aes/key.h"
#include "ui_configure_system.h"
#ifdef ENABLE_WEB_SERVICE
#include "web_service/nus_titles.h"
#endif
static const std::array<int, 12> days_in_month = {{
31,
@@ -239,6 +247,8 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
&ConfigureSystem::UpdateInitTime);
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID);
connect(ui->button_start_download, &QPushButton::clicked, this,
&ConfigureSystem::DownloadFromNUS);
for (u8 i = 0; i < country_names.size(); i++) {
if (std::strcmp(country_names.at(i), "") != 0) {
ui->combo_country->addItem(tr(country_names.at(i)), i);
@@ -257,6 +267,30 @@ ConfigureSystem::ConfigureSystem(QWidget* parent)
ui->clock_speed_combo->setVisible(!Settings::IsConfiguringGlobal());
SetupPerGameUI();
ui->combo_download_mode->setCurrentIndex(1); // set to Recommended
bool keys_available = true;
HW::AES::InitKeys(true);
for (u8 i = 0; i < HW::AES::MaxCommonKeySlot; i++) {
HW::AES::SelectCommonKeyIndex(i);
if (!HW::AES::IsNormalKeyAvailable(HW::AES::KeySlotID::TicketCommonKey)) {
keys_available = false;
break;
}
}
if (keys_available) {
ui->button_start_download->setEnabled(true);
ui->combo_download_mode->setEnabled(true);
ui->label_nus_download->setText(tr("Download System Files from Nintendo servers"));
} else {
ui->button_start_download->setEnabled(false);
ui->combo_download_mode->setEnabled(false);
ui->label_nus_download->setText(
tr("Citra is missing keys to download system files. <br><a "
"href='https://citra-emu.org/wiki/aes-keys/'><span style=\"text-decoration: "
"underline; color:#039be5;\">How to get keys?</span></a>"));
}
ConfigureTime();
}
@@ -542,3 +576,44 @@ void ConfigureSystem::SetupPerGameUI() {
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
is_new_3ds);
}
void ConfigureSystem::DownloadFromNUS() {
#ifdef ENABLE_WEB_SERVICE
ui->button_start_download->setEnabled(false);
const auto mode = static_cast<Title::Mode>(ui->combo_download_mode->currentIndex());
const std::vector<u64> titles = BuildFirmwareTitleList(mode, cfg->GetRegionValue());
QProgressDialog progress(tr("Downloading files..."), tr("Cancel"), 0,
static_cast<int>(titles.size()), this);
progress.setWindowModality(Qt::WindowModal);
QFutureWatcher<void> future_watcher;
QObject::connect(&future_watcher, &QFutureWatcher<void>::finished, &progress,
&QProgressDialog::reset);
QObject::connect(&progress, &QProgressDialog::canceled, &future_watcher,
&QFutureWatcher<void>::cancel);
QObject::connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &progress,
&QProgressDialog::setValue);
auto failed = false;
const auto download_title = [&future_watcher, &failed](const u64& title_id) {
if (Service::AM::InstallFromNus(title_id) != Service::AM::InstallStatus::Success) {
failed = true;
future_watcher.cancel();
}
};
future_watcher.setFuture(QtConcurrent::map(titles, download_title));
progress.exec();
future_watcher.waitForFinished();
if (failed) {
QMessageBox::critical(this, tr("Citra"), tr("Downloading system files failed."));
} else if (!future_watcher.isCanceled()) {
QMessageBox::information(this, tr("Citra"), tr("Successfully downloaded system files."));
}
ui->button_start_download->setEnabled(true);
#endif
}

View File

@@ -43,6 +43,8 @@ private:
void SetupPerGameUI();
void DownloadFromNUS();
ConfigurationShared::CheckState is_new_3ds;
std::unique_ptr<Ui::ConfigureSystem> ui;
bool enabled = false;

View File

@@ -361,6 +361,52 @@
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QLabel" name="label_nus_download">
<property name="text">
<string>Download System Files from Nitendo servers</string>
</property>
</widget>
</item>
<item row="15" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_nus_download">
<item>
<widget class="QComboBox" name="combo_download_mode">
<item>
<property name="text">
<string>All</string>
</property>
</item>
<item>
<property name="text">
<string>Recommended</string>
</property>
</item>
<item>
<property name="text">
<string>Minimal</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="button_start_download">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Download</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>

View File

@@ -1920,6 +1920,7 @@ void GMainWindow::OnLoadState() {
}
void GMainWindow::OnConfigure() {
game_list->SetDirectoryWatcherEnabled(false);
Settings::SetConfiguringGlobal(true);
ConfigureDialog configureDialog(this, hotkey_registry,
!multiplayer_state->IsHostingPublicRoom());
@@ -1931,6 +1932,7 @@ void GMainWindow::OnConfigure() {
const auto old_touch_from_button_maps = Settings::values.touch_from_button_maps;
const bool old_discord_presence = UISettings::values.enable_discord_presence.GetValue();
auto result = configureDialog.exec();
game_list->SetDirectoryWatcherEnabled(true);
if (result == QDialog::Accepted) {
configureDialog.ApplyConfiguration();
InitializeHotkeys();