aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-09-19 15:09:49 +0300
committerThomas Guillemard <thog@protonmail.com>2018-09-19 14:09:49 +0200
commitfae097408e5ef28848e97022766017e540b0da37 (patch)
treee97dc440eead87671cd92cd95e07dcfd33ff3cbb
parentb8133c19971c7a2026af803003fafedbdb70488e (diff)
Show Game Title on Titlebar (#408)
* support reading control data * show game info on titlebar * use first language is default is not available * use seperate language enums for titles * fix hex display
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs102
-rw-r--r--Ryujinx.HLE/HOS/Process.cs3
-rw-r--r--Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs4
-rw-r--r--Ryujinx.HLE/HOS/SystemState/TitleLanguage.cs21
-rw-r--r--Ryujinx/Ui/GLScreen.cs7
5 files changed, 119 insertions, 18 deletions
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index c7a824c0..f8ec8914 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -47,6 +47,10 @@ namespace Ryujinx.HLE.HOS
private bool HasStarted;
+ public Nacp ControlData { get; set; }
+
+ public string CurrentTitle { get; private set; }
+
public Horizon(Switch Device)
{
this.Device = Device;
@@ -137,6 +141,8 @@ namespace Ryujinx.HLE.HOS
throw new NotImplementedException("32-bit titles are unsupported!");
}
+ CurrentTitle = MainProcess.MetaData.ACI0.TitleId.ToString("x16");
+
LoadNso("rtld");
MainProcess.SetEmptyArgs();
@@ -154,27 +160,28 @@ namespace Ryujinx.HLE.HOS
Xci Xci = new Xci(KeySet, File);
- Nca Nca = GetXciMainNca(Xci);
+ (Nca MainNca, Nca ControlNca) = GetXciGameData(Xci);
- if (Nca == null)
+ if (MainNca == null)
{
Device.Log.PrintError(LogClass.Loader, "Unable to load XCI");
return;
}
- LoadNca(Nca);
+ LoadNca(MainNca, ControlNca);
}
- private Nca GetXciMainNca(Xci Xci)
+ private (Nca Main, Nca Control) GetXciGameData(Xci Xci)
{
if (Xci.SecurePartition == null)
{
throw new InvalidDataException("Could not find XCI secure partition");
}
- Nca MainNca = null;
- Nca PatchNca = null;
+ Nca MainNca = null;
+ Nca PatchNca = null;
+ Nca ControlNca = null;
foreach (PfsFileEntry FileEntry in Xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
{
@@ -193,6 +200,10 @@ namespace Ryujinx.HLE.HOS
PatchNca = Nca;
}
}
+ else if (Nca.Header.ContentType == ContentType.Control)
+ {
+ ControlNca = Nca;
+ }
}
if (MainNca == null)
@@ -201,8 +212,24 @@ namespace Ryujinx.HLE.HOS
}
MainNca.SetBaseNca(PatchNca);
+
+ if (ControlNca != null)
+ {
+ ReadControlData(ControlNca);
+ }
- return MainNca;
+ return (MainNca, ControlNca);
+ }
+
+ public void ReadControlData(Nca ControlNca)
+ {
+ Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false));
+
+ byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");
+
+ BinaryReader Reader = new BinaryReader(new MemoryStream(ControlFile));
+
+ ControlData = new Nacp(Reader);
}
public void LoadNca(string NcaFile)
@@ -211,7 +238,7 @@ namespace Ryujinx.HLE.HOS
Nca Nca = new Nca(KeySet, File, true);
- LoadNca(Nca);
+ LoadNca(Nca, null);
}
public void LoadNsp(string NspFile)
@@ -231,25 +258,37 @@ namespace Ryujinx.HLE.HOS
KeySet.TitleKeys[Ticket.RightsId] = Ticket.GetTitleKey(KeySet);
}
+ Nca MainNca = null;
+ Nca ControlNca = null;
+
foreach (PfsFileEntry NcaFile in Nsp.Files.Where(x => x.Name.EndsWith(".nca")))
{
Nca Nca = new Nca(KeySet, Nsp.OpenFile(NcaFile), true);
if (Nca.Header.ContentType == ContentType.Program)
{
- LoadNca(Nca);
-
- return;
+ MainNca = Nca;
}
+ else if (Nca.Header.ContentType == ContentType.Control)
+ {
+ ControlNca = Nca;
+ }
+ }
+
+ if (MainNca != null)
+ {
+ LoadNca(MainNca, ControlNca);
+
+ return;
}
Device.Log.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file");
}
- public void LoadNca(Nca Nca)
+ public void LoadNca(Nca MainNca, Nca ControlNca)
{
- NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
- NcaSection ExefsSection = Nca.Sections.FirstOrDefault(x => x?.IsExefs == true);
+ NcaSection RomfsSection = MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
+ NcaSection ExefsSection = MainNca.Sections.FirstOrDefault(x => x?.IsExefs == true);
if (ExefsSection == null)
{
@@ -265,10 +304,12 @@ namespace Ryujinx.HLE.HOS
return;
}
- Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false);
+ Stream RomfsStream = MainNca.OpenSection(RomfsSection.SectionNum, false);
+
Device.FileSystem.SetRomFs(RomfsStream);
- Stream ExefsStream = Nca.OpenSection(ExefsSection.SectionNum, false);
+ Stream ExefsStream = MainNca.OpenSection(ExefsSection.SectionNum, false);
+
Pfs Exefs = new Pfs(ExefsStream);
Npdm MetaData = null;
@@ -305,6 +346,35 @@ namespace Ryujinx.HLE.HOS
}
}
+ Nacp ReadControlData()
+ {
+ Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false));
+
+ byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");
+
+ BinaryReader Reader = new BinaryReader(new MemoryStream(ControlFile));
+
+ Nacp ControlData = new Nacp(Reader);
+
+ CurrentTitle = ControlData.Languages[(int)State.DesiredTitleLanguage].Title;
+
+ if (string.IsNullOrWhiteSpace(CurrentTitle))
+ {
+ CurrentTitle = ControlData.Languages.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
+ }
+
+ return ControlData;
+ }
+
+ if (ControlNca != null)
+ {
+ MainProcess.ControlData = ReadControlData();
+ }
+ else
+ {
+ CurrentTitle = MainProcess.MetaData.ACI0.TitleId.ToString("x16");
+ }
+
if (!MainProcess.MetaData.Is64Bits)
{
throw new NotImplementedException("32-bit titles are unsupported!");
diff --git a/Ryujinx.HLE/HOS/Process.cs b/Ryujinx.HLE/HOS/Process.cs
index 289920be..7900705d 100644
--- a/Ryujinx.HLE/HOS/Process.cs
+++ b/Ryujinx.HLE/HOS/Process.cs
@@ -2,6 +2,7 @@ using ChocolArm64;
using ChocolArm64.Events;
using ChocolArm64.Memory;
using ChocolArm64.State;
+using LibHac;
using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
using Ryujinx.HLE.HOS.Kernel;
@@ -42,6 +43,8 @@ namespace Ryujinx.HLE.HOS
public Npdm MetaData { get; private set; }
+ public Nacp ControlData { get; set; }
+
public KProcessHandleTable HandleTable { get; private set; }
public AppletStateMgr AppletState { get; private set; }
diff --git a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs
index bd1dbd78..2a3c8288 100644
--- a/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs
+++ b/Ryujinx.HLE/HOS/SystemState/SystemStateMgr.cs
@@ -37,6 +37,8 @@ namespace Ryujinx.HLE.HOS.SystemState
internal long DesiredLanguageCode { get; private set; }
+ public TitleLanguage DesiredTitleLanguage { get; private set; }
+
internal string ActiveAudioOutput { get; private set; }
public bool DockedMode { get; set; }
@@ -64,6 +66,8 @@ namespace Ryujinx.HLE.HOS.SystemState
public void SetLanguage(SystemLanguage Language)
{
DesiredLanguageCode = GetLanguageCode((int)Language);
+
+ DesiredTitleLanguage = Enum.Parse<TitleLanguage>(Enum.GetName(typeof(SystemLanguage), Language));
}
public void SetAudioOutputAsTv()
diff --git a/Ryujinx.HLE/HOS/SystemState/TitleLanguage.cs b/Ryujinx.HLE/HOS/SystemState/TitleLanguage.cs
new file mode 100644
index 00000000..f481ac29
--- /dev/null
+++ b/Ryujinx.HLE/HOS/SystemState/TitleLanguage.cs
@@ -0,0 +1,21 @@
+namespace Ryujinx.HLE.HOS.SystemState
+{
+ public enum TitleLanguage
+ {
+ AmericanEnglish,
+ BritishEnglish,
+ Japanese,
+ French,
+ German,
+ LatinAmericanSpanish,
+ Spanish,
+ Italian,
+ Dutch,
+ CanadianFrench,
+ Portuguese,
+ Russian,
+ Korean,
+ Taiwanese,
+ Chinese
+ }
+}
diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs
index 8adff9c0..27f3f08b 100644
--- a/Ryujinx/Ui/GLScreen.cs
+++ b/Ryujinx/Ui/GLScreen.cs
@@ -258,8 +258,11 @@ namespace Ryujinx
double HostFps = Device.Statistics.GetSystemFrameRate();
double GameFps = Device.Statistics.GetGameFrameRate();
- NewTitle = $"Ryujinx | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0} | Game Vsync: " +
- (Device.EnableDeviceVsync ? "On" : "Off");
+ string TitleSection = string.IsNullOrWhiteSpace(Device.System.CurrentTitle) ? string.Empty
+ : " | " + Device.System.CurrentTitle;
+
+ NewTitle = $"Ryujinx{TitleSection} | Host FPS: {HostFps:0.0} | Game FPS: {GameFps:0.0} | " +
+ $"Game Vsync: {(Device.EnableDeviceVsync ? "On" : "Off")}";
TitleEvent = true;