feat(chat): Campaign CH slice CH6a — retail chat-window layout + 8-grip resize
Swap ChatWindowController's imported main-chat LayoutDesc from the wrong 0x21000006 (an unrelated layout whose root and 800px resize bar appear nowhere in the EoR gameplay UI) to retail's ACTUAL main chat window, 0x2100006F (window root 0x10000600, authored 410x100 — confirmed by a direct DAT dump, found in dats.Local not dats.Portal). Every downstream compensation that existed only to paper over the wrong import is deleted: the hand-cropped 490px content width, the dropped 800px resize bar, the 9px transcript patch, the orphan-sibling pruning, the max/min-vs-scrollbar overlap shift, and the scrollbar top-reclaim. The window now mounts with RetailWindowChrome.Imported (0x2100006F's own 8 border/corner elements are its complete chrome) instead of the universal nine-slice wrapper. LayoutImporter/DatWidgetFactory gain a Type-9 (UIElement_Resizebar) case: UiResizeGrip decodes retail's exact four-bool BorderLocation algorithm (0x2A=bottom/0x2B=left/0x2C=right/0x2D=top, UIElement_Resizebar::StartMouseResizing @0x0046B7E0) into a ResizeEdges bitmask. A direct DAT dump established the true shape: only 7 of the 8 grip-position ids are Type 9 — the straight top-EDGE strip (0x1000069C) is a Type-2 Dragbar (move handle), not a Resizebar, because the main window has no title bar. UiRoot now gives a directly-hit grip's own edges priority over its generic proximity heuristic, and a directly-hit move handle the same priority over ambient proximity — so the plain top strip moves the window while its two corner grips resize it including the Y axis, and all 4 edges + 4 corners work everywhere else. This also fixes the reported "no diagonal cursor at corners" (CursorFeedbackController's existing RetailCursorCatalog cursor ids already matched the DAT exactly; they just never received a genuine diagonal edge combination) and "cannot grow in Y from the bottom-right corner" (the old NineSlice+crop mount's indirection is gone; the Imported mount uses the DAT's real minH=100/maxH=2000/minW=300/maxW=2000 directly). The 8 cosmetic "_Locked" border-art twins default hidden (register row AP-185 — retail's UiLocked-driven art swap between the two skins is not ported; UiRoot.UiLocked continues to gate the underlying interaction correctly either way). The 4 chat-window-1..4 indicator buttons import generically (visible, inert) for CH6b to wire. The two hand-drawn translucent-black tints on the transcript/input are removed now that their parent panels draw their own authored background sprites. Filed #366 (chat window's new-unseen-text indicator 0x1000048C is swallowed by UiText.ConsumesDatChildren, pre-existing and out of scope). Corrected the research doc's "all eight grips" claim against the direct DAT dump. Full Release suite: 12,317 passed / 4 skipped / 0 failed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
ab82347d42
commit
1fd515436c
19 changed files with 6734 additions and 5694 deletions
|
|
@ -30,9 +30,13 @@ regression; item 6 is folded into CH6a's existing scope. Item 1
|
|||
fixed — round 1's press-edge logic is provably correct by construction
|
||||
from source, a live headless repro was attempted and blocked (no
|
||||
character on the probe account), and two temporary graphical-only probes
|
||||
are left behind for the next round. Status stays CODE-COMPLETE pending
|
||||
the next user gate round (still needed for item 1, CH6, and a final
|
||||
in-client visual pass on everything fixed so far).
|
||||
are left behind for the next round. **CH6a (main-window layout + 8-grip
|
||||
resize) landed CODE-COMPLETE the same day** — see its ledger row and the
|
||||
updated round-1 items H/I and round-2 item 6 dispositions below; CH6b
|
||||
(floating windows 1–4) and CH6c (opacity) remain not started. Status
|
||||
stays CODE-COMPLETE pending the next user gate round (still needed for
|
||||
item 1, CH6a's own visual confirmation, CH6b/CH6c, 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.
|
||||
|
|
@ -135,6 +139,26 @@ implementer per slice against a pinned contract (per
|
|||
bottom-right corner (a corner-grip axis-composition bug, likely the
|
||||
same resize-mask gap already scoped for the Top edge above, now
|
||||
confirmed to also affect corner grips specifically).
|
||||
**CODE-COMPLETE (this commit).** The wrong layout swap, the 8-grip
|
||||
`LayoutImporter`/`UiResizeGrip` port, and both round-2 symptoms landed
|
||||
together: the real DAT ground-truth (`0x2100006F` lives in
|
||||
`dats.Local`, not `dats.Portal`) showed the top strip is authored as a
|
||||
Type-2 Dragbar, not an 8th Resizebar grip as the research doc's
|
||||
decomp-only reading assumed — `UiRoot` now gives a directly-hit grip's
|
||||
own edges priority over its generic proximity heuristic, and a
|
||||
directly-hit move handle the same priority over ambient proximity, so
|
||||
the plain top strip moves the window while its two corners (which ARE
|
||||
grips) resize it including the Y axis, matching retail exactly. The
|
||||
diagonal-cursor gap needed no new cursor plumbing —
|
||||
`CursorFeedbackController`/`RetailCursorCatalog` already had the exact
|
||||
DAT-matching Type-9 cursor ids pinned; they just never received a
|
||||
genuine diagonal edge combination before. The corner-grow gap
|
||||
dissolved with the `RetailWindowChrome.Imported` mount (0x2100006F's
|
||||
own border art IS the window chrome — no nine-slice wrapper, no
|
||||
content crop, frame==content) using the DAT's real
|
||||
minH=100/maxH=2000/minW=300/maxW=2000. Register row AP-185 files the
|
||||
one accepted simplification (the `_Locked` cosmetic border-art swap on
|
||||
`UiLocked` is not ported; the live grip skin shows unconditionally).
|
||||
- **CH6b — floating windows 1–4.** Mount `0x2100005B` ×4 as
|
||||
always-resident children per `gmGamePlayUI::SetupChildren
|
||||
@0x004E9EC0` (ids 0x10000505/0x1000050E/0x1000050F/0x10000510);
|
||||
|
|
@ -174,7 +198,8 @@ implementer per slice against a pinned contract (per
|
|||
| CH4 commands | `090825e7` | 12,221 passed / 4 skipped / 0 failed | REJECT; fixed `724ef2d3`; re-review APPROVE-WITH-FIXES; closed `5d247d55` | pending |
|
||||
| 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 |
|
||||
| CH6 chat-window shell parity | not started | — | — | filed 2026-08-09 at user gate round 1; research first |
|
||||
| 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 |
|
||||
| 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) |
|
||||
|
||||
### CH4 closeout (2026-08-09)
|
||||
|
|
@ -514,9 +539,9 @@ round's scope and filed as slice CH6.
|
|||
| E | `/hslist villas` (and the other three CH4-added request commands) is accepted server-side but produces no visible response. | **FIXED this SHA, closes #362.** New `ClientCommandResponses.cs` parses and renders `ChannelIndex`/`ChannelList`/`AvailableHouses`/`AllegianceInfoResponse`, each ported line-for-line from the named-retail decomp's inbound handlers. Register row TS-70 retired. |
|
||||
| F | Multi-line server text (e.g. `/help`'s reply) doesn't split on embedded `\n` — "probably broken in many places." | **FIXED this SHA.** `ChatWindowController.WrapText` now splits on `\n`/`\r\n` first, then word-wraps each segment independently; the confirmed-correct single-line early-out is unchanged for text with no embedded newline. |
|
||||
| G | The chat input line overflows the window's right edge when the window is resized. | **FIXED this SHA.** The input field's right edge no longer holds a fixed absolute pixel position across a resize (retail edge-mode 0's "frozen at current" fallback, or the `AnchorEdges` default with no `Right` bit) — `ChatWindowController.Bind` now upgrades it to retail edge-mode 1 (`UiLayoutPolicy`) or the equivalent `AnchorEdges.Right` stretch, so the right edge tracks every resize instead of only the bind-time/channel-change recompute. |
|
||||
| H | Extra/duplicate chat windows appear on number keys 1/2/3/4. | **NEW SLICE CH6** — see the slice list above. Retail has real multi-window chat with per-window type filters; this needs research before a fix, not a quick patch. |
|
||||
| I | Resizing the chat window only works from one corner, not every corner. | **NEW SLICE CH6** — bundled with H and J as "all-corner resize." |
|
||||
| J | The chat window has transparency issues / visual artifacts, and the user wants a transparency setting eventually. | **NEW SLICE CH6** — bundled as "opacity"; the future user-facing transparency setting is noted in the slice's own scope, not promised for CH6's first cut. |
|
||||
| H | Extra/duplicate chat windows appear on number keys 1/2/3/4. | **STILL CH6b** (not this commit) — retail's real floating windows 1–4 (`0x2100005B` ×4) and their `ToggleFloatingChatWindow1..4` keybinds are a separate slice; CH6a only fixed the shell (import/resize) of the main window. |
|
||||
| I | Resizing the chat window only works from one corner, not every corner. | **FIXED at CH6a (this commit).** Root cause: the main window imported the WRONG LayoutDesc (`0x21000006`, an unrelated layout whose root/resize-bar appear nowhere in the EoR gameplay UI) instead of retail's real `0x2100006F`; every symptom (crop hacks, the dropped resize bar, the one-corner-only resize) was downstream of that. The swap + a new `LayoutImporter` case for element type 9 (`UIElement_Resizebar`, `UiResizeGrip`) + `UiRoot` grip-priority hit-testing now resize from all 4 edges and all 4 corners, while the top strip (a Type-2 Dragbar, not a grip) correctly remains a move-only affordance. |
|
||||
| J | The chat window has transparency issues / visual artifacts, and the user wants a transparency setting eventually. | **Artifacts FIXED at CH6a (this commit)** — the reported visual glitches were downstream of importing the wrong LayoutDesc (stray unparented siblings, the hand-cropped content width, the 9px patch); all retired with the correct import, and the two hard-coded translucent-black tints on the transcript/input are removed now that their parent panels draw their own authored background sprites. **Real opacity (the future transparency SETTING) remains CH6c** — `UiRenderContext.AlphaMod` still has no draw-path consumer. |
|
||||
|
||||
Findings A–G's evidence: this commit's diff + the new/updated tests in
|
||||
`tests/AcDream.Runtime.Tests/Gameplay/PlayerMovementControllerTests.cs`,
|
||||
|
|
@ -541,7 +566,7 @@ The user tested round 1's fixes live and reported six more findings.
|
|||
| 2 | Retail shows "In Portal Space…" at the TOP of the screen, SMALL font, tell-yellow (the SpewBox) — acdream renders a big centered white/yellow overlay instead. | **FIXED this SHA.** Verified in the decomp: `gmSmartBoxUI::UseTime`'s notice emits via `ECM_UI::SendNotice_DisplayStringInfo(0x1A, ...)`, which forwards to `AddTextToScroll(str, 0x1A, 1, 0)` — type `0x1A` is HARDCODED to the SpewBox (`docs/research/2026-08-09-chat-retail-interface-text.md` §1.1/§4.2), the same surface every other `ClientLocal` refusal (jump-in-air, etc.) already uses. `PortalWaitNoticeController` (the dedicated centered-overlay presentation) and its lease are DELETED outright; `PortalTunnelPresentation`'s round-1 per-rotation-segment emission cadence is unchanged, now writing straight into `RuntimeCommunicationState.AddText(text, RetailLogTextType.ClientLocal)` — the SpewBox's own dedupe-at-index-0 (`SpewBoxState.Tick`) collapses the per-segment repetition exactly as retail's `gmSpewBoxUI::Update` does. No conflict with the decomp — the fix and the user's report agree exactly. |
|
||||
| 3 | (Round 1 item B, `[System] ` prefix) | **CONFIRMED FIXED** — no regression, no further action. |
|
||||
| 4+5 | `/help` output differs from retail; `/help death` prints an acdream META-MESSAGE ("This is a retail help-topic group; acdream has not yet extracted its exact retail listing text…"); spacing/alignment is off. | **FIXED this SHA via verbatim extraction, not authorship.** `tools/pdb-extract/sweep_weenie_strings.py` generalized to decode narrow `PStringBase<char>` literals (the Help* family's shape) alongside its original UTF-16LE support, then swept every `ClientCommunicationSystem::HelpXxxGroup` function's exact byte extent (read from the pseudo-C's own function-header addresses) against the PDB-paired `C:\Users\erikn\Downloads\acclient.exe` (verified MATCH). 4 of 7 groups (death/status/text/allegiances) are now COMPLETE verbatim listings — `/help death` now prints retail's real 8-line text, byte-exact including the retail-authentic trailing space on the `@day` line. The other 3 (channels/chatting/commands) delegate part or all of their detail text to `ClientCommunicationSystem::HelpStupidChannelHack @0x0056f290`, which builds its output from BN-mislabeled data fragments around a live channel-name lookup — genuinely not decodable with confidence; each keeps its own verbatim summary line plus an explicit UNVERIFIED note citing the address, never a fabricated meta-message. 7 of the ~35 channel one-liners are also now verbatim (a/guild/gu, general/cg, trade/ct, lfg/clfg, roleplay/crp, society/soc, olthoi/o), each including retail's own "Also: @alias" text — this is also the alignment/spacing fix, since the fabricated summaries never matched retail's exact wording. Register row AP-184 filed; ISSUES.md #364 tracks the remaining 3-group gap. `RetailCommandHelpTableTests.cs` (new) pins every complete listing and the partial/UNVERIFIED shape byte-exact. |
|
||||
| 6 | Resize is still buggy: missing diagonal (corner) cursor feedback, and the window cannot grow in the Y axis when dragging from the bottom-right corner. | **FOLDED into CH6a's spec** (not fixed this SHA — CH6a itself has not started; see the slice list above, now carrying these two symptoms alongside the pre-existing resize-mask/LayoutDesc-import scope). |
|
||||
| 6 | Resize is still buggy: missing diagonal (corner) cursor feedback, and the window cannot grow in the Y axis when dragging from the bottom-right corner. | **FIXED at CH6a (this commit).** The 4 corner grips (`0x1000069B`/`D`/`F`, `0x100006A1`) decode retail's exact per-grip `BorderLocation` bools (`0x2A`-`0x2D`) and `UiRoot` gives a directly-hit grip's own edges priority, so `CursorFeedbackController`'s existing (already retail-pinned) `KindForResize` now actually receives a diagonal edge combination when hovering a corner — no new cursor ids were invented; `RetailCursorCatalog`'s pinned Type-9 cursor ids already matched the DAT exactly. The corner-grow gap traced to the same wrong-LayoutDesc root cause as item I: mounting through the universal nine-slice wrapper + a 490px content crop against 0x21000006's own (irrelevant) constraints created an indirection prone to stale-baseline growth bugs; 0x2100006F's root IS the complete retail chrome, so CH6a mounts it with `RetailWindowChrome.Imported` (no wrapper, no crop, frame==content) using the DAT's real `minH=100/maxH=2000/minW=300/maxW=2000`, collapsing the whole class. `ChatLayoutConformanceTests.MountedChatWindow_BottomRightGrip_GrowsBothAxes_NotOnlyShrinks` exercises the exact reported gesture end-to-end. |
|
||||
|
||||
Evidence for items 2, 4, and 5: this commit's diff + `tests/AcDream.UI.Abstractions.Tests/Panels/Chat/RetailCommandHelpTableTests.cs` (new) + the deletion of
|
||||
`tests/AcDream.App.Tests/UI/PortalWaitNoticeControllerTests.cs` (its subject
|
||||
|
|
@ -553,3 +578,15 @@ diagnostics; the two temporary probes and the `jump-probe` headless bot
|
|||
policy are the round's deliverable for item 1, pending either a successful
|
||||
next-round repro or a character created on `probeaccount2`. Full Release
|
||||
suite green (see the commit message for the exact count).
|
||||
|
||||
Item 6's evidence landed in a LATER commit, the CH6a slice itself (see the
|
||||
ledger row above): `src/AcDream.App/UI/UiResizeGrip.cs` (new),
|
||||
`src/AcDream.App/UI/Layout/DatWidgetFactory.cs` (Type-9 factory case),
|
||||
`src/AcDream.App/UI/UiRoot.cs` (grip-priority hit-testing in `OnMouseDown` /
|
||||
`HoverResizeEdges`), `src/AcDream.App/UI/Layout/ChatWindowController.cs` and
|
||||
`src/AcDream.App/UI/RetailUiRuntime.cs` (the `0x2100006F` swap + `Imported`
|
||||
chrome mount), plus new/updated tests in
|
||||
`tests/AcDream.App.Tests/UI/Layout/DatWidgetFactoryTests.cs`,
|
||||
`tests/AcDream.App.Tests/UI/UiRootInputTests.cs`,
|
||||
`tests/AcDream.App.Tests/UI/CursorFeedbackControllerTests.cs`, and
|
||||
`tests/AcDream.App.Tests/UI/Layout/ChatLayoutConformanceTests.cs`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue