mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-15 10:37:04 +00:00
added a titleid_map.ndjson, and game names in titleid.txt
This commit is contained in:
parent
c125d08636
commit
8707fd5232
1 changed files with 45 additions and 66 deletions
|
|
@ -35,7 +35,6 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
namespace LibKenjinx
|
namespace LibKenjinx
|
||||||
|
|
@ -936,19 +935,18 @@ namespace LibKenjinx
|
||||||
|
|
||||||
// TitleId string normalized
|
// TitleId string normalized
|
||||||
string titleIdHex = titleId.ToString("x16");
|
string titleIdHex = titleId.ToString("x16");
|
||||||
|
string titleName = TryGetTitleName(ref control) ?? "Unknown";
|
||||||
|
|
||||||
// Marker file in the save folder + central mapping under .../save/_titleid_map.json
|
// Marker file in the save folder + central mapping under .../save/_titleid_map.json
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 1) If we have recognized the newly created folder: Put a marker in
|
|
||||||
if (!string.IsNullOrEmpty(createdSaveDirName))
|
if (!string.IsNullOrEmpty(createdSaveDirName))
|
||||||
{
|
{
|
||||||
string markerFile = Path.Combine(savesRoot, createdSaveDirName, "TITLEID.txt");
|
string markerFile = Path.Combine(savesRoot, createdSaveDirName, "TITLEID.txt");
|
||||||
File.WriteAllText(markerFile, titleIdHex);
|
File.WriteAllText(markerFile, $"{titleIdHex}\n{titleName}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Load/update mapping file
|
AppendTitleMapNdjson(savesRoot, titleIdHex, titleName, createdSaveDirName);
|
||||||
WriteOrUpdateTitleMapJson(savesRoot, titleIdHex, createdSaveDirName);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -956,75 +954,56 @@ namespace LibKenjinx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- Helper for TitleId→SaveId mapping ----------
|
private static string EscapeJson(string s)
|
||||||
|
|
||||||
private sealed class TitleMap
|
|
||||||
{
|
{
|
||||||
public Dictionary<string, string> Map { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
if (string.IsNullOrEmpty(s)) return "";
|
||||||
|
return s
|
||||||
|
.Replace("\\", "\\\\")
|
||||||
|
.Replace("\"", "\\\"")
|
||||||
|
.Replace("\r", "\\r")
|
||||||
|
.Replace("\n", "\\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void WriteOrUpdateTitleMapJson(string savesRoot, string titleIdHex, string? createdSaveDirName)
|
/// <summary>
|
||||||
|
/// Writes a line in NDJSON format to .../save/titleid_map.ndjson
|
||||||
|
/// </summary>
|
||||||
|
private static void AppendTitleMapNdjson(string savesRoot, string titleIdHex, string titleName, string createdFolder)
|
||||||
{
|
{
|
||||||
string mapFile = Path.Combine(savesRoot, "_titleid_map.json");
|
Directory.CreateDirectory(savesRoot);
|
||||||
|
string mapPath = Path.Combine(savesRoot, "titleid_map.ndjson");
|
||||||
|
|
||||||
TitleMap map;
|
string line = $"{{\"titleId\":\"{EscapeJson(titleIdHex)}\",\"name\":\"{EscapeJson(titleName)}\",\"folder\":\"{EscapeJson(createdFolder ?? "")}\",\"timestamp\":\"{DateTime.UtcNow:O}\"}}{Environment.NewLine}";
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(mapFile))
|
|
||||||
{
|
|
||||||
var json = File.ReadAllText(mapFile);
|
|
||||||
map = JsonSerializer.Deserialize<TitleMap>(json) ?? new TitleMap();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
map = new TitleMap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
map = new TitleMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we know the newly created folder, use this information.
|
// Append-only, erstellt die Datei falls sie nicht existiert:
|
||||||
// Otherwise, do not overwrite anything (existing mapping remains intact).
|
File.AppendAllText(mapPath, line, Encoding.UTF8);
|
||||||
if (!string.IsNullOrEmpty(createdSaveDirName))
|
|
||||||
{
|
|
||||||
map.Map[titleIdHex] = createdSaveDirName!;
|
|
||||||
}
|
|
||||||
else if (!map.Map.ContainsKey(titleIdHex))
|
|
||||||
{
|
|
||||||
// Heuristic: Scan folder with TITLEID.txt and assign if necessary
|
|
||||||
try
|
|
||||||
{
|
|
||||||
foreach (var dir in Directory.GetDirectories(savesRoot))
|
|
||||||
{
|
|
||||||
var marker = Path.Combine(dir, "TITLEID.txt");
|
|
||||||
if (File.Exists(marker))
|
|
||||||
{
|
|
||||||
var txt = File.ReadAllText(marker).Trim();
|
|
||||||
if (string.Equals(txt, titleIdHex, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
map.Map[titleIdHex] = Path.GetFileName(dir);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch { /* ignore */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var json = JsonSerializer.Serialize(map, new JsonSerializerOptions { WriteIndented = true });
|
|
||||||
File.WriteAllText(mapFile, json);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignore – mapping is “best effort”.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------
|
/// <summary>
|
||||||
|
/// Gets the (preferably American) title from the NACP, as a fallback the first non-empty one.
|
||||||
|
/// </summary>
|
||||||
|
private static string? TryGetTitleName(ref LibHac.Ns.ApplicationControlProperty control)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Preferred: AmericanEnglish
|
||||||
|
int idx = (int)Language.AmericanEnglish;
|
||||||
|
if (control.Title.Length > idx)
|
||||||
|
{
|
||||||
|
var s = control.Title[idx].NameString.ToString();
|
||||||
|
if (!string.IsNullOrWhiteSpace(s)) return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: first non-empty localization
|
||||||
|
foreach (ref readonly var t in control.Title)
|
||||||
|
{
|
||||||
|
var s = t.NameString.ToString();
|
||||||
|
if (!string.IsNullOrWhiteSpace(s)) return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { /* ignore */ }
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
internal void ReloadFileSystem()
|
internal void ReloadFileSystem()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue