Add EnsureSaveData. Use ApplicationControlProperty struct
This commit is contained in:
parent
41812939fa
commit
6cb52a5909
5 changed files with 44 additions and 216 deletions
|
@ -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<ApplicationControlProperty> 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<ApplicationControlProperty>(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")
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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<Uid>();
|
||||
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)]
|
||||
|
|
|
@ -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<unknown, 6>)
|
||||
// GetApplicationControlData(u8, u64) -> (unknown<4>, buffer<unknown, 6>)
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Concentus" Version="1.1.7" />
|
||||
<PackageReference Include="LibHac" Version="0.7.0--save-tweaks.20" />
|
||||
<PackageReference Include="LibHac" Version="0.7.0--save-tweaks.22" />
|
||||
<PackageReference Include="TimeZoneConverter.Posix" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue