Allow launching with custom data directories (#1505)

* Allow launching with custom data directories

Don't load alternate keys when using custom directory

* Address gdkchan's comments

* Misc fixes to log levels

Added more enabled log levels by default

Moved successful config updation to Notice as
1. It's not a warning
2. Warnings could've been disabled by the config load and hence message
   would be lost
This commit is contained in:
mageven 2020-08-30 22:21:53 +05:30 committed by GitHub
parent f3e12d5b02
commit b9398f1f3a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 159 additions and 70 deletions

View file

@ -1,6 +1,7 @@
using ARMeilleure.CodeGen; using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Memory; using ARMeilleure.Memory;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
@ -22,8 +23,6 @@ namespace ARMeilleure.Translation.PTC
private const int InternalVersion = 1471; //! To be incremented manually for each change to the ARMeilleure project. private const int InternalVersion = 1471; //! To be incremented manually for each change to the ARMeilleure project.
private const string BaseDir = "Ryujinx";
private const string ActualDir = "0"; private const string ActualDir = "0";
private const string BackupDir = "1"; private const string BackupDir = "1";
@ -49,8 +48,6 @@ namespace ARMeilleure.Translation.PTC
private static readonly AutoResetEvent _loggerEvent; private static readonly AutoResetEvent _loggerEvent;
private static readonly string _basePath;
private static readonly object _lock; private static readonly object _lock;
private static bool _disposed; private static bool _disposed;
@ -83,8 +80,6 @@ namespace ARMeilleure.Translation.PTC
_loggerEvent = new AutoResetEvent(false); _loggerEvent = new AutoResetEvent(false);
_basePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), BaseDir);
_lock = new object(); _lock = new object();
_disposed = false; _disposed = false;
@ -130,8 +125,8 @@ namespace ARMeilleure.Translation.PTC
if (enabled) if (enabled)
{ {
string workPathActual = Path.Combine(_basePath, "games", TitleIdText, "cache", "cpu", ActualDir); string workPathActual = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", ActualDir);
string workPathBackup = Path.Combine(_basePath, "games", TitleIdText, "cache", "cpu", BackupDir); string workPathBackup = Path.Combine(AppDataManager.GamesDirPath, TitleIdText, "cache", "cpu", BackupDir);
if (!Directory.Exists(workPathActual)) if (!Directory.Exists(workPathActual))
{ {

View file

@ -0,0 +1,69 @@
using Ryujinx.Common.Logging;
using System;
using System.IO;
namespace Ryujinx.Common.Configuration
{
public static class AppDataManager
{
private static readonly string _defaultBaseDirPath;
private const string DefaultBaseDir = "Ryujinx";
// The following 3 are always part of Base Directory
private const string GamesDir = "games";
private const string ProfilesDir = "profiles";
private const string KeysDir = "system";
public static bool IsCustomBasePath { get; private set; }
public static string BaseDirPath { get; private set; }
public static string GamesDirPath { get; private set; }
public static string ProfilesDirPath { get; private set; }
public static string KeysDirPath { get; private set; }
public static string KeysDirPathAlt { get; }
public const string DefaultNandDir = "bis";
public const string DefaultSdcardDir = "sdcard";
private const string DefaultModsDir = "mods";
public static string CustomModsPath { get; set; }
public static string CustomNandPath { get; set; } // TODO: Actually implement this into VFS
public static string CustomSdCardPath { get; set; } // TODO: Actually implement this into VFS
static AppDataManager()
{
_defaultBaseDirPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir);
KeysDirPathAlt = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch");
}
public static void Initialize(string baseDirPath)
{
BaseDirPath = _defaultBaseDirPath;
if (baseDirPath != null && baseDirPath != _defaultBaseDirPath)
{
if (!Directory.Exists(baseDirPath))
{
Logger.Error?.Print(LogClass.Application, $"Custom Data Directory '{baseDirPath}' does not exist. Using defaults...");
}
else
{
BaseDirPath = baseDirPath;
IsCustomBasePath = true;
}
}
SetupBasePaths();
}
private static void SetupBasePaths()
{
Directory.CreateDirectory(BaseDirPath);
Directory.CreateDirectory(GamesDirPath = Path.Combine(BaseDirPath, GamesDir));
Directory.CreateDirectory(ProfilesDirPath = Path.Combine(BaseDirPath, ProfilesDir));
Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir));
}
public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultModsDir)).FullName;
}
}

View file

@ -750,7 +750,7 @@ namespace Ryujinx.Configuration
{ {
ToFileFormat().SaveConfig(configurationFilePath); ToFileFormat().SaveConfig(configurationFilePath);
Common.Logging.Logger.Warning?.Print(LogClass.Application, "Configuration file has been updated!"); Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
} }
} }

View file

@ -112,6 +112,11 @@ namespace Ryujinx.Common.Logging
AsyncLogTargetOverflowAction.Discard)); AsyncLogTargetOverflowAction.Discard));
Notice = new Log(LogLevel.Notice); Notice = new Log(LogLevel.Notice);
// Enable important log levels before configuration is loaded
Error = new Log(LogLevel.Error);
Warning = new Log(LogLevel.Warning);
Info = new Log(LogLevel.Info);
} }
public static void RestartTime() public static void RestartTime()

View file

@ -4,6 +4,7 @@ using LibHac.Fs;
using LibHac.FsService; using LibHac.FsService;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Spl; using LibHac.Spl;
using Ryujinx.Common.Configuration;
using Ryujinx.HLE.FileSystem.Content; using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using System; using System;
@ -13,11 +14,8 @@ namespace Ryujinx.HLE.FileSystem
{ {
public class VirtualFileSystem : IDisposable public class VirtualFileSystem : IDisposable
{ {
public const string BasePath = "Ryujinx"; public const string NandPath = AppDataManager.DefaultNandDir;
public const string NandPath = "bis"; public const string SdCardPath = AppDataManager.DefaultSdcardDir;
public const string SdCardPath = "sdcard";
public const string SystemPath = "system";
public const string ModsPath = "mods";
public static string SafeNandPath = Path.Combine(NandPath, "safe"); public static string SafeNandPath = Path.Combine(NandPath, "safe");
public static string SystemNandPath = Path.Combine(NandPath, "system"); public static string SystemNandPath = Path.Combine(NandPath, "system");
@ -77,20 +75,10 @@ namespace Ryujinx.HLE.FileSystem
return fullPath; return fullPath;
} }
public string GetBaseModsPath() internal string GetBasePath() => AppDataManager.BaseDirPath;
{ internal string GetSdCardPath() => MakeFullPath(SdCardPath);
var baseModsDir = Path.Combine(GetBasePath(), "mods");
ModLoader.EnsureBaseDirStructure(baseModsDir);
return baseModsDir;
}
public string GetSdCardPath() => MakeFullPath(SdCardPath);
public string GetNandPath() => MakeFullPath(NandPath); public string GetNandPath() => MakeFullPath(NandPath);
public string GetSystemPath() => MakeFullPath(SystemPath);
internal string GetSavePath(ServiceCtx context, SaveInfo saveInfo, bool isDirectory = true) internal string GetSavePath(ServiceCtx context, SaveInfo saveInfo, bool isDirectory = true)
{ {
string saveUserPath = ""; string saveUserPath = "";
@ -207,13 +195,6 @@ namespace Ryujinx.HLE.FileSystem
return new DriveInfo(Path.GetPathRoot(GetBasePath())); return new DriveInfo(Path.GetPathRoot(GetBasePath()));
} }
public string GetBasePath()
{
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
return Path.Combine(appDataPath, BasePath);
}
public void Reload() public void Reload()
{ {
ReloadKeySet(); ReloadKeySet();
@ -245,10 +226,12 @@ namespace Ryujinx.HLE.FileSystem
string titleKeyFile = null; string titleKeyFile = null;
string consoleKeyFile = null; string consoleKeyFile = null;
string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); if (!AppDataManager.IsCustomBasePath)
{
LoadSetAtPath(AppDataManager.KeysDirPathAlt);
}
LoadSetAtPath(Path.Combine(home, ".switch")); LoadSetAtPath(AppDataManager.KeysDirPath);
LoadSetAtPath(GetSystemPath());
void LoadSetAtPath(string basePath) void LoadSetAtPath(string basePath)
{ {

View file

@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS
Npdm metaData = ReadNpdm(codeFs); Npdm metaData = ReadNpdm(codeFs);
_fileSystem.ModLoader.CollectMods(TitleId, _fileSystem.GetBaseModsPath()); _fileSystem.ModLoader.CollectMods(TitleId, _fileSystem.ModLoader.GetModsBasePath());
if (TitleId != 0) if (TitleId != 0)
{ {
@ -224,7 +224,7 @@ namespace Ryujinx.HLE.HOS
IFileSystem codeFs = null; IFileSystem codeFs = null;
// Load Update // Load Update
string titleUpdateMetadataPath = Path.Combine(_fileSystem.GetBasePath(), "games", mainNca.Header.TitleId.ToString("x16"), "updates.json"); string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "updates.json");
if (File.Exists(titleUpdateMetadataPath)) if (File.Exists(titleUpdateMetadataPath))
{ {
@ -261,7 +261,7 @@ namespace Ryujinx.HLE.HOS
} }
// Load Aoc // Load Aoc
string titleAocMetadataPath = Path.Combine(_fileSystem.GetBasePath(), "games", mainNca.Header.TitleId.ToString("x16"), "dlc.json"); string titleAocMetadataPath = Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "dlc.json");
if (File.Exists(titleAocMetadataPath)) if (File.Exists(titleAocMetadataPath))
{ {
@ -310,7 +310,7 @@ namespace Ryujinx.HLE.HOS
Npdm metaData = ReadNpdm(codeFs); Npdm metaData = ReadNpdm(codeFs);
_fileSystem.ModLoader.CollectMods(TitleId, _fileSystem.GetBaseModsPath()); _fileSystem.ModLoader.CollectMods(TitleId, _fileSystem.ModLoader.GetModsBasePath());
if (controlNca != null) if (controlNca != null)
{ {

View file

@ -2,6 +2,7 @@ using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.FsSystem.RomFs; using LibHac.FsSystem.RomFs;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.Loaders.Mods; using Ryujinx.HLE.Loaders.Mods;
using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Executables;
@ -105,15 +106,18 @@ namespace Ryujinx.HLE.HOS
private static bool StrEquals(string s1, string s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase); private static bool StrEquals(string s1, string s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase);
public void EnsureBaseDirStructure(string modsBasePath) public string GetModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetModsPath());
private string EnsureBaseDirStructure(string modsBasePath)
{ {
var modsDir = new DirectoryInfo(modsBasePath); var modsDir = new DirectoryInfo(modsBasePath);
modsDir.Create();
modsDir.CreateSubdirectory(AmsContentsDir); modsDir.CreateSubdirectory(AmsContentsDir);
modsDir.CreateSubdirectory(AmsNsoPatchDir); modsDir.CreateSubdirectory(AmsNsoPatchDir);
modsDir.CreateSubdirectory(AmsNroPatchDir); modsDir.CreateSubdirectory(AmsNroPatchDir);
// modsDir.CreateSubdirectory(AmsKipPatchDir); // uncomment when KIPs are supported // modsDir.CreateSubdirectory(AmsKipPatchDir); // uncomment when KIPs are supported
return modsDir.FullName;
} }
private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId) private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId)

View file

@ -1,5 +1,6 @@
using ARMeilleure.Translation.PTC; using ARMeilleure.Translation.PTC;
using Gtk; using Gtk;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInfo; using Ryujinx.Common.SystemInfo;
using Ryujinx.Configuration; using Ryujinx.Configuration;
@ -20,6 +21,29 @@ namespace Ryujinx
static void Main(string[] args) static void Main(string[] args)
{ {
// Parse Arguments
string launchPath = null;
string baseDirPath = null;
for (int i = 0; i < args.Length; ++i)
{
string arg = args[i];
if (arg == "-r" || arg == "--root-data-dir")
{
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
baseDirPath = args[++i];
}
else if (launchPath == null)
{
launchPath = arg;
}
}
Toolkit.Init(new ToolkitOptions Toolkit.Init(new ToolkitOptions
{ {
Backend = PlatformBackend.PreferNative, Backend = PlatformBackend.PreferNative,
@ -38,6 +62,9 @@ namespace Ryujinx
AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => ProgramExit(); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => ProgramExit();
// Setup base data directory
AppDataManager.Initialize(baseDirPath);
// Initialize the configuration // Initialize the configuration
ConfigurationState.Initialize(); ConfigurationState.Initialize();
@ -48,8 +75,7 @@ namespace Ryujinx
DiscordIntegrationModule.Initialize(); DiscordIntegrationModule.Initialize();
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
string globalBasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Ryujinx"); string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
string globalConfigurationPath = Path.Combine(globalBasePath, "Config.json");
// Now load the configuration as the other subsystems are now registered // Now load the configuration as the other subsystems are now registered
if (File.Exists(localConfigurationPath)) if (File.Exists(localConfigurationPath))
@ -60,24 +86,21 @@ namespace Ryujinx
ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
} }
else if (File.Exists(globalConfigurationPath)) else if (File.Exists(appDataConfigurationPath))
{ {
ConfigurationPath = globalConfigurationPath; ConfigurationPath = appDataConfigurationPath;
ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(globalConfigurationPath); ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(appDataConfigurationPath);
ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath);
} }
else else
{ {
// No configuration, we load the default values and save it on disk // No configuration, we load the default values and save it on disk
ConfigurationPath = globalConfigurationPath; ConfigurationPath = appDataConfigurationPath;
// Make sure to create the Ryujinx directory if needed.
Directory.CreateDirectory(globalBasePath);
ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.LoadDefault();
ConfigurationState.Instance.ToFileFormat().SaveConfig(globalConfigurationPath); ConfigurationState.Instance.ToFileFormat().SaveConfig(appDataConfigurationPath);
} }
PrintSystemInfo(); PrintSystemInfo();
@ -86,9 +109,9 @@ namespace Ryujinx
Application.Init(); Application.Init();
string globalProdKeysPath = Path.Combine(globalBasePath, "system", "prod.keys"); bool hasGlobalProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys"); bool hasAltProdKeys = !AppDataManager.IsCustomBasePath && File.Exists(Path.Combine(AppDataManager.KeysDirPathAlt, "prod.keys"));
if (!File.Exists(globalProdKeysPath) && !File.Exists(userProfilePath) && !Migration.IsMigrationNeeded()) if (!hasGlobalProdKeys && !hasAltProdKeys && !Migration.IsMigrationNeeded())
{ {
GtkDialog.CreateWarningDialog("Key file was not found", "Please refer to `KEYS.md` for more info"); GtkDialog.CreateWarningDialog("Key file was not found", "Please refer to `KEYS.md` for more info");
} }
@ -96,9 +119,9 @@ namespace Ryujinx
MainWindow mainWindow = new MainWindow(); MainWindow mainWindow = new MainWindow();
mainWindow.Show(); mainWindow.Show();
if (args.Length == 1) if (launchPath != null)
{ {
mainWindow.LoadApplication(args[0]); mainWindow.LoadApplication(launchPath);
} }
Application.Run(); Application.Run();
@ -114,6 +137,11 @@ namespace Ryujinx
var enabledLogs = Logger.GetEnabledLevels(); var enabledLogs = Logger.GetEnabledLevels();
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}"); Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}");
if (AppDataManager.IsCustomBasePath)
{
Logger.Notice.Print(LogClass.Application, $"Custom Data Directory: {AppDataManager.BaseDirPath}");
}
} }
private static void ProcessUnhandledException(Exception e, bool isTerminating) private static void ProcessUnhandledException(Exception e, bool isTerminating)

View file

@ -480,7 +480,7 @@ namespace Ryujinx.Ui
internal static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null) internal static ApplicationMetadata LoadAndSaveMetaData(string titleId, Action<ApplicationMetadata> modifyFunction = null)
{ {
string metadataFolder = Path.Combine(_virtualFileSystem.GetBasePath(), "games", titleId, "gui"); string metadataFolder = Path.Combine(AppDataManager.GamesDirPath, titleId, "gui");
string metadataFile = Path.Combine(metadataFolder, "metadata.json"); string metadataFile = Path.Combine(metadataFolder, "metadata.json");
ApplicationMetadata appMetadata; ApplicationMetadata appMetadata;
@ -618,7 +618,7 @@ namespace Ryujinx.Ui
private static bool IsUpdateApplied(string titleId, out string version) private static bool IsUpdateApplied(string titleId, out string version)
{ {
string jsonPath = Path.Combine(_virtualFileSystem.GetBasePath(), "games", titleId, "updates.json"); string jsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId, "updates.json");
if (File.Exists(jsonPath)) if (File.Exists(jsonPath))
{ {

View file

@ -1,5 +1,6 @@
using Gtk; using Gtk;
using OpenTK.Input; using OpenTK.Input;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.Configuration; using Ryujinx.Configuration;
@ -602,7 +603,7 @@ namespace Ryujinx.Ui
private string GetProfileBasePath() private string GetProfileBasePath()
{ {
string path = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "profiles"); string path = AppDataManager.ProfilesDirPath;
if (_inputDevice.ActiveId.StartsWith("keyboard")) if (_inputDevice.ActiveId.StartsWith("keyboard"))
{ {

View file

@ -38,7 +38,7 @@ namespace Ryujinx.Ui
_titleId = titleId; _titleId = titleId;
_virtualFileSystem = virtualFileSystem; _virtualFileSystem = virtualFileSystem;
_dlcJsonPath = System.IO.Path.Combine(virtualFileSystem.GetBasePath(), "games", _titleId, "dlc.json"); _dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json");
_baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]"; _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]";
try try

View file

@ -339,7 +339,7 @@ namespace Ryujinx.Ui
return; return;
} }
string titleUpdateMetadataPath = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "games", mainNca.Header.TitleId.ToString("x16"), "updates.json"); string titleUpdateMetadataPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, mainNca.Header.TitleId.ToString("x16"), "updates.json");
if (File.Exists(titleUpdateMetadataPath)) if (File.Exists(titleUpdateMetadataPath))
{ {
@ -614,7 +614,7 @@ namespace Ryujinx.Ui
{ {
string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower(); string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
var modsBasePath = _virtualFileSystem.GetBaseModsPath(); var modsBasePath = _virtualFileSystem.ModLoader.GetModsBasePath();
var titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId); var titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId);
Process.Start(new ProcessStartInfo Process.Start(new ProcessStartInfo
@ -643,7 +643,7 @@ namespace Ryujinx.Ui
private void OpenPtcDir_Clicked(object sender, EventArgs args) private void OpenPtcDir_Clicked(object sender, EventArgs args)
{ {
string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower(); string titleId = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n")[1].ToLower();
string ptcDir = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "games", titleId, "cache", "cpu"); string ptcDir = System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "cpu");
string mainPath = System.IO.Path.Combine(ptcDir, "0"); string mainPath = System.IO.Path.Combine(ptcDir, "0");
string backupPath = System.IO.Path.Combine(ptcDir, "1"); string backupPath = System.IO.Path.Combine(ptcDir, "1");
@ -668,8 +668,8 @@ namespace Ryujinx.Ui
string[] tableEntry = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n"); string[] tableEntry = _gameTableStore.GetValue(_rowIter, 2).ToString().Split("\n");
string titleId = tableEntry[1].ToLower(); string titleId = tableEntry[1].ToLower();
DirectoryInfo mainDir = new DirectoryInfo(System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "games", titleId, "cache", "cpu", "0")); DirectoryInfo mainDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "cpu", "0"));
DirectoryInfo backupDir = new DirectoryInfo(System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "games", titleId, "cache", "cpu", "1")); DirectoryInfo backupDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, titleId, "cache", "cpu", "1"));
MessageDialog warningDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null) MessageDialog warningDialog = new MessageDialog(null, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null)
{ {

View file

@ -3,6 +3,7 @@ using Gtk;
using LibHac.Common; using LibHac.Common;
using LibHac.Ns; using LibHac.Ns;
using Ryujinx.Audio; using Ryujinx.Audio;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.System; using Ryujinx.Common.System;
using Ryujinx.Configuration; using Ryujinx.Configuration;
@ -873,7 +874,7 @@ namespace Ryujinx.Ui
{ {
Process.Start(new ProcessStartInfo() Process.Start(new ProcessStartInfo()
{ {
FileName = _virtualFileSystem.GetBasePath(), FileName = AppDataManager.BaseDirPath,
UseShellExecute = true, UseShellExecute = true,
Verb = "open" Verb = "open"
}); });
@ -1113,7 +1114,7 @@ namespace Ryujinx.Ui
private void Update_Pressed(object sender, EventArgs args) private void Update_Pressed(object sender, EventArgs args)
{ {
string ryuUpdater = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "RyuUpdater.exe"); string ryuUpdater = System.IO.Path.Combine(AppDataManager.BaseDirPath, "RyuUpdater.exe");
try try
{ {

View file

@ -1,5 +1,6 @@
using Gtk; using Gtk;
using LibHac; using LibHac;
using Ryujinx.Common.Configuration;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using System; using System;
using System.IO; using System.IO;
@ -175,6 +176,8 @@ namespace Ryujinx.Ui
public static bool IsMigrationNeeded() public static bool IsMigrationNeeded()
{ {
if (AppDataManager.IsCustomBasePath) return false;
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string oldBasePath = Path.Combine(appDataPath, "RyuFs"); string oldBasePath = Path.Combine(appDataPath, "RyuFs");

View file

@ -41,7 +41,7 @@ namespace Ryujinx.Ui
_titleId = titleId; _titleId = titleId;
_virtualFileSystem = virtualFileSystem; _virtualFileSystem = virtualFileSystem;
_updateJsonPath = System.IO.Path.Combine(_virtualFileSystem.GetBasePath(), "games", _titleId, "updates.json"); _updateJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "updates.json");
_radioButtonToPathDictionary = new Dictionary<RadioButton, string>(); _radioButtonToPathDictionary = new Dictionary<RadioButton, string>();
try try