diff options
| author | TSRBerry <20988865+TSRBerry@users.noreply.github.com> | 2023-11-11 21:56:57 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-11 21:56:57 +0100 |
| commit | 5c3cfb84c09b0566da677425915afa0b2d76da55 (patch) | |
| tree | d53c683c3ed3e685bec5b16ca661755d8815f66e /src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs | |
| parent | 55557525b16f8256d91f769e026874b5c70c3b2d (diff) | |
Add support for multi game XCIs (#5638)
* Add default values to ApplicationData directly
* Refactor application loading
It should now be possible to load multi game XCIs.
Included updates won't be detected for now.
Opening a game from the command line currently only opens the first one.
* Only include program NCAs where at least one tuple item is not null
* Get application data by title id and add programIndex check back
* Refactor application loading again and remove duplicate code
* Actually use patch ncas for updates
* Fix number of applications found with multi game xcis
* Don't load bundled updates from multi game xcis
* Change ApplicationData.TitleId type to ulong & Add TitleIdString property
* Use cnmt files and ContentCollection to load programs
* Ava: Add updates and DLCs from gamecarts
* Get the cnmt file from its NCA
* Ava: Identify bundled updates in updater window
* Fix the (hopefully) last few bugs
* Add idOffset parameter to GetNcaByType
* Handle missing file for dlc.json
* Ava: Shorten error message for invalid files
* Gtk: Add additional string for bundled updates in TitleUpdateWindow
* Hopefully fix DLC issues
* Apply formatting
* Finally fix DLC issues
* Adjust property names and fileSize field
* Read the correct update file
* Fix wrong casing for application id strings
* Rename TitleId to ApplicationId
* Address review comments
* Fix formatting issues
* Apply suggestions from code review
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
* Gracefully fail when loading pfs for update and dlc window
* Fix applications with multiple programs
* Fix DLCWindow crash on GTK
* Fix some GUI issues
* Remove IsXci again
---------
Co-authored-by: gdkchan <gab.dark.100@gmail.com>
Diffstat (limited to 'src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs')
| -rw-r--r-- | src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs index 5090a8c7..7bb96131 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs @@ -1,4 +1,3 @@ -using Avalonia; using Avalonia.Collections; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; @@ -8,6 +7,7 @@ using LibHac.Fs; using LibHac.Fs.Fsa; using LibHac.FsSystem; using LibHac.Ns; +using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Ava.Common.Locale; @@ -17,12 +17,16 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.Ui.App.Common; +using Ryujinx.Ui.Common.Configuration; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Application = Avalonia.Application; +using ContentType = LibHac.Ncm.ContentType; using Path = System.IO.Path; using SpanHelpers = LibHac.Common.SpanHelpers; @@ -33,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels public TitleUpdateMetadata TitleUpdateWindowData; public readonly string TitleUpdateJsonPath; private VirtualFileSystem VirtualFileSystem { get; } - private ulong TitleId { get; } + private ApplicationData ApplicationData { get; } private AvaloniaList<TitleUpdateModel> _titleUpdates = new(); private AvaloniaList<object> _views = new(); @@ -73,18 +77,18 @@ namespace Ryujinx.Ava.UI.ViewModels public IStorageProvider StorageProvider; - public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) + public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ApplicationData applicationData) { VirtualFileSystem = virtualFileSystem; - TitleId = titleId; + ApplicationData = applicationData; if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { StorageProvider = desktop.MainWindow.StorageProvider; } - TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); + TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, ApplicationData.IdString, "updates.json"); try { @@ -92,7 +96,7 @@ namespace Ryujinx.Ava.UI.ViewModels } catch { - Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {TitleId} at {TitleUpdateJsonPath}"); + Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {ApplicationData.IdString} at {TitleUpdateJsonPath}"); TitleUpdateWindowData = new TitleUpdateMetadata { @@ -108,6 +112,9 @@ namespace Ryujinx.Ava.UI.ViewModels private void LoadUpdates() { + // Try to load updates from PFS first + AddUpdate(ApplicationData.Path, true); + foreach (string path in TitleUpdateWindowData.Paths) { AddUpdate(path); @@ -162,17 +169,41 @@ namespace Ryujinx.Ava.UI.ViewModels } } - private void AddUpdate(string path) + private void AddUpdate(string path, bool ignoreNotFound = false) { if (File.Exists(path) && TitleUpdates.All(x => x.Path != path)) { + IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + using FileStream file = new(path, FileMode.Open, FileAccess.Read); + IFileSystem pfs; + try { - var pfs = new PartitionFileSystem(); - pfs.Initialize(file.AsStorage()).ThrowIfFailure(); - (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0); + if (Path.GetExtension(path).ToLower() == ".xci") + { + pfs = new Xci(VirtualFileSystem.KeySet, file.AsStorage()).OpenPartition(XciPartitionType.Secure); + } + else + { + var pfsTemp = new PartitionFileSystem(); + pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure(); + pfs = pfsTemp; + } + + Dictionary<ulong, ContentCollection> updates = pfs.GetUpdateData(VirtualFileSystem, checkLevel); + + Nca patchNca = null; + Nca controlNca = null; + + if (updates.TryGetValue(ApplicationData.Id, out ContentCollection content)) + { + patchNca = content.GetNcaByType(VirtualFileSystem.KeySet, ContentType.Program); + controlNca = content.GetNcaByType(VirtualFileSystem.KeySet, ContentType.Control); + } if (controlNca != null && patchNca != null) { @@ -187,7 +218,10 @@ namespace Ryujinx.Ava.UI.ViewModels } else { - Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage])); + if (!ignoreNotFound) + { + Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage])); + } } } catch (Exception ex) |
