diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index 2205f4c1fc..fbf7f0a349 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -2086,7 +2086,8 @@ void QtHost::PrintCommandLineHelp(const std::string_view progname) std::fprintf(stderr, " -version: Displays version information and exits.\n"); std::fprintf(stderr, " -batch: Enables batch mode (exits after shutting down).\n"); std::fprintf(stderr, " -nogui: Hides main window while running (implies batch mode).\n"); - std::fprintf(stderr, " -portable: Force enable portable mode to store data in local PCSX2 path instead of the default configuration path.\n"); + std::fprintf(stderr, " -portable: Force enable portable mode to store data in local PCSX2 path instead of the default configuration path. Overrides '-datapath'.\n"); + std::fprintf(stderr, " -datapath : Specify the directory to be used for all application data.\n"); std::fprintf(stderr, " -elf : Overrides the boot ELF with the specified filename.\n"); std::fprintf(stderr, " -gameargs : passes the specified quoted space-delimited string of launch arguments.\n"); std::fprintf(stderr, " -disc : Uses the specified host DVD drive as a source.\n"); @@ -2165,6 +2166,12 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptrtoStdString(); + EmuConfig.CustomDataPath = path; + continue; + } else if (CHECK_ARG(QStringLiteral("-fastboot"))) { AutoBoot(autoboot)->fast_boot = true; @@ -2297,7 +2304,7 @@ bool QtHost::ParseCommandLineOptions(const QStringList& args, std::shared_ptrstart_turbo.value_or(false) && autoboot->start_unlimited.value_or(false)) { Console.Warning("Both turbo and unlimited frame limit modes requested. Using unlimited."); diff --git a/pcsx2/Config.h b/pcsx2/Config.h index b012a719b3..f338cead3c 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -1403,6 +1403,7 @@ struct Pcsx2Config std::string CurrentBlockdump; std::string CurrentIRX; std::string CurrentGameArgs; + std::string CustomDataPath; AspectRatioType CurrentAspectRatio = AspectRatioType::RAuto4_3_3_2; // Fall back aspect ratio for games that have patches (when AspectRatioType::RAuto4_3_3_2) is active. float CurrentCustomAspectRatio = 0.f; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 624ad699d7..18a00d98c4 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -2195,51 +2195,58 @@ std::string EmuFolders::GetPortableModePath() bool EmuFolders::SetDataDirectory(Error* error) { + // Portable mode has the absolute priority. if (!ShouldUsePortableMode()) { + // Also check if the user has overriden the DataRoot path. + if (EmuConfig.CustomDataPath.empty()) + { #if defined(_WIN32) - // On Windows, use My Documents\PCSX2 to match old installs. - PWSTR documents_directory; - if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory))) - { - if (std::wcslen(documents_directory) > 0) - DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2"); - CoTaskMemFree(documents_directory); - } + // On Windows, use My Documents\PCSX2 to match old installs. + PWSTR documents_directory; + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &documents_directory))) + { + if (std::wcslen(documents_directory) > 0) + DataRoot = Path::Combine(StringUtil::WideStringToUTF8String(documents_directory), "PCSX2"); + CoTaskMemFree(documents_directory); + } #elif defined(__linux__) || defined(__FreeBSD__) - // Use $XDG_CONFIG_HOME/PCSX2 if it exists. - const char* xdg_config_home = getenv("XDG_CONFIG_HOME"); - if (xdg_config_home && Path::IsAbsolute(xdg_config_home)) - { - DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "PCSX2")); - } - else - { - // Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG. + // Use $XDG_CONFIG_HOME/PCSX2 if it exists. + const char* xdg_config_home = getenv("XDG_CONFIG_HOME"); + if (xdg_config_home && Path::IsAbsolute(xdg_config_home)) + { + DataRoot = Path::RealPath(Path::Combine(xdg_config_home, "PCSX2")); + } + else + { + // Use ~/PCSX2 for non-XDG, and ~/.config/PCSX2 for XDG. + const char* home_dir = getenv("HOME"); + if (home_dir) + { + // ~/.config should exist, but just in case it doesn't and this is a fresh profile.. + const std::string config_dir(Path::Combine(home_dir, ".config")); + if (!FileSystem::DirectoryExists(config_dir.c_str())) + FileSystem::CreateDirectoryPath(config_dir.c_str(), false); + + DataRoot = Path::RealPath(Path::Combine(config_dir, "PCSX2")); + } + } +#elif defined(__APPLE__) + static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2"; const char* home_dir = getenv("HOME"); if (home_dir) - { - // ~/.config should exist, but just in case it doesn't and this is a fresh profile.. - const std::string config_dir(Path::Combine(home_dir, ".config")); - if (!FileSystem::DirectoryExists(config_dir.c_str())) - FileSystem::CreateDirectoryPath(config_dir.c_str(), false); - - DataRoot = Path::RealPath(Path::Combine(config_dir, "PCSX2")); - } - } -#elif defined(__APPLE__) - static constexpr char MAC_DATA_DIR[] = "Library/Application Support/PCSX2"; - const char* home_dir = getenv("HOME"); - if (home_dir) - DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR)); + DataRoot = Path::RealPath(Path::Combine(home_dir, MAC_DATA_DIR)); #endif - } + } + else // Otherwise use the custom path provided by the user + DataRoot = Path::RealPath(Path::Combine(EmuConfig.CustomDataPath, "PCSX2")); + } - // couldn't determine the data directory, or using portable mode? fallback to portable. + // Couldn't determine the data directory, or using portable mode? fallback to portable. if (DataRoot.empty()) { #if defined(__linux__) - // special check if we're on appimage + // Special check if we're on appimage // always make sure that DataRoot // is adjacent next to the appimage if (getenv("APPIMAGE")) @@ -2254,10 +2261,10 @@ bool EmuFolders::SetDataDirectory(Error* error) #endif } - // inis is always below the data root + // Inis is always below the data root Settings = Path::Combine(DataRoot, "inis"); - // make sure it exists + // Make sure it exists Console.WriteLnFmt("DataRoot Directory: {}", DataRoot); return (FileSystem::EnsureDirectoryExists(DataRoot.c_str(), false, error) && FileSystem::EnsureDirectoryExists(Settings.c_str(), false, error));