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
|
|
@ -43,10 +43,13 @@ mounts flush to the viewport top and resolves a real (smaller) retail dat
|
|||
font instead of the unwired 15px debug fallback; bare `/help` and
|
||||
`/help <verb>` (including `/help death`) now print retail's exact
|
||||
`DoHelp` shape — two scroll entries in the right order, not one
|
||||
acdream-invented blob. Status stays CODE-COMPLETE pending the next user
|
||||
gate round (still needed for CH6a's own visual confirmation, CH6b/CH6c,
|
||||
round 3's fixes, and a final in-client visual pass on everything fixed so
|
||||
far).
|
||||
acdream-invented blob. **CH6b (floating chat windows 1-4) landed
|
||||
CODE-COMPLETE 2026-08-10** under this session's hard constraints (no
|
||||
subagents, no client launches) — see its ledger row and Slices bullet;
|
||||
CH6c (opacity) remains not started. Status stays CODE-COMPLETE pending
|
||||
the next user gate round (still needed for CH6a's own visual
|
||||
confirmation, CH6b's keybind/mirror/filter behavior, CH6c, round 3's
|
||||
fixes, and a final in-client visual pass on everything fixed so far).
|
||||
|
||||
**Why now:** first track of the alpha-release program (chat is the most
|
||||
visible daily surface for the friend-alpha). User-directed 2026-08-09.
|
||||
|
|
@ -179,6 +182,37 @@ implementer per slice against a pinned contract (per
|
|||
the toggle; per-window PostInit filter defaults (color research §4)
|
||||
with the `windowId == m_eWindowID OR (windowId==0 && TypeIsActive)`
|
||||
display rule.
|
||||
**CODE-COMPLETE 2026-08-10 (this commit — hard constraint: no
|
||||
subagents, no client launches).** `ChatWindowState` (Runtime, borrowed
|
||||
from `RuntimeCommunicationState.ChatWindows`) owns the exact
|
||||
PostInit-default filters + open flags for ids 0-4 and the full
|
||||
`ShouldDisplay(windowId, targetWindowId, logTextType)` predicate;
|
||||
`FloatingChatWindowController` (new sibling to `ChatWindowController`,
|
||||
sharing the wrap/color algorithm via the new `ChatTranscriptRenderer`)
|
||||
binds all four windows, each importing its own widget tree from one
|
||||
shared `0x2100005B` `ElementInfo` parse. The keymap default confirmed
|
||||
**Alt+1..4** (`MetaKeys` index 3 = `0x00000004`, cross-checked against
|
||||
the file's own Alt+A/D strafe and Alt+Enter/Tab/F4 rows — `KeyBindings`
|
||||
already carried this binding since Phase K.1c). A direct decomp read of
|
||||
`gmMainChatUI::ListenToElementMessage @0x004CDA80` (the only function
|
||||
in the binary that branches on a click message) settled the
|
||||
button-mirror-vs-toggle question the research doc had left as a
|
||||
hedge: **the four indicator buttons carry NO click handler in
|
||||
retail** — `ChatWindowController.SetIndicatorOpen` ports this as a
|
||||
pure one-directional mirror, no `OnClick`. `RetailUiRuntime.
|
||||
OnWindowVisibilityChanged` is the single chokepoint that both syncs
|
||||
`ChatWindowState.SetOpen` and calls the indicator mirror, regardless
|
||||
of what changed a window's visibility (keybind, close button, or a
|
||||
restored layout). Geometry + open/visible persist for free through
|
||||
the existing `RetailWindowLayoutPersistence` path once each window
|
||||
registers under its own `WindowNames` entry; the filter masks get a
|
||||
dedicated local `ChatSettings` round-trip (register row AP-187 — no
|
||||
retail `0x1000008C` wire yet). One approximation, register row
|
||||
AP-188: a floaty window's entry field always sends on `Say` (no
|
||||
talk-focus menu is authored on `0x2100005B`, and whether retail's
|
||||
ACTUAL send path reads a per-window or a shared globally-current
|
||||
channel is unconfirmed). Full Release suite 12,392 passed / 4
|
||||
skipped / 0 failed.
|
||||
- **CH6c — opacity.** Implement `UiRenderContext.AlphaMod`
|
||||
consumption (whole-composited-window alpha per
|
||||
`ChatInterface::SetOpacity @0x004F3120`); the two GLOBAL retail
|
||||
|
|
@ -209,11 +243,13 @@ implementer per slice against a pinned contract (per
|
|||
| CH5 closeout | (this commit) | — (docs/memory only, no build) | — | pending (connected gate — see test script) |
|
||||
| User gate round 1 | (this commit) | 12,221 passed / 4 skipped / 0 failed (baseline; items A–G fixed this commit) | — | items A–G user-gate round 1 fixed; ten findings total, see "User gate — round 1" below |
|
||||
| CH6a main-window layout + 8-grip resize | (this commit) | 12,317 passed / 4 skipped / 0 failed | pending (no subagent review pass this session — implementer-only) | pending — needs the next in-client round (items H/I round 1, item 6 round 2) |
|
||||
| CH6b/CH6c floating windows + opacity | not started | — | — | not started |
|
||||
| CH6b/CH6c floating windows + opacity | superseded — split below | — | — | superseded |
|
||||
| User gate round 2 | (this commit) | 12,267 passed / 4 skipped / 0 failed | — | items 2/4/5 fixed this commit, item 3 confirmed-fixed, item 6 folded into CH6a's spec, item 1 NOT reproduced (see "User gate — round 2" below) |
|
||||
| CH6a main-window layout + 8-grip resize | `1fd51543` | 12,317 passed / 4 skipped / 0 failed | pending | pending — landed same day as round 2 |
|
||||
| Jump-in-air root cause (round-2 item 1, resolved) | `a5a7eb4f` | Runtime tests 1,323/0 | — | round-3 probe evidence pinpointed a missing `OnInterfaceText` wire on the production controller-commit path (`RuntimeLocalPlayerMovementState.CommitRuntimeOwnedController`); FIXED, regression test added |
|
||||
| User gate round 3 | (this commit) | Debug (all projects): 12,329 passed / 4 skipped / 1 failed (pre-existing #351 Debug-only flake — reproduces identically on the pristine pre-round-3 commit, not a regression); Release (every project reachable while a live `AcDream.App.exe` client — PID 15064, must not be killed per project policy — holds its own Release binaries locked, blocking `AcDream.App`/`AcDream.App.Tests`/`AcDream.Core.Tests` specifically): `AcDream.UI.Abstractions.Tests` (the layer this round's `/help` fix lives in) 867/867, plus `Core.Net.Tests` 823/823, `Runtime.Tests` 1,323/1,323, `Content.Tests` 130/130, `Headless.Tests` 89/89, `Bake.Tests` 15/15, `Cli.Tests` 4/4 — all 0 failed | — | findings (a)-(c) fixed this commit — SpewBox flush-top + retail dat font, `/help`/`/help death` exact retail print sequence (see "User gate — round 3" below) |
|
||||
| CH6b floating windows 1–4 | (this commit) | 12,392 passed / 4 skipped / 0 failed | pending (no subagent review pass this session — implementer-only, per this session's HARD CONSTRAINT of no subagents) | pending — no client launches this session (hard constraint); needs the next connected round for keybind/mirror/filter visual confirmation |
|
||||
| CH6c opacity | not started | — | — | not started |
|
||||
|
||||
### CH4 closeout (2026-08-09)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue