aboutsummaryrefslogtreecommitdiff
path: root/src/yuzu/user_data_migration.cpp
diff options
context:
space:
mode:
authorswurl <swurl@swurl.xyz>2025-05-08 22:16:07 +0000
committercrueter <crueter@noreply.localhost>2025-05-08 22:16:07 +0000
commitf786802b9b699548d0160cf52dff58018566fd70 (patch)
tree0a88e2558bbfa25e4cc2eb9153ae53fe0038efe8 /src/yuzu/user_data_migration.cpp
parentd659d6f5b4a03f27d0cde7e1fd2f9da60095b5d0 (diff)
User Data Migration from Citron, Sudachi, and Yuzu (#91)
Includes citron, sudachi, yuzu currently broken, because the eden dir is always made early? Signed-off-by: swurl <swurl@swurl.xyz> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/91 Co-authored-by: swurl <swurl@swurl.xyz> Co-committed-by: swurl <swurl@swurl.xyz>
Diffstat (limited to 'src/yuzu/user_data_migration.cpp')
-rw-r--r--src/yuzu/user_data_migration.cpp168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/yuzu/user_data_migration.cpp b/src/yuzu/user_data_migration.cpp
new file mode 100644
index 0000000000..d890550222
--- /dev/null
+++ b/src/yuzu/user_data_migration.cpp
@@ -0,0 +1,168 @@
+// Copyright Citra Emulator Project / Azahar Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <QMessageBox>
+#include <QPushButton>
+#include <QString>
+#include <QTranslator>
+#include "common/fs/path_util.h"
+#include "user_data_migration.h"
+
+// Needs to be included at the end due to https://bugreports.qt.io/browse/QTBUG-73263
+#include <QCheckBox>
+#include <filesystem>
+
+namespace fs = std::filesystem;
+
+UserDataMigrator::UserDataMigrator(QMainWindow* main_window) {
+ // NOTE: Logging is not initialized yet, do not produce logs here.
+
+ // Check migration if config directory does not exist
+ // TODO: ProfileManager messes with us a bit here, and force-creates the /nand/system/save/8000000000000010/su/avators/profiles.dat
+ // file. Find a way to reorder operations and have it create after this guy runs.
+ if (!fs::is_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir))) {
+ ShowMigrationPrompt(main_window);
+ }
+}
+
+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; The old data will not be deleted)\n\n"
+ "Clearing shader cache is recommended for all users.\nDo not uncheck unless you know what you're doing.");
+
+ bool any_found = false;
+
+ QMessageBox migration_prompt;
+ migration_prompt.setWindowTitle(main_window->tr("Migration"));
+ migration_prompt.setIcon(QMessageBox::Information);
+
+ QCheckBox *clear_shaders = new QCheckBox(&migration_prompt);
+ clear_shaders->setText(main_window->tr("Clear Shader Cache"));
+ clear_shaders->setChecked(true);
+ migration_prompt.setCheckBox(clear_shaders);
+
+ // Reflection would make this code 10x better
+ // but for now... MACRO MADNESS!!!!
+ QMap<QString, bool> found;
+ QMap<QString, 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)] = 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;
+
+ buttonMap[iter.key()] = migration_prompt.addButton(iter.key(), QMessageBox::YesRole);
+ 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(QMessageBox::No);
+
+ migration_prompt.exec();
+
+ QMapIterator buttonIter(buttonMap);
+
+ while (buttonIter.hasNext()) {
+ buttonIter.next();
+ if (buttonIter.value() == migration_prompt.clickedButton()) {
+ MigrateUserData(main_window, legacyMap[iter.key()], clear_shaders->isChecked());
+ return;
+ }
+ }
+
+ // If we're here, the user chose not to migrate
+ ShowMigrationCancelledMessage(main_window);
+ }
+
+ else // no other data was found
+ return;
+}
+
+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")
+ .arg(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ConfigDir))),
+ QMessageBox::Ok);
+}
+
+void UserDataMigrator::MigrateUserData(QMainWindow* main_window,
+ const LegacyEmu selected_legacy_emu, const bool clear_shader_cache) {
+ 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
+
+ fs::copy(legacy_user_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir), copy_options);
+
+ if (fs::is_directory(legacy_config_dir)) {
+ fs::copy(legacy_config_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir),
+ copy_options);
+ }
+ if (fs::is_directory(legacy_cache_dir)) {
+ fs::copy(legacy_cache_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir),
+ copy_options);
+ }
+
+ // Delete and re-create shader dir
+ if (clear_shader_cache) {
+ fs::remove_all(Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir));
+ fs::create_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir));
+ }
+
+ QMessageBox::information(
+ main_window, main_window->tr("Migration"),
+ main_window
+ ->tr("Data was migrated successfully.\n\n"
+ "If you wish to clean up the files which were left in the old "
+ "data location, you can do so by deleting the following directory:\n"
+ "%1")
+ .arg(QString::fromStdString(legacy_user_dir)),
+ QMessageBox::Ok);
+}