Add 'Set Up System Files' option (#642)

* Add 'Set Up System Files' option

* Fix CIA installation and HLE module loading when no console unique data provided.
This commit is contained in:
PabloMK7
2025-03-10 11:48:11 +01:00
committed by GitHub
parent 6262ddafa6
commit e3a21c8ef1
34 changed files with 1006 additions and 450 deletions

View File

@@ -489,7 +489,7 @@ void GMainWindow::InitializeWidgets() {
artic_traffic_label = new QLabel();
artic_traffic_label->setToolTip(
tr("Current Artic Base traffic speed. Higher values indicate bigger transfer loads."));
tr("Current Artic traffic speed. Higher values indicate bigger transfer loads."));
emu_speed_label = new QLabel();
emu_speed_label->setToolTip(tr("Current emulation speed. Values higher or lower than 100% "
@@ -982,6 +982,7 @@ void GMainWindow::ConnectMenuEvents() {
connect_menu(ui->action_Load_File, &GMainWindow::OnMenuLoadFile);
connect_menu(ui->action_Install_CIA, &GMainWindow::OnMenuInstallCIA);
connect_menu(ui->action_Connect_Artic, &GMainWindow::OnMenuConnectArticBase);
connect_menu(ui->action_Setup_System_Files, &GMainWindow::OnMenuSetUpSystemFiles);
for (u32 region = 0; region < Core::NUM_SYSTEM_TITLE_REGIONS; region++) {
connect_menu(ui->menu_Boot_Home_Menu->actions().at(region),
[this, region] { OnMenuBootHomeMenu(region); });
@@ -1367,9 +1368,9 @@ bool GMainWindow::LoadROM(const QString& filename) {
case Core::System::ResultStatus::ErrorArticDisconnected:
QMessageBox::critical(
this, tr("Artic Base Server"),
this, tr("Artic Server"),
tr(fmt::format(
"An error has occurred whilst communicating with the Artic Base Server.\n{}",
"An error has occurred whilst communicating with the Artic Server.\n{}",
system.GetStatusDetails())
.c_str()));
break;
@@ -1401,7 +1402,9 @@ void GMainWindow::BootGame(const QString& filename) {
ShutdownGame();
}
const bool is_artic = filename.startsWith(QString::fromStdString("articbase://"));
const bool is_artic = filename.startsWith(QString::fromStdString("articbase:/")) ||
filename.startsWith(QString::fromStdString("articinio:/")) ||
filename.startsWith(QString::fromStdString("articinin:/"));
if (!is_artic && filename.endsWith(QStringLiteral(".cia"))) {
const auto answer = QMessageBox::question(
@@ -1444,7 +1447,7 @@ void GMainWindow::BootGame(const QString& filename) {
QtConfig per_game_config(config_file_name, QtConfig::ConfigType::PerGameConfig);
}
// Artic Base Server cannot accept a client multiple times, so multiple loaders are not
// Artic Server cannot accept a client multiple times, so multiple loaders are not
// possible. Instead register the app loader early and do not create it again on system load.
if (!loader->SupportsMultipleInstancesForSameFile()) {
system.RegisterAppLoaderEarly(loader);
@@ -2192,6 +2195,92 @@ void GMainWindow::OnMenuLoadFile() {
BootGame(filename);
}
void GMainWindow::OnMenuSetUpSystemFiles() {
QDialog dialog(this);
dialog.setWindowTitle(tr("Set Up System Files"));
QVBoxLayout layout(&dialog);
QLabel label_description(
tr("<p>Azahar needs files from a real console to be able to use some of its features.<br>"
"You can get such files with the <a "
"href=https://github.com/azahar-emu/ArticSetupTool>Azahar "
"Artic Setup Tool</a><br> Notes:<ul><li><b>This operation will install console unique "
"files "
"to Azahar, do not share your user or nand folders<br>after performing the setup "
"process!</b></li><li>Old 3DS setup is needed for the New 3DS setup to "
"work.</li><li>Both setup modes will work regardless of the model of the console "
"running the setup tool.</li></ul><hr></p>"),
&dialog);
label_description.setOpenExternalLinks(true);
layout.addWidget(&label_description);
QHBoxLayout layout_h(&dialog);
layout.addLayout(&layout_h);
QLabel label_enter(tr("Enter Azahar Artic Setup Tool address:"), &dialog);
layout_h.addWidget(&label_enter);
QLineEdit textInput(UISettings::values.last_artic_base_addr, &dialog);
layout_h.addWidget(&textInput);
QLabel label_select(tr("<br>Choose setup mode:"), &dialog);
layout.addWidget(&label_select);
std::pair<bool, bool> install_state = Core::AreSystemTitlesInstalled();
QRadioButton radio1(&dialog);
QRadioButton radio2(&dialog);
if (!install_state.first) {
radio1.setText(tr("(\u2139\uFE0F) Old 3DS setup"));
radio1.setToolTip(tr("Setup is possible."));
radio2.setText(tr("(\u26A0) New 3DS setup"));
radio2.setToolTip(tr("Old 3DS setup is required first."));
radio2.setEnabled(false);
} else {
radio1.setText(tr("(\u2705) Old 3DS setup"));
radio1.setToolTip(tr("Setup completed."));
if (!install_state.second) {
radio2.setText(tr("(\u2139\uFE0F) New 3DS setup"));
radio2.setToolTip(tr("Setup is possible."));
} else {
radio2.setText(tr("(\u2705) New 3DS setup"));
radio2.setToolTip(tr("Setup completed."));
}
}
radio1.setChecked(true);
layout.addWidget(&radio1);
layout.addWidget(&radio2);
QDialogButtonBox buttonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
layout.addWidget(&buttonBox);
int res = dialog.exec();
if (res == QDialog::Accepted) {
bool is_o3ds = radio1.isChecked();
if ((is_o3ds && install_state.first) || (!is_o3ds && install_state.second)) {
QMessageBox::StandardButton answer =
QMessageBox::question(this, tr("Set Up System Files"),
tr("The system files for the selected mode are already set "
"up.\nReinstall the files anyway?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (answer != QMessageBox::Yes) {
return;
}
}
Core::UninstallSystemFiles(is_o3ds ? Core::SystemTitleSet::Old3ds
: Core::SystemTitleSet::New3ds);
QString addr = textInput.text();
UISettings::values.last_artic_base_addr = addr;
BootGame(QString::fromStdString(is_o3ds ? "articinio://" : "articinin://").append(addr));
}
}
void GMainWindow::OnMenuInstallCIA() {
QStringList filepaths = QFileDialog::getOpenFileNames(
this, tr("Load Files"), UISettings::values.roms_path,
@@ -3131,16 +3220,16 @@ void GMainWindow::UpdateStatusBar() {
QStringLiteral("QLabel { color: %0; }").arg(label_color[style_index]);
artic_traffic_label->setText(
tr("Artic Base Traffic: %1 %2%3").arg(value, 0, 'f', 0).arg(unit).arg(event));
tr("Artic Traffic: %1 %2%3").arg(value, 0, 'f', 0).arg(unit).arg(event));
artic_traffic_label->setStyleSheet(style_sheet);
}
if (Settings::values.frame_limit.GetValue() == 0) {
if (Settings::GetFrameLimit() == 0) {
emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0));
} else {
emu_speed_label->setText(tr("Speed: %1% / %2%")
.arg(results.emulation_speed * 100.0, 0, 'f', 0)
.arg(Settings::values.frame_limit.GetValue()));
.arg(Settings::GetFrameLimit()));
}
game_fps_label->setText(tr("App: %1 FPS").arg(results.game_fps, 0, 'f', 0));
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
@@ -3321,7 +3410,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
message = QString::fromStdString(details);
error_severity_icon = QMessageBox::Icon::Warning;
} else if (result == Core::System::ResultStatus::ErrorArticDisconnected) {
title = tr("Artic Base Server");
title = tr("Artic Server");
message =
tr(fmt::format("A communication error has occurred. The game will quit.\n{}", details)
.c_str());

View File

@@ -244,6 +244,7 @@ private slots:
void OnGameListOpenPerGameProperties(const QString& file);
void OnConfigurePerGame();
void OnMenuLoadFile();
void OnMenuSetUpSystemFiles();
void OnMenuInstallCIA();
void OnMenuConnectArticBase();
void OnMenuBootHomeMenu(u32 region);

View File

@@ -237,8 +237,7 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
&ConfigureSystem::UpdateInitTicks);
connect(ui->button_regenerate_console_id, &QPushButton::clicked, this,
&ConfigureSystem::RefreshConsoleID);
connect(ui->button_start_download, &QPushButton::clicked, this,
&ConfigureSystem::DownloadFromNUS);
connect(ui->button_regenerate_mac, &QPushButton::clicked, this, &ConfigureSystem::RefreshMAC);
connect(ui->button_secure_info, &QPushButton::clicked, this, [this] {
ui->button_secure_info->setEnabled(false);
@@ -281,34 +280,6 @@ ConfigureSystem::ConfigureSystem(Core::System& system_, QWidget* parent)
}
SetupPerGameUI();
ui->combo_download_set->setCurrentIndex(0); // set to Minimal
ui->combo_download_region->setCurrentIndex(0); // set to the base region
HW::AES::InitKeys(true);
bool keys_available = HW::AES::IsKeyXAvailable(HW::AES::KeySlotID::NCCHSecure1) &&
HW::AES::IsKeyXAvailable(HW::AES::KeySlotID::NCCHSecure2);
for (u8 i = 0; i < HW::AES::MaxCommonKeySlot && keys_available; 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_set->setEnabled(true);
ui->combo_download_region->setEnabled(true);
ui->label_nus_download->setText(tr("Download System Files from Nintendo servers"));
} else {
ui->button_start_download->setEnabled(false);
ui->combo_download_set->setEnabled(false);
ui->combo_download_region->setEnabled(false);
ui->label_nus_download->setTextInteractionFlags(Qt::TextBrowserInteraction);
ui->label_nus_download->setOpenExternalLinks(true);
ui->label_nus_download->setText(tr("Azahar is missing keys to download system files."));
}
ConfigureTime();
}
@@ -385,14 +356,13 @@ void ConfigureSystem::ReadSystemSettings() {
u64 console_id = cfg->GetConsoleUniqueId();
ui->label_console_id->setText(
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
mac_address = cfg->GetMacAddress();
ui->label_mac->setText(tr("MAC: %1").arg(QString::fromStdString(mac_address)));
// set play coin
play_coin = Service::PTM::Module::GetPlayCoins();
ui->spinBox_play_coins->setValue(play_coin);
// set firmware download region
ui->combo_download_region->setCurrentIndex(static_cast<int>(cfg->GetRegionValue()));
// Refresh secure data status
RefreshSecureDataStatus();
}
@@ -484,6 +454,9 @@ void ConfigureSystem::ApplyConfiguration() {
Settings::values.plugin_loader_enabled.SetValue(ui->plugin_loader->isChecked());
Settings::values.allow_plugin_loader.SetValue(ui->allow_plugin_loader->isChecked());
cfg->GetMacAddress() = mac_address;
cfg->SaveMacAddress();
}
}
@@ -548,10 +521,11 @@ void ConfigureSystem::UpdateInitTicks(int init_ticks_type) {
void ConfigureSystem::RefreshConsoleID() {
QMessageBox::StandardButton reply;
QString warning_text = tr("This will replace your current virtual 3DS with a new one. "
"Your current virtual 3DS will not be recoverable. "
"This might have unexpected effects in applications. This might fail "
"if you use an outdated config save. Continue?");
QString warning_text =
tr("This will replace your current virtual 3DS console ID with a new one. "
"Your current virtual 3DS console ID will not be recoverable. "
"This might have unexpected effects in applications. This might fail "
"if you use an outdated config save. Continue?");
reply = QMessageBox::critical(this, tr("Warning"), warning_text,
QMessageBox::No | QMessageBox::Yes);
if (reply == QMessageBox::No) {
@@ -565,6 +539,21 @@ void ConfigureSystem::RefreshConsoleID() {
tr("Console ID: 0x%1").arg(QString::number(console_id, 16).toUpper()));
}
void ConfigureSystem::RefreshMAC() {
QMessageBox::StandardButton reply;
QString warning_text = tr("This will replace your current MAC address with a new one. "
"It is not recommended to do this if you got the MAC address from "
"your real console using the setup tool. Continue?");
reply =
QMessageBox::warning(this, tr("Warning"), warning_text, QMessageBox::No | QMessageBox::Yes);
if (reply == QMessageBox::No) {
return;
}
mac_address = Service::CFG::GenerateRandomMAC();
ui->label_mac->setText(tr("MAC: %1").arg(QString::fromStdString(mac_address)));
}
void ConfigureSystem::InstallSecureData(const std::string& from_path, const std::string& to_path) {
std::string from =
FileUtil::SanitizePath(from_path, FileUtil::DirectorySeparator::PlatformDefault);
@@ -655,20 +644,9 @@ void ConfigureSystem::SetupPerGameUI() {
ui->label_plugin_loader->setVisible(false);
ui->plugin_loader->setVisible(false);
ui->allow_plugin_loader->setVisible(false);
// Disable the system firmware downloader.
ui->label_nus_download->setVisible(false);
ui->body_nus_download->setVisible(false);
ConfigurationShared::SetColoredTristate(ui->toggle_new_3ds, Settings::values.is_new_3ds,
is_new_3ds);
ConfigurationShared::SetColoredTristate(ui->toggle_lle_applets, Settings::values.lle_applets,
lle_applets);
}
void ConfigureSystem::DownloadFromNUS() {
ui->button_start_download->setEnabled(false);
QMessageBox::critical(this, tr("Azahar"), tr("Downloading from NUS has been deprecated."));
ui->button_start_download->setEnabled(true);
}

View File

@@ -1,4 +1,4 @@
// Copyright 2016 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -51,14 +51,13 @@ private:
void UpdateInitTime(int init_clock);
void UpdateInitTicks(int init_ticks_type);
void RefreshConsoleID();
void RefreshMAC();
void InstallSecureData(const std::string& from_path, const std::string& to_path);
void RefreshSecureDataStatus();
void SetupPerGameUI();
void DownloadFromNUS();
private:
std::unique_ptr<Ui::ConfigureSystem> ui;
Core::System& system;
@@ -75,4 +74,5 @@ private:
u8 country_code;
u16 play_coin;
bool system_setup;
std::string mac_address;
};

View File

@@ -455,113 +455,49 @@
</widget>
</item>
<item row="16" column="0">
<widget class="QLabel" name="label_mac">
<property name="text">
<string>MAC:</string>
</property>
</widget>
</item>
<item row="16" column="1">
<widget class="QPushButton" name="button_regenerate_mac">
<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>Regenerate</string>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="label_plugin_loader">
<property name="text">
<string>3GX Plugin Loader:</string>
</property>
</widget>
</item>
<item row="16" column="1">
<item row="17" column="1">
<widget class="QCheckBox" name="plugin_loader">
<property name="text">
<string>Enable 3GX plugin loader</string>
</property>
</widget>
</item>
<item row="17" column="1">
<item row="18" column="1">
<widget class="QCheckBox" name="allow_plugin_loader">
<property name="text">
<string>Allow applications to change plugin loader state</string>
</property>
</widget>
</item>
<item row="18" column="0">
<widget class="QLabel" name="label_nus_download">
<property name="text">
<string>Download System Files from Nintendo servers</string>
</property>
</widget>
</item>
<item row="18" column="1">
<widget class="QWidget" name="body_nus_download">
<layout class="QHBoxLayout" name="horizontalLayout_nus_download">
<item>
<widget class="QComboBox" name="combo_download_set">
<item>
<property name="text">
<string>Minimal</string>
</property>
</item>
<item>
<property name="text">
<string>Old 3DS</string>
</property>
</item>
<item>
<property name="text">
<string>New 3DS</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QComboBox" name="combo_download_region">
<item>
<property name="text">
<string>JPN</string>
</property>
</item>
<item>
<property name="text">
<string>USA</string>
</property>
</item>
<item>
<property name="text">
<string>EUR</string>
</property>
</item>
<item>
<property name="text">
<string>AUS</string>
</property>
</item>
<item>
<property name="text">
<string>CHN</string>
</property>
</item>
<item>
<property name="text">
<string>KOR</string>
</property>
</item>
<item>
<property name="text">
<string>TWN</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>
</widget>
</item>
</layout>
</widget>
</item>
@@ -762,6 +698,7 @@
<tabstop>spinBox_play_coins</tabstop>
<tabstop>spinBox_steps_per_hour</tabstop>
<tabstop>button_regenerate_console_id</tabstop>
<tabstop>button_regenerate_mac</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@@ -79,6 +79,8 @@
<addaction name="action_Load_File"/>
<addaction name="action_Install_CIA"/>
<addaction name="action_Connect_Artic"/>
<addaction name="separator"/>
<addaction name="action_Setup_System_Files"/>
<addaction name="menu_Boot_Home_Menu"/>
<addaction name="separator"/>
<addaction name="menu_recent_files"/>
@@ -238,6 +240,11 @@
<string>Connect to Artic Base...</string>
</property>
</action>
<action name="action_Setup_System_Files">
<property name="text">
<string>Set Up System Files...</string>
</property>
</action>
<action name="action_Boot_Home_Menu_JPN">
<property name="text">
<string>JPN</string>