diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 1e218c87d7..c665a2ddb1 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -1,8 +1,10 @@ using LibHac; +using LibHac.Common; using LibHac.Fs; using LibHac.FsService; using LibHac.FsSystem; using LibHac.FsSystem.NcaUtils; +using LibHac.Ns; using LibHac.Spl; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem.Content; @@ -103,7 +105,7 @@ namespace Ryujinx.HLE.HOS private bool _hasStarted; - public Nacp ControlData { get; set; } + public BlitStruct ControlData { get; set; } public string CurrentTitle { get; private set; } @@ -118,11 +120,13 @@ namespace Ryujinx.HLE.HOS internal long HidBaseAddress { get; private set; } internal FileSystemServer FsServer { get; private set; } + internal FileSystemClient FsClient { get; private set; } + internal EmulatedGameCard GameCard { get; private set; } public Horizon(Switch device) { - ControlData = new Nacp(); + ControlData = new BlitStruct(1); Device = device; @@ -247,6 +251,7 @@ namespace Ryujinx.HLE.HOS }; FsServer = new FileSystemServer(fsServerConfig); + FsClient = FsServer.CreateFileSystemClient(); } public void LoadCart(string exeFsDir, string romFsFile = null) @@ -364,9 +369,13 @@ namespace Ryujinx.HLE.HOS if (result.IsSuccess()) { - ControlData = new Nacp(controlFile.AsStream()); + result = controlFile.Read(out long bytesRead, 0, ControlData.ByteSpan, ReadOption.None); - TitleName = CurrentTitle = ControlData.Descriptions[(int) State.DesiredTitleLanguage].Title; + if (result.IsSuccess() && bytesRead == ControlData.ByteSpan.Length) + { + TitleName = CurrentTitle = ControlData.Value + .GetTitles()[(int) State.DesiredTitleLanguage].Name.ToString(); + } } } @@ -615,28 +624,28 @@ namespace Ryujinx.HLE.HOS if (nacpSize != 0) { input.Seek(obj.FileSize + (long)nacpOffset, SeekOrigin.Begin); - using (MemoryStream stream = new MemoryStream(reader.ReadBytes((int)nacpSize))) - { - ControlData = new Nacp(stream); - } - metaData.TitleName = ControlData.Descriptions[(int)State.DesiredTitleLanguage].Title; + reader.Read(ControlData.ByteSpan); + + ref ApplicationControlProperty nacp = ref ControlData.Value; + + metaData.TitleName = nacp.GetTitles()[(int)State.DesiredTitleLanguage].Name.ToString(); if (string.IsNullOrWhiteSpace(metaData.TitleName)) { - metaData.TitleName = ControlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; + metaData.TitleName = nacp.GetTitles().ToArray().FirstOrDefault(x => x.Name[0] != 0).ToString(); } - metaData.Aci0.TitleId = ControlData.PresenceGroupId; + metaData.Aci0.TitleId = nacp.PresenceGroupId; if (metaData.Aci0.TitleId == 0) { - metaData.Aci0.TitleId = ControlData.SaveDataOwnerId; + metaData.Aci0.TitleId = nacp.SaveDataOwnerId.Value; } if (metaData.Aci0.TitleId == 0) { - metaData.Aci0.TitleId = ControlData.AddOnContentBaseId - 0x1000; + metaData.Aci0.TitleId = nacp.AddOnContentBaseId - 0x1000; } if (metaData.Aci0.TitleId.ToString("x16") == "fffffffffffff000") diff --git a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs index f8e6b22a5d..ec26d11faf 100644 --- a/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs +++ b/Ryujinx.HLE/HOS/Services/Account/Acc/IAccountServiceForApplication.cs @@ -287,7 +287,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc // Account actually calls nn::arp::detail::IReader::GetApplicationControlProperty() with the current PID and store the result (NACP File) internally. // But since we use LibHac and we load one Application at a time, it's not necessary. - context.ResponseData.Write(context.Device.System.ControlData.UserAccountSwitchLock); + context.ResponseData.Write(context.Device.System.ControlData.Value.UserAccountSwitchLock); Logger.PrintStub(LogClass.ServiceAcc); diff --git a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 464d0b47b0..51c057f2c3 100644 --- a/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -1,13 +1,18 @@ +using LibHac; +using LibHac.Account; +using LibHac.Ncm; +using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Ipc; using Ryujinx.HLE.HOS.Kernel.Common; using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage; using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService; using Ryujinx.HLE.Utilities; using System; +using static LibHac.Fs.ApplicationSaveDataManagement; + namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy { class IApplicationFunctions : IpcService @@ -24,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati public ResultCode PopLaunchParameter(ServiceCtx context) { // Only the first 0x18 bytes of the Data seems to be actually used. - MakeObject(context, new IStorage(StorageHelper.MakeLaunchParams())); + MakeObject(context, new AppletAE.IStorage(StorageHelper.MakeLaunchParams())); return ResultCode.Success; } @@ -33,13 +38,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati // EnsureSaveData(nn::account::Uid) -> u64 public ResultCode EnsureSaveData(ServiceCtx context) { - UInt128 userId = new UInt128(context.RequestData.ReadBytes(0x10)); + Uid userId = context.RequestData.ReadStruct(); + TitleId titleId = new TitleId(context.Process.TitleId); - context.ResponseData.Write(0L); + Result result = EnsureApplicationSaveData(context.Device.System.FsClient, out long requiredSize, titleId, + ref context.Device.System.ControlData.Value, ref userId); - Logger.PrintStub(LogClass.ServiceAm, new { userId }); + context.ResponseData.Write(requiredSize); - return ResultCode.Success; + return (ResultCode)result.Value; } [Command(21)] diff --git a/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs b/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs index d09403f9d0..e185233be5 100644 --- a/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs +++ b/Ryujinx.HLE/HOS/Services/Ns/IApplicationManagerInterface.cs @@ -1,8 +1,4 @@ -using LibHac; -using System; -using System.Text; - -namespace Ryujinx.HLE.HOS.Services.Ns +namespace Ryujinx.HLE.HOS.Services.Ns { [Service("ns:am")] class IApplicationManagerInterface : IpcService @@ -10,201 +6,17 @@ namespace Ryujinx.HLE.HOS.Services.Ns public IApplicationManagerInterface(ServiceCtx context) { } [Command(400)] - // GetApplicationControlData(unknown<0x10>) -> (unknown<4>, buffer) + // GetApplicationControlData(u8, u64) -> (unknown<4>, buffer) public ResultCode GetApplicationControlData(ServiceCtx context) { + byte source = (byte)context.RequestData.ReadInt64(); + ulong titleId = (byte)context.RequestData.ReadUInt64(); + long position = context.Request.ReceiveBuff[0].Position; - Nacp nacp = context.Device.System.ControlData; + byte[] nacpData = context.Device.System.ControlData.ByteSpan.ToArray(); - for (int i = 0; i < 0x10; i++) - { - NacpDescription description = nacp.Descriptions[i]; - - byte[] titleData = new byte[0x200]; - byte[] developerData = new byte[0x100]; - - if (description !=null && description.Title != null) - { - byte[] titleDescriptionData = Encoding.ASCII.GetBytes(description.Title); - Buffer.BlockCopy(titleDescriptionData, 0, titleData, 0, titleDescriptionData.Length); - - } - - if (description != null && description.Developer != null) - { - byte[] developerDescriptionData = Encoding.ASCII.GetBytes(description.Developer); - Buffer.BlockCopy(developerDescriptionData, 0, developerData, 0, developerDescriptionData.Length); - } - - context.Memory.WriteBytes(position, titleData); - context.Memory.WriteBytes(position + 0x200, developerData); - - position += i * 0x300; - } - - byte[] isbn = new byte[0x25]; - - if (nacp.Isbn != null) - { - byte[] isbnData = Encoding.ASCII.GetBytes(nacp.Isbn); - Buffer.BlockCopy(isbnData, 0, isbn, 0, isbnData.Length); - } - - context.Memory.WriteBytes(position, isbn); - position += isbn.Length; - - context.Memory.WriteByte(position++, nacp.StartupUserAccount); - context.Memory.WriteByte(position++, nacp.UserAccountSwitchLock); - context.Memory.WriteByte(position++, nacp.AocRegistrationType); - - context.Memory.WriteInt32(position, nacp.AttributeFlag); - position += 4; - - context.Memory.WriteUInt32(position, nacp.SupportedLanguageFlag); - position += 4; - - context.Memory.WriteUInt32(position, nacp.ParentalControlFlag); - position += 4; - - context.Memory.WriteByte(position++, nacp.Screenshot); - context.Memory.WriteByte(position++, nacp.VideoCapture); - context.Memory.WriteByte(position++, nacp.DataLossConfirmation); - context.Memory.WriteByte(position++, nacp.PlayLogPolicy); - - context.Memory.WriteUInt64(position, nacp.PresenceGroupId); - position += 8; - - for (int i = 0; i < nacp.RatingAge.Length; i++) - { - context.Memory.WriteSByte(position++, nacp.RatingAge[i]); - } - - byte[] displayVersion = new byte[0x10]; - - if (nacp.DisplayVersion != null) - { - byte[] displayVersionData = Encoding.ASCII.GetBytes(nacp.DisplayVersion); - Buffer.BlockCopy(displayVersionData, 0, displayVersion, 0, displayVersionData.Length); - } - - context.Memory.WriteBytes(position, displayVersion); - position += displayVersion.Length; - - context.Memory.WriteUInt64(position, nacp.AddOnContentBaseId); - position += 8; - - context.Memory.WriteUInt64(position, nacp.SaveDataOwnerId); - position += 8; - - context.Memory.WriteInt64(position, nacp.UserAccountSaveDataSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.UserAccountSaveDataJournalSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.DeviceSaveDataSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.DeviceSaveDataJournalSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.BcatDeliveryCacheStorageSize); - position += 8; - - byte[] applicationErrorCodeCategory = new byte[0x8]; - - if (nacp.ApplicationErrorCodeCategory != null) - { - byte[] applicationErrorCodeCategoryData = Encoding.ASCII.GetBytes(nacp.ApplicationErrorCodeCategory); - Buffer.BlockCopy(applicationErrorCodeCategoryData, 0, applicationErrorCodeCategoryData, 0, applicationErrorCodeCategoryData.Length); - } - - context.Memory.WriteBytes(position, applicationErrorCodeCategory); - position += applicationErrorCodeCategory.Length; - - for (int i = 0; i < nacp.LocalCommunicationId.Length; i++) - { - context.Memory.WriteUInt64(position, nacp.LocalCommunicationId[i]); - position += 8; - } - - context.Memory.WriteByte(position++, nacp.LogoType); - context.Memory.WriteByte(position++, nacp.LogoHandling); - context.Memory.WriteByte(position++, nacp.RuntimeAddOnContentInstall); - - byte[] reserved000 = new byte[0x3]; - context.Memory.WriteBytes(position, reserved000); - position += reserved000.Length; - - context.Memory.WriteByte(position++, nacp.CrashReport); - context.Memory.WriteByte(position++, nacp.Hdcp); - context.Memory.WriteUInt64(position, nacp.SeedForPseudoDeviceId); - position += 8; - - byte[] bcatPassphrase = new byte[65]; - if (nacp.BcatPassphrase != null) - { - byte[] bcatPassphraseData = Encoding.ASCII.GetBytes(nacp.BcatPassphrase); - Buffer.BlockCopy(bcatPassphraseData, 0, bcatPassphrase, 0, bcatPassphraseData.Length); - } - - context.Memory.WriteBytes(position, bcatPassphrase); - position += bcatPassphrase.Length; - - context.Memory.WriteByte(position++, nacp.Reserved01); - - byte[] reserved02 = new byte[0x6]; - context.Memory.WriteBytes(position, reserved02); - position += reserved02.Length; - - context.Memory.WriteInt64(position, nacp.UserAccountSaveDataSizeMax); - position += 8; - - context.Memory.WriteInt64(position, nacp.UserAccountSaveDataJournalSizeMax); - position += 8; - - context.Memory.WriteInt64(position, nacp.DeviceSaveDataSizeMax); - position += 8; - - context.Memory.WriteInt64(position, nacp.DeviceSaveDataJournalSizeMax); - position += 8; - - context.Memory.WriteInt64(position, nacp.TemporaryStorageSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.CacheStorageSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.CacheStorageJournalSize); - position += 8; - - context.Memory.WriteInt64(position, nacp.CacheStorageDataAndJournalSizeMax); - position += 8; - - context.Memory.WriteInt16(position, nacp.CacheStorageIndex); - position += 2; - - byte[] reserved03 = new byte[0x6]; - context.Memory.WriteBytes(position, reserved03); - position += reserved03.Length; - - for (int i = 0; i < 16; i++) - { - ulong value = 0; - - if (nacp.PlayLogQueryableApplicationId.Count > i) - { - value = nacp.PlayLogQueryableApplicationId[i]; - } - - context.Memory.WriteUInt64(position, value); - position += 8; - } - - context.Memory.WriteByte(position++, nacp.PlayLogQueryCapability); - context.Memory.WriteByte(position++, nacp.RepairFlag); - context.Memory.WriteByte(position++, nacp.ProgramIndex); + context.Memory.WriteBytes(position, nacpData); return ResultCode.Success; } diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj index 2b6837ccdf..202dca4b29 100644 --- a/Ryujinx.HLE/Ryujinx.HLE.csproj +++ b/Ryujinx.HLE/Ryujinx.HLE.csproj @@ -51,7 +51,7 @@ - +