From 18e6a18d01975ec1a13d1dd314ad1ce7b5137ca8 Mon Sep 17 00:00:00 2001
From: YoshiCrystal9 <89108143+YoshiCrystal9@users.noreply.github.com>
Date: Sun, 15 Mar 2026 17:42:40 +0100
Subject: [PATCH] claudemaxxed names.txt reader for hashes
---
WoomLink/Converter/NamesTextParser.cs | 47 +++++++++++++++++++++++++++
WoomLink/Program.cs | 28 ++++++++++++++--
2 files changed, 73 insertions(+), 2 deletions(-)
create mode 100644 WoomLink/Converter/NamesTextParser.cs
diff --git a/WoomLink/Converter/NamesTextParser.cs b/WoomLink/Converter/NamesTextParser.cs
new file mode 100644
index 0000000..308d8a6
--- /dev/null
+++ b/WoomLink/Converter/NamesTextParser.cs
@@ -0,0 +1,47 @@
+using System.Collections.Generic;
+using System.IO;
+using WoomLink.sead;
+
+namespace WoomLink.Converter;
+
+///
+/// Reads a plain text file containing one name per line and builds a
+/// CRC32 hash-to-name lookup table for resolving xlink user hashes.
+///
+/// Example names.txt:
+/// Player
+/// Enemy_Bokoblin
+/// Npc_Zelda
+///
+public static class NamesTextParser
+{
+ public static Dictionary Parse(string path)
+ {
+ var map = new Dictionary();
+
+ foreach (var rawLine in File.ReadLines(path))
+ {
+ var name = rawLine.Trim();
+
+ // Skip empty lines and comment lines (starting with #)
+ if (name.Length == 0 || name.StartsWith('#'))
+ continue;
+
+ uint hash = HashCrc32.CalcStringHash(name);
+ map.TryAdd(hash, name);
+ }
+
+ return map;
+ }
+
+ ///
+ /// Merges into .
+ /// Entries already present in are kept as-is
+ /// (actordb.yaml takes precedence when both files are supplied).
+ ///
+ public static void MergeInto(Dictionary target, Dictionary source)
+ {
+ foreach (var (hash, name) in source)
+ target.TryAdd(hash, name);
+ }
+}
diff --git a/WoomLink/Program.cs b/WoomLink/Program.cs
index d58fdac..236b08b 100644
--- a/WoomLink/Program.cs
+++ b/WoomLink/Program.cs
@@ -47,7 +47,10 @@ static void PrintUsage()
Console.Error.WriteLine("WoomLink - XLink binary converter");
Console.Error.WriteLine();
Console.Error.WriteLine("Convert binary to text:");
- Console.Error.WriteLine(" WoomLink convert [--output ] [--actors ]");
+ Console.Error.WriteLine(" WoomLink convert [--output ] [--actors ] [--names ]");
+ Console.Error.WriteLine();
+ Console.Error.WriteLine(" --actors ActorDb.yaml resolve hashes from a BOTW/TOTK actor YAML database");
+ Console.Error.WriteLine(" --names names.txt resolve hashes from a plain text file (one name per line)");
Console.Error.WriteLine();
Console.Error.WriteLine("Rebuild text to binary:");
Console.Error.WriteLine(" WoomLink rebuild [--output ]");
@@ -60,19 +63,22 @@ static void RunConvert(string[] args)
{
if (args.Length < 2)
{
- Console.Error.WriteLine("Usage: WoomLink convert [--output ] [--actors ]");
+ Console.Error.WriteLine("Usage: WoomLink convert [--output ] [--actors ] [--names ]");
return;
}
string input = args[1];
string? output = null;
string? actorsPath = null;
+ string? namesPath = null;
for (int i = 2; i < args.Length; i++)
{
if (args[i] == "--output" && i + 1 < args.Length)
output = args[++i];
else if (args[i] == "--actors" && i + 1 < args.Length)
actorsPath = args[++i];
+ else if (args[i] == "--names" && i + 1 < args.Length)
+ namesPath = args[++i];
}
var data = File.ReadAllBytes(input);
@@ -80,12 +86,30 @@ static void RunConvert(string[] args)
var model = reader.Read(data);
Dictionary? actorNames = null;
+
if (actorsPath != null)
{
actorNames = Converter.ActorYamlParser.Parse(actorsPath);
Console.Error.WriteLine($"Loaded {actorNames.Count} actor names from {actorsPath}");
}
+ if (namesPath != null)
+ {
+ var namesFromTxt = Converter.NamesTextParser.Parse(namesPath);
+ Console.Error.WriteLine($"Loaded {namesFromTxt.Count} names from {namesPath}");
+
+ if (actorNames == null)
+ {
+ actorNames = namesFromTxt;
+ }
+ else
+ {
+ // Merge: actordb.yaml takes precedence for collisions
+ Converter.NamesTextParser.MergeInto(actorNames, namesFromTxt);
+ Console.Error.WriteLine($"Combined lookup table has {actorNames.Count} entries");
+ }
+ }
+
System.IO.TextWriter writer;
if (output != null)
{