Compare commits

...

3 Commits

Author SHA1 Message Date
Erdem Keskin
6279f5e430 Update SettingsWindow.cs (#4785)
fix saving if directory path directly pasted in to the text field instead of using FileChooser.
2023-05-03 16:04:40 +02:00
Mary
b7d2bff6aa Revert "ModLoader: Fix case sensitivy issues (#4720)" (#4781)
This reverts commit cc1a933a2f.
2023-05-03 11:20:05 +02:00
riperiperi
7c327fecb3 Vulkan: Record modifications after changing the framebuffer (#4775)
Our Vulkan backend inserts image barriers when a texture is sampled after it is rendered. This is done via a "modification flag" which is set when a render target is unbound (presuming that a texture has finished drawing to it).

Imagine the following scenario:
- Game sets render target to texture A
- Game renders to texture A
- (render pass ends)
- Game binds texture A to a sampler
- Game sets render target to texture B
- Renders to texture B using texture A (barrier required)

Because of the previous behaviour, the check to add a barrier for sampling a texture actually happens before it is registered as modified, meaning no barrier was added at all. This isn't always the case, but it was definitely causing issues in Xenoblade 2.

This doesn't fix any more complicated issues where a texture is repeatedly sampled while it is currently being rendered.

Fixes visual glitches at lower resolutions in Xenoblade 2. May fix other cases.
2023-05-03 10:42:21 +02:00
9 changed files with 150 additions and 160 deletions

View File

@@ -1576,8 +1576,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
if (SelectedApplication != null) if (SelectedApplication != null)
{ {
string modsBasePath = ModLoader.GetModsBasePath(); string modsBasePath = VirtualFileSystem.ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, SelectedApplication.TitleId); string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, SelectedApplication.TitleId);
OpenHelper.OpenFolder(titleModsPath); OpenHelper.OpenFolder(titleModsPath);
} }
@@ -1587,8 +1587,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
if (SelectedApplication != null) if (SelectedApplication != null)
{ {
string sdModsBasePath = ModLoader.GetSdModsBasePath(); string sdModsBasePath = VirtualFileSystem.ModLoader.GetSdModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, SelectedApplication.TitleId); string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, SelectedApplication.TitleId);
OpenHelper.OpenFolder(titleModsPath); OpenHelper.OpenFolder(titleModsPath);
} }

View File

@@ -35,8 +35,8 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent(); InitializeComponent();
string modsBasePath = ModLoader.GetModsBasePath(); string modsBasePath = virtualFileSystem.ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId); string titleModsPath = virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId);
ulong titleIdValue = ulong.Parse(titleId, System.Globalization.NumberStyles.HexNumber); ulong titleIdValue = ulong.Parse(titleId, System.Globalization.NumberStyles.HexNumber);
_enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt"); _enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt");

View File

@@ -1015,8 +1015,8 @@ namespace Ryujinx.Graphics.Vulkan
private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked) private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked)
{ {
FramebufferParams?.UpdateModifications();
CreateFramebuffer(colors, depthStencil, filterWriteMasked); CreateFramebuffer(colors, depthStencil, filterWriteMasked);
FramebufferParams?.UpdateModifications();
CreateRenderPass(); CreateRenderPass();
SignalStateChange(); SignalStateChange();
SignalAttachmentChange(); SignalAttachmentChange();

View File

@@ -89,7 +89,7 @@ namespace Ryujinx.HLE.HOS
} }
// Title independent mods // Title independent mods
private class PatchCache public class PatchCache
{ {
public List<Mod<DirectoryInfo>> NsoPatches { get; } public List<Mod<DirectoryInfo>> NsoPatches { get; }
public List<Mod<DirectoryInfo>> NroPatches { get; } public List<Mod<DirectoryInfo>> NroPatches { get; }
@@ -107,14 +107,14 @@ namespace Ryujinx.HLE.HOS
} }
} }
private readonly Dictionary<ulong, ModCache> _appMods; // key is TitleId public Dictionary<ulong, ModCache> AppMods; // key is TitleId
private PatchCache _patches; public PatchCache Patches;
private static readonly EnumerationOptions DirEnumOptions; private static readonly EnumerationOptions _dirEnumOptions;
static ModLoader() static ModLoader()
{ {
DirEnumOptions = new EnumerationOptions _dirEnumOptions = new EnumerationOptions
{ {
MatchCasing = MatchCasing.CaseInsensitive, MatchCasing = MatchCasing.CaseInsensitive,
MatchType = MatchType.Simple, MatchType = MatchType.Simple,
@@ -125,73 +125,37 @@ namespace Ryujinx.HLE.HOS
public ModLoader() public ModLoader()
{ {
_appMods = new Dictionary<ulong, ModCache>(); AppMods = new Dictionary<ulong, ModCache>();
_patches = new PatchCache(); Patches = new PatchCache();
} }
private void Clear() public void Clear()
{ {
_appMods.Clear(); AppMods.Clear();
_patches = new PatchCache(); Patches = new PatchCache();
} }
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 static string GetModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetModsPath()); public string GetModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetModsPath());
public static string GetSdModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetSdModsPath()); public string GetSdModsBasePath() => EnsureBaseDirStructure(AppDataManager.GetSdModsPath());
private static string EnsureBaseDirStructure(string modsBasePath) private string EnsureBaseDirStructure(string modsBasePath)
{ {
var modsDir = new DirectoryInfo(modsBasePath); var modsDir = new DirectoryInfo(modsBasePath);
modsDir.CreateSubdirectory(AmsContentsDir); modsDir.CreateSubdirectory(AmsContentsDir);
modsDir.CreateSubdirectory(AmsNsoPatchDir); modsDir.CreateSubdirectory(AmsNsoPatchDir);
modsDir.CreateSubdirectory(AmsNroPatchDir); modsDir.CreateSubdirectory(AmsNroPatchDir);
// TODO: uncomment when KIPs are supported // modsDir.CreateSubdirectory(AmsKipPatchDir); // uncomment when KIPs are supported
// modsDir.CreateSubdirectory(AmsKipPatchDir);
return modsDir.FullName; return modsDir.FullName;
} }
private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId) private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId)
=> contentsDir.EnumerateDirectories($"{titleId}*", DirEnumOptions).FirstOrDefault(); => contentsDir.EnumerateDirectories($"{titleId}*", _dirEnumOptions).FirstOrDefault();
private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, string titleId) public string GetTitleDir(string modsBasePath, string titleId)
{
System.Text.StringBuilder types = new();
foreach (var modDir in dir.EnumerateDirectories())
{
types.Clear();
Mod<DirectoryInfo> mod = new("", null);
if (StrEquals(RomfsDir, modDir.Name))
{
mods.RomfsDirs.Add(mod = new Mod<DirectoryInfo>($"<{titleId} RomFs>", modDir));
types.Append('R');
}
else if (StrEquals(ExefsDir, modDir.Name))
{
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>($"<{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 contentsDir = new DirectoryInfo(Path.Combine(modsBasePath, AmsContentsDir));
var titleModsPath = FindTitleDir(contentsDir, titleId); var titleModsPath = FindTitleDir(contentsDir, titleId);
@@ -206,32 +170,17 @@ namespace Ryujinx.HLE.HOS
} }
// Static Query Methods // Static Query Methods
private static void QueryPatchDirs(PatchCache cache, DirectoryInfo patchDir) public static void QueryPatchDirs(PatchCache cache, DirectoryInfo patchDir)
{ {
if (cache.Initialized || !patchDir.Exists) if (cache.Initialized || !patchDir.Exists) return;
{
return;
}
List<Mod<DirectoryInfo>> patches; var patches = cache.KipPatches;
string type; string type = null;
if (StrEquals(AmsNsoPatchDir, patchDir.Name)) if (StrEquals(AmsNsoPatchDir, patchDir.Name)) { patches = cache.NsoPatches; type = "NSO"; }
{ else if (StrEquals(AmsNroPatchDir, patchDir.Name)) { patches = cache.NroPatches; type = "NRO"; }
patches = cache.NsoPatches; type = "NSO"; else if (StrEquals(AmsKipPatchDir, patchDir.Name)) { patches = cache.KipPatches; type = "KIP"; }
} else return;
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()) foreach (var modDir in patchDir.EnumerateDirectories())
{ {
@@ -240,12 +189,9 @@ namespace Ryujinx.HLE.HOS
} }
} }
private static void QueryTitleDir(ModCache mods, DirectoryInfo titleDir) public static void QueryTitleDir(ModCache mods, DirectoryInfo titleDir)
{ {
if (!titleDir.Exists) if (!titleDir.Exists) return;
{
return;
}
var fsFile = new FileInfo(Path.Combine(titleDir.FullName, RomfsContainer)); var fsFile = new FileInfo(Path.Combine(titleDir.FullName, RomfsContainer));
if (fsFile.Exists) if (fsFile.Exists)
@@ -259,15 +205,64 @@ namespace Ryujinx.HLE.HOS
mods.ExefsContainers.Add(new Mod<FileInfo>($"<{titleDir.Name} ExeFs>", fsFile)); mods.ExefsContainers.Add(new Mod<FileInfo>($"<{titleDir.Name} ExeFs>", fsFile));
} }
AddModsFromDirectory(mods, titleDir, titleDir.Name); System.Text.StringBuilder types = new System.Text.StringBuilder(5);
foreach (var modDir in titleDir.EnumerateDirectories())
{
types.Clear();
Mod<DirectoryInfo> mod = new Mod<DirectoryInfo>("", null);
if (StrEquals(RomfsDir, modDir.Name))
{
mods.RomfsDirs.Add(mod = new Mod<DirectoryInfo>($"<{titleDir.Name} RomFs>", modDir));
types.Append('R');
}
else if (StrEquals(ExefsDir, modDir.Name))
{
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>($"<{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<DirectoryInfo>(modDir.Name, romfs));
types.Append('R');
}
if (exefs.Exists)
{
mods.ExefsDirs.Add(mod = new Mod<DirectoryInfo>(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}]");
}
} }
public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong titleId) public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong titleId)
{ {
if (!contentsDir.Exists) if (!contentsDir.Exists) return;
{
return;
}
Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((titleId & 0x1000) != 0 ? "DLC" : "Title")} {titleId:X16}"); Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((titleId & 0x1000) != 0 ? "DLC" : "Title")} {titleId:X16}");
@@ -307,16 +302,9 @@ namespace Ryujinx.HLE.HOS
continue; continue;
} }
int oldCheatsCount = mods.Cheats.Count;
// A cheat file can contain several cheats for the same executable, so the file must be parsed in // A cheat file can contain several cheats for the same executable, so the file must be parsed in
// order to properly enumerate them. // order to properly enumerate them.
mods.Cheats.AddRange(GetCheatsInFile(file)); mods.Cheats.AddRange(GetCheatsInFile(file));
if (mods.Cheats.Count - oldCheatsCount > 0)
{
numMods++;
}
} }
return numMods; return numMods;
@@ -325,11 +313,13 @@ namespace Ryujinx.HLE.HOS
private static IEnumerable<Cheat> GetCheatsInFile(FileInfo cheatFile) private static IEnumerable<Cheat> GetCheatsInFile(FileInfo cheatFile)
{ {
string cheatName = DefaultCheatName; string cheatName = DefaultCheatName;
List<string> instructions = new(); List<string> instructions = new List<string>();
List<Cheat> cheats = new(); List<Cheat> cheats = new List<Cheat>();
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(); line = line.Trim();
@@ -342,18 +332,18 @@ namespace Ryujinx.HLE.HOS
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 Array.Empty<Cheat>(); return new List<Cheat>();
} }
// Add the previous section to the list. // Add the previous section to the list.
if (instructions.Count > 0) if (instructions.Count != 0)
{ {
cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions));
} }
// Start a new cheat section. // Start a new cheat section.
cheatName = line.Substring(1, line.Length - 2); cheatName = line.Substring(1, line.Length - 2);
instructions.Clear(); instructions = new List<string>();
} }
else if (line.Length > 0) else if (line.Length > 0)
{ {
@@ -363,16 +353,17 @@ namespace Ryujinx.HLE.HOS
} }
// Add the last section being processed. // Add the last section being processed.
if (instructions.Count > 0) if (instructions.Count != 0)
{ {
cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions));
} }
}
return cheats; return cheats;
} }
// Assumes searchDirPaths don't overlap // Assumes searchDirPaths don't overlap
private static void CollectMods(Dictionary<ulong, ModCache> modCaches, PatchCache patches, params string[] searchDirPaths) public static void CollectMods(Dictionary<ulong, ModCache> modCaches, PatchCache patches, params string[] searchDirPaths)
{ {
static bool IsPatchesDir(string name) => StrEquals(AmsNsoPatchDir, name) || static bool IsPatchesDir(string name) => StrEquals(AmsNsoPatchDir, name) ||
StrEquals(AmsNroPatchDir, name) || StrEquals(AmsNroPatchDir, name) ||
@@ -384,7 +375,7 @@ namespace Ryujinx.HLE.HOS
{ {
if (IsContentsDir(searchDir.Name)) if (IsContentsDir(searchDir.Name))
{ {
foreach ((ulong titleId, ModCache cache) in modCaches) foreach (var (titleId, cache) in modCaches)
{ {
QueryContentsDir(cache, searchDir, titleId); QueryContentsDir(cache, searchDir, titleId);
} }
@@ -428,15 +419,15 @@ namespace Ryujinx.HLE.HOS
foreach (ulong titleId in titles) 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) 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; return baseStorage;
} }
@@ -496,7 +487,7 @@ namespace Ryujinx.HLE.HOS
return newStorage; return newStorage;
} }
private static void AddFiles(IFileSystem fs, string modName, ISet<string> fileSet, RomFsBuilder builder) private static void AddFiles(IFileSystem fs, string modName, HashSet<string> fileSet, RomFsBuilder builder)
{ {
foreach (var entry in fs.EnumerateEntries() foreach (var entry in fs.EnumerateEntries()
.Where(f => f.Type == DirectoryEntryType.File) .Where(f => f.Type == DirectoryEntryType.File)
@@ -518,7 +509,7 @@ namespace Ryujinx.HLE.HOS
internal bool ReplaceExefsPartition(ulong titleId, ref IFileSystem exefs) 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; return false;
} }
@@ -546,13 +537,13 @@ namespace Ryujinx.HLE.HOS
internal ModLoadResult ApplyExefsMods(ulong titleId, NsoExecutable[] nsos) internal ModLoadResult ApplyExefsMods(ulong titleId, NsoExecutable[] nsos)
{ {
ModLoadResult modLoadResult = new() ModLoadResult modLoadResult = new ModLoadResult
{ {
Stubs = new BitVector32(), Stubs = new BitVector32(),
Replaces = 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; return modLoadResult;
} }
@@ -570,7 +561,7 @@ namespace Ryujinx.HLE.HOS
{ {
var nsoName = ProcessConst.ExeFsPrefixes[i]; var nsoName = ProcessConst.ExeFsPrefixes[i];
FileInfo nsoFile = new(Path.Combine(mod.Path.FullName, nsoName)); FileInfo nsoFile = new FileInfo(Path.Combine(mod.Path.FullName, nsoName));
if (nsoFile.Exists) if (nsoFile.Exists)
{ {
if (modLoadResult.Replaces[1 << i]) if (modLoadResult.Replaces[1 << i])
@@ -589,7 +580,7 @@ namespace Ryujinx.HLE.HOS
modLoadResult.Stubs[1 << i] |= File.Exists(Path.Combine(mod.Path.FullName, nsoName + StubExtension)); modLoadResult.Stubs[1 << i] |= File.Exists(Path.Combine(mod.Path.FullName, nsoName + StubExtension));
} }
FileInfo npdmFile = new(Path.Combine(mod.Path.FullName, "main.npdm")); FileInfo npdmFile = new FileInfo(Path.Combine(mod.Path.FullName, "main.npdm"));
if (npdmFile.Exists) if (npdmFile.Exists)
{ {
if (modLoadResult.Npdm != null) if (modLoadResult.Npdm != null)
@@ -620,7 +611,7 @@ namespace Ryujinx.HLE.HOS
internal void ApplyNroPatches(NroExecutable nro) internal void ApplyNroPatches(NroExecutable nro)
{ {
var nroPatches = _patches.NroPatches; var nroPatches = Patches.NroPatches;
if (nroPatches.Count == 0) return; if (nroPatches.Count == 0) return;
@@ -631,9 +622,9 @@ namespace Ryujinx.HLE.HOS
internal bool ApplyNsoPatches(ulong titleId, params IExecutable[] programs) internal bool ApplyNsoPatches(ulong titleId, params IExecutable[] programs)
{ {
IEnumerable<Mod<DirectoryInfo>> nsoMods = _patches.NsoPatches; IEnumerable<Mod<DirectoryInfo>> nsoMods = Patches.NsoPatches;
if (_appMods.TryGetValue(titleId, out ModCache mods)) if (AppMods.TryGetValue(titleId, out ModCache mods))
{ {
nsoMods = nsoMods.Concat(mods.ExefsDirs); nsoMods = nsoMods.Concat(mods.ExefsDirs);
} }
@@ -645,7 +636,7 @@ namespace Ryujinx.HLE.HOS
internal void LoadCheats(ulong titleId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine) internal void LoadCheats(ulong titleId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine)
{ {
if (tamperInfo?.BuildIds == null || tamperInfo.CodeAddresses == null) if (tamperInfo == null || tamperInfo.BuildIds == null || tamperInfo.CodeAddresses == null)
{ {
Logger.Error?.Print(LogClass.ModLoader, "Unable to install cheat because the associated process is invalid"); Logger.Error?.Print(LogClass.ModLoader, "Unable to install cheat because the associated process is invalid");
@@ -654,14 +645,14 @@ namespace Ryujinx.HLE.HOS
Logger.Info?.Print(LogClass.ModLoader, $"Build ids found for title {titleId:X16}:\n {String.Join("\n ", tamperInfo.BuildIds)}"); 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; return;
} }
var cheats = mods.Cheats; var cheats = mods.Cheats;
var processExes = tamperInfo.BuildIds.Zip(tamperInfo.CodeAddresses, (k, v) => new { k, v }) var processExes = tamperInfo.BuildIds.Zip(tamperInfo.CodeAddresses, (k, v) => new { k, v })
.ToDictionary(x => x.k[..Math.Min(Cheat.CheatIdSize, x.k.Length)], x => x.v); .ToDictionary(x => x.k.Substring(0, Math.Min(Cheat.CheatIdSize, x.k.Length)), x => x.v);
foreach (var cheat in cheats) foreach (var cheat in cheats)
{ {

View File

@@ -2,7 +2,6 @@
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.Loader; using LibHac.Loader;
using LibHac.Ns; using LibHac.Ns;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Loaders.Processes.Extensions;
using ApplicationId = LibHac.Ncm.ApplicationId; using ApplicationId = LibHac.Ncm.ApplicationId;
@@ -18,8 +17,8 @@ namespace Ryujinx.HLE.Loaders.Processes
device.Configuration.VirtualFileSystem.ModLoader.CollectMods( device.Configuration.VirtualFileSystem.ModLoader.CollectMods(
new[] { programId }, new[] { programId },
ModLoader.GetModsBasePath(), device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(),
ModLoader.GetSdModsBasePath()); device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
if (programId != 0) if (programId != 0)
{ {

View File

@@ -8,7 +8,6 @@ using LibHac.Ns;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using ApplicationId = LibHac.Ncm.ApplicationId; using ApplicationId = LibHac.Ncm.ApplicationId;
@@ -36,8 +35,8 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
// Collecting mods related to AocTitleIds and ProgramId. // Collecting mods related to AocTitleIds and ProgramId.
device.Configuration.VirtualFileSystem.ModLoader.CollectMods( device.Configuration.VirtualFileSystem.ModLoader.CollectMods(
device.Configuration.ContentManager.GetAocTitleIds().Prepend(metaLoader.GetProgramId()), device.Configuration.ContentManager.GetAocTitleIds().Prepend(metaLoader.GetProgramId()),
ModLoader.GetModsBasePath(), device.Configuration.VirtualFileSystem.ModLoader.GetModsBasePath(),
ModLoader.GetSdModsBasePath()); device.Configuration.VirtualFileSystem.ModLoader.GetSdModsBasePath());
// Load Nacp file. // Load Nacp file.
var nacpData = new BlitStruct<ApplicationControlProperty>(1); var nacpData = new BlitStruct<ApplicationControlProperty>(1);

View File

@@ -460,16 +460,16 @@ namespace Ryujinx.Ui.Widgets
private void OpenTitleModDir_Clicked(object sender, EventArgs args) private void OpenTitleModDir_Clicked(object sender, EventArgs args)
{ {
string modsBasePath = ModLoader.GetModsBasePath(); string modsBasePath = _virtualFileSystem.ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText); string titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, _titleIdText);
OpenHelper.OpenFolder(titleModsPath); OpenHelper.OpenFolder(titleModsPath);
} }
private void OpenTitleSdModDir_Clicked(object sender, EventArgs args) private void OpenTitleSdModDir_Clicked(object sender, EventArgs args)
{ {
string sdModsBasePath = ModLoader.GetSdModsBasePath(); string sdModsBasePath = _virtualFileSystem.ModLoader.GetSdModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText); string titleModsPath = _virtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, _titleIdText);
OpenHelper.OpenFolder(titleModsPath); OpenHelper.OpenFolder(titleModsPath);
} }

View File

@@ -28,8 +28,8 @@ namespace Ryujinx.Ui.Windows
builder.Autoconnect(this); builder.Autoconnect(this);
_baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]"; _baseTitleInfoLabel.Text = $"Cheats Available for {titleName} [{titleId:X16}]";
string modsBasePath = ModLoader.GetModsBasePath(); string modsBasePath = virtualFileSystem.ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16")); string titleModsPath = virtualFileSystem.ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16"));
_enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt"); _enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt");

View File

@@ -720,6 +720,7 @@ namespace Ryujinx.Ui.Windows
if (Directory.Exists(_addGameDirBox.Buffer.Text)) if (Directory.Exists(_addGameDirBox.Buffer.Text))
{ {
_gameDirsBoxStore.AppendValues(_addGameDirBox.Buffer.Text); _gameDirsBoxStore.AppendValues(_addGameDirBox.Buffer.Text);
_directoryChanged = true;
} }
else else
{ {