From 1f664100bd6d5244f63f973798f0bb1ffc80ae71 Mon Sep 17 00:00:00 2001 From: TSRBerry <20988865+TSRBerry@users.noreply.github.com> Date: Fri, 5 May 2023 09:39:08 +0200 Subject: [PATCH] ModLoader: Fix case sensitivy issues without breaking cheats (#4783) * Fix case sensitivity for mod subdirectories * Small refactoring of ModLoader * Don't share instruction list between all cheats Co-authored-by: riperiperi --------- Co-authored-by: riperiperi --- .../Controls/ApplicationContextMenu.axaml.cs | 48 ++-- .../UI/Windows/CheatWindow.axaml.cs | 4 +- src/Ryujinx.HLE/HOS/ModLoader.cs | 269 +++++++++--------- .../Extensions/LocalFileSystemExtensions.cs | 7 +- .../Processes/Extensions/NcaExtensions.cs | 5 +- .../Ui/Widgets/GameTableContextMenu.cs | 8 +- src/Ryujinx/Ui/Windows/CheatWindow.cs | 4 +- 7 files changed, 179 insertions(+), 166 deletions(-) diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs index dc0dee2a..83fe29ea 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs +++ b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs @@ -10,6 +10,7 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; +using Ryujinx.HLE.HOS; using Ryujinx.Ui.Common.Helper; using System; using System.Collections.Generic; @@ -36,7 +37,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite; @@ -51,9 +52,10 @@ namespace Ryujinx.Ava.UI.Controls public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args) { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low)); + if ((sender as MenuItem)?.DataContext is MainWindowViewModel viewModel) + { + OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low)); + } } public void OpenDeviceSaveDirectory_Click(object sender, RoutedEventArgs args) @@ -70,9 +72,9 @@ namespace Ryujinx.Ava.UI.Controls OpenSaveDirectory(viewModel, SaveDataType.Bcat, userId: default); } - private void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId) + private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId) { - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { if (!ulong.TryParse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber)) { @@ -94,7 +96,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { await TitleUpdateWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); } @@ -104,7 +106,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { await DownloadableContentManagerWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); } @@ -114,7 +116,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { await new CheatWindow(viewModel.VirtualFileSystem, viewModel.SelectedApplication.TitleId, viewModel.SelectedApplication.TitleName).ShowDialog(viewModel.TopLevel as Window); } @@ -124,10 +126,10 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { - string modsBasePath = viewModel.VirtualFileSystem.ModLoader.GetModsBasePath(); - string titleModsPath = viewModel.VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, viewModel.SelectedApplication.TitleId); + string modsBasePath = ModLoader.GetModsBasePath(); + string titleModsPath = ModLoader.GetTitleDir(modsBasePath, viewModel.SelectedApplication.TitleId); OpenHelper.OpenFolder(titleModsPath); } @@ -137,10 +139,10 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { - string sdModsBasePath = viewModel.VirtualFileSystem.ModLoader.GetSdModsBasePath(); - string titleModsPath = viewModel.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, viewModel.SelectedApplication.TitleId); + string sdModsBasePath = ModLoader.GetSdModsBasePath(); + string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, viewModel.SelectedApplication.TitleId); OpenHelper.OpenFolder(titleModsPath); } @@ -150,7 +152,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning], LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.TitleName), @@ -197,7 +199,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning], LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.TitleName), @@ -253,7 +255,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu"); string mainDir = Path.Combine(ptcDir, "0"); @@ -274,7 +276,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader"); @@ -291,7 +293,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { await ApplicationHelper.ExtractSection(NcaSectionType.Logo, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName); } @@ -301,7 +303,7 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { await ApplicationHelper.ExtractSection(NcaSectionType.Data, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName); } @@ -311,10 +313,10 @@ namespace Ryujinx.Ava.UI.Controls { var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - if (viewModel.SelectedApplication != null) + if (viewModel?.SelectedApplication != null) { await ApplicationHelper.ExtractSection(NcaSectionType.Code, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName); } } } -} +} \ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs index cb939763..241a6c34 100644 --- a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs +++ b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs @@ -35,8 +35,8 @@ namespace Ryujinx.Ava.UI.Windows InitializeComponent(); - string modsBasePath = virtualFileSystem.ModLoader.GetModsBasePath(); - string titleModsPath = virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId); + string modsBasePath = ModLoader.GetModsBasePath(); + string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId); ulong titleIdValue = ulong.Parse(titleId, System.Globalization.NumberStyles.HexNumber); _enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt"); diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs index 16512541..bde4d11c 100644 --- a/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -89,7 +89,7 @@ namespace Ryujinx.HLE.HOS } // Title independent mods - public class PatchCache + private class PatchCache { public List> NsoPatches { get; } public List> NroPatches { get; } @@ -107,14 +107,14 @@ namespace Ryujinx.HLE.HOS } } - public Dictionary AppMods; // key is TitleId - public PatchCache Patches; + private readonly Dictionary _appMods; // key is TitleId + private PatchCache _patches; - private static readonly EnumerationOptions _dirEnumOptions; + private static readonly EnumerationOptions DirEnumOptions; static ModLoader() { - _dirEnumOptions = new EnumerationOptions + DirEnumOptions = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, MatchType = MatchType.Simple, @@ -125,37 +125,73 @@ namespace Ryujinx.HLE.HOS public ModLoader() { - AppMods = new Dictionary(); - Patches = new PatchCache(); + _appMods = new Dictionary(); + _patches = new PatchCache(); } - public void Clear() + private void Clear() { - AppMods.Clear(); - Patches = new PatchCache(); + _appMods.Clear(); + _patches = new PatchCache(); } private static bool StrEquals(string s1, string s2) => string.Equals(s1, s2, StringComparison.OrdinalIgnoreCase); - public string GetModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetModsPath()); - public string GetSdModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetSdModsPath()); + public static string GetModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetModsPath()); + public static string GetSdModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetSdModsPath()); - private string EnsureBaseDirStructure(string modsBasePath) + private static string EnsureBaseDirStructure(string modsBasePath) { var modsDir = new DirectoryInfo(modsBasePath); modsDir.CreateSubdirectory(AmsContentsDir); modsDir.CreateSubdirectory(AmsNsoPatchDir); modsDir.CreateSubdirectory(AmsNroPatchDir); - // modsDir.CreateSubdirectory(AmsKipPatchDir); // uncomment when KIPs are supported + // TODO: uncomment when KIPs are supported + // modsDir.CreateSubdirectory(AmsKipPatchDir); return modsDir.FullName; } private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId) - => contentsDir.EnumerateDirectories($"{titleId}*", _dirEnumOptions).FirstOrDefault(); + => contentsDir.EnumerateDirectories($"{titleId}*", DirEnumOptions).FirstOrDefault(); - public string GetTitleDir(string modsBasePath, string titleId) + private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, string titleId) + { + System.Text.StringBuilder types = new(); + + foreach (var modDir in dir.EnumerateDirectories()) + { + types.Clear(); + Mod mod = new("", null); + + if (StrEquals(RomfsDir, modDir.Name)) + { + mods.RomfsDirs.Add(mod = new Mod($"<{titleId} RomFs>", modDir)); + types.Append('R'); + } + else if (StrEquals(ExefsDir, modDir.Name)) + { + mods.ExefsDirs.Add(mod = new Mod($"<{titleId} ExeFs>", modDir)); + types.Append('E'); + } + else if (StrEquals(CheatDir, modDir.Name)) + { + types.Append('C', QueryCheatsDir(mods, modDir)); + } + else + { + AddModsFromDirectory(mods, modDir, titleId); + } + + if (types.Length > 0) + { + Logger.Info?.Print(LogClass.ModLoader, $"Found mod '{mod.Name}' [{types}]"); + } + } + } + + public static string GetTitleDir(string modsBasePath, string titleId) { var contentsDir = new DirectoryInfo(Path.Combine(modsBasePath, AmsContentsDir)); var titleModsPath = FindTitleDir(contentsDir, titleId); @@ -170,17 +206,32 @@ namespace Ryujinx.HLE.HOS } // Static Query Methods - public static void QueryPatchDirs(PatchCache cache, DirectoryInfo patchDir) + private static void QueryPatchDirs(PatchCache cache, DirectoryInfo patchDir) { - if (cache.Initialized || !patchDir.Exists) return; + if (cache.Initialized || !patchDir.Exists) + { + return; + } - var patches = cache.KipPatches; - string type = null; + List> patches; + string type; - if (StrEquals(AmsNsoPatchDir, patchDir.Name)) { patches = cache.NsoPatches; type = "NSO"; } - else if (StrEquals(AmsNroPatchDir, patchDir.Name)) { patches = cache.NroPatches; type = "NRO"; } - else if (StrEquals(AmsKipPatchDir, patchDir.Name)) { patches = cache.KipPatches; type = "KIP"; } - else return; + if (StrEquals(AmsNsoPatchDir, patchDir.Name)) + { + patches = cache.NsoPatches; type = "NSO"; + } + else if (StrEquals(AmsNroPatchDir, patchDir.Name)) + { + patches = cache.NroPatches; type = "NRO"; + } + else if (StrEquals(AmsKipPatchDir, patchDir.Name)) + { + patches = cache.KipPatches; type = "KIP"; + } + else + { + return; + } foreach (var modDir in patchDir.EnumerateDirectories()) { @@ -189,9 +240,12 @@ namespace Ryujinx.HLE.HOS } } - public static void QueryTitleDir(ModCache mods, DirectoryInfo titleDir) + private static void QueryTitleDir(ModCache mods, DirectoryInfo titleDir) { - if (!titleDir.Exists) return; + if (!titleDir.Exists) + { + return; + } var fsFile = new FileInfo(Path.Combine(titleDir.FullName, RomfsContainer)); if (fsFile.Exists) @@ -205,64 +259,15 @@ namespace Ryujinx.HLE.HOS mods.ExefsContainers.Add(new Mod($"<{titleDir.Name} ExeFs>", fsFile)); } - System.Text.StringBuilder types = new System.Text.StringBuilder(5); - - foreach (var modDir in titleDir.EnumerateDirectories()) - { - types.Clear(); - Mod mod = new Mod("", null); - - if (StrEquals(RomfsDir, modDir.Name)) - { - mods.RomfsDirs.Add(mod = new Mod($"<{titleDir.Name} RomFs>", modDir)); - types.Append('R'); - } - else if (StrEquals(ExefsDir, modDir.Name)) - { - mods.ExefsDirs.Add(mod = new Mod($"<{titleDir.Name} ExeFs>", modDir)); - types.Append('E'); - } - else if (StrEquals(CheatDir, modDir.Name)) - { - for (int i = 0; i < QueryCheatsDir(mods, modDir); i++) - { - types.Append('C'); - } - } - else - { - var romfs = new DirectoryInfo(Path.Combine(modDir.FullName, RomfsDir)); - var exefs = new DirectoryInfo(Path.Combine(modDir.FullName, ExefsDir)); - var cheat = new DirectoryInfo(Path.Combine(modDir.FullName, CheatDir)); - - if (romfs.Exists) - { - mods.RomfsDirs.Add(mod = new Mod(modDir.Name, romfs)); - types.Append('R'); - } - - if (exefs.Exists) - { - mods.ExefsDirs.Add(mod = new Mod(modDir.Name, exefs)); - types.Append('E'); - } - - if (cheat.Exists) - { - for (int i = 0; i < QueryCheatsDir(mods, cheat); i++) - { - types.Append('C'); - } - } - } - - if (types.Length > 0) Logger.Info?.Print(LogClass.ModLoader, $"Found mod '{mod.Name}' [{types}]"); - } + AddModsFromDirectory(mods, titleDir, titleDir.Name); } public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong titleId) { - if (!contentsDir.Exists) return; + if (!contentsDir.Exists) + { + return; + } Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((titleId & 0x1000) != 0 ? "DLC" : "Title")} {titleId:X16}"); @@ -302,9 +307,16 @@ namespace Ryujinx.HLE.HOS continue; } + int oldCheatsCount = mods.Cheats.Count; + // A cheat file can contain several cheats for the same executable, so the file must be parsed in // order to properly enumerate them. mods.Cheats.AddRange(GetCheatsInFile(file)); + + if (mods.Cheats.Count - oldCheatsCount > 0) + { + numMods++; + } } return numMods; @@ -313,57 +325,54 @@ namespace Ryujinx.HLE.HOS private static IEnumerable GetCheatsInFile(FileInfo cheatFile) { string cheatName = DefaultCheatName; - List instructions = new List(); - List cheats = new List(); + List instructions = new(); + List cheats = new(); - using (StreamReader cheatData = cheatFile.OpenText()) + using StreamReader cheatData = cheatFile.OpenText(); + while (cheatData.ReadLine() is { } line) { - string line; - while ((line = cheatData.ReadLine()) != null) + line = line.Trim(); + + if (line.StartsWith('[')) { - line = line.Trim(); - - if (line.StartsWith('[')) + // This line starts a new cheat section. + if (!line.EndsWith(']') || line.Length < 3) { - // This line starts a new cheat section. - if (!line.EndsWith(']') || line.Length < 3) - { - // Skip the entire file if there's any error while parsing the cheat file. + // Skip the entire file if there's any error while parsing the cheat file. - Logger.Warning?.Print(LogClass.ModLoader, $"Ignoring cheat '{cheatFile.FullName}' because it is malformed"); + Logger.Warning?.Print(LogClass.ModLoader, $"Ignoring cheat '{cheatFile.FullName}' because it is malformed"); - return new List(); - } - - // Add the previous section to the list. - if (instructions.Count != 0) - { - cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); - } - - // Start a new cheat section. - cheatName = line.Substring(1, line.Length - 2); - instructions = new List(); + return Array.Empty(); } - else if (line.Length > 0) + + // Add the previous section to the list. + if (instructions.Count > 0) { - // The line contains an instruction. - instructions.Add(line); + cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); } + + // Start a new cheat section. + cheatName = line.Substring(1, line.Length - 2); + instructions = new List(); } - - // Add the last section being processed. - if (instructions.Count != 0) + else if (line.Length > 0) { - cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); + // The line contains an instruction. + instructions.Add(line); } } + // Add the last section being processed. + if (instructions.Count > 0) + { + cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); + } + return cheats; } // Assumes searchDirPaths don't overlap - public static void CollectMods(Dictionary modCaches, PatchCache patches, params string[] searchDirPaths) + private static void CollectMods(Dictionary modCaches, PatchCache patches, params string[] searchDirPaths) { static bool IsPatchesDir(string name) => StrEquals(AmsNsoPatchDir, name) || StrEquals(AmsNroPatchDir, name) || @@ -375,7 +384,7 @@ namespace Ryujinx.HLE.HOS { if (IsContentsDir(searchDir.Name)) { - foreach (var (titleId, cache) in modCaches) + foreach ((ulong titleId, ModCache cache) in modCaches) { QueryContentsDir(cache, searchDir, titleId); } @@ -419,15 +428,15 @@ namespace Ryujinx.HLE.HOS foreach (ulong titleId in titles) { - AppMods[titleId] = new ModCache(); + _appMods[titleId] = new ModCache(); } - CollectMods(AppMods, Patches, searchDirPaths); + CollectMods(_appMods, _patches, searchDirPaths); } internal IStorage ApplyRomFsMods(ulong titleId, IStorage baseStorage) { - if (!AppMods.TryGetValue(titleId, out ModCache mods) || mods.RomfsDirs.Count + mods.RomfsContainers.Count == 0) + if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.RomfsDirs.Count + mods.RomfsContainers.Count == 0) { return baseStorage; } @@ -487,7 +496,7 @@ namespace Ryujinx.HLE.HOS return newStorage; } - private static void AddFiles(IFileSystem fs, string modName, HashSet fileSet, RomFsBuilder builder) + private static void AddFiles(IFileSystem fs, string modName, ISet fileSet, RomFsBuilder builder) { foreach (var entry in fs.EnumerateEntries() .Where(f => f.Type == DirectoryEntryType.File) @@ -509,7 +518,7 @@ namespace Ryujinx.HLE.HOS internal bool ReplaceExefsPartition(ulong titleId, ref IFileSystem exefs) { - if (!AppMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsContainers.Count == 0) + if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsContainers.Count == 0) { return false; } @@ -537,13 +546,13 @@ namespace Ryujinx.HLE.HOS internal ModLoadResult ApplyExefsMods(ulong titleId, NsoExecutable[] nsos) { - ModLoadResult modLoadResult = new ModLoadResult + ModLoadResult modLoadResult = new() { Stubs = new BitVector32(), Replaces = new BitVector32() }; - if (!AppMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsDirs.Count == 0) + if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsDirs.Count == 0) { return modLoadResult; } @@ -561,7 +570,7 @@ namespace Ryujinx.HLE.HOS { var nsoName = ProcessConst.ExeFsPrefixes[i]; - FileInfo nsoFile = new FileInfo(Path.Combine(mod.Path.FullName, nsoName)); + FileInfo nsoFile = new(Path.Combine(mod.Path.FullName, nsoName)); if (nsoFile.Exists) { if (modLoadResult.Replaces[1 << i]) @@ -580,7 +589,7 @@ namespace Ryujinx.HLE.HOS modLoadResult.Stubs[1 << i] |= File.Exists(Path.Combine(mod.Path.FullName, nsoName + StubExtension)); } - FileInfo npdmFile = new FileInfo(Path.Combine(mod.Path.FullName, "main.npdm")); + FileInfo npdmFile = new(Path.Combine(mod.Path.FullName, "main.npdm")); if (npdmFile.Exists) { if (modLoadResult.Npdm != null) @@ -611,7 +620,7 @@ namespace Ryujinx.HLE.HOS internal void ApplyNroPatches(NroExecutable nro) { - var nroPatches = Patches.NroPatches; + var nroPatches = _patches.NroPatches; if (nroPatches.Count == 0) return; @@ -622,9 +631,9 @@ namespace Ryujinx.HLE.HOS internal bool ApplyNsoPatches(ulong titleId, params IExecutable[] programs) { - IEnumerable> nsoMods = Patches.NsoPatches; + IEnumerable> nsoMods = _patches.NsoPatches; - if (AppMods.TryGetValue(titleId, out ModCache mods)) + if (_appMods.TryGetValue(titleId, out ModCache mods)) { nsoMods = nsoMods.Concat(mods.ExefsDirs); } @@ -636,7 +645,7 @@ namespace Ryujinx.HLE.HOS internal void LoadCheats(ulong titleId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine) { - if (tamperInfo == null || tamperInfo.BuildIds == null || tamperInfo.CodeAddresses == null) + if (tamperInfo?.BuildIds == null || tamperInfo.CodeAddresses == null) { Logger.Error?.Print(LogClass.ModLoader, "Unable to install cheat because the associated process is invalid"); @@ -645,14 +654,14 @@ namespace Ryujinx.HLE.HOS Logger.Info?.Print(LogClass.ModLoader, $"Build ids found for title {titleId:X16}:\n {String.Join("\n ", tamperInfo.BuildIds)}"); - if (!AppMods.TryGetValue(titleId, out ModCache mods) || mods.Cheats.Count == 0) + if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.Cheats.Count == 0) { return; } var cheats = mods.Cheats; var processExes = tamperInfo.BuildIds.Zip(tamperInfo.CodeAddresses, (k, v) => new { k, v }) - .ToDictionary(x => x.k.Substring(0, Math.Min(Cheat.CheatIdSize, x.k.Length)), x => x.v); + .ToDictionary(x => x.k[..Math.Min(Cheat.CheatIdSize, x.k.Length)], x => x.v); foreach (var cheat in cheats) { @@ -758,4 +767,4 @@ namespace Ryujinx.HLE.HOS return count > 0; } } -} +} \ No newline at end of file diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs index 28d90785..fb85329d 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs @@ -2,6 +2,7 @@ using LibHac.FsSystem; using LibHac.Loader; using LibHac.Ns; +using Ryujinx.HLE.HOS; using Ryujinx.HLE.Loaders.Processes.Extensions; using ApplicationId = LibHac.Ncm.ApplicationId; @@ -17,8 +18,8 @@ namespace Ryujinx.HLE.Loaders.Processes device.Configuration.VirtualFileSystem.ModLoader.CollectMods( new[] { programId }, - device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(), - device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath()); + ModLoader.GetModsBasePath(), + ModLoader.GetSdModsBasePath()); if (programId != 0) { @@ -36,4 +37,4 @@ namespace Ryujinx.HLE.Loaders.Processes return processResult; } } -} +} \ No newline at end of file diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs index 473f374d..e11b81d7 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs @@ -8,6 +8,7 @@ using LibHac.Ns; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS; using System.IO; using System.Linq; using ApplicationId = LibHac.Ncm.ApplicationId; @@ -35,8 +36,8 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions // Collecting mods related to AocTitleIds and ProgramId. device.Configuration.VirtualFileSystem.ModLoader.CollectMods( device.Configuration.ContentManager.GetAocTitleIds().Prepend(metaLoader.GetProgramId()), - device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(), - device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath()); + ModLoader.GetModsBasePath(), + ModLoader.GetSdModsBasePath()); // Load Nacp file. var nacpData = new BlitStruct(1); diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs index 558288aa..6d833165 100644 --- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs +++ b/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs @@ -460,16 +460,16 @@ namespace Ryujinx.Ui.Widgets private void OpenTitleModDir_Clicked(object sender, EventArgs args) { - string modsBasePath = _virtualFileSystem.ModLoader.GetModsBasePath(); - string titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, _titleIdText); + string modsBasePath = ModLoader.GetModsBasePath(); + string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText); OpenHelper.OpenFolder(titleModsPath); } private void OpenTitleSdModDir_Clicked(object sender, EventArgs args) { - string sdModsBasePath = _virtualFileSystem.ModLoader.GetSdModsBasePath(); - string titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, _titleIdText); + string sdModsBasePath = ModLoader.GetSdModsBasePath(); + string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText); OpenHelper.OpenFolder(titleModsPath); } diff --git a/src/Ryujinx/Ui/Windows/CheatWindow.cs b/src/Ryujinx/Ui/Windows/CheatWindow.cs index 917603b2..7dbea012 100644 --- a/src/Ryujinx/Ui/Windows/CheatWindow.cs +++ b/src/Ryujinx/Ui/Windows/CheatWindow.cs @@ -28,8 +28,8 @@ namespace Ryujinx.Ui.Windows builder.Autoconnect(this); _baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]"; - string modsBasePath = virtualFileSystem.ModLoader.GetModsBasePath(); - string titleModsPath = virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16")); + string modsBasePath = ModLoader.GetModsBasePath(); + string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16")); _enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt");