Rename "RyuFs" directory to "Ryujinx" and use the same savedata system the Switch uses (#801)
* Use savedata FS commands from LibHac * Add EnsureSaveData. Use ApplicationControlProperty struct * Add a function to migrate to the new directory layout * LibHac update * Change backup structure * Don't create UI files in the save path * Update RyuFs paths * Add GetProgramIndexForAccessLog Ryujinx only runs one program at a time, so always return values reflecting that * Load control NCA when loading from an NSP * Skip over UI stats when exiting * Set TitleName and TitleId in more cases. Fix TitleID naming style * Completely comment out GUI play stats code * rebase * Update LibHac * Update LibHac * Revert UI changes * Do migration automatically at startup * Rename RyuFs directory to Ryujinx * Update RyuFs text * Store savedata paths in the GUI * Make "Open Save Directory" work * Use a dummy NACP in EnsureSaveData if one is not loaded * Remove manual migration button * Respond to feedback * Don't read the installer config to get a version string * Delete nuget.config * Exclude 'sdcard' and 'bis' during migration Co-authored-by: Thog <thog@protonmail.com>
This commit is contained in:
parent
e0e12b1672
commit
63b24b4af2
22 changed files with 877 additions and 384 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 TitleName { get; private set; }
|
||||
|
||||
|
@ -116,11 +118,13 @@ namespace Ryujinx.HLE.HOS
|
|||
internal long HidBaseAddress { get; private set; }
|
||||
|
||||
internal FileSystemServer FsServer { get; private set; }
|
||||
public 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;
|
||||
|
||||
|
@ -245,6 +249,7 @@ namespace Ryujinx.HLE.HOS
|
|||
};
|
||||
|
||||
FsServer = new FileSystemServer(fsServerConfig);
|
||||
FsClient = FsServer.CreateFileSystemClient();
|
||||
}
|
||||
|
||||
public void LoadCart(string exeFsDir, string romFsFile = null)
|
||||
|
@ -350,6 +355,10 @@ namespace Ryujinx.HLE.HOS
|
|||
{
|
||||
ReadControlData(controlNca);
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlData.ByteSpan.Clear();
|
||||
}
|
||||
|
||||
return (mainNca, patchNca, controlNca);
|
||||
}
|
||||
|
@ -362,9 +371,23 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
ControlData = new Nacp(controlFile.AsStream());
|
||||
result = controlFile.Read(out long bytesRead, 0, ControlData.ByteSpan, ReadOption.None);
|
||||
|
||||
TitleName = ControlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
|
||||
if (result.IsSuccess() && bytesRead == ControlData.ByteSpan.Length)
|
||||
{
|
||||
TitleName = ControlData.Value
|
||||
.Titles[(int) State.DesiredTitleLanguage].Name.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(TitleName))
|
||||
{
|
||||
TitleName = ControlData.Value.Titles.ToArray()
|
||||
.FirstOrDefault(x => x.Name[0] != 0).Name.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ControlData.ByteSpan.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,33 +512,16 @@ namespace Ryujinx.HLE.HOS
|
|||
}
|
||||
|
||||
LoadExeFs(codeFs, out Npdm metaData);
|
||||
|
||||
Nacp ReadControlData()
|
||||
{
|
||||
IFileSystem controlRomfs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
|
||||
|
||||
controlRomfs.OpenFile(out IFile controlFile, "/control.nacp", OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nacp controlData = new Nacp(controlFile.AsStream());
|
||||
|
||||
TitleName = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
|
||||
TitleId = metaData.Aci0.TitleId.ToString("x16");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(TitleName))
|
||||
{
|
||||
TitleName = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
|
||||
}
|
||||
|
||||
return controlData;
|
||||
}
|
||||
|
||||
TitleId = metaData.Aci0.TitleId.ToString("x16");
|
||||
|
||||
if (controlNca != null)
|
||||
{
|
||||
ReadControlData();
|
||||
ReadControlData(controlNca);
|
||||
}
|
||||
else
|
||||
{
|
||||
TitleId = metaData.Aci0.TitleId.ToString("x16");
|
||||
ControlData.ByteSpan.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,28 +619,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.Titles[(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.Titles.ToArray().FirstOrDefault(x => x.Name[0] != 0).Name.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")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue