Compare commits

...

3 Commits

Author SHA1 Message Date
Evan Husted
315a1819c0 Attempt #2 2024-12-07 05:31:37 -06:00
Evan Husted
4ffb8aef12 Try and fix nullref 2024-12-07 05:21:16 -06:00
Evan Husted
290a6ad5de HLE: extract custom NACP data functionality into a static helper for generic reuse elsewhere, and clarify magic numbers. 2024-12-07 04:30:04 -06:00
4 changed files with 57 additions and 29 deletions

View File

@@ -0,0 +1,37 @@
using LibHac.Common;
using LibHac.Ns;
using System;
using System.Text;
namespace Ryujinx.HLE
{
public static class StructHelpers
{
public static BlitStruct<ApplicationControlProperty> CreateCustomNacpData(string name, string version)
{
// https://switchbrew.org/wiki/NACP
const int OffsetOfDisplayVersion = 0x3060;
// https://switchbrew.org/wiki/NACP#ApplicationTitle
const int TotalApplicationTitles = 0x10;
const int SizeOfApplicationTitle = 0x300;
const int OffsetOfApplicationPublisherStrings = 0x200;
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
// name and publisher buffer
// repeat once for each locale (the ApplicationControlProperty has 16 locales)
for (int i = 0; i < TotalApplicationTitles; i++)
{
Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle)..]);
"Ryujinx"u8.CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle + OffsetOfApplicationPublisherStrings)..]);
}
// version buffer
Encoding.ASCII.GetBytes(version).AsSpan().CopyTo(nacpData.ByteSpan[OffsetOfDisplayVersion..]);
return nacpData;
}
}
}

View File

@@ -1079,14 +1079,15 @@ namespace Ryujinx.UI.App.Common
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
{
if (update == null) return false;
var currentlySelected = TitleUpdates.Items.FindFirst(it =>
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
var shouldSelect = !currentlySelected.HasValue ||
currentlySelected.Value.TitleUpdate.Version < update.Version;
var shouldSelect = currentlySelected.Check(curr => curr.TitleUpdate?.Version < update.Version);
_titleUpdates.AddOrUpdate((update, shouldSelect));
if (currentlySelected.HasValue && shouldSelect)
{
_titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false));
@@ -1478,7 +1479,7 @@ namespace Ryujinx.UI.App.Common
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates))
{
var savedUpdateLookup = savedUpdates.Select(update => update.Item1).ToHashSet();
var savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet();
bool updatesChanged = false;
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
@@ -1486,11 +1487,10 @@ namespace Ryujinx.UI.App.Common
if (!savedUpdateLookup.Contains(update))
{
bool shouldSelect = false;
if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version)
if (selectedUpdate.Check(su => su.Update?.Version < update.Version))
{
shouldSelect = true;
if (selectedUpdate)
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Item1, false));
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Update, false));
selectedUpdate = (update, true);
}

View File

@@ -28,7 +28,7 @@ namespace Ryujinx.UI.Common.Helper
{
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
{
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
@@ -77,7 +77,7 @@ namespace Ryujinx.UI.Common.Helper
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
}
private static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
{
var result = new List<(TitleUpdateModel, bool IsSelected)>();

View File

@@ -13,6 +13,7 @@ using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
@@ -126,32 +127,22 @@ namespace Ryujinx.Ava.UI.Views.Main
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
{
const string name = "miiEdit";
const ulong programId = 0x0100000000001009;
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(programId, StorageId.BuiltInSystem, NcaContentType.Program);
const string AppletName = "miiEdit";
const ulong AppletProgramId = 0x0100000000001009;
const string AppletVersion = "1.0.0";
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(AppletProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
if (!string.IsNullOrEmpty(contentPath))
{
ApplicationData applicationData = new()
{
Name = name,
Id = programId,
Path = contentPath,
Name = AppletName,
Id = AppletProgramId,
Path = contentPath
};
string version = "1.0.0";
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
//version buffer
Encoding.ASCII.GetBytes(version).AsSpan().CopyTo(nacpData.ByteSpan.Slice(0x3060));
//name and distributor buffer
//repeat once for each locale (the ApplicationControlProperty has 16 locales)
for (int i = 0; i < 0x10; i++)
{
Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(nacpData.ByteSpan.Slice(i * 0x300));
"Ryujinx"u8.ToArray().AsSpan().CopyTo(nacpData.ByteSpan.Slice(i * 0x300 + 0x200));
}
var nacpData = StructHelpers.CreateCustomNacpData(AppletName, AppletVersion);
await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
}