melonDS-emu / melonDS

DS emulator, sorta
https://melonds.kuribo64.net
GNU General Public License v3.0
3.18k stars 524 forks source link

[FEATURE REQUEST] Add the ability to eject the current cartridge losing dldi capabilities. #2025

Open sergiotarxz opened 5 months ago

sergiotarxz commented 5 months ago

I would want to be able to lose the dldi capabilities on hot to develop software that depends on the capability of extracting the flashcart, read a real cartridge and be able to recover the dldi capabilities later. Currently the feature of ejecting the cartridge exists, but toggling dldi requires restarting the emulator defeating this use case.

sergiotarxz commented 5 months ago

I got it working with this patch:

diff --git a/src/frontend/qt_sdl/EmuSettingsDialog.cpp b/src/frontend/qt_sdl/EmuSettingsDialog.cpp
index ca9c6716..2deaa562 100644
--- a/src/frontend/qt_sdl/EmuSettingsDialog.cpp
+++ b/src/frontend/qt_sdl/EmuSettingsDialog.cpp
@@ -37,6 +37,7 @@ EmuSettingsDialog* EmuSettingsDialog::currentDlg = nullptr;
 extern bool RunningSomething;

 bool EmuSettingsDialog::needsReset = false;
+bool EmuSettingsDialog::needsDLDIUpdate = false;

 inline void updateLastBIOSFolder(QString& filename)
 {
@@ -200,6 +201,7 @@ void EmuSettingsDialog::verifyFirmware()
 void EmuSettingsDialog::done(int r)
 {
     needsReset = false;
+    needsDLDIUpdate = false;

     if (r == QDialog::Accepted)
     {
@@ -283,12 +285,6 @@ void EmuSettingsDialog::done(int r)
             || dsiSDFolderSync != Config::DSiSDFolderSync
             || dsiSDFolderPath != Config::DSiSDFolderPath)
         {
-            if (RunningSomething
-                && QMessageBox::warning(this, "Reset necessary to apply changes",
-                    "The emulation will be reset for the changes to take place.",
-                    QMessageBox::Ok, QMessageBox::Cancel) != QMessageBox::Ok)
-                return;
-
             Config::ExternalBIOSEnable = externalBiosEnable;
             Config::BIOS9Path = bios9Path;
             Config::BIOS7Path = bios7Path;
@@ -334,7 +330,8 @@ void EmuSettingsDialog::done(int r)

             Config::Save();

-            needsReset = true;
+            needsReset = false;
+            needsDLDIUpdate = true;
         }
     }

diff --git a/src/frontend/qt_sdl/EmuSettingsDialog.h b/src/frontend/qt_sdl/EmuSettingsDialog.h
index b53d090b..c464d93e 100644
--- a/src/frontend/qt_sdl/EmuSettingsDialog.h
+++ b/src/frontend/qt_sdl/EmuSettingsDialog.h
@@ -51,6 +51,7 @@ public:
     }

     static bool needsReset;
+    static bool needsDLDIUpdate;

 private slots:
     void done(int r);
diff --git a/src/frontend/qt_sdl/EmuThread.cpp b/src/frontend/qt_sdl/EmuThread.cpp
index d16aead4..09488118 100644
--- a/src/frontend/qt_sdl/EmuThread.cpp
+++ b/src/frontend/qt_sdl/EmuThread.cpp
@@ -180,6 +180,19 @@ std::unique_ptr<NDS> EmuThread::CreateConsole(
     return std::make_unique<melonDS::NDS>(std::move(ndsargs));
 }

+void EmuThread::UpdateDLDI() {
+    std::unique_ptr<NDSCart::CartCommon> nextndscart;
+    nextndscart = NDS ? NDS->EjectCart() : nullptr;
+    if (auto* cartsd = dynamic_cast<NDSCart::CartSD*>(nextndscart.get()))
+    {
+        // LoadDLDISDCard will return nullopt if the SD card is disabled;
+        // SetSDCard will accept nullopt, which means no SD card
+        cartsd->SetSDCard(ROMManager::GetDLDISDCardArgs());
+    }
+    NDS->SetNDSCart(std::move(nextndscart));
+    NDS::Current = NDS.get();
+}
+
 bool EmuThread::UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept
 {
     // Let's get the cart we want to use;
diff --git a/src/frontend/qt_sdl/EmuThread.h b/src/frontend/qt_sdl/EmuThread.h
index 4950ebbf..a07371ca 100644
--- a/src/frontend/qt_sdl/EmuThread.h
+++ b/src/frontend/qt_sdl/EmuThread.h
@@ -71,6 +71,7 @@ public:
     /// @return \c true if the console was updated.
     /// If this returns \c false, then the existing NDS console is not modified.
     bool UpdateConsole(UpdateConsoleNDSArgs&& ndsargs, UpdateConsoleGBAArgs&& gbaargs) noexcept;
+    void UpdateDLDI();
     std::unique_ptr<melonDS::NDS> NDS; // TODO: Proper encapsulation and synchronization
 signals:
     void windowUpdate();
diff --git a/src/frontend/qt_sdl/Window.cpp b/src/frontend/qt_sdl/Window.cpp
index 23ba784e..8c41bd75 100644
--- a/src/frontend/qt_sdl/Window.cpp
+++ b/src/frontend/qt_sdl/Window.cpp
@@ -1557,6 +1557,14 @@ void MainWindow::onPause(bool checked)
     }
 }

+void MainWindow::onDLDIUpdate()
+{
+    if (!RunningSomething) return;
+    emuThread->emuPause();
+    emuThread->UpdateDLDI();
+    emuThread->emuRun();
+}
+
 void MainWindow::onReset()
 {
     if (!RunningSomething) return;
@@ -1678,6 +1686,9 @@ void MainWindow::onEmuSettingsDialogFinished(int res)

     if (EmuSettingsDialog::needsReset)
         onReset();
+    if (EmuSettingsDialog::needsDLDIUpdate) {
+        onDLDIUpdate();
+    }

     actCurrentGBACart->setText("GBA slot: " + ROMManager::GBACartLabel());

diff --git a/src/frontend/qt_sdl/Window.h b/src/frontend/qt_sdl/Window.h
index bc207480..53419b83 100644
--- a/src/frontend/qt_sdl/Window.h
+++ b/src/frontend/qt_sdl/Window.h
@@ -150,6 +150,7 @@ private slots:

     void onPause(bool checked);
     void onReset();
+    void onDLDIUpdate();
     void onStop();
     void onFrameStep();
     void onOpenPowerManagement();

But it is not mergeable since it assumes every emu setting change is a dldi change.