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) {