From 300b23cf9bd71cf54b2ece693a806ce28beed534 Mon Sep 17 00:00:00 2001 From: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Date: Sat, 22 Jul 2023 07:27:13 +0200 Subject: [PATCH] Cleanup LibRyujinx and add more verbose logging --- src/LibRyujinx/Android/AndroidLogTarget.cs | 10 +- src/LibRyujinx/Android/JniExportedMethods.cs | 107 ++++++------ src/LibRyujinx/LibRyujinx.Device.cs | 8 +- src/LibRyujinx/LibRyujinx.Graphics.cs | 2 +- src/LibRyujinx/LibRyujinx.cs | 154 +++++++++++------- .../Configuration/AppDataManager.cs | 2 +- 6 files changed, 155 insertions(+), 128 deletions(-) diff --git a/src/LibRyujinx/Android/AndroidLogTarget.cs b/src/LibRyujinx/Android/AndroidLogTarget.cs index 937b02bf2..109886f82 100644 --- a/src/LibRyujinx/Android/AndroidLogTarget.cs +++ b/src/LibRyujinx/Android/AndroidLogTarget.cs @@ -1,10 +1,7 @@ -using Ryujinx.Common; -using Ryujinx.Common.Logging; +using Ryujinx.Common.Logging; using Ryujinx.Common.Logging.Formatters; using Ryujinx.Common.Logging.Targets; using System; -using System.IO; -using System.Linq; namespace LibRyujinx { @@ -26,7 +23,7 @@ namespace LibRyujinx Logcat.AndroidLogPrint(GetLogLevel(args.Level), _name, _formatter.Format(args)); } - private Logcat.LogLevel GetLogLevel(LogLevel logLevel) + private static Logcat.LogLevel GetLogLevel(LogLevel logLevel) { return logLevel switch { @@ -39,13 +36,14 @@ namespace LibRyujinx LogLevel.AccessLog => Logcat.LogLevel.Info, LogLevel.Notice => Logcat.LogLevel.Info, LogLevel.Trace => Logcat.LogLevel.Verbose, - _ => throw new NotImplementedException() + _ => throw new NotImplementedException(), }; } public void Dispose() { + GC.SuppressFinalize(this); } } } diff --git a/src/LibRyujinx/Android/JniExportedMethods.cs b/src/LibRyujinx/Android/JniExportedMethods.cs index f9bf65434..77f5518f9 100644 --- a/src/LibRyujinx/Android/JniExportedMethods.cs +++ b/src/LibRyujinx/Android/JniExportedMethods.cs @@ -1,27 +1,28 @@ -using System; -using System.Runtime.InteropServices; -using Ryujinx.Common.Configuration; -using System.Collections.Generic; +using LibRyujinx.Jni; using LibRyujinx.Jni.Pointers; +using LibRyujinx.Jni.Primitives; using LibRyujinx.Jni.References; using LibRyujinx.Jni.Values; -using LibRyujinx.Jni.Primitives; -using LibRyujinx.Jni; +using LibRyujinx.Shared.Audio.Oboe; +using Microsoft.Win32.SafeHandles; using Rxmxnx.PInvoke; -using System.Text; -using LibRyujinx.Jni.Internal.Pointers; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Logging.Targets; +using Ryujinx.Common.SystemInfo; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.Input; +using Silk.NET.Core.Loader; using Silk.NET.Vulkan; using Silk.NET.Vulkan.Extensions.KHR; -using LibRyujinx.Shared.Audio.Oboe; -using System.Threading; +using System; +using System.Collections.Generic; using System.IO; -using Microsoft.Win32.SafeHandles; -using Newtonsoft.Json.Linq; +using System.Numerics; +using System.Runtime.InteropServices; using System.Security.Cryptography; -using LibHac.Tools.Fs; -using Ryujinx.HLE.HOS.SystemState; +using System.Text; +using System.Threading; namespace LibRyujinx { @@ -53,9 +54,16 @@ namespace LibRyujinx [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_initialize")] public static JBoolean JniInitialize(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef jpath, JBoolean enableDebugLogs) { - var path = GetString(jEnv, jpath); + SystemInfo.IsBionic = true; - Ryujinx.Common.SystemInfo.SystemInfo.IsBionic = true; + Logger.AddTarget( + new AsyncLogTargetWrapper( + new AndroidLogTarget("Ryujinx"), + 1000, + AsyncLogTargetOverflowAction.Block + )); + + var path = GetString(jEnv, jpath); var init = Initialize(path, enableDebugLogs); @@ -63,17 +71,10 @@ namespace LibRyujinx _surfaceEvent = new ManualResetEvent(false); - Logger.AddTarget( - new AsyncLogTargetWrapper( - new AndroidLogTarget("Ryujinx"), - 1000, - AsyncLogTargetOverflowAction.Block - )); - return init; } - private static string GetString(JEnvRef jEnv, JStringLocalRef jString) + private static string? GetString(JEnvRef jEnv, JStringLocalRef jString) { var stringPtr = getStringPointer(jEnv, jString); @@ -179,7 +180,7 @@ namespace LibRyujinx var jobject = getObjectClass(jEnv, graphicObject); - GraphicsConfiguration graphicsConfiguration = new GraphicsConfiguration() + GraphicsConfiguration graphicsConfiguration = new() { EnableShaderCache = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableShaderCache"), GetCCharSequence("Z"))), EnableMacroHLE = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroHLE"), GetCCharSequence("Z"))), @@ -191,17 +192,17 @@ namespace LibRyujinx MaxAnisotropy = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("MaxAnisotropy"), GetCCharSequence("F"))), BackendThreading = (BackendThreading)(int)getIntField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("BackendThreading"), GetCCharSequence("I"))) }; - Silk.NET.Core.Loader.SearchPathContainer.Platform = Silk.NET.Core.Loader.UnderlyingPlatform.Android; + SearchPathContainer.Platform = UnderlyingPlatform.Android; return InitializeGraphics(graphicsConfiguration); } private static CCharSequence GetCCharSequence(string s) { - return (CCharSequence)Encoding.UTF8.GetBytes(s).AsSpan(); + return Encoding.UTF8.GetBytes(s).AsSpan(); } [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsSetSurface")] - public unsafe static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr) + public static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr) { _surfacePtr = surfacePtr; @@ -235,7 +236,7 @@ namespace LibRyujinx var getLongField = getLongFieldPtr.GetUnsafeDelegate(); var getObjectField = getObjectFieldPtr.GetUnsafeDelegate(); - List extensions = new List(); + List extensions = new(); var count = getArrayLength(jEnv, extensionsArray); @@ -249,9 +250,9 @@ namespace LibRyujinx _surfaceEvent.Set(); - _surfacePtr = (long)surfacePtr; + _surfacePtr = surfacePtr; - CreateSurface createSurfaceFunc = (IntPtr instance) => + CreateSurface createSurfaceFunc = instance => { _surfaceEvent.WaitOne(); _surfaceEvent.Reset(); @@ -259,10 +260,10 @@ namespace LibRyujinx var api = Vk.GetApi(); if (api.TryGetInstanceExtension(new Instance(instance), out KhrAndroidSurface surfaceExtension)) { - var createInfo = new AndroidSurfaceCreateInfoKHR() + var createInfo = new AndroidSurfaceCreateInfoKHR { SType = StructureType.AndroidSurfaceCreateInfoKhr, - Window = (nint*)_surfacePtr + Window = (nint*)_surfacePtr, }; var result = surfaceExtension.CreateAndroidSurface(new Instance(instance), createInfo, null, out var surface); @@ -296,9 +297,8 @@ namespace LibRyujinx [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfoFromPath")] public static JObjectLocalRef JniGetGameInfo(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef path) { - var info = GetGameInfo(GetString(jEnv, path)) ?? new GameInfo(); - SHA256 sha; - return GetInfo(jEnv, info, out sha); + var info = GetGameInfo(GetString(jEnv, path)); + return GetInfo(jEnv, info, out SHA256 _); } [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfo")] @@ -306,12 +306,11 @@ namespace LibRyujinx { using var stream = OpenFile(fileDescriptor); - var info = GetGameInfo(stream, isXci) ?? new GameInfo(); - SHA256 sha; - return GetInfo(jEnv, info, out sha); + var info = GetGameInfo(stream, isXci); + return GetInfo(jEnv, info, out SHA256 _); } - private static JObjectLocalRef GetInfo(JEnvRef jEnv, GameInfo info, out SHA256 sha) + private static JObjectLocalRef GetInfo(JEnvRef jEnv, GameInfo? info, out SHA256 sha) { var javaClassName = GetCCharSequence("org/ryujinx/android/viewmodels/GameInfo"); @@ -339,7 +338,7 @@ namespace LibRyujinx var constructor = getMethod(jEnv, javaClass, GetCCharSequence(""), GetCCharSequence("()V")); var newObj = newObject(jEnv, javaClass, constructor, 0); sha = SHA256.Create(); - var iconCacheByte = sha.ComputeHash(info.Icon ?? new byte[0]); + var iconCacheByte = sha.ComputeHash(info?.Icon ?? Array.Empty()); var iconCache = BitConverter.ToString(iconCacheByte).Replace("-", ""); var cacheDirectory = Path.Combine(AppDataManager.BaseDirPath, "iconCache"); @@ -348,21 +347,23 @@ namespace LibRyujinx var cachePath = Path.Combine(cacheDirectory, iconCache); if (!File.Exists(cachePath)) { - File.WriteAllBytes(cachePath, info.Icon ?? new byte[0]); + File.WriteAllBytes(cachePath, info?.Icon ?? Array.Empty()); } - setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleName"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info.TitleName)._value); - setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleId"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info.TitleId)._value); - setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Developer"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info.Developer)._value); - setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Version"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info.Version)._value); + setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleName"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.TitleName)._value); + setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleId"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.TitleId)._value); + setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Developer"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.Developer)._value); + setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Version"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, info?.Version)._value); setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("IconCache"), GetCCharSequence("Ljava/lang/String;")), CreateString(jEnv, iconCache)._value); - setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("FileSize"), GetCCharSequence("D")), info.FileSize); + setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("FileSize"), GetCCharSequence("D")), info?.FileSize ?? 0d); return newObj; } - private static JStringLocalRef CreateString(JEnvRef jEnv, string s) + private static JStringLocalRef CreateString(JEnvRef jEnv, string? s) { + s ??= string.Empty; + var ptr = Marshal.StringToHGlobalAnsi(s); var str = createString(jEnv, ptr); @@ -417,19 +418,19 @@ namespace LibRyujinx [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonPressed")] public static void JniSetButtonPressed(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JInt id) { - SetButtonPressed((Ryujinx.Input.GamepadButtonInputId)(int)button, id); + SetButtonPressed((GamepadButtonInputId)(int)button, id); } [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonReleased")] public static void JniSetButtonReleased(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JInt id) { - SetButtonReleased((Ryujinx.Input.GamepadButtonInputId)(int)button, id); + SetButtonReleased((GamepadButtonInputId)(int)button, id); } [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetStickAxis")] public static void JniSetStickAxis(JEnvRef jEnv, JObjectLocalRef jObj, JInt stick, JFloat x, JFloat y, JInt id) { - SetStickAxis((Ryujinx.Input.StickInputId)(int)stick, new System.Numerics.Vector2(x, y), id); + SetStickAxis((StickInputId)(int)stick, new Vector2(x, y), id); } [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputConnectGamepad")] @@ -438,7 +439,7 @@ namespace LibRyujinx return ConnectGamepad(index); } - private static Stream OpenFile(int descriptor) + private static FileStream OpenFile(int descriptor) { var safeHandle = new SafeFileHandle(descriptor, false); @@ -464,7 +465,7 @@ namespace LibRyujinx Warn = 0x05, Error = 0x06, Fatal = 0x07, - Silent = 0x08 + Silent = 0x08, } } } diff --git a/src/LibRyujinx/LibRyujinx.Device.cs b/src/LibRyujinx/LibRyujinx.Device.cs index cdd805172..fd7cc16fc 100644 --- a/src/LibRyujinx/LibRyujinx.Device.cs +++ b/src/LibRyujinx/LibRyujinx.Device.cs @@ -2,12 +2,8 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.SystemState; using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; namespace LibRyujinx { @@ -27,7 +23,7 @@ namespace LibRyujinx bool enableDockedMode, bool enablePtc, bool enableInternetAccess, - string timeZone, + string? timeZone, bool ignoreMissingServices) { if (SwitchDevice == null) @@ -66,7 +62,7 @@ namespace LibRyujinx return (isXci ? emulationContext?.LoadXci(stream) : emulationContext.LoadNsp(stream)) ?? false; } - public static bool LoadApplication(string path) + public static bool LoadApplication(string? path) { var emulationContext = SwitchDevice.EmulationContext; diff --git a/src/LibRyujinx/LibRyujinx.Graphics.cs b/src/LibRyujinx/LibRyujinx.Graphics.cs index cb0cb3624..21fc7ad51 100644 --- a/src/LibRyujinx/LibRyujinx.Graphics.cs +++ b/src/LibRyujinx/LibRyujinx.Graphics.cs @@ -78,7 +78,7 @@ namespace LibRyujinx return InitializeGraphicsRenderer(graphicsBackend, createSurfaceFunc, extensions.ToArray()); } - public static bool InitializeGraphicsRenderer(GraphicsBackend graphicsBackend, CreateSurface createSurfaceFunc, string[] requiredExtensions) + public static bool InitializeGraphicsRenderer(GraphicsBackend graphicsBackend, CreateSurface createSurfaceFunc, string?[] requiredExtensions) { if (Renderer != null) { diff --git a/src/LibRyujinx/LibRyujinx.cs b/src/LibRyujinx/LibRyujinx.cs index 235d3e4a4..c19f5f476 100644 --- a/src/LibRyujinx/LibRyujinx.cs +++ b/src/LibRyujinx/LibRyujinx.cs @@ -21,9 +21,6 @@ using LibHac.Common; using LibHac.Ns; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ui.App.Common; -using System.Text; -using System.Threading; using LibHac.Fs.Fsa; using LibHac.FsSystem; using LibHac.Fs; @@ -34,7 +31,6 @@ using Ryujinx.Common.Utilities; using System.Globalization; using Ryujinx.Ui.Common.Configuration.System; using Ryujinx.Common.Logging.Targets; -using Ryujinx.Common; namespace LibRyujinx { @@ -42,7 +38,7 @@ namespace LibRyujinx { internal static IHardwareDeviceDriver AudioDriver { get; set; } = new DummyHardwareDeviceDriver(); - private static readonly TitleUpdateMetadataJsonSerializerContext TitleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + private static readonly TitleUpdateMetadataJsonSerializerContext _titleSerializerContext = new(JsonHelper.GetDefaultSerializerOptions()); public static SwitchDevice? SwitchDevice { get; set; } [UnmanagedCallersOnly(EntryPoint = "initialize")] @@ -71,8 +67,6 @@ namespace LibRyujinx ConfigurationState.Initialize(); LoggerModule.Initialize(); - SwitchDevice = new SwitchDevice(); - Logger.SetEnable(LogLevel.Debug, enableDebugLogs); Logger.SetEnable(LogLevel.Stub, false); Logger.SetEnable(LogLevel.Info, true); @@ -80,18 +74,27 @@ namespace LibRyujinx Logger.SetEnable(LogLevel.Error, true); Logger.SetEnable(LogLevel.Trace, false); Logger.SetEnable(LogLevel.Guest, true); - Logger.SetEnable(LogLevel.AccessLog, false); - + Logger.SetEnable(LogLevel.AccessLog, false); + Logger.AddTarget(new AsyncLogTargetWrapper( new FileLogTarget(AppDataManager.BaseDirPath, "file"), 1000, AsyncLogTargetOverflowAction.Block )); + + Logger.Notice.Print(LogClass.Application, "Initializing..."); + Logger.Notice.Print(LogClass.Application, $"Using base path: {AppDataManager.BaseDirPath}"); + + SwitchDevice = new SwitchDevice(); } catch (Exception ex) { + Console.WriteLine(ex); return false; } + + Logger.Notice.Print(LogClass.Application, "RyujinxAndroid is ready!"); + return true; } @@ -107,7 +110,7 @@ namespace LibRyujinx var context = SwitchDevice.EmulationContext; - return new GameStats() + return new GameStats { Fifo = context.Statistics.GetFifoPercent(), GameFps = context.Statistics.GetGameFrameRate(), @@ -116,24 +119,37 @@ namespace LibRyujinx } - public static GameInfo GetGameInfo(string file) + public static GameInfo? GetGameInfo(string? file) { + if (string.IsNullOrWhiteSpace(file)) + { + return new GameInfo(); + } + + Logger.Info?.Print(LogClass.Application, $"Getting game info for file: {file}"); + using var stream = File.Open(file, FileMode.Open); return GetGameInfo(stream, file.ToLower().EndsWith("xci")); } - public static GameInfo GetGameInfo(Stream gameStream, bool isXci) + public static GameInfo? GetGameInfo(Stream gameStream, bool isXci) { - var gameInfo = new GameInfo(); - gameInfo.FileSize = gameStream.Length * 0.000000000931; - gameInfo.TitleName = "Unknown"; - gameInfo.TitleId = "0000000000000000"; - gameInfo.Developer = "Unknown"; - gameInfo.Version = "0"; - gameInfo.Icon = null; + if (SwitchDevice == null) + { + Logger.Error?.Print(LogClass.Application, "SwitchDevice is not initialized."); + return null; + } - Language titleLanguage = Language.AmericanEnglish; + var gameInfo = new GameInfo + { + FileSize = gameStream.Length * 0.000000000931, TitleName = "Unknown", TitleId = "0000000000000000", + Developer = "Unknown", + Version = "0", + Icon = null, + }; + + const Language TitleLanguage = Language.AmericanEnglish; BlitStruct controlHolder = new(1); @@ -205,13 +221,12 @@ namespace LibRyujinx } else { - var id = gameInfo.TitleId; - GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out id); + GetControlFsAndTitleId(pfs, out IFileSystem? controlFs, out string? id); gameInfo.TitleId = id; // Check if there is an update available. - if (IsUpdateApplied(gameInfo.TitleId, out IFileSystem updatedControlFs)) + if (IsUpdateApplied(gameInfo.TitleId, out IFileSystem? updatedControlFs)) { // Replace the original ControlFs by the updated one. controlFs = updatedControlFs; @@ -226,7 +241,7 @@ namespace LibRyujinx { using UniqueRef icon = new(); - controlFs.OpenFile(ref icon.Ref, $"/icon_{titleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + controlFs?.OpenFile(ref icon.Ref, $"/icon_{TitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); using MemoryStream stream = new(); @@ -244,7 +259,7 @@ namespace LibRyujinx using var icon = new UniqueRef(); - controlFs.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + controlFs?.OpenFile(ref icon.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); using MemoryStream stream = new(); @@ -264,10 +279,9 @@ namespace LibRyujinx { Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); } - catch (InvalidDataException) + catch (InvalidDataException exception) { - - Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. "); + Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. {exception}"); } catch (Exception exception) { @@ -281,17 +295,17 @@ namespace LibRyujinx Logger.Warning?.Print(LogClass.Application, exception.Message); } - void ReadControlData(IFileSystem controlFs, Span outProperty) + void ReadControlData(IFileSystem? controlFs, Span outProperty) { using UniqueRef controlFile = new(); - controlFs.OpenFile(ref controlFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); + controlFs?.OpenFile(ref controlFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); controlFile.Get.Read(out _, 0, outProperty, ReadOption.None).ThrowIfFailure(); } - void GetGameInformation(ref ApplicationControlProperty controlData, out string titleName, out string titleId, out string publisher, out string version) + void GetGameInformation(ref ApplicationControlProperty controlData, out string? titleName, out string titleId, out string? publisher, out string? version) { - _ = Enum.TryParse(titleLanguage.ToString(), out TitleLanguage desiredTitleLanguage); + _ = Enum.TryParse(TitleLanguage.ToString(), out TitleLanguage desiredTitleLanguage); if (controlData.Title.ItemsRo.Length > (int)desiredTitleLanguage) { @@ -350,20 +364,28 @@ namespace LibRyujinx version = controlData.DisplayVersionString.ToString(); } - void GetControlFsAndTitleId(PartitionFileSystem pfs, out IFileSystem controlFs, out string titleId) + void GetControlFsAndTitleId(PartitionFileSystem pfs, out IFileSystem? controlFs, out string? titleId) { - (_, _, Nca controlNca) = GetGameData(SwitchDevice.VirtualFileSystem, pfs, 0); + if (SwitchDevice == null) + { + Logger.Error?.Print(LogClass.Application, "SwitchDevice is not initialized."); + + controlFs = null; + titleId = null; + return; + } + (_, _, Nca? controlNca) = GetGameData(SwitchDevice.VirtualFileSystem, pfs, 0); // Return the ControlFS controlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); titleId = controlNca?.Header.TitleId.ToString("x16"); } - (Nca main, Nca patch, Nca control) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex) + (Nca? mainNca, Nca? patchNca, Nca? controlNca) GetGameData(VirtualFileSystem fileSystem, PartitionFileSystem pfs, int programIndex) { - Nca mainNca = null; - Nca patchNca = null; - Nca controlNca = null; + Nca? mainNca = null; + Nca? patchNca = null; + Nca? controlNca = null; fileSystem.ImportTickets(pfs); @@ -371,9 +393,11 @@ namespace LibRyujinx { using var ncaFile = new UniqueRef(); + Logger.Info?.Print(LogClass.Application, $"Loading file from PFS: {fileEntry.FullPath}"); + pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - Nca nca = new Nca(fileSystem.KeySet, ncaFile.Release().AsStorage()); + Nca nca = new(fileSystem.KeySet, ncaFile.Release().AsStorage()); int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF); @@ -404,22 +428,28 @@ namespace LibRyujinx return (mainNca, patchNca, controlNca); } - bool IsUpdateApplied(string titleId, out IFileSystem updatedControlFs) + bool IsUpdateApplied(string? titleId, out IFileSystem? updatedControlFs) { updatedControlFs = null; - string updatePath = "(unknown)"; + string? updatePath = "(unknown)"; + + if (SwitchDevice?.VirtualFileSystem == null) + { + Logger.Error?.Print(LogClass.Application, "SwitchDevice was not initialized."); + return false; + } try { - (Nca patchNca, Nca controlNca) = GetGameUpdateData(SwitchDevice.VirtualFileSystem, titleId, 0, out updatePath); + (Nca? patchNca, Nca? controlNca) = GetGameUpdateData(SwitchDevice.VirtualFileSystem, titleId, 0, out updatePath); if (patchNca != null && controlNca != null) { - updatedControlFs = controlNca?.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); - - return true; + updatedControlFs = controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None); } + + return true; } catch (InvalidDataException) { @@ -433,7 +463,7 @@ namespace LibRyujinx return false; } - (Nca patch, Nca control) GetGameUpdateData(VirtualFileSystem fileSystem, string titleId, int programIndex, out string updatePath) + (Nca? patch, Nca? control) GetGameUpdateData(VirtualFileSystem fileSystem, string? titleId, int programIndex, out string? updatePath) { updatePath = null; @@ -447,12 +477,12 @@ namespace LibRyujinx if (File.Exists(titleUpdateMetadataPath)) { - updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, TitleSerializerContext.TitleUpdateMetadata).Selected; + updatePath = JsonHelper.DeserializeFromFile(titleUpdateMetadataPath, _titleSerializerContext.TitleUpdateMetadata).Selected; if (File.Exists(updatePath)) { - FileStream file = new FileStream(updatePath, FileMode.Open, FileAccess.Read); - PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); + FileStream file = new(updatePath, FileMode.Open, FileAccess.Read); + PartitionFileSystem nsp = new(file.AsStorage()); return GetGameUpdateDataFromPartition(fileSystem, nsp, titleIdBase.ToString("x16"), programIndex); } @@ -462,10 +492,10 @@ namespace LibRyujinx return (null, null); } - (Nca patch, Nca control) GetGameUpdateDataFromPartition(VirtualFileSystem fileSystem, PartitionFileSystem pfs, string titleId, int programIndex) + (Nca? patchNca, Nca? controlNca) GetGameUpdateDataFromPartition(VirtualFileSystem fileSystem, PartitionFileSystem pfs, string titleId, int programIndex) { - Nca patchNca = null; - Nca controlNca = null; + Nca? patchNca = null; + Nca? controlNca = null; fileSystem.ImportTickets(pfs); @@ -475,7 +505,7 @@ namespace LibRyujinx pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - Nca nca = new Nca(fileSystem.KeySet, ncaFile.Release().AsStorage()); + Nca nca = new(fileSystem.KeySet, ncaFile.Release().AsStorage()); int ncaProgramIndex = (int)(nca.Header.TitleId & 0xF); @@ -518,7 +548,9 @@ namespace LibRyujinx public void Dispose() { - VirtualFileSystem?.Dispose(); + GC.SuppressFinalize(this); + + VirtualFileSystem.Dispose(); InputManager?.Dispose(); EmulationContext?.Dispose(); } @@ -546,7 +578,7 @@ namespace LibRyujinx bool enableDockedMode, bool enablePtc, bool enableInternetAccess, - string timeZone, + string? timeZone, bool ignoreMissingServices) { if (LibRyujinx.Renderer == null) @@ -605,11 +637,11 @@ namespace LibRyujinx public class GameInfo { public double FileSize; - public string TitleName; - public string TitleId; - public string Developer; - public string Version; - public byte[] Icon; + public string? TitleName; + public string? TitleId; + public string? Developer; + public string? Version; + public byte[]? Icon; } public class GameStats @@ -618,4 +650,4 @@ namespace LibRyujinx public double GameFps; public double GameTime; } -} \ No newline at end of file +} diff --git a/src/Ryujinx.Common/Configuration/AppDataManager.cs b/src/Ryujinx.Common/Configuration/AppDataManager.cs index 8a226d9ab..e91295331 100644 --- a/src/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/src/Ryujinx.Common/Configuration/AppDataManager.cs @@ -127,7 +127,7 @@ namespace Ryujinx.Common.Configuration } // Check if existing old baseDirPath is a symlink, to prevent possible errors. - // Should be removed, when the existance of the old directory isn't checked anymore. + // Should be removed, when the existence of the old directory isn't checked anymore. private static bool IsPathSymlink(string path) { FileAttributes attributes = File.GetAttributes(path);