aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorcrueter <swurl@swurl.xyz>2025-06-11 22:57:13 +0000
committercrueter <crueter@noreply.localhost>2025-06-11 22:57:13 +0000
commitc4ca8d2367e3283e2adcc37833376d68b2ece6fc (patch)
tree88d9dc9a3a112ac4fb2ad2f6854515e9b7e97ebc /src
parent8ff1b9d282a9a7a8a02df86eecf19dbbd8440557 (diff)
Properly migrate internal NAND, Load, etc. directories (#167)
Signed-off-by: crueter <swurl@swurl.xyz> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/167 Co-authored-by: crueter <swurl@swurl.xyz> Co-committed-by: crueter <swurl@swurl.xyz>
Diffstat (limited to 'src')
-rw-r--r--src/yuzu/main.cpp29
-rw-r--r--src/yuzu/migration_dialog.cpp3
-rw-r--r--src/yuzu/migration_worker.cpp37
-rw-r--r--src/yuzu/migration_worker.h53
-rw-r--r--src/yuzu/user_data_migration.cpp245
-rw-r--r--src/yuzu/user_data_migration.h5
6 files changed, 202 insertions, 170 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index b5db06ae9d..3dbe2e3243 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
-#include <cinttypes>
#include <clocale>
#include <cmath>
#include <fstream>
@@ -36,6 +35,7 @@
#include "configuration/configure_per_game.h"
#include "configuration/configure_tas.h"
#include "core/file_sys/romfs_factory.h"
+#include "core/core_timing.h"
#include "core/file_sys/vfs/vfs.h"
#include "core/file_sys/vfs/vfs_real.h"
#include "core/frontend/applets/cabinet.h"
@@ -121,7 +121,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#endif
#include "common/settings.h"
#include "core/core.h"
-#include "core/core_timing.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
@@ -149,7 +148,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "video_core/shader_notify.h"
#include "yuzu/about_dialog.h"
#include "yuzu/bootmanager.h"
-#include "yuzu/compatdb.h"
#include "yuzu/compatibility_list.h"
#include "yuzu/configuration/configure_dialog.h"
#include "yuzu/configuration/configure_input_per_game.h"
@@ -319,6 +317,22 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
Common::FS::CreateEdenPaths();
this->config = std::make_unique<QtConfig>();
+ if (user_data_migrator.migrated) {
+ // Sort-of hack whereby we only move the old dir if it's a subfolder of the user dir
+ #define MIGRATE_DIR(type) std::string type##path = Common::FS::GetEdenPathString(Common::FS::EdenPath::type##Dir); \
+ if (type##path.starts_with(user_data_migrator.selected_emu.get_user_dir())) { \
+ boost::replace_all(type##path, user_data_migrator.selected_emu.lower_name(), "eden"); \
+ Common::FS::SetEdenPath(Common::FS::EdenPath::type##Dir, type##path); \
+ }
+
+ MIGRATE_DIR(NAND)
+ MIGRATE_DIR(SDMC)
+ MIGRATE_DIR(Dump)
+ MIGRATE_DIR(Load)
+
+ #undef MIGRATE_DIR
+ }
+
#ifdef __unix__
SetupSigInterrupts();
SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue());
@@ -506,13 +520,14 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
SetupPrepareForSleep();
+ // Some moron added a race condition to the status bar
+ // so now we have to make this completely unnecessary call
+ // to prevent the UI from blowing up.
+ UpdateUITheme();
+
QStringList args = QApplication::arguments();
if (args.size() < 2) {
- // Some moron added a race condition to the status bar
- // so now we have to make this completely unnecessary call
- // to prevent the UI from blowing up.
- UpdateUITheme();
return;
}
diff --git a/src/yuzu/migration_dialog.cpp b/src/yuzu/migration_dialog.cpp
index d4a6e9cd3c..9cc40841e8 100644
--- a/src/yuzu/migration_dialog.cpp
+++ b/src/yuzu/migration_dialog.cpp
@@ -47,10 +47,11 @@ QAbstractButton *MigrationDialog::addButton(
m_buttons->addWidget(button, 1);
connect(button, &QAbstractButton::clicked, this, [this, button, reject]() {
+ m_clickedButton = button;
+
if (reject) {
this->reject();
} else {
- m_clickedButton = button;
this->accept();
}
});
diff --git a/src/yuzu/migration_worker.cpp b/src/yuzu/migration_worker.cpp
index 2bb6eee944..bd96fec5de 100644
--- a/src/yuzu/migration_worker.cpp
+++ b/src/yuzu/migration_worker.cpp
@@ -1,10 +1,13 @@
#include "migration_worker.h"
+#include <QMap>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/replace.hpp>
#include <filesystem>
#include "common/fs/path_util.h"
-MigrationWorker::MigrationWorker(const LegacyEmu selected_legacy_emu_,
+MigrationWorker::MigrationWorker(const Emulator selected_legacy_emu_,
const bool clear_shader_cache_,
const MigrationStrategy strategy_)
: QObject()
@@ -18,31 +21,13 @@ void MigrationWorker::process()
namespace fs = std::filesystem;
const auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive;
- std::string legacy_user_dir;
- std::string legacy_config_dir;
- std::string legacy_cache_dir;
-
-#define LEGACY_EMU(emu) \
- case LegacyEmu::emu: \
- legacy_user_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##Dir).string(); \
- legacy_config_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##ConfigDir) \
- .string(); \
- legacy_cache_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##CacheDir) \
- .string(); \
- break;
-
- switch (selected_legacy_emu) {
- LEGACY_EMU(Citron)
- LEGACY_EMU(Sudachi)
- LEGACY_EMU(Yuzu)
- LEGACY_EMU(Suyu)
- }
-
-#undef LEGACY_EMU
+ std::string legacy_user_dir = selected_legacy_emu.get_user_dir();
+ std::string legacy_config_dir = selected_legacy_emu.get_config_dir();
+ std::string legacy_cache_dir = selected_legacy_emu.get_cache_dir();
- fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
+ fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
fs::path config_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
- fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
+ fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
fs::path shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
try {
@@ -62,7 +47,7 @@ void MigrationWorker::process()
emit error(tr("Linking the old directory failed. You may need to re-run with "
"administrative privileges on Windows.\nOS gave error: %1")
.arg(tr(e.what())));
- return;
+ std::exit(-1);
}
// Windows doesn't need any more links, because cache and config
@@ -119,5 +104,5 @@ void MigrationWorker::process()
fs::create_directory(shader_dir);
}
- emit finished(success_text);
+ emit finished(success_text, legacy_user_dir);
}
diff --git a/src/yuzu/migration_worker.h b/src/yuzu/migration_worker.h
index 49bb695b32..205e552a94 100644
--- a/src/yuzu/migration_worker.h
+++ b/src/yuzu/migration_worker.h
@@ -2,25 +2,58 @@
#define MIGRATION_WORKER_H
#include <QObject>
+#include "common/fs/path_util.h"
+
+using namespace Common::FS;
+
+typedef struct Emulator {
+ const char *name;
+
+ LegacyPath e_user_dir;
+ LegacyPath e_config_dir;
+ LegacyPath e_cache_dir;
+
+ const std::string get_user_dir() const {
+ return Common::FS::GetLegacyPath(e_user_dir).string();
+ }
+
+ const std::string get_config_dir() const {
+ return Common::FS::GetLegacyPath(e_config_dir).string();
+ }
+
+ const std::string get_cache_dir() const {
+ return Common::FS::GetLegacyPath(e_cache_dir).string();
+ }
+
+ const std::string lower_name() const {
+ std::string lower_name{name};
+ std::transform(lower_name.begin(), lower_name.end(), lower_name.begin(),
+ [](unsigned char c){ return std::tolower(c); });
+
+ return lower_name;
+ }
+} Emulator;
+
+#define EMU(name) Emulator{#name, name##Dir, name##ConfigDir, name##CacheDir}
+static constexpr std::array<Emulator, 4> legacy_emus = {
+ EMU(Citron),
+ EMU(Sudachi),
+ EMU(Suyu),
+ EMU(Yuzu),
+};
+#undef EMU
class MigrationWorker : public QObject
{
Q_OBJECT
public:
- enum class LegacyEmu {
- Citron,
- Sudachi,
- Yuzu,
- Suyu,
- };
-
enum class MigrationStrategy {
Copy,
Move,
Link,
};
- MigrationWorker(const LegacyEmu selected_legacy_emu,
+ MigrationWorker(const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationStrategy strategy);
@@ -28,11 +61,11 @@ public slots:
void process();
signals:
- void finished(const QString &success_text);
+ void finished(const QString &success_text, const std::string &user_dir);
void error(const QString &error_message);
private:
- LegacyEmu selected_legacy_emu;
+ Emulator selected_legacy_emu;
bool clear_shader_cache;
MigrationStrategy strategy;
QString success_text = tr("Data was migrated successfully.");
diff --git a/src/yuzu/user_data_migration.cpp b/src/yuzu/user_data_migration.cpp
index 3851e183b2..7424fc2c44 100644
--- a/src/yuzu/user_data_migration.cpp
+++ b/src/yuzu/user_data_migration.cpp
@@ -40,150 +40,144 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow *main_window)
{
namespace fs = std::filesystem;
- const QString migration_prompt_message = main_window->tr(
- "Would you like to migrate your data for use in Eden?\n"
- "Select the corresponding button to migrate data from that emulator.\n"
- "This may take a while.");
+ // define strings here for easy access
+ static constexpr const char *prompt_prefix_text
+ = "Eden has detected user data for the following emulators:";
- bool any_found = false;
+ static constexpr const char *migration_prompt_message
+ = "Would you like to migrate your data for use in Eden?\n"
+ "Select the corresponding button to migrate data from that emulator.\n"
+ "This may take a while.";
+
+ static constexpr const char *clear_shader_tooltip
+ = "Clearing shader cache is recommended for all "
+ "users.\nDo not uncheck unless you know what "
+ "you're doing.";
+
+ static constexpr const char *keep_old_data_tooltip
+ = "Keeps the old data directory. This is recommended if you aren't\n"
+ "space-constrained and want to keep separate data for the old emulator.";
+
+ static constexpr const char *clear_old_data_tooltip
+ = "Deletes the old data directory.\nThis is recommended on "
+ "devices with space constraints.";
+
+ static constexpr const char *link_old_dir_tooltip
+ = "Creates a filesystem link between the old directory and Eden directory.\n"
+ "This is recommended if you want to share data between emulators.";
+
+ // actual migration code
MigrationDialog migration_prompt;
- migration_prompt.setWindowTitle(main_window->tr("Migration"));
-
- QCheckBox *clear_shaders = new QCheckBox(&migration_prompt);
- clear_shaders->setText(main_window->tr("Clear Shader Cache"));
- clear_shaders->setToolTip(main_window->tr(
- "Clearing shader cache is recommended for all users.\nDo not uncheck unless you know what "
- "you're doing."));
- clear_shaders->setChecked(true);
-
- QRadioButton *keep_old = new QRadioButton(&migration_prompt);
- keep_old->setText(main_window->tr("Keep Old Data"));
- keep_old->setToolTip(
- main_window->tr("Keeps the old data directory. This is recommended if you aren't\n"
- "space-constrained and want to keep separate data for the old emulator."));
- keep_old->setChecked(true);
-
- QRadioButton *clear_old = new QRadioButton(&migration_prompt);
- clear_old->setText(main_window->tr("Clear Old Data"));
- clear_old->setToolTip(main_window->tr("Deletes the old data directory.\nThis is recommended on "
- "devices with space constraints."));
- clear_old->setChecked(false);
-
- QRadioButton *link = new QRadioButton(&migration_prompt);
- link->setText(main_window->tr("Link Old Directory"));
- link->setToolTip(
- main_window->tr("Creates a filesystem link between the old directory and Eden directory.\n"
- "This is recommended if you want to share data between emulators.."));
- link->setChecked(false);
-
- // Link and Clear Old are mutually exclusive
+ migration_prompt.setWindowTitle(QObject::tr("Migration"));
+
+ // mutually exclusive
QButtonGroup *group = new QButtonGroup(&migration_prompt);
- group->addButton(keep_old);
- group->addButton(clear_old);
- group->addButton(link);
-
- migration_prompt.addBox(clear_shaders);
- migration_prompt.addBox(keep_old);
- migration_prompt.addBox(clear_old);
- migration_prompt.addBox(link);
-
- // Reflection would make this code 10x better
- // but for now... MACRO MADNESS!!!!
- QMap<QString, bool> found;
- QMap<QString, MigrationWorker::LegacyEmu> legacyMap;
- QMap<QString, QAbstractButton *> buttonMap;
-
-#define EMU_MAP(name) \
- const bool name##_found = fs::is_directory( \
- Common::FS::GetLegacyPath(Common::FS::LegacyPath::name##Dir)); \
- legacyMap[main_window->tr(#name)] = MigrationWorker::LegacyEmu::name; \
- found[main_window->tr(#name)] = name##_found; \
- if (name##_found) \
- any_found = true;
-
- EMU_MAP(Citron)
- EMU_MAP(Sudachi)
- EMU_MAP(Yuzu)
- EMU_MAP(Suyu)
-
-#undef EMU_MAP
-
- if (any_found) {
- QString promptText = main_window->tr(
- "Eden has detected user data for the following emulators:");
- QMapIterator iter(found);
-
- while (iter.hasNext()) {
- iter.next();
- if (!iter.value())
- continue;
-
- QAbstractButton *button = migration_prompt.addButton(iter.key());
-
- buttonMap[iter.key()] = button;
- promptText.append(main_window->tr("\n- %1").arg(iter.key()));
- }
-
- promptText.append(main_window->tr("\n\n"));
-
- migration_prompt.setText(promptText + migration_prompt_message);
- migration_prompt.addButton(main_window->tr("No"), true);
-
- migration_prompt.exec();
-
- MigrationWorker::MigrationStrategy strategy;
- if (link->isChecked()) {
- strategy = MigrationWorker::MigrationStrategy::Link;
- } else if (clear_old->isChecked()) {
- strategy = MigrationWorker::MigrationStrategy::Move;
- } else {
- strategy = MigrationWorker::MigrationStrategy::Copy;
- }
-
- QMapIterator buttonIter(buttonMap);
-
- while (buttonIter.hasNext()) {
- buttonIter.next();
- if (buttonIter.value() == migration_prompt.clickedButton()) {
- MigrateUserData(main_window,
- legacyMap[buttonIter.key()],
- clear_shaders->isChecked(),
- strategy);
- return;
- }
- }
-
- // If we're here, the user chose not to migrate
- ShowMigrationCancelledMessage(main_window);
- }
- else // no other data was found
+ // MACRO MADNESS
+
+#define BUTTON(clazz, name, text, tooltip, checkState) \
+ clazz *name = new clazz(&migration_prompt); \
+ name->setText(QObject::tr(text)); \
+ name->setToolTip(QObject::tr(tooltip)); \
+ name->setChecked(checkState); \
+ migration_prompt.addBox(name);
+
+ BUTTON(QCheckBox, clear_shaders, "Clear Shader Cache", clear_shader_tooltip, true)
+
+#define RADIO(name, text, tooltip, checkState) \
+ BUTTON(QRadioButton, name, text, tooltip, checkState) \
+ group->addButton(name);
+
+ RADIO(keep_old, "Keep Old Data", keep_old_data_tooltip, true)
+ RADIO(clear_old, "Clear Old Data", clear_old_data_tooltip, false)
+ RADIO(link_old, "Link Old Directory", link_old_dir_tooltip, false)
+
+#undef RADIO
+#undef BUTTON
+
+ std::vector<Emulator> found{};
+
+ for (const Emulator &emu : legacy_emus)
+ if (fs::is_directory(emu.get_user_dir()))
+ found.emplace_back(emu);
+
+ if (found.empty()) {
return;
+ }
+
+ // makes my life easier
+ qRegisterMetaType<Emulator>();
+
+ QString prompt_text = QObject::tr(prompt_prefix_text);
+
+ // natural language processing is a nightmare
+ for (const Emulator &emu : found) {
+ prompt_text.append(QStringLiteral("\n- %1").arg(QObject::tr(emu.name)));
+
+ QAbstractButton *button = migration_prompt.addButton(QObject::tr(emu.name));
+
+ // This is cursed, but it's actually the most efficient way by a mile
+ button->setProperty("emulator", QVariant::fromValue(emu));
+ }
+
+ prompt_text.append(QObject::tr("\n\n"));
+ prompt_text.append(QObject::tr(migration_prompt_message));
+
+ migration_prompt.setText(prompt_text);
+ migration_prompt.addButton(QObject::tr("No"), true);
+
+ migration_prompt.exec();
+
+ QAbstractButton *button = migration_prompt.clickedButton();
+
+ if (button->text() == QObject::tr("No")) {
+ return ShowMigrationCancelledMessage(main_window);
+ }
+
+ MigrationWorker::MigrationStrategy strategy;
+ switch (group->checkedId()) {
+ default:
+ [[fallthrough]];
+ case 0:
+ strategy = MigrationWorker::MigrationStrategy::Copy;
+ break;
+ case 1:
+ strategy = MigrationWorker::MigrationStrategy::Move;
+ break;
+ case 2:
+ strategy = MigrationWorker::MigrationStrategy::Link;
+ break;
+ }
+
+ MigrateUserData(main_window,
+ button->property("emulator").value<Emulator>(),
+ clear_shaders->isChecked(),
+ strategy);
}
void UserDataMigrator::ShowMigrationCancelledMessage(QMainWindow *main_window)
{
QMessageBox::information(main_window,
- main_window->tr("Migration"),
- main_window
- ->tr("You can manually re-trigger this prompt by deleting the "
- "new config directory:\n"
- "%1")
+ QObject::tr("Migration"),
+ QObject::tr("You can manually re-trigger this prompt by deleting the "
+ "new config directory:\n%1")
.arg(QString::fromStdString(Common::FS::GetEdenPathString(
Common::FS::EdenPath::ConfigDir))),
QMessageBox::Ok);
}
void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
- const MigrationWorker::LegacyEmu selected_legacy_emu,
+ const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationWorker::MigrationStrategy strategy)
{
- // Create a dialog to let the user know it's migrating, some users noted confusion.
+ selected_emu = selected_legacy_emu;
+
+ // Create a dialog to let the user know it's migrating
QProgressDialog *progress = new QProgressDialog(main_window);
- progress->setWindowTitle(main_window->tr("Migrating"));
- progress->setLabelText(main_window->tr("Migrating, this may take a while..."));
+ progress->setWindowTitle(QObject::tr("Migrating"));
+ progress->setLabelText(QObject::tr("Migrating, this may take a while..."));
progress->setRange(0, 0);
progress->setCancelButton(nullptr);
progress->setWindowModality(Qt::WindowModality::ApplicationModal);
@@ -194,13 +188,14 @@ void UserDataMigrator::MigrateUserData(QMainWindow *main_window,
thread->connect(thread, &QThread::started, worker, &MigrationWorker::process);
- thread->connect(worker, &MigrationWorker::finished, progress, [=](const QString &success_text) {
+ thread->connect(worker, &MigrationWorker::finished, progress, [=, this](const QString &success_text, const std::string &path) {
progress->close();
QMessageBox::information(main_window,
- main_window->tr("Migration"),
+ QObject::tr("Migration"),
success_text,
QMessageBox::Ok);
+ migrated = true;
thread->quit();
});
diff --git a/src/yuzu/user_data_migration.h b/src/yuzu/user_data_migration.h
index 3482b6c398..3684d14916 100644
--- a/src/yuzu/user_data_migration.h
+++ b/src/yuzu/user_data_migration.h
@@ -14,11 +14,14 @@ class UserDataMigrator {
public:
UserDataMigrator(QMainWindow* main_window);
+ bool migrated{false};
+ Emulator selected_emu;
+
private:
void ShowMigrationPrompt(QMainWindow* main_window);
void ShowMigrationCancelledMessage(QMainWindow* main_window);
void MigrateUserData(QMainWindow* main_window,
- const MigrationWorker::LegacyEmu selected_legacy_emu,
+ const Emulator selected_legacy_emu,
const bool clear_shader_cache,
const MigrationWorker::MigrationStrategy strategy);
};