fix(chat): CH6a/b rework — grip media, retail window-id model, floaty fixture
Applies docs/research/2026-08-10-ch6ab-review-findings.md in full:
- BLOCKER 1: UiResizeGrip now carries its ElementInfo/resolve pair and
draws its own authored DirectState media (a synthetic parameterless
grip still draws nothing, preserving existing resize-drag tests).
DatWidgetFactory.BuildResizeGrip threads resolve through. All seven
live grips on the main chat window now resolve a non-zero sprite,
restoring the visible borders/corners CH6a silently dropped.
- SHOULD-FIX 2: ChatWindowState gains BroadcastTargetWindow, a sentinel
distinct from every real window id (0-4), fixing the bug where the
main window's explicit-addressing branch coincided with the broadcast
check (both were literal 0). SetFilter's main-window no-op is dropped
— the main window's filter is now genuinely settable. ChatWindowController
.Bind takes a ChatWindowState (the same canonical instance the floating
windows already share) and GetTranscriptLines builds a real accept
predicate instead of accept:null. Verified safe: ClientLocal (0x1A)
never reaches ChatLog (AddText routes it to the SpewBox and returns),
so nothing observable regresses.
- SHOULD-FIX 3: UiButton.SuppressSelfToggle stops the four chat-window
indicator buttons (DAT property 0x0B=true, no retail click handler)
from flipping their own Selected mirror on a stray click.
- SHOULD-FIX 4: generated and committed chat_floaty_2100005b.json from
the real installed dats; added the permanent RetailLayoutFixtureGenerator
entry. All three flagged FloatingChatWindowController assumptions
(input field, title bar, close button) are confirmed correct against
real data — no controller code changes needed. New finding: unlike the
main window, ALL EIGHT floaty border/corner elements are live Type-9
grips (the floaty's own title bar is its move handle), so a floaty
window resizes from every edge and corner.
- SHOULD-FIX 5: register row AP-189 documents the shared-500-entry/
200-line-tail vs retail's per-window 10,000-line scrollback depth gap.
- NITs 1-5: documented the filter-persistence-only-on-/saveautoui
asymmetry and the reconnect-preserves-filters intent; corrected the
research doc's modifier-mask mislabel and the "ONLY function" false
superlative; moved WrapText off ChatWindowController onto
ChatTranscriptRenderer, closing the circular dependency.
Full Release suite: 12,420 passed / 4 skipped / 0 failed (baseline
12,392/4/0 at 22020ef2; net +28 tests, zero regressions).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
56b84deeab
commit
1aa7709988
23 changed files with 6284 additions and 248 deletions
File diff suppressed because one or more lines are too long
|
|
@ -245,10 +245,10 @@ implementer per slice against a pinned contract (per
|
|||
| 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 | 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 |
|
||||
| CH6a main-window layout + 8-grip resize | `1fd51543`, reworked (this commit) | 12,420 passed / 4 skipped / 0 failed | REJECT (docs/research/2026-08-10-ch6ab-review-findings.md, BLOCKER 1) → reworked (this commit) | pending — needs the next in-client round to confirm the border/corner art now renders |
|
||||
| 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 | REJECT (docs/research/2026-08-10-ch6ab-review-findings.md); rework in progress | pending — no client launches this session (hard constraint); needs the next connected round for keybind/mirror/filter visual confirmation |
|
||||
| CH6b floating windows 1–4 | `22020ef2`, reworked (this commit) | 12,420 passed / 4 skipped / 0 failed | REJECT (docs/research/2026-08-10-ch6ab-review-findings.md) → reworked (this commit) — SHOULD-FIXES 2/3/4/5 + NITs 1-5 applied | pending — no client launches this session (hard constraint); needs the next connected round for keybind/mirror/filter visual confirmation, plus the new 0x2100005B fixture's resolved-type assumptions |
|
||||
| CH6c opacity | not started | — | — | not started |
|
||||
|
||||
### CH4 closeout (2026-08-09)
|
||||
|
|
@ -722,3 +722,98 @@ retail LayoutDesc dumps) to find the smallest font id actually CONFIRMED
|
|||
in use by any retail UI import acdream has ported, rather than merely
|
||||
present in the DAT. `0x40000025` (11px) was both the global minimum across
|
||||
those fixtures AND the chat window's own minimum — no tie-break needed.
|
||||
|
||||
## CH6a/b REJECT-review rework (2026-08-10)
|
||||
|
||||
Applied everything in `docs/research/2026-08-10-ch6ab-review-findings.md`
|
||||
under the session's hard constraints (no subagents, no client launches).
|
||||
The retail research itself held up under independent re-derivation
|
||||
(masks, Alt+1..4, pure-mirror indicators all CONFIRMED); the rework was
|
||||
entirely against the FIX list, not the research.
|
||||
|
||||
- **BLOCKER 1 (CH6a — invisible borders).** `UiResizeGrip` (`src/AcDream.App/UI/UiResizeGrip.cs`)
|
||||
gained a second constructor carrying its `ElementInfo`/sprite-resolve
|
||||
pair and an `OnDraw` override that stamps the active DirectState sprite
|
||||
exactly like `UiDatElement` — a synthetic (parameterless) grip still
|
||||
draws nothing, matching every existing resize-drag unit test.
|
||||
`DatWidgetFactory.BuildResizeGrip` now threads `resolve` through.
|
||||
`SpriteFile` exposes the raw dat sprite id for conformance tests without
|
||||
needing a live GL context; `ChatLayoutConformanceTests
|
||||
.MountedChatWindow_LiveGrip_ResolvesNonZeroSprite` pins all seven live
|
||||
grips against the committed `chat_2100006f.json` fixture.
|
||||
- **SHOULD-FIX 2 (CH6b — window-id model).** `ChatWindowState` gained
|
||||
`BroadcastTargetWindow` (a sentinel distinct from every real window id
|
||||
`0`-`4`) so `ShouldDisplay`'s explicit-addressing branch can no longer
|
||||
coincide with the broadcast check for the main window (id `0`).
|
||||
`SetFilter`'s main-window no-op is dropped — the main window's filter is
|
||||
now genuinely settable, matching retail's options-page-driven main
|
||||
filter. `ChatWindowController.Bind` gained a `ChatWindowState
|
||||
windowFilters` parameter (the same canonical
|
||||
`RuntimeCommunicationState.ChatWindows` instance the floating windows
|
||||
already read) and `GetTranscriptLines` now builds a real accept
|
||||
predicate from it instead of `accept: null` — verified safe: `0x1A`
|
||||
(`ClientLocal`) never reaches `ChatLog` in the first place
|
||||
(`RuntimeCommunicationState.AddText` routes it to the SpewBox and
|
||||
returns before `Chat.OnSystemMessage`), so excluding it from the main
|
||||
filter has zero effect on WeenieError/refusal text. Every production
|
||||
gameplay chat type (Speech/Tell/Social/Fellowship/Allegiance/Turbine
|
||||
rooms) stays within the default filter's covered bits. Register row
|
||||
AP-189 documents the resulting shallower shared-log scrollback depth
|
||||
(SHOULD-FIX 5, below) as the one behavioral residual.
|
||||
- **SHOULD-FIX 3 (CH6b — indicator self-toggle).** `UiButton` gained
|
||||
`SuppressSelfToggle`, checked alongside `ToggleBehavior` at the
|
||||
press-release toggle site; `ChatWindowController.Bind` sets it on all
|
||||
four chat-window indicator buttons (which carry DAT property `0x0B` =
|
||||
true but have no retail click handler). New `UiButtonTests
|
||||
.SuppressSelfToggle_PressReleaseDoesNotFlipSelected` and an extended
|
||||
`MountedChatWindow_IndicatorButtons_ImportVisibleAndInert` (now presses
|
||||
and releases the real fixture's indicator, asserting `Selected`
|
||||
unchanged) replace the "wrong level" `OnClick == null` check.
|
||||
- **SHOULD-FIX 4 (CH6b — 0x2100005B never dumped).** The floaty layout
|
||||
DAT dir at `%USERPROFILE%\Documents\Asheron's Call\` (the default
|
||||
`ConformanceDats.ResolveDatDir()`/`RetailLayoutFixtureGenerator` path)
|
||||
IS reachable in this environment — `chat_floaty_2100005b.json` (171 KB,
|
||||
5,473 lines) was generated for real and committed;
|
||||
`RetailLayoutFixtureGenerator.Layouts` gained the permanent entry for
|
||||
future regenerations. All three flagged untested assumptions in
|
||||
`FloatingChatWindowController` turned out CORRECT against the real
|
||||
fixture — no controller code changed: `0x10000016` is Type 12 with
|
||||
property `0x16` (Editable) = true, resolving to `UiField`; `0x100004D9`
|
||||
is Type 12 with NO `0x16`, resolving to `UiText`; `0x1000052A` is Type 1,
|
||||
resolving to `UiButton`. One extra finding beyond the three named
|
||||
assumptions: unlike the main window (whose plain top strip is a Type-2
|
||||
Dragbar move handle because the main window has no title bar), the
|
||||
floaty window's move handle is its own title bar group (`0x10000529`,
|
||||
Type 2) — so ALL EIGHT of the floaty's border/corner elements are live
|
||||
Type-9 grips, not seven; a floaty window resizes from every edge and
|
||||
corner. New `FloatingChatLayoutConformanceTests.cs` pins the resolved
|
||||
widget types and extends BLOCKER 1's sprite-non-zero guard to all eight
|
||||
floaty grips.
|
||||
- **SHOULD-FIX 5 (register row).** AP-189 files the shared-500-entry/
|
||||
200-line-tail vs. retail's per-window 10,000-line log scrollback-depth
|
||||
divergence — the accumulate-while-closed and independent-per-window-
|
||||
scroll BEHAVIORS both reproduce correctly; only the numeric DEPTH ceiling
|
||||
differs.
|
||||
- **NITs 1-5.** N1: documented the filter-persistence-only-on-`/saveautoui`
|
||||
asymmetry on `RetailUiRuntime.SaveChatWindowFilters`, deferred to CH6e.
|
||||
N2: documented why `ChatWindows.ResetToDefaults()` only runs in
|
||||
`RuntimeCommunicationState.Dispose` (full teardown), not on reconnect —
|
||||
deliberate, matches window-geometry persistence. N3: replaced the §1.3
|
||||
UNVERIFIED modifier-mapping hedge and the "`0x00000002` = shift" mislabel
|
||||
with `retail-default.keymap.txt`'s own `MetaKeys` legend (Shift=`0x1`,
|
||||
Ctrl=`0x2`, Alt=`0x4`, Win=`0x8`) — no code change, `KeyBindings` already
|
||||
had `ModifierMask.Alt` right. N4: fixed the false "ONLY function that
|
||||
branches on `idMessage == 1`" superlative in §1.4 and
|
||||
`ChatWindowController.SetIndicatorOpen`'s doc
|
||||
(`gmFloatyChatUI::ListenToElementMessage @0x004CE330` also does); the
|
||||
substantive "no case for the indicator ids" claim stands. N5: moved
|
||||
`WrapText`/`WrapSingleLine` off `ChatWindowController` onto
|
||||
`ChatTranscriptRenderer` (closing the circular dependency where
|
||||
`BuildLines` called back into one of its own two consumers); updated the
|
||||
two unrelated external callers (`IndicatorDetailText.cs`,
|
||||
`ItemAppraisalReport.cs`) and moved the WrapText tests into the new
|
||||
`ChatTranscriptRendererTests.cs`.
|
||||
|
||||
Full Release suite: 12,420 passed / 4 skipped / 0 failed (baseline
|
||||
12,392/4/0 at `22020ef2`; net +28 tests, all new coverage from this
|
||||
rework, zero regressions).
|
||||
|
|
|
|||
|
|
@ -87,11 +87,30 @@ ToggleFloatingChatWindow4 [ "" [ 0 DIK_4 ] 0x00000004 ]
|
|||
```
|
||||
|
||||
`0x00000004` is the modifier mask (the same mask the `UseQuickSlot_14..18` rows
|
||||
use for `Alt`+digit, versus `0x00000002` for the shift-digit quickslot rows).
|
||||
use for `Alt`+digit, versus `0x00000002` for the CTRL-digit quickslot rows —
|
||||
corrected below; the original filing mislabeled `0x00000002` as "shift").
|
||||
So retail's default is **Alt+1 … Alt+4**, not bare 1–4.
|
||||
UNVERIFIED: the exact modifier bit → key mapping (4 = Alt vs 4 = Ctrl). Cheapest
|
||||
resolution: read `keymap-default.txt`'s modifier legend, or one cdb breakpoint on
|
||||
`UIElementManager::KeyPressEvent`. The *mechanism* below is independent of this.
|
||||
RESOLVED at Campaign CH slice CH6b: `retail-default.keymap.txt`'s own
|
||||
`MetaKeys` legend (not a guess — the keymap file's literal index table) reads
|
||||
```
|
||||
MetaKeys
|
||||
[
|
||||
1 [ 0 DIK_LSHIFT ]
|
||||
2 [ 0 DIK_LCONTROL ]
|
||||
2 [ 0 DIK_RCONTROL ]
|
||||
3 [ 0 DIK_LMENU ]
|
||||
3 [ 0 DIK_RALT ]
|
||||
4 [ 0 DIK_LWIN ]
|
||||
4 [ 0 DIK_RWIN ]
|
||||
]
|
||||
```
|
||||
so the modifier-mask bit for MetaKeys index *N* is `1 << (N-1)`: **index 1 =
|
||||
Shift → `0x1`, index 2 = Ctrl → `0x2`, index 3 = Alt → `0x4`, index 4 = Win →
|
||||
`0x8`**. `0x00000004` on the `ToggleFloatingChatWindow1..4` rows is therefore
|
||||
unambiguously **Alt**, cross-checked against the same file's own Alt+A/D
|
||||
strafe and Alt+Enter/Tab/F4 rows (all `0x00000004`). `KeyBindings` already
|
||||
carried `ModifierMask.Alt` for these four actions since Phase K.1c — no code
|
||||
change was needed, only removing this hedge.
|
||||
|
||||
The dispatch chain is fully generic — there is no chat-specific code in it:
|
||||
|
||||
|
|
@ -151,10 +170,15 @@ 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`.
|
||||
|
||||
**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
|
||||
**RESOLVED 2026-08-10 at Campaign CH slice CH6b; wording corrected at the
|
||||
CH6a/b REJECT-review (NIT 4) — the original "ONLY function in the whole 2013
|
||||
binary that branches on `idMessage == 1`" superlative was false**
|
||||
(`gmFloatyChatUI::ListenToElementMessage @0x004CE330`, the floaty windows'
|
||||
close-button handler, also branches on `idMessage == 1`; §1.5). **The
|
||||
substantive claim stands: within `gmMainChatUI::ListenToElementMessage`
|
||||
specifically, there is no case for `0x10000522`-`0x10000525`.** The prior
|
||||
UNVERIFIED paragraph's hedge ("safe to wire both") is superseded by a direct
|
||||
read of `gmMainChatUI::ListenToElementMessage @0x004CDA80`. 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue