From 5c6864609382962132830028a6e276be46595ae1 Mon Sep 17 00:00:00 2001 From: Jannify <23176718+Jannify@users.noreply.github.com> Date: Sat, 8 Mar 2025 20:57:04 +0100 Subject: [PATCH] Get correct ApplicationData dir on linux/wine --- NitroxModel/Helper/NitroxUser.cs | 353 ++++++++++++++++--------------- 1 file changed, 185 insertions(+), 168 deletions(-) diff --git a/NitroxModel/Helper/NitroxUser.cs b/NitroxModel/Helper/NitroxUser.cs index 1554c4452d..badc22889d 100644 --- a/NitroxModel/Helper/NitroxUser.cs +++ b/NitroxModel/Helper/NitroxUser.cs @@ -10,230 +10,247 @@ using NitroxModel.Platforms.Store; using NitroxModel.Platforms.Store.Interfaces; -namespace NitroxModel.Helper +namespace NitroxModel.Helper; + +public static class NitroxUser { - public static class NitroxUser + public const string LAUNCHER_PATH_ENV_KEY = "NITROX_LAUNCHER_PATH"; + private const string PREFERRED_GAMEPATH_KEY = "PreferredGamePath"; + private static string appDataPath; + private static string launcherPath; + private static string gamePath; + private static string executableRootPath; + private static string executablePath; + private static string assetsPath; + + private static readonly IEnumerable> launcherPathDataSources = new List> { - public const string LAUNCHER_PATH_ENV_KEY = "NITROX_LAUNCHER_PATH"; - private const string PREFERRED_GAMEPATH_KEY = "PreferredGamePath"; - private static string appDataPath; - private static string launcherPath; - private static string gamePath; - private static string executableRootPath; - private static string executablePath; - private static string assetsPath; - - private static readonly IEnumerable> launcherPathDataSources = new List> + () => Environment.GetEnvironmentVariable(LAUNCHER_PATH_ENV_KEY), + () => { - () => Environment.GetEnvironmentVariable(LAUNCHER_PATH_ENV_KEY), - () => + Assembly currentAsm = Assembly.GetEntryAssembly(); + if (currentAsm?.GetName().Name.Equals("Nitrox.Launcher") ?? false) { - Assembly currentAsm = Assembly.GetEntryAssembly(); - if (currentAsm?.GetName().Name.Equals("Nitrox.Launcher") ?? false) - { - return Path.GetDirectoryName(currentAsm.Location); - } + return Path.GetDirectoryName(currentAsm.Location); + } - DirectoryInfo execParentDir; - Assembly execAsm = Assembly.GetExecutingAssembly(); - if (string.IsNullOrEmpty(execAsm.Location)) - { - execParentDir = Directory.GetParent(Directory.GetCurrentDirectory()); - } - else - { - execParentDir = Directory.GetParent(execAsm.Location); - } + Assembly execAsm = Assembly.GetExecutingAssembly(); + string execDir = string.IsNullOrEmpty(execAsm.Location) ? Directory.GetCurrentDirectory() : execAsm.Location; + DirectoryInfo execParentDir = Directory.GetParent(execDir); - // When running tests LanguageFiles is in same directory - if (execParentDir != null && Directory.Exists(Path.Combine(execParentDir.FullName, "LanguageFiles"))) - { - return execParentDir.FullName; - } + // When running tests LanguageFiles is in same directory + if (execParentDir != null && Directory.Exists(Path.Combine(execParentDir.FullName, "LanguageFiles"))) + { + return execParentDir.FullName; + } - // NitroxModel, NitroxServer and other assemblies are stored in Nitrox.Launcher/lib - if (execParentDir?.Parent != null && Directory.Exists(Path.Combine(execParentDir.Parent.FullName, "Resources", "LanguageFiles"))) - { - return execParentDir.Parent.FullName; - } + // NitroxModel, NitroxServer and other assemblies are stored in Nitrox.Launcher/lib + if (execParentDir?.Parent != null && Directory.Exists(Path.Combine(execParentDir.Parent.FullName, "Resources", "LanguageFiles"))) + { + return execParentDir.Parent.FullName; + } - return null; - }, - () => + return null; + }, + () => + { + using ProcessEx proc = ProcessEx.GetFirstProcess("Nitrox.Launcher"); + string executable = proc?.MainModule?.FileName; + return !string.IsNullOrWhiteSpace(executable) ? Path.GetDirectoryName(executable) : null; + } + }; + + public static string AppDataPath + { + get + { + if (appDataPath != null) { - using ProcessEx proc = ProcessEx.GetFirstProcess("Nitrox.Launcher"); - string executable = proc?.MainModule?.FileName; - return !string.IsNullOrWhiteSpace(executable) ? Path.GetDirectoryName(executable) : null; + return appDataPath; } - }; - public static string AppDataPath { get; } = appDataPath ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Nitrox"); + string applicationData; - /// - /// Tries to get the launcher path that was previously saved by other Nitrox code. - /// - public static string LauncherPath + // On linux Environment.SpecialFolder.ApplicationData returns the windows version inside wine, this bypasses that + string homeInWine = Environment.GetEnvironmentVariable("WINEHOMEDIR"); + if (homeInWine != null && Directory.Exists(homeInWine[4..])) // WINEHOMEDIR is prefixed with \??\ + { + applicationData = Path.Combine(homeInWine[4..], ".config"); + } + else + { + applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + } + + return appDataPath = Path.Combine(applicationData, "Nitrox"); + } + } + + /// + /// Tries to get the launcher path that was previously saved by other Nitrox code. + /// + public static string LauncherPath + { + get { - get + if (launcherPath != null) { - if (launcherPath != null) - { - return launcherPath; - } + return launcherPath; + } - foreach (Func retriever in launcherPathDataSources) + foreach (Func retriever in launcherPathDataSources) + { + string path = retriever(); + if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path)) { - string path = retriever(); - if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path)) - { - return launcherPath = path; - } + return launcherPath = path; } - - return null; } + + return null; } + } - public static string AssetBundlePath => Path.Combine(LauncherPath, "Resources", "AssetBundles"); - public static string LanguageFilesPath => Path.Combine(LauncherPath, "Resources", "LanguageFiles"); + public static string AssetBundlePath => Path.Combine(LauncherPath, "Resources", "AssetBundles"); + public static string LanguageFilesPath => Path.Combine(LauncherPath, "Resources", "LanguageFiles"); - public static string PreferredGamePath - { - get => KeyValueStore.Instance.GetValue(PREFERRED_GAMEPATH_KEY); - set => KeyValueStore.Instance.SetValue(PREFERRED_GAMEPATH_KEY, value); - } + public static string PreferredGamePath + { + get => KeyValueStore.Instance.GetValue(PREFERRED_GAMEPATH_KEY); + set => KeyValueStore.Instance.SetValue(PREFERRED_GAMEPATH_KEY, value); + } - private static IGamePlatform gamePlatform; - public static event Action GamePlatformChanged; - public static IGamePlatform GamePlatform + private static IGamePlatform gamePlatform; + public static event Action GamePlatformChanged; + + public static IGamePlatform GamePlatform + { + get { - get + if (gamePlatform == null) { - if (gamePlatform == null) - { - _ = GamePath; // Ensure gamePath is set - } - return gamePlatform; + _ = GamePath; // Ensure gamePath is set } - set + return gamePlatform; + } + set + { + if (gamePlatform != value) { - if (gamePlatform != value) - { - gamePlatform = value; - GamePlatformChanged?.Invoke(); - } + gamePlatform = value; + GamePlatformChanged?.Invoke(); } } + } - public static string GamePath + public static string GamePath + { + get { - get + if (!string.IsNullOrEmpty(gamePath)) { - if (!string.IsNullOrEmpty(gamePath)) - { - return gamePath; - } + return gamePath; + } - List finderResults = GameInstallationFinder.Instance.FindGame(GameInfo.Subnautica).TakeUntilInclusive(r => r is { IsOk: false }).ToList(); - GameFinderResult potentiallyValidResult = finderResults.LastOrDefault(); - if (potentiallyValidResult?.IsOk == true) - { - Log.Debug($"Game installation was found by {potentiallyValidResult.FinderName} at '{potentiallyValidResult.Path}'"); - gamePath = potentiallyValidResult.Path; - GamePlatform = GamePlatforms.GetPlatformByGameDir(gamePath); - return gamePath; - } + List finderResults = GameInstallationFinder.Instance.FindGame(GameInfo.Subnautica).TakeUntilInclusive(r => r is { IsOk: false }).ToList(); + GameFinderResult potentiallyValidResult = finderResults.LastOrDefault(); + if (potentiallyValidResult?.IsOk == true) + { + Log.Debug($"Game installation was found by {potentiallyValidResult.FinderName} at '{potentiallyValidResult.Path}'"); + gamePath = potentiallyValidResult.Path; + GamePlatform = GamePlatforms.GetPlatformByGameDir(gamePath); + return gamePath; + } - Log.Error($"Could not locate Subnautica installation directory: {Environment.NewLine}{string.Join(Environment.NewLine, finderResults.Select(i => $"{i.FinderName}: {i.ErrorMessage}"))}"); - return string.Empty; + Log.Error($"Could not locate Subnautica installation directory: {Environment.NewLine}{string.Join(Environment.NewLine, finderResults.Select(i => $"{i.FinderName}: {i.ErrorMessage}"))}"); + return string.Empty; + } + set + { + if (string.IsNullOrWhiteSpace(value)) + { + return; } - set + if (!Directory.Exists(value)) { - if (string.IsNullOrWhiteSpace(value)) - { - return; - } - if (!Directory.Exists(value)) - { - throw new ArgumentException("Given path is an invalid directory"); - } - - // Ensures the path looks alright (no mixed / and \ path separators) - gamePath = Path.GetFullPath(value); - GamePlatform = GamePlatforms.GetPlatformByGameDir(gamePath); + throw new ArgumentException("Given path is an invalid directory"); } + + // Ensures the path looks alright (no mixed / and \ path separators) + gamePath = Path.GetFullPath(value); + GamePlatform = GamePlatforms.GetPlatformByGameDir(gamePath); } + } - public static string ExecutableRootPath + public static string ExecutableRootPath + { + get { - get + if (!string.IsNullOrWhiteSpace(executableRootPath)) { - if (!string.IsNullOrWhiteSpace(executableRootPath)) - { - return executableRootPath; - } - string exePath = ExecutableFilePath; - if (exePath == null) - { - return null; - } - - return executableRootPath = Path.GetDirectoryName(exePath); + return executableRootPath; } + string exePath = ExecutableFilePath; + if (exePath == null) + { + return null; + } + + return executableRootPath = Path.GetDirectoryName(exePath); } + } - public static string ExecutableFilePath + public static string ExecutableFilePath + { + get { - get + if (!string.IsNullOrWhiteSpace(executablePath)) { - if (!string.IsNullOrWhiteSpace(executablePath)) - { - return executablePath; - } + return executablePath; + } - Assembly entryAssembly = Assembly.GetEntryAssembly(); - if (entryAssembly == null) - { - return null; - } - string path = entryAssembly.Location; - // File URI works different on Linux/OSX, so only do uri parsing on Windows. - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - path = new Uri(path).LocalPath; - } - return executablePath = path; + Assembly entryAssembly = Assembly.GetEntryAssembly(); + if (entryAssembly == null) + { + return null; + } + string path = entryAssembly.Location; + // File URI works different on Linux/OSX, so only do uri parsing on Windows. + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + path = new Uri(path).LocalPath; } + return executablePath = path; } + } - public static string AssetsPath + public static string AssetsPath + { + get { - get + if (!string.IsNullOrWhiteSpace(assetsPath)) { - if (!string.IsNullOrWhiteSpace(assetsPath)) - { - return assetsPath; - } - - string nitroxAssets; - if (NitroxEnvironment.IsTesting) + return assetsPath; + } + + string nitroxAssets; + if (NitroxEnvironment.IsTesting) + { + nitroxAssets = Directory.GetCurrentDirectory(); + while (nitroxAssets != null && Path.GetFileName(nitroxAssets) != "Nitrox.Test") { - nitroxAssets = Directory.GetCurrentDirectory(); - while (nitroxAssets != null && Path.GetFileName(nitroxAssets) != "Nitrox.Test") - { - nitroxAssets = Directory.GetParent(nitroxAssets)?.FullName; - } - if (nitroxAssets != null) - { - nitroxAssets = Path.Combine(Directory.GetParent(nitroxAssets)?.FullName ?? throw new Exception("Failed to get Nitrox assets during tests"), "Nitrox.Assets.Subnautica"); - } + nitroxAssets = Directory.GetParent(nitroxAssets)?.FullName; } - else + if (nitroxAssets != null) { - nitroxAssets = LauncherPath ?? ExecutableRootPath; + nitroxAssets = Path.Combine(Directory.GetParent(nitroxAssets)?.FullName ?? throw new Exception("Failed to get Nitrox assets during tests"), "Nitrox.Assets.Subnautica"); } - return assetsPath = nitroxAssets; } + else + { + nitroxAssets = LauncherPath ?? ExecutableRootPath; + } + return assetsPath = nitroxAssets; } } }