Skip to content

Commit

Permalink
Implement emulator data migration functionality + prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
OpenSauce04 authored and Gamer64ytb committed Jul 27, 2024
1 parent 4ec4892 commit 3c9b7c1
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 7 deletions.
11 changes: 8 additions & 3 deletions src/common/common_paths.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,22 @@
#else
#ifdef _WIN32
#define EMU_DATA_DIR "Mandarine"
#define LEGACY_EMU_DATA_DIR "Citra"
#elif defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
#if TARGET_OS_IPHONE // TODO: Kill iOS
#define APPLE_EMU_DATA_DIR "Documents" DIR_SEP "Mandarine"
#define LEGACY_APPLE_EMU_DATA_DIR "Documents" DIR_SEP "Citra"
#else
#define APPLE_EMU_DATA_DIR "Library" DIR_SEP "Application Support" DIR_SEP "Mandarine"
#define LEGACY_APPLE_EMU_DATA_DIR "Library" DIR_SEP "Application Support" DIR_SEP "Citra"
#endif
// For compatibility with XDG paths.
#define EMU_DATA_DIR "mandarine"
#define EMU_DATA_DIR "mandarine-emu"
#define LEGACY_EMU_DATA_DIR "citra-emu"
#else
#define EMU_DATA_DIR "mandarine"
#define EMU_DATA_DIR "mandarine-emu"
#define LEGACY_EMU_DATA_DIR "citra-emu"
#endif
#endif

Expand Down
12 changes: 12 additions & 0 deletions src/common/file_util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,11 @@ void SetUserPath(const std::string& path) {
} else {
#ifdef _WIN32
user_path = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
std::string& legacy_user_path = g_paths[UserPath::LegacyUserDir];

if (!FileUtil::IsDirectory(user_path)) {
user_path = AppDataRoamingDirectory() + DIR_SEP EMU_DATA_DIR DIR_SEP;
legacy_user_path = AppDataRoamingDirectory() + DIR_SEP LEGACY_EMU_DATA_DIR DIR_SEP;
} else {
LOG_INFO(Common_Filesystem, "Using the local user directory");
}
Expand All @@ -784,6 +787,7 @@ void SetUserPath(const std::string& path) {
g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
#else
std::string& legacy_user_path = g_paths[UserPath::LegacyUserDir];
auto current_dir = FileUtil::GetCurrentDir();
if (current_dir.has_value() &&
FileUtil::Exists(current_dir.value() + USERDATA_DIR DIR_SEP)) {
Expand All @@ -792,23 +796,31 @@ void SetUserPath(const std::string& path) {
g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
} else {
std::string data_dir = GetUserDirectory("XDG_DATA_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP;
std::string legacy_data_dir =
GetUserDirectory("XDG_DATA_HOME") + DIR_SEP LEGACY_EMU_DATA_DIR DIR_SEP;
std::string config_dir =
GetUserDirectory("XDG_CONFIG_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP;
std::string cache_dir =
GetUserDirectory("XDG_CACHE_HOME") + DIR_SEP EMU_DATA_DIR DIR_SEP;
g_paths.emplace(UserPath::LegacyConfigDir, GetUserDirectory("XDG_CONFIG_HOME") +
DIR_SEP LEGACY_EMU_DATA_DIR DIR_SEP);
g_paths.emplace(UserPath::LegacyCacheDir, GetUserDirectory("XDG_CACHE_HOME") +
DIR_SEP LEGACY_EMU_DATA_DIR DIR_SEP);

#if defined(__APPLE__)
// If XDG directories don't already exist from a previous setup, use standard macOS
// paths.
if (!FileUtil::Exists(data_dir) && !FileUtil::Exists(config_dir) &&
!FileUtil::Exists(cache_dir)) {
data_dir = GetHomeDirectory() + DIR_SEP APPLE_EMU_DATA_DIR DIR_SEP;
legacy_data_dir = GetHomeDirectory() + DIR_SEP LEGACY_APPLE_EMU_DATA_DIR DIR_SEP;
config_dir = data_dir + CONFIG_DIR DIR_SEP;
cache_dir = data_dir + CACHE_DIR DIR_SEP;
}
#endif

user_path = data_dir;
legacy_user_path = legacy_data_dir;
g_paths.emplace(UserPath::ConfigDir, config_dir);
g_paths.emplace(UserPath::CacheDir, cache_dir);
}
Expand Down
7 changes: 5 additions & 2 deletions src/common/file_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ enum class UserPath {
ConfigDir,
DLLDir,
DumpDir,
IconsDir,
LegacyCacheDir, // LegacyCacheDir and LegacyConfigDir are only defined if migrating these
LegacyConfigDir, // directories is necessary (aka not a child of LegacyUserDir)
LegacyUserDir,
LoadDir,
LogDir,
NANDDir,
PlayTimeDir,
RootDir,
SDMCDir,
ShaderDir,
StatesDir,
SysDataDir,
UserDir,
IconsDir,
PlayTimeDir,
};

// Replaces install-specific paths with standard placeholders, and back again
Expand Down
57 changes: 55 additions & 2 deletions src/mandarine_qt/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,8 @@ static QString PrettyProductName() {
enum APP_MODE { Default, AllowDark, ForceDark, ForceLight, Max };

GMainWindow::GMainWindow(Core::System& system_)
: ui{std::make_unique<Ui::MainWindow>()}, system{system_}, movie{system.Movie()},
config{std::make_unique<Config>()}, emu_thread{nullptr} {
: ui{std::make_unique<Ui::MainWindow>()}, system{system_}, movie{system.Movie()}, emu_thread{
nullptr} {
Common::Log::Initialize();
Common::Log::Start();
#ifdef _WIN32
Expand All @@ -176,6 +176,10 @@ GMainWindow::GMainWindow(Core::System& system_)

Debugger::ToggleConsole();

CheckForMigration();

this->config = std::make_unique<Config>();

#ifdef __unix__
SetGamemodeEnabled(Settings::values.enable_gamemode.GetValue());
#endif
Expand Down Expand Up @@ -1105,6 +1109,55 @@ void GMainWindow::ShowUpdaterWidgets() {
}
#endif

void GMainWindow::CheckForMigration() {
namespace fs = std::filesystem;
if (fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyUserDir)) &&
!fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::UserDir))) {
if (QMessageBox::information(
this, tr("Migration"),
tr("Mandarine has moved to a new data directory.\n\n"
"Would you like to migrate your Citra data to this new "
"location?\n"
"(This may take a while; The old data will not be deleted)"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes) {
MigrateUserData();
} else {
QMessageBox::information(this, tr("Migration"),
tr("You can manually re-trigger this prompt by deleting the "
"new user data directory:\n"
"%1")
.arg(QString::fromStdString(
FileUtil::GetUserPath(FileUtil::UserPath::UserDir))),
QMessageBox::Ok);
}
}
}

void GMainWindow::MigrateUserData() {
namespace fs = std::filesystem;
const auto copyOptions = fs::copy_options::update_existing | fs::copy_options::recursive;

fs::copy(FileUtil::GetUserPath(FileUtil::UserPath::LegacyUserDir),
FileUtil::GetUserPath(FileUtil::UserPath::UserDir), copyOptions);
if (fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyConfigDir))) {
fs::copy(FileUtil::GetUserPath(FileUtil::UserPath::LegacyConfigDir),
FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir), copyOptions);
}
if (fs::is_directory(FileUtil::GetUserPath(FileUtil::UserPath::LegacyCacheDir))) {
fs::copy(FileUtil::GetUserPath(FileUtil::UserPath::LegacyCacheDir),
FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), copyOptions);
}

QMessageBox::information(
this, tr("Migration"),
tr("Data was migrated successfully. Mandarine will now start.\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(FileUtil::GetUserPath(FileUtil::UserPath::LegacyUserDir))),
QMessageBox::Ok);
}

#if defined(HAVE_SDL2) && defined(__unix__) && !defined(__APPLE__)
static std::optional<QDBusObjectPath> HoldWakeLockLinux(u32 window_id = 0) {
if (!QDBusConnection::sessionBus().isConnected()) {
Expand Down
3 changes: 3 additions & 0 deletions src/mandarine_qt/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ public slots:
void CheckForUpdates();
#endif

void CheckForMigration();
void MigrateUserData();

/**
* Stores the filename in the recently loaded files list.
* The new filename is stored at the beginning of the recently loaded files list.
Expand Down

0 comments on commit 3c9b7c1

Please sign in to comment.