diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs index 94f06475c5..89ba07c292 100644 --- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs +++ b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs @@ -12,16 +12,21 @@ namespace Ryujinx.HLE.FileSystem.Content { private Dictionary> _locationEntries; - private Dictionary _sharedFontTitleDictionary; - private SortedDictionary<(ulong, ContentType), string> _contentDictionary; + private Dictionary _currentApplicationAocData; + + private Dictionary _sharedFontTitleDictionary; + private Switch _device; public ContentManager(Switch device) { + _locationEntries = new Dictionary>(); + _contentDictionary = new SortedDictionary<(ulong, ContentType), string>(); - _locationEntries = new Dictionary>(); + + _currentApplicationAocData = new Dictionary(); _sharedFontTitleDictionary = new Dictionary { @@ -293,5 +298,34 @@ namespace Ryujinx.HLE.FileSystem.Content return locationList.ToList().Find(x => x.TitleId == titleId && x.ContentType == contentType); } + + public void SetCurrentApplicationAocData(int index, Nca aocData) + { + _currentApplicationAocData.Add(aocData.Header.TitleId, (index, aocData)); + } + + public Nca GetCurrentApplicationAocData(long titleId) + { + return _currentApplicationAocData[(ulong)titleId].Item2; + } + + public int GetCurrentApplicationAocDataCount() + { + return _currentApplicationAocData.Count; + } + + public int[] GetCurrentApplicationAocDataIndices() + { + List indices = new List(); + + foreach ((int index, Nca aocData) tuple in _currentApplicationAocData.Values) + { + indices.Add(tuple.index); + } + + indices.Sort(); + + return indices.ToArray(); + } } } diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs index 8a419af343..e22ab24884 100644 --- a/Ryujinx.HLE/HOS/Horizon.cs +++ b/Ryujinx.HLE/HOS/Horizon.cs @@ -292,6 +292,8 @@ namespace Ryujinx.HLE.HOS Nca nca = new Nca(KeySet, ncaStorage, true); + nca.Filename = fileEntry.Name; + if (nca.Header.ContentType == ContentType.Program) { if (nca.Sections.Any(x => x?.Type == SectionType.Romfs)) @@ -303,6 +305,10 @@ namespace Ryujinx.HLE.HOS patchNca = nca; } } + else if (nca.Header.ContentType == ContentType.AocData) + { + ContentManager.SetCurrentApplicationAocData(fileEntry.Index, nca); + } else if (nca.Header.ContentType == ContentType.Control) { controlNca = nca; diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs index 878f2e4ef4..7e077148d8 100644 --- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs +++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs @@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv return 0; } - // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer, 0x19, 0x301> path) + // OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer, 0x19, 0x301> path) // -> object contentFs public long OpenFileSystemWithId(ServiceCtx context) { @@ -151,6 +151,19 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv byte[] padding = context.RequestData.ReadBytes(7); long titleId = context.RequestData.ReadInt64(); + if (storageId == StorageId.None) + { + Nca nca = context.Device.System.ContentManager.GetCurrentApplicationAocData(titleId); + + NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs); + + Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream(); + + MakeObject(context, new IStorage(romfsStream)); + + return 0; + } + ContentType contentType = ContentType.Data; StorageId installedStorage = @@ -175,22 +188,25 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv if (File.Exists(ncaPath)) { - LibHac.IO.IStorage ncaStorage = new FileStream(ncaPath, FileMode.Open, FileAccess.Read).AsStorage(); - Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false); - NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs); - Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream(); + LibHac.IO.IStorage ncaStorage = new FileStream(ncaPath, FileMode.Open, FileAccess.Read).AsStorage(); + + Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false); + + NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs); + + Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream(); MakeObject(context, new IStorage(romfsStream)); return 0; } else - { + { throw new FileNotFoundException($"No Nca found in Path `{ncaPath}`."); } } else - { + { throw new DirectoryNotFoundException($"Path for title id {titleId:x16} on Storage {storageId} was not found in Path {installPath}."); } } @@ -221,7 +237,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv long titleId = context.RequestData.ReadInt64(); UInt128 userId = new UInt128( - context.RequestData.ReadInt64(), + context.RequestData.ReadInt64(), context.RequestData.ReadInt64()); long saveId = context.RequestData.ReadInt64(); @@ -297,7 +313,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv Pfs nsp = new Pfs(pfsFile.AsStorage()); ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); - + string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); if (nsp.FileExists(filename)) diff --git a/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs b/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs index 94c0e81036..db506e3a44 100644 --- a/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs +++ b/Ryujinx.HLE/HOS/Services/Ns/IAddOnContentManager.cs @@ -14,27 +14,46 @@ namespace Ryujinx.HLE.HOS.Services.Ns { _commands = new Dictionary { - { 2, CountAddOnContent }, - { 3, ListAddOnContent } + { 2, CountAddOnContent }, + { 3, ListAddOnContent }, + { 5, GetAddOnContentBaseId }, + { 7, PrepareAddOnContent } }; } public static long CountAddOnContent(ServiceCtx context) { - context.ResponseData.Write(0); - - Logger.PrintStub(LogClass.ServiceNs); + context.ResponseData.Write(context.Device.System.ContentManager.GetCurrentApplicationAocDataCount()); return 0; } public static long ListAddOnContent(ServiceCtx context) { - Logger.PrintStub(LogClass.ServiceNs); + int[] aocIndices = context.Device.System.ContentManager.GetCurrentApplicationAocDataIndices(); - //TODO: This is supposed to write a u32 array aswell. - //It's unknown what it contains. - context.ResponseData.Write(0); + for (int index = 0; index < aocIndices.Length; index++) + { + long address = context.Request.ReceiveBuff[0].Position + index * 4; + + context.Memory.WriteInt32(address, aocIndices[index]); + } + + context.ResponseData.Write(aocIndices.Length); + + return 0; + } + + public static long GetAddOnContentBaseId(ServiceCtx context) + { + context.ResponseData.Write(context.Process.TitleId + 0x1000); + + return 0; + } + + public static long PrepareAddOnContent(ServiceCtx context) + { + Logger.PrintStub(LogClass.ServiceNs); return 0; }