diff --git a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs index 99e4dc078..7339d725c 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs @@ -19,6 +19,7 @@ using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Utilities; using Ryujinx.UI.Common.Configuration; using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Common.Models; using System; using System.Collections.Generic; using System.IO; @@ -29,6 +30,7 @@ using System.Text.Json; using System.Threading; using ContentType = LibHac.Ncm.ContentType; using Path = System.IO.Path; +using SpanHelpers = LibHac.Common.SpanHelpers; using TimeSpan = System.TimeSpan; namespace Ryujinx.UI.App.Common @@ -477,7 +479,7 @@ namespace Ryujinx.UI.App.Common return true; } - public bool TryGetDownloadableContentFromFile(string filePath, out List<(ulong TitleId, string ContainerPath, string FullPath)> titleUpdates) + public bool TryGetDownloadableContentFromFile(string filePath, out List titleUpdates) { titleUpdates = []; @@ -512,7 +514,7 @@ namespace Ryujinx.UI.App.Common if (nca.Header.ContentType == NcaContentType.PublicData) { - titleUpdates.Add((nca.Header.TitleId, filePath, fileEntry.FullPath)); + titleUpdates.Add(new DownloadableContentModel(nca.Header.TitleId, filePath, fileEntry.FullPath, false)); } } @@ -539,7 +541,7 @@ namespace Ryujinx.UI.App.Common return false; } - public bool TryGetTitleUpdatesFromFile(string filePath, out List<(ulong, string)> titleUpdates) + public bool TryGetTitleUpdatesFromFile(string filePath, out List titleUpdates) { titleUpdates = []; @@ -557,17 +559,43 @@ namespace Ryujinx.UI.App.Common IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; - - using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem); - Dictionary updates = pfs.GetContentData(ContentMetaType.Patch, _virtualFileSystem, checkLevel); + using IFileSystem pfs = + PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem); + + Dictionary updates = + pfs.GetContentData(ContentMetaType.Patch, _virtualFileSystem, checkLevel); + if (updates.Count == 0) { return false; } - titleUpdates.AddRange(updates.Select(it => (it.Key, filePath))); + foreach ((_, ContentMetaData content) in updates) + { + Nca patchNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Program); + Nca controlNca = content.GetNcaByType(_virtualFileSystem.KeySet, ContentType.Control); + if (controlNca != null && patchNca != null) + { + ApplicationControlProperty controlData = new(); + + using UniqueRef nacpFile = new(); + + controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None) + .OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read) + .ThrowIfFailure(); + nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), + ReadOption.None).ThrowIfFailure(); + + var displayVersion = controlData.DisplayVersionString.ToString(); + var update = new TitleUpdateModel(content.ApplicationId, content.Version.Version, + displayVersion, filePath); + + titleUpdates.Add(update); + } + } + return true; } } @@ -729,7 +757,6 @@ namespace Ryujinx.UI.App.Common public void LoadDownloadableContents(List appDirs) { - // Logger.Warning?.Print(LogClass.Application, "JIMMY load DLC"); _cancellationToken = new CancellationTokenSource(); // Builds the applications list with paths to found applications @@ -806,15 +833,13 @@ namespace Ryujinx.UI.App.Common return; } - if (TryGetDownloadableContentFromFile(applicationPath, out List<(ulong, string, string)> applications)) + if (TryGetDownloadableContentFromFile(applicationPath, out List downloadableContents)) { - foreach (var application in applications) + foreach (var downloadableContent in downloadableContents) { OnDownloadableContentAdded(new DownloadableContentAddedEventArgs { - TitleId = application.Item1, - ContainerFilePath = application.Item2, - NcaPath = application.Item3 + DownloadableContent = downloadableContent, }); } } @@ -830,7 +855,6 @@ namespace Ryujinx.UI.App.Common public void LoadTitleUpdates(List appDirs) { - // Logger.Warning?.Print(LogClass.Application, "JIMMY title updates"); _cancellationToken = new CancellationTokenSource(); // Builds the applications list with paths to found applications @@ -908,15 +932,13 @@ namespace Ryujinx.UI.App.Common return; } - if (TryGetTitleUpdatesFromFile(applicationPath, - out List<(ulong, string)> titleUpdates)) + if (TryGetTitleUpdatesFromFile(applicationPath, out List titleUpdates)) { - foreach (var application in titleUpdates) + foreach (var titleUpdate in titleUpdates) { OnTitleUpdateAdded(new TitleUpdateAddedEventArgs() { - TitleId = application.Item1, - FilePath = application.Item2, + TitleUpdate = titleUpdate, }); } } diff --git a/src/Ryujinx.UI.Common/App/DownloadableContentAddedEventArgs.cs b/src/Ryujinx.UI.Common/App/DownloadableContentAddedEventArgs.cs index ebf70b8a3..f81caa62b 100644 --- a/src/Ryujinx.UI.Common/App/DownloadableContentAddedEventArgs.cs +++ b/src/Ryujinx.UI.Common/App/DownloadableContentAddedEventArgs.cs @@ -1,11 +1,10 @@ +using Ryujinx.UI.Common.Models; using System; namespace Ryujinx.UI.App.Common { public class DownloadableContentAddedEventArgs : EventArgs { - public ulong TitleId { get; set; } - public string ContainerFilePath { get; set; } - public string NcaPath { get; set; } + public DownloadableContentModel DownloadableContent { get; set; } } } diff --git a/src/Ryujinx.UI.Common/App/TitleUpdateAddedEventArgs.cs b/src/Ryujinx.UI.Common/App/TitleUpdateAddedEventArgs.cs index e28e3cc3c..bb266d639 100644 --- a/src/Ryujinx.UI.Common/App/TitleUpdateAddedEventArgs.cs +++ b/src/Ryujinx.UI.Common/App/TitleUpdateAddedEventArgs.cs @@ -1,10 +1,10 @@ +using Ryujinx.UI.Common.Models; using System; namespace Ryujinx.UI.App.Common { public class TitleUpdateAddedEventArgs : EventArgs { - public ulong TitleId { get; set; } - public string FilePath { get; set; } + public TitleUpdateModel TitleUpdate { get; set; } } } diff --git a/src/Ryujinx.UI.Common/Models/DownloadableContentModel.cs b/src/Ryujinx.UI.Common/Models/DownloadableContentModel.cs index 6668fb212..cea338592 100644 --- a/src/Ryujinx.UI.Common/Models/DownloadableContentModel.cs +++ b/src/Ryujinx.UI.Common/Models/DownloadableContentModel.cs @@ -10,6 +10,7 @@ namespace Ryujinx.UI.Common.Models public string FileName => System.IO.Path.GetFileName(ContainerPath); public string TitleIdStr => TitleId.ToString("X16"); + public ulong TitleIdBase => TitleId & ~0x1FFFUL; public DownloadableContentModel(ulong titleId, string containerPath, string fullPath, bool enabled) { diff --git a/src/Ryujinx.UI.Common/Models/TitleUpdateModel.cs b/src/Ryujinx.UI.Common/Models/TitleUpdateModel.cs index 259a623f6..2f89d16b3 100644 --- a/src/Ryujinx.UI.Common/Models/TitleUpdateModel.cs +++ b/src/Ryujinx.UI.Common/Models/TitleUpdateModel.cs @@ -9,6 +9,7 @@ namespace Ryujinx.UI.Common.Models public bool IsBundled { get; } public string TitleIdStr => TitleId.ToString("X16"); + public ulong TitleIdBase => TitleId & ~0x1FFFUL; public TitleUpdateModel(ulong titleId, ulong version, string displayVersion, string path) { diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index 884b717c7..b59bf5009 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -146,12 +146,14 @@ namespace Ryujinx.Ava.UI.Windows private void ApplicationLibrary_DownloadableContentAdded(object sender, DownloadableContentAddedEventArgs e) { - // Console.WriteLine("[{0}]: {1} ({2})", e.TitleId, e.ContainerFilePath, e.NcaPath); + var it = e.DownloadableContent; + Console.WriteLine("[{0}]: {1} ({2})", it.TitleIdBase, it.ContainerPath, it.FullPath); } private void ApplicationLibrary_TitleUpdateAdded(object sender, TitleUpdateAddedEventArgs e) { - // Console.WriteLine("[{0}]: {1}", e.TitleId, e.FilePath); + var it = e.TitleUpdate; + Console.WriteLine("[{0}]: {1}", it.TitleIdBase, it.Path); } private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e)