@
docs(D.2b): chat-window re-drive design spec + list-ui-layouts research tool
Plan-2 chat piece of the LayoutDesc importer. Identifies the chat window as
LayoutDesc 0x21000006 (gmMainChatUI, element class 0x10000041) and grounds a
faithful, data-driven re-drive in the named retail decomp (ChatInterface +
gmMainChatUI + UIElement_Text/_Scrollable/_Scrollbar/_Menu) plus a user-provided
retail screenshot.
Design (full-faithful scope, user-approved):
- transcript = UIElement_Text 0x10000011 (dat font, bottom-pinned, 10k behead cap,
pixel scroll, 1 line/wheel-notch)
- scrollbar = right-side track 0x10000012 + thumb 0x1000048c + up/down
- input = editable UIElement_Text 0x10000016 (caret, 100-entry history, Enter/Send)
- channel menu = UIElement_Menu 0x10000014 ("Chat" selector -> active channel)
- shared ChatCommandRouter extracted from ChatPanel
- screenshot correction: the four 0x10000522-525 left-edge elements are the
numbered CHAT TABS (1-4), not scroll buttons (a research-agent inference the
retail screenshot refutes)
- deferred (need non-UI plumbing, each gets a divergence row): tab switching/
filtering, squelch, clickable name-tags, in-element word-wrap, styled runs,
font config, opacity transition
Tooling: AcDream.Cli `list-ui-layouts <datdir> [0xRootType]` — read-only index of
every UI LayoutDesc by root element class + size + element-Type histogram; how the
chat layout was located (root type 0x10000041). Reusable for future panel re-drives.
Spec: docs/superpowers/specs/2026-06-15-chat-window-redrive-design.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
This commit is contained in:
parent
50758d4795
commit
26cb34f126
3 changed files with 380 additions and 0 deletions
101
src/AcDream.Cli/LayoutIndexDump.cs
Normal file
101
src/AcDream.Cli/LayoutIndexDump.cs
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
using System.Reflection;
|
||||
using DatReaderWriter;
|
||||
using DatReaderWriter.DBObjs;
|
||||
using DatReaderWriter.Options;
|
||||
using DatReaderWriter.Types;
|
||||
|
||||
namespace AcDream.Cli;
|
||||
|
||||
/// <summary>
|
||||
/// Read-only research diagnostic: index EVERY UI <see cref="LayoutDesc"/> in the
|
||||
/// dat by its root element's <c>Type</c> + size + an element-Type histogram, so a
|
||||
/// panel re-drive can locate its layout from the decomp-registered class id
|
||||
/// (e.g. <c>gmMainChatUI</c> registers type <c>0x10000041</c> → 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.
|
||||
/// </summary>
|
||||
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<LayoutDesc>().OrderBy(x => x))
|
||||
{
|
||||
var l = dats.Get<LayoutDesc>(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<uint, int>();
|
||||
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<uint, int> 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}",
|
||||
};
|
||||
}
|
||||
|
|
@ -31,6 +31,18 @@ if (args.Length >= 1 && args[0] == "dump-vitals-layout")
|
|||
return VitalsLayoutDump.Run(dvlDatDir, dvlLayout);
|
||||
}
|
||||
|
||||
if (args.Length >= 1 && args[0] == "list-ui-layouts")
|
||||
{
|
||||
string? luiDatDir = args.ElementAtOrDefault(1) ?? Env.GetEnvironmentVariable("ACDREAM_DAT_DIR");
|
||||
string? luiRootType = args.ElementAtOrDefault(2);
|
||||
if (string.IsNullOrWhiteSpace(luiDatDir))
|
||||
{
|
||||
Console.Error.WriteLine("usage: AcDream.Cli list-ui-layouts <dat-directory> [0xRootType]");
|
||||
return 2;
|
||||
}
|
||||
return LayoutIndexDump.Run(luiDatDir, luiRootType);
|
||||
}
|
||||
|
||||
if (args.Length >= 1 && args[0] == "render-vitals-mockup")
|
||||
{
|
||||
string? rvmDatDir = args.ElementAtOrDefault(1) ?? Env.GetEnvironmentVariable("ACDREAM_DAT_DIR");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue