feat(chat): Campaign CH slice CH6b — floating chat windows 1-4
Mounts retail's four floating chat windows as always-resident, born-hidden children per gmGamePlayUI::SetupChildren @0x004E9EC0, all sharing LayoutDesc 0x2100005B (window ids 0x10000505/0x1000050E/0x1000050F/0x10000510). New FloatingChatWindowController (AcDream.App/UI/Layout) binds each window's own widget tree — built fresh per instance from one shared imported ElementInfo — reusing ChatWindowController's word-wrap + retail color-carry algorithm via the extracted ChatTranscriptRenderer instead of duplicating it. A floaty window has no talk-focus menu (research doc §2.2), so its entry field always sends on Say; the mismatch against retail's possible shared-channel behavior is UNVERIFIED and filed as #369/AP-188. Runtime owns the per-window filter/open state: ChatWindowState (new, AcDream.Core.Chat) seeds retail's exact PostInit defaults per window (window 1 0x0000101C Speech/Tell/DirectSend/Emote, window 2 0x00040C00 Social/SocialSend/Allegiance, window 3 0x00080000 Fellowship, window 4 0x78000000 Turbine General/Trade/LFG/Roleplay) and implements the full ShouldDisplay(windowId, targetWindowId, logTextType) display predicate from ChatInterface::RecvNotice_DisplayFinalStringInfo @0x004F4640. It lives on RuntimeCommunicationState.ChatWindows so every host borrows the same instance. The main window's filter (0xFBFFFFFF, "no user filter") never actually gates anything because its own explicit-address branch already covers every broadcast line — that's why UpdateFromPlayerModule early-returns for window 0 in retail, ported here by construction rather than a special case. Keybind wiring: InputAction.ToggleFloatingChatWindow1..4 and their KeyBindings.RetailDefaults() chords already existed since Phase K.1c (unwired until now). The MetaKeys table confirms retail's default is Alt+1 through Alt+4 (index 3 = bit 0x00000004, cross-checked against the same file's Alt+A/D strafe and Alt+Enter/Tab/F4 rows). Routes through GameplayInputCommandController -> RetainedGameplayWindowCommands -> RetailUiRuntime.ToggleFloatingChatWindow -> the generic UiHost.ToggleWindow, whose visibility-change event is the single chokepoint that syncs ChatWindowState.SetOpen and mirrors the main window's 1-4 indicator button regardless of what changed a window's visibility (keybind, close button, or a restored layout). A direct decomp read of gmMainChatUI::ListenToElementMessage @0x004CDA80 — the only function in the whole binary that branches on a click message — settles what the research doc had left as a hedge: it handles exactly 0x1000046f (max/min) and the talk-focus menu's selection message, with NO case for 0x10000522-0x10000525. The four indicator buttons are PURE one-directional mirrors in retail; clicking them does nothing. ChatWindowController.SetIndicatorOpen ports this with no OnClick at all. Corrected research doc §1.4 accordingly. Persistence is local-only (register row AP-187; the retail 0x1000008C GameplayOptions wire remains deferred to CH6f): window geometry and open/visible state ride the existing generic RetailWindowLayoutPersistence path for free once each window registers under its own WindowNames entry; the four filter masks get a dedicated ChatSettings round-trip (ChatWindow1Filter..ChatWindow4Filter, defaulting to the retail PostInit constants) loaded at mount and saved alongside SaveLayout(). Tests: ChatWindowStateTests (defaults, TypeIsActive, the full display-rule matrix, toggle/reset, revision counter), FloatingChatWindowControllerTests (bind smoke tests against a synthetic 0x2100005B tree, per-window filter routing, filter-change cache invalidation, fixed-Say submit), new ChatWindowController.SetIndicatorOpen tests (Highlight/Normal state, cross-window isolation, range validation), GameplayInputCommandController routing for the four toggle actions, and a SettingsStore filter round-trip. Full Release suite: 12,392 passed / 4 skipped / 0 failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
41b408f3e6
commit
22020ef2c4
21 changed files with 1699 additions and 46 deletions
|
|
@ -151,16 +151,28 @@ State 6 = "on/depressed", state 1 = "normal". No handler anywhere in the binary
|
|||
switches on `0x10000522..0x10000525` as a *source* of a click — `grep` over the
|
||||
whole pseudo-C returns only `gmMainChatUI::RecvNotice_SetPanelVisibility`.
|
||||
|
||||
UNVERIFIED (and the one place I would not guess): whether clicking those four
|
||||
buttons does anything in retail at all. Two readings are consistent with the
|
||||
decomp — (a) they are pure indicators, and (b) they carry the same LayoutDesc
|
||||
property `0x24` input-action value as the windows themselves, so a click routes
|
||||
through the generic `UIElement` action path rather than through any chat code.
|
||||
(b) is the more likely reading given §1.3's generic mechanism. Cheapest
|
||||
resolution: the same LayoutDesc property dump as above, reading property `0x24`
|
||||
on `0x10000522`–`0x10000525`. **For CH6 it is safe to wire both: keybind AND
|
||||
button click both call the same toggle**, because retail's observable behaviour
|
||||
(button lights up iff window is visible) is satisfied either way.
|
||||
**RESOLVED 2026-08-10 at Campaign CH slice CH6b.** The prior UNVERIFIED
|
||||
paragraph's hedge ("safe to wire both") is superseded by a direct read of
|
||||
`gmMainChatUI::ListenToElementMessage @0x004CDA80` — the ONLY function in the
|
||||
whole 2013 binary that branches on `idMessage == 1` ("clicked"). It handles
|
||||
exactly two element ids: `0x1000046f` (max/min, dispatching
|
||||
`HandleMaximizeButton`) and the talk-focus menu's selection message
|
||||
(`idMessage == 7`, checked against `this->m_pCCS` / a `0x1000000b` attribute
|
||||
read). There is no case, anywhere in that function or its base-class fallback
|
||||
(`ChatInterface::ListenToElementMessage`, called unconditionally at the
|
||||
function's tail), for `0x10000522`–`0x10000525`. **Clicking a chat-window
|
||||
indicator button does NOTHING in retail — reading (a), pure indicator, is
|
||||
correct; reading (b) is refuted.** The `0x24` input-action-property theory
|
||||
in reading (b) does not even apply to a mouse click on the button itself: that
|
||||
property only wires *keyboard* dispatch (`UIElementManager::
|
||||
DoVisibilityToggleAction` in §1.3), not a button's own `UIElement` click
|
||||
message, which routes to its LISTENING PARENT — and that parent's handler has
|
||||
no case for these four ids. acdream ports this exactly: the four indicator
|
||||
buttons (`ChatWindowController._indicatorButtons`) carry no `OnClick` at all;
|
||||
`ChatWindowController.SetIndicatorOpen` is their only writer, called only from
|
||||
`RetailUiRuntime.OnWindowVisibilityChanged` in response to the floating
|
||||
window's own visibility changing (keybind or otherwise) — a pure one-directional
|
||||
mirror, matching retail exactly.
|
||||
|
||||
### 1.5 Closing a floaty window from its own title bar
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue