aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs')
-rw-r--r--src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs77
1 files changed, 50 insertions, 27 deletions
diff --git a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
index 5989ce09..6c38edb3 100644
--- a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs
@@ -1,4 +1,3 @@
-using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform.Storage;
@@ -6,7 +5,7 @@ using Avalonia.Threading;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
-using LibHac.FsSystem;
+using LibHac.Ncm;
using LibHac.Ns;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
@@ -17,12 +16,17 @@ using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
+using Ryujinx.HLE.Loaders.Processes.Extensions;
+using Ryujinx.HLE.Utilities;
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,38 +169,54 @@ 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))
+ if (!File.Exists(path) || TitleUpdates.Any(x => x.Path == path))
+ {
+ return;
+ }
+
+ IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
+ ? IntegrityCheckLevel.ErrorOnInvalid
+ : IntegrityCheckLevel.None;
+
+ try
{
- using FileStream file = new(path, FileMode.Open, FileAccess.Read);
+ using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(path, VirtualFileSystem);
+
+ Dictionary<ulong, ContentMetaData> updates = pfs.GetContentData(ContentMetaType.Patch, VirtualFileSystem, checkLevel);
+
+ Nca patchNca = null;
+ Nca controlNca = null;
- try
+ if (updates.TryGetValue(ApplicationData.Id, out ContentMetaData content))
{
- var pfs = new PartitionFileSystem();
- pfs.Initialize(file.AsStorage()).ThrowIfFailure();
- (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0);
+ patchNca = content.GetNcaByType(VirtualFileSystem.KeySet, ContentType.Program);
+ controlNca = content.GetNcaByType(VirtualFileSystem.KeySet, ContentType.Control);
+ }
- if (controlNca != null && patchNca != null)
- {
- ApplicationControlProperty controlData = new();
+ if (controlNca != null && patchNca != null)
+ {
+ ApplicationControlProperty controlData = new();
- using UniqueRef<IFile> nacpFile = new();
+ using UniqueRef<IFile> 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();
+ 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();
- TitleUpdates.Add(new TitleUpdateModel(controlData, path));
- }
- else
+ TitleUpdates.Add(new TitleUpdateModel(controlData, path));
+ }
+ else
+ {
+ if (!ignoreNotFound)
{
Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage]));
}
}
- catch (Exception ex)
- {
- Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, ex.Message, path)));
- }
+ }
+ catch (Exception ex)
+ {
+ Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, ex.Message, path)));
}
}