add stream based loaders

* extend stream loading support

* fix content manager rebase

* fix update searching
This commit is contained in:
Emmanuel Hansen
2025-06-28 13:41:52 -05:00
committed by KeatonTheBot
parent 6ecd6111d5
commit c16559f20e
6 changed files with 462 additions and 262 deletions
@@ -127,7 +127,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
return nca.Header.ContentType == NcaContentType.Control;
}
public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath)
public static (Nca, Nca) GetUpdateData(this Nca mainNca, VirtualFileSystem fileSystem, IntegrityCheckLevel checkLevel, int programIndex, out string updatePath, Stream updateStream = null)
{
updatePath = null;
@@ -138,28 +138,40 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
// Clear the program index part.
ulong titleIdBase = mainNca.GetProgramIdBase();
// Load update information if exists.
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
if (File.Exists(titleUpdateMetadataPath))
IFileSystem updatePartitionFileSystem = null;
if (updateStream == null)
{
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected;
if (File.Exists(updatePath))
// Load update information if exists.
string titleUpdateMetadataPath = Path.Combine(AppDataManager.GamesDirPath, titleIdBase.ToString("x16"), "updates.json");
if (File.Exists(titleUpdateMetadataPath))
{
IFileSystem updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem);
foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel))
updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _applicationSerializerContext.TitleUpdateMetadata).Selected;
if (File.Exists(updatePath))
{
if ((applicationTitleId & ~0x1FFFUL) != titleIdBase)
{
continue;
}
updatePatchNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Program, programIndex);
updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex);
break;
updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updatePath, fileSystem);
}
}
}
else
{
updatePartitionFileSystem = PartitionFileSystemUtils.OpenApplicationFileSystem(updateStream, false, fileSystem);
}
if (updatePartitionFileSystem != null)
{
foreach ((ulong applicationTitleId, ContentMetaData content) in updatePartitionFileSystem.GetContentData(ContentMetaType.Patch, fileSystem, checkLevel))
{
if ((applicationTitleId & ~0x1FFFUL) != titleIdBase)
{
continue;
}
updatePatchNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Program, programIndex);
updateControlNca = content.GetNcaByType(fileSystem.KeySet, ContentType.Control, programIndex);
break;
}
}
return (updatePatchNca, updateControlNca);
}
@@ -52,7 +52,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
return programs;
}
internal static (bool, ProcessResult) TryLoad<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, string path, ulong applicationId, out string errorMessage)
internal static (bool, ProcessResult) TryLoad<TMetaData, TFormat, THeader, TEntry>(this PartitionFileSystemCore<TMetaData, TFormat, THeader, TEntry> partitionFileSystem, Switch device, Stream stream, ulong applicationId, out string errorMessage, string extension, Stream updateStream = null)
where TMetaData : PartitionFileSystemMetaCore<TFormat, THeader, TEntry>, new()
where TFormat : IPartitionFileSystemFormat
where THeader : unmanaged, IPartitionFileSystemHeader
@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
return (false, ProcessResult.Failed);
}
(Nca updatePatchNca, Nca updateControlNca) = mainNca.GetUpdateData(device.FileSystem, device.System.FsIntegrityCheckLevel, device.Configuration.UserChannelPersistence.Index, out string _);
(Nca updatePatchNca, Nca updateControlNca) = mainNca.GetUpdateData(device.FileSystem, device.System.FsIntegrityCheckLevel, device.Configuration.UserChannelPersistence.Index, out string _, updateStream);
if (updatePatchNca != null)
{
@@ -131,7 +131,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
{
if (downloadableContentNca.Enabled)
{
device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, downloadableContentContainer.ContainerPath, downloadableContentNca.FullPath);
device.Configuration.ContentManager.AddAocItem(downloadableContentNca.TitleId, stream, downloadableContentNca.FullPath, System.IO.Path.GetExtension(downloadableContentContainer.ContainerPath));
}
}
else