From 03d4fffc702a5f36b96c995d7f2073766131693c Mon Sep 17 00:00:00 2001
From: Narr the Reg <juangerman-13@hotmail.com>
Date: Thu, 28 Sep 2023 22:35:08 -0600
Subject: [PATCH] yuzu: Allow to launch cabinet applet from firmware

---
 src/yuzu/main.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++--
 src/yuzu/main.h   |  5 +++++
 src/yuzu/main.ui  | 30 ++++++++++++++++++++++++++++++
 3 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index adb7b332f9..0879d61681 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1551,6 +1551,14 @@ void GMainWindow::ConnectMenuEvents() {
     // Tools
     connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this,
                                                 ReinitializeKeyBehavior::Warning));
+    connect_menu(ui->action_Load_Cabinet_Nickname_Owner,
+                 [this]() { OnCabinet(Service::NFP::CabinetMode::StartNicknameAndOwnerSettings); });
+    connect_menu(ui->action_Load_Cabinet_Eraser,
+                 [this]() { OnCabinet(Service::NFP::CabinetMode::StartGameDataEraser); });
+    connect_menu(ui->action_Load_Cabinet_Restorer,
+                 [this]() { OnCabinet(Service::NFP::CabinetMode::StartRestorer); });
+    connect_menu(ui->action_Load_Cabinet_Formatter,
+                 [this]() { OnCabinet(Service::NFP::CabinetMode::StartFormatter); });
     connect_menu(ui->action_Load_Mii_Edit, &GMainWindow::OnMiiEdit);
     connect_menu(ui->action_Capture_Screenshot, &GMainWindow::OnCaptureScreenshot);
 
@@ -1568,6 +1576,7 @@ void GMainWindow::ConnectMenuEvents() {
 
 void GMainWindow::UpdateMenuState() {
     const bool is_paused = emu_thread == nullptr || !emu_thread->IsRunning();
+    const bool is_firmware_available = CheckFirmwarePresence();
 
     const std::array running_actions{
         ui->action_Stop,
@@ -1578,10 +1587,22 @@ void GMainWindow::UpdateMenuState() {
         ui->action_Pause,
     };
 
+    const std::array applet_actions{
+        ui->action_Load_Cabinet_Nickname_Owner,
+        ui->action_Load_Cabinet_Eraser,
+        ui->action_Load_Cabinet_Restorer,
+        ui->action_Load_Cabinet_Formatter,
+        ui->action_Load_Mii_Edit,
+    };
+
     for (QAction* action : running_actions) {
         action->setEnabled(emulation_running);
     }
 
+    for (QAction* action : applet_actions) {
+        action->setEnabled(is_firmware_available && !emulation_running);
+    }
+
     ui->action_Capture_Screenshot->setEnabled(emulation_running && !is_paused);
 
     if (emulation_running && is_paused) {
@@ -1591,8 +1612,6 @@ void GMainWindow::UpdateMenuState() {
     }
 
     multiplayer_state->UpdateNotificationStatus();
-
-    ui->action_Load_Mii_Edit->setEnabled(CheckFirmwarePresence());
 }
 
 void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -4134,6 +4153,27 @@ void GMainWindow::OnToggleStatusBar() {
     statusBar()->setVisible(ui->action_Show_Status_Bar->isChecked());
 }
 
+void GMainWindow::OnCabinet(Service::NFP::CabinetMode mode) {
+    constexpr u64 CabinetId = 0x0100000000001002ull;
+    auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
+    if (!bis_system) {
+        QMessageBox::warning(this, tr("No firmware available"),
+                             tr("Please install the firmware to use the Cabinet applet."));
+        return;
+    }
+
+    auto cabinet_nca = bis_system->GetEntry(CabinetId, FileSys::ContentRecordType::Program);
+    if (!cabinet_nca) {
+        QMessageBox::warning(this, tr("Cabinet Applet"),
+                             tr("Cabinet applet is not available. Please reinstall firmware."));
+        return;
+    }
+
+    const auto filename = QString::fromStdString(cabinet_nca->GetFullPath());
+    UISettings::values.roms_path = QFileInfo(filename).path();
+    BootGame(filename);
+}
+
 void GMainWindow::OnMiiEdit() {
     constexpr u64 MiiEditId = 0x0100000000001009ull;
     auto bis_system = system->GetFileSystemController().GetSystemNANDContents();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index ba318eb11e..52028234c7 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -102,6 +102,10 @@ namespace Service::NFC {
 class NfcDevice;
 } // namespace Service::NFC
 
+namespace Service::NFP {
+enum class CabinetMode : u8;
+} // namespace Service::NFP
+
 namespace Ui {
 class MainWindow;
 }
@@ -365,6 +369,7 @@ private slots:
     void ResetWindowSize720();
     void ResetWindowSize900();
     void ResetWindowSize1080();
+    void OnCabinet(Service::NFP::CabinetMode mode);
     void OnMiiEdit();
     void OnCaptureScreenshot();
     void OnReinitializeKeys(ReinitializeKeyBehavior behavior);
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 91d6c5ef3f..31c3de9ef9 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -137,6 +137,15 @@
     <property name="title">
      <string>&amp;Tools</string>
     </property>
+    <widget class="QMenu" name="menu_cabinet_applet">
+     <property name="title">
+      <string>&amp;Amiibo</string>
+     </property>
+     <addaction name="action_Load_Cabinet_Nickname_Owner"/>
+     <addaction name="action_Load_Cabinet_Eraser"/>
+     <addaction name="action_Load_Cabinet_Restorer"/>
+     <addaction name="action_Load_Cabinet_Formatter"/>
+    </widget>
     <widget class="QMenu" name="menuTAS">
      <property name="title">
       <string>&amp;TAS</string>
@@ -150,6 +159,7 @@
     <addaction name="action_Rederive"/>
     <addaction name="action_Verify_installed_contents"/>
     <addaction name="separator"/>
+    <addaction name="menu_cabinet_applet"/>
     <addaction name="action_Load_Mii_Edit"/>
     <addaction name="separator"/>
     <addaction name="action_Capture_Screenshot"/>
@@ -370,6 +380,26 @@
     <string>&amp;Capture Screenshot</string>
    </property>
   </action>
+  <action name="action_Load_Cabinet_Nickname_Owner">
+   <property name="text">
+    <string>&amp;Set Nickname and Owner</string>
+   </property>
+  </action>
+  <action name="action_Load_Cabinet_Eraser">
+   <property name="text">
+    <string>&amp;Delete Game Data</string>
+   </property>
+  </action>
+  <action name="action_Load_Cabinet_Restorer">
+   <property name="text">
+    <string>&amp;Restore Amiibo</string>
+   </property>
+  </action>
+  <action name="action_Load_Cabinet_Formatter">
+   <property name="text">
+    <string>&amp;Format Amiibo</string>
+   </property>
+  </action>
   <action name="action_Load_Mii_Edit">
     <property name="text">
       <string>Open &amp;Mii Editor</string>
-- 
GitLab