using System.Reflection; using DatReaderWriter; using DatReaderWriter.DBObjs; using DatReaderWriter.Options; using DatReaderWriter.Types; namespace AcDream.Cli; /// /// Read-only research diagnostic: index EVERY UI in the /// dat by its root element's Type + size + an element-Type histogram, so a /// panel re-drive can locate its layout from the decomp-registered class id /// (e.g. gmMainChatUI registers type 0x10000041 → the chat window /// is the layout whose root element has Type 0x10000041). Optionally filter to a /// single root Type. No writes; purely a console dump used during brainstorming. /// public static class LayoutIndexDump { public static int Run(string datDir, string? rootTypeText) { if (!Directory.Exists(datDir)) { Console.Error.WriteLine($"error: dir not found: {datDir}"); return 2; } using var dats = new DatCollection(datDir, DatAccessType.Read); uint? filter = null; if (!string.IsNullOrWhiteSpace(rootTypeText)) { var t = rootTypeText.Trim(); if (t.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) t = t[2..]; if (uint.TryParse(t, System.Globalization.NumberStyles.HexNumber, null, out var f)) filter = f; } Console.WriteLine(filter is { } ff ? $"=== LayoutDescs with a root element of Type 0x{ff:X8} ===" : "=== All LayoutDescs (id : root element Type : size : #elements : type histogram) ==="); int total = 0, shown = 0; foreach (var id in dats.GetAllIdsOfType().OrderBy(x => x)) { var l = dats.Get(id); if (l is null) continue; total++; // The root is the single top-level element (or, if several, the largest). ElementDesc? root = null; foreach (var kv in l.Elements) if (root is null || Area(kv.Value) > Area(root)) root = kv.Value; if (root is null) continue; if (filter is { } want && root.Type != want) continue; shown++; var hist = new SortedDictionary(); int count = 0; CountTypes(root, hist, ref count); string h = string.Join(" ", hist.Select(kv => $"{TypeName(kv.Key)}×{kv.Value}")); Console.WriteLine( $" 0x{id:X8} root=0x{root.ElementId:X8} type=0x{root.Type:X8}({TypeName(root.Type)}) " + $"{root.Width}x{root.Height} n={count} [{h}]"); } Console.WriteLine(); Console.WriteLine($"shown {shown} / {total} LayoutDescs."); return 0; } private static long Area(ElementDesc e) => (long)e.Width * e.Height; private static void CountTypes(ElementDesc e, SortedDictionary hist, ref int count) { count++; hist[e.Type] = hist.TryGetValue(e.Type, out var c) ? c + 1 : 1; foreach (var kv in e.Children) CountTypes(kv.Value, hist, ref count); } private static string TypeName(uint t) => t switch { 0 => "Text0", 1 => "Button", 2 => "Dragbar", 3 => "Field", 5 => "ListBox", 6 => "Menu", 7 => "Meter", 8 => "Panel", 9 => "Resizebar", 0xB => "Scrollbar", 0xC => "Text", 0xD => "Viewport", 0xE => "Browser", 0x10 => "ColorPicker", 0x11 => "GroupBox", 0x12 => "Proto", 0x10000041 => "gmMainChatUI", 0x10000040 => "gmFloatyChatUI", 0x10000050 => "gmFloatyMainChatUI", 0x10000042 => "gmChatOptionsUI", 0x10000009 => "gmVitalsUI", _ => $"0x{t:X}", }; }