fix(D.2b): chat input resolves the live command bus lazily (was bound to null) + register thumb-3-slice row

The live session + its LiveCommandBus are created after the retail-UI block in
OnLoad, so binding the bus by value captured NullCommandBus and silently dropped
outbound chat. Pass a Func<ICommandBus> resolved at submit time (mirrors how the
ImGui ChatPanel re-reads the bus each frame).

AP-41: scrollbar thumb drawn as single stretched tile (0x06004C63) instead of
retail's 3-slice top-cap/middle/bottom-cap — acknowledged in UiChatScrollbar.cs:37,
registered per the divergence-register rule.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-15 23:24:44 +02:00
parent 12ab9663d2
commit 0ec36f6197
4 changed files with 16 additions and 11 deletions

View file

@ -1849,7 +1849,8 @@ public sealed class GameWindow : IDisposable
if (chatRootInfo is not null && chatLayout is not null)
{
var chatController = AcDream.App.UI.Layout.ChatWindowController.Bind(
chatRootInfo, chatLayout, retailChatVm, _commandBus ?? (AcDream.UI.Abstractions.ICommandBus)AcDream.UI.Abstractions.NullCommandBus.Instance,
chatRootInfo, chatLayout, retailChatVm,
() => _commandBus ?? (AcDream.UI.Abstractions.ICommandBus)AcDream.UI.Abstractions.NullCommandBus.Instance,
vitalsDatFont, _debugFont, ResolveChrome);
if (chatController is not null)
{

View file

@ -93,7 +93,10 @@ public sealed class ChatWindowController
/// <see cref="LayoutImporter.ImportInfos"/>.</param>
/// <param name="layout">Widget tree from <see cref="LayoutImporter.Build"/>.</param>
/// <param name="vm">Chat view-model (transcript data + command routing).</param>
/// <param name="bus">Command bus for <c>SendChatCmd</c> publishes.</param>
/// <param name="busProvider">Factory that returns the live command bus at submit time.
/// Called on every chat submit so it resolves <see cref="AcDream.UI.Abstractions.LiveCommandBus"/>
/// even when the live session is established AFTER <see cref="Bind"/> runs
/// (mirrors the ImGui <c>ChatPanel</c> which re-reads the bus each frame).</param>
/// <param name="datFont">Retail dat font for transcript + input rendering.</param>
/// <param name="debugFont">Fallback debug bitmap font (used when
/// <paramref name="datFont"/> is null).</param>
@ -103,7 +106,7 @@ public sealed class ChatWindowController
ElementInfo rootInfo,
ImportedLayout layout,
ChatVM vm,
ICommandBus bus,
Func<ICommandBus> busProvider,
UiDatFont? datFont,
BitmapFont? debugFont,
Func<uint, (uint tex, int w, int h)> resolve)
@ -158,7 +161,7 @@ public sealed class ChatWindowController
Font = debugFont,
};
inputBar.AddChild(c.Input);
c.Input.OnSubmit = text => ChatCommandRouter.Submit(text, vm, bus, c._activeChannel);
c.Input.OnSubmit = text => ChatCommandRouter.Submit(text, vm, busProvider(), c._activeChannel);
// ── Scrollbar — replace the imported track placeholder ────────────
// The factory created a UiDatElement for the track. Remove it and place a