aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSomebody Whoisbored <13044396+shadowninja108@users.noreply.github.com>2020-12-29 12:54:32 -0700
committerGitHub <noreply@github.com>2020-12-29 20:54:32 +0100
commitfb0db323385047afa179d3fcf1d5eee627eedfdc (patch)
treeb35b9d106553480d73dbc0c4bb28d37444b979ad
parent9a808fe48471f51fbb9685a7d7d2f3adcf3df793 (diff)
Add the ability to add individual files exefs with mod loader (#1766)
Co-authored-by: Ac_K <Acoustik666@gmail.com>
-rw-r--r--Ryujinx.HLE/HOS/ApplicationLoader.cs67
-rw-r--r--Ryujinx.HLE/HOS/ModLoader.cs64
2 files changed, 90 insertions, 41 deletions
diff --git a/Ryujinx.HLE/HOS/ApplicationLoader.cs b/Ryujinx.HLE/HOS/ApplicationLoader.cs
index 9bf9a7bf..2c4708d7 100644
--- a/Ryujinx.HLE/HOS/ApplicationLoader.cs
+++ b/Ryujinx.HLE/HOS/ApplicationLoader.cs
@@ -21,6 +21,7 @@ using System.Linq;
using System.Reflection;
using static LibHac.Fs.ApplicationSaveDataManagement;
+using static Ryujinx.HLE.HOS.ModLoader;
using ApplicationId = LibHac.Ncm.ApplicationId;
namespace Ryujinx.HLE.HOS
@@ -30,7 +31,22 @@ namespace Ryujinx.HLE.HOS
public class ApplicationLoader
{
// Binaries from exefs are loaded into mem in this order. Do not change.
- private static readonly string[] ExeFsPrefixes = { "rtld", "main", "subsdk*", "sdk" };
+ internal static readonly string[] ExeFsPrefixes =
+ {
+ "rtld",
+ "main",
+ "subsdk0",
+ "subsdk1",
+ "subsdk2",
+ "subsdk3",
+ "subsdk4",
+ "subsdk5",
+ "subsdk6",
+ "subsdk7",
+ "subsdk8",
+ "subsdk9",
+ "sdk"
+ };
private readonly Switch _device;
private readonly ContentManager _contentManager;
@@ -463,37 +479,48 @@ namespace Ryujinx.HLE.HOS
metaData ??= ReadNpdm(codeFs);
- List<NsoExecutable> nsos = new List<NsoExecutable>();
+ NsoExecutable[] nsos = new NsoExecutable[ExeFsPrefixes.Length];
- foreach (string exePrefix in ExeFsPrefixes) // Load binaries with standard prefixes
+ for(int i = 0; i < nsos.Length; i++)
{
- foreach (DirectoryEntryEx file in codeFs.EnumerateEntries("/", exePrefix))
- {
- if (Path.GetExtension(file.Name) != string.Empty)
- {
- continue;
- }
+ string name = ExeFsPrefixes[i];
- Logger.Info?.Print(LogClass.Loader, $"Loading {file.Name}...");
+ if (!codeFs.FileExists(name))
+ {
+ continue; // file doesn't exist, skip
+ }
- codeFs.OpenFile(out IFile nsoFile, file.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
+ Logger.Info?.Print(LogClass.Loader, $"Loading {name}...");
- NsoExecutable nso = new NsoExecutable(nsoFile.AsStorage(), file.Name);
+ codeFs.OpenFile(out IFile nsoFile, $"/{name}".ToU8Span(), OpenMode.Read).ThrowIfFailure();
- nsos.Add(nso);
- }
+ nsos[i] = new NsoExecutable(nsoFile.AsStorage(), name);
}
// ExeFs file replacements
- bool modified = _fileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
+ ModLoadResult modLoadResult = _fileSystem.ModLoader.ApplyExefsMods(TitleId, nsos);
+
+ // collect the nsos, ignoring ones that aren't used
+ NsoExecutable[] programs = nsos.Where(x => x != null).ToArray();
- NsoExecutable[] programs = nsos.ToArray();
+ // take the npdm from mods if present
+ if (modLoadResult.Npdm != null)
+ {
+ metaData = modLoadResult.Npdm;
+ }
- modified |= _fileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
+ bool hasPatches = _fileSystem.ModLoader.ApplyNsoPatches(TitleId, programs);
_contentManager.LoadEntries(_device);
- if (_device.System.EnablePtc && modified)
+ bool usePtc = _device.System.EnablePtc;
+
+ // don't use PTC if exefs files have been replaced
+ usePtc &= !modLoadResult.Modified;
+ // don't use PTC if exefs files have been patched
+ usePtc &= !hasPatches;
+
+ if (_device.System.EnablePtc && !usePtc)
{
Logger.Warning?.Print(LogClass.Ptc, $"Detected exefs modifications. PPTC disabled.");
}
@@ -501,7 +528,7 @@ namespace Ryujinx.HLE.HOS
Graphics.Gpu.GraphicsConfig.TitleId = TitleIdText;
_device.Gpu.HostInitalized.Set();
- Ptc.Initialize(TitleIdText, DisplayVersion, _device.System.EnablePtc && !modified);
+ Ptc.Initialize(TitleIdText, DisplayVersion, usePtc);
ProgramLoader.LoadNsos(_device.System.KernelContext, metaData, executables: programs);
}
@@ -657,4 +684,4 @@ namespace Ryujinx.HLE.HOS
return resultCode;
}
}
-} \ No newline at end of file
+}
diff --git a/Ryujinx.HLE/HOS/ModLoader.cs b/Ryujinx.HLE/HOS/ModLoader.cs
index 3d701525..d2f80ebd 100644
--- a/Ryujinx.HLE/HOS/ModLoader.cs
+++ b/Ryujinx.HLE/HOS/ModLoader.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.IO;
+using Ryujinx.HLE.Loaders.Npdm;
namespace Ryujinx.HLE.HOS
{
@@ -381,66 +382,87 @@ namespace Ryujinx.HLE.HOS
return true;
}
- internal bool ApplyExefsMods(ulong titleId, List<NsoExecutable> nsos)
+ public struct ModLoadResult
{
+ public BitVector32 Stubs;
+ public BitVector32 Replaces;
+ public Npdm Npdm;
+
+ public bool Modified => (Stubs.Data | Replaces.Data) != 0;
+ }
+
+ internal ModLoadResult ApplyExefsMods(ulong titleId, NsoExecutable[] nsos)
+ {
+ ModLoadResult modLoadResult = new ModLoadResult
+ {
+ Stubs = new BitVector32(),
+ Replaces = new BitVector32()
+ };
+
if (!AppMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsDirs.Count == 0)
{
- return false;
+ return modLoadResult;
}
- bool replaced = false;
- if (nsos.Count > 32)
+ if (nsos.Length != ApplicationLoader.ExeFsPrefixes.Length)
{
- throw new ArgumentOutOfRangeException("NSO Count is more than 32");
+ throw new ArgumentOutOfRangeException("NSO Count is incorrect");
}
var exeMods = mods.ExefsDirs;
- BitVector32 stubs = new BitVector32();
- BitVector32 repls = new BitVector32();
-
foreach (var mod in exeMods)
{
- for (int i = 0; i < nsos.Count; ++i)
+ for (int i = 0; i < ApplicationLoader.ExeFsPrefixes.Length; ++i)
{
- var nso = nsos[i];
- var nsoName = nso.Name;
+ var nsoName = ApplicationLoader.ExeFsPrefixes[i];
FileInfo nsoFile = new FileInfo(Path.Combine(mod.Path.FullName, nsoName));
if (nsoFile.Exists)
{
- if (repls[1 << i])
+ if (modLoadResult.Replaces[1 << i])
{
Logger.Warning?.Print(LogClass.ModLoader, $"Multiple replacements to '{nsoName}'");
+
continue;
}
- repls[1 << i] = true;
+ modLoadResult.Replaces[1 << i] = true;
nsos[i] = new NsoExecutable(nsoFile.OpenRead().AsStorage(), nsoName);
Logger.Info?.Print(LogClass.ModLoader, $"NSO '{nsoName}' replaced");
+ }
- replaced = true;
+ modLoadResult.Stubs[1 << i] |= File.Exists(Path.Combine(mod.Path.FullName, nsoName + StubExtension));
+ }
+
+ FileInfo npdmFile = new FileInfo(Path.Combine(mod.Path.FullName, "main.npdm"));
+ if(npdmFile.Exists)
+ {
+ if(modLoadResult.Npdm != null)
+ {
+ Logger.Warning?.Print(LogClass.ModLoader, "Multiple replacements to 'main.npdm'");
continue;
}
- stubs[1 << i] |= File.Exists(Path.Combine(mod.Path.FullName, nsoName + StubExtension));
+ modLoadResult.Npdm = new Npdm(npdmFile.OpenRead());
+
+ Logger.Info?.Print(LogClass.ModLoader, $"main.npdm replaced");
}
}
- for (int i = nsos.Count - 1; i >= 0; --i)
+ for (int i = ApplicationLoader.ExeFsPrefixes.Length - 1; i >= 0; --i)
{
- if (stubs[1 << i] && !repls[1 << i]) // Prioritizes replacements over stubs
+ if (modLoadResult.Stubs[1 << i] && !modLoadResult.Replaces[1 << i]) // Prioritizes replacements over stubs
{
Logger.Info?.Print(LogClass.ModLoader, $" NSO '{nsos[i].Name}' stubbed");
- nsos.RemoveAt(i);
- replaced = true;
+ nsos[i] = null;
}
}
- return replaced;
+ return modLoadResult;
}
internal void ApplyNroPatches(NroExecutable nro)
@@ -542,4 +564,4 @@ namespace Ryujinx.HLE.HOS
return count > 0;
}
}
-} \ No newline at end of file
+}