fix(chargen): Campaign CC gate round 1 Batch D — gmCG3DView environment backdrop
Retail's chargen 3D views (Appearance and Summary) are not black behind the model: gmCG3DView::Update @0x004EE9D0 constructs a SECOND CPhysicsObj from the current heritage's HeritageGroup_CG.environmentSetupID field (acclient.h verbatim struct layout; the decompiler elides the actual field read, but HeritageGroup_CG::GetSubDataIDs @0x005c05d0 explicitly walks iconImage/setupID/environmentSetupID by name, confirming the identity) and adds it to the SAME viewport's creature_mode_objects the player object lives in, inserted BEFORE the player (whose own re-AddObject happens much later, at ~0x004ef199, after the full clothing ObjDesc composes). The backdrop gets no explicit position/orientation/scale — CPhysicsObj:: makeObject(eax_32, 0, 1) leaves it at the scene origin with identity orientation, same as the player object's own placement. This id was already parsed as ChargenHeritageOptions.EnvironmentSetupId (ChargenTableReader.cs) but never consumed anywhere in production (GF-7/ GF-14). Fixed by: - ChargenPreviewEntityBuilder.TryBuildBackdrop: builds a plain, unposed Setup mesh from the heritage's EnvironmentSetupId, returning null for id 0/unset or an unresolvable Setup (retail's own INVALID_DID gate). - PrivateEntityViewportRenderer: an optional second entity slot (SetBackdrop), reserved via a backdropRenderId constructor parameter so paperdoll and creature-appraisal — which never pass one — cannot acquire a second entity even by accident (SetBackdrop throws without a reserved slot). Per-entity mesh-reference/texture-owner lifetime is factored into a private EntitySlot helper shared by both the main and backdrop slots. Draw-entity assembly is a pure, directly-testable helper (BuildDrawEntities) that puts the backdrop first, matching retail's own AddObject insertion order. - ChargenPreviewController.Rebuild: rebuilds the backdrop whenever the HERITAGE changes (narrower than the existing camera-eye-reset gate, since environmentSetupID is a pure function of heritage, never gender or appearance selection). Both Appearance and Summary get the fix from the same ChargenPreviewRenderer facade — confirmed both pages call the identical gmCG3DView::Update on their own gmCG3DView instance, so no page-specific code was needed. Lighting was independently re-verified against the same function's SetLight call (DISTANT_LIGHT, intensity 2.0, direction (0.3, 1.9, 0.65), default white color) and found to already match byte-for-byte what CC6a shipped. Also files docs/ISSUES.md #409 for GF-16 (client-wide UI tooltip system), investigated in the same root-cause pass but explicitly out of this batch's scope, and marks it DEFERRED in the findings doc. Tests: 11 new/extended (ChargenPreviewEntityBuilderTests.TryBuildBackdrop_*, ChargenPreviewControllerTests backdrop rebuild/swap/absent/no-op cases, PrivateEntityViewportRendererDrawOrderTests pinning the paperdoll/creature- appraisal single-entity invariant). Live-DAT measurement: all 13 retail heritages' EnvironmentSetupId resolve to a real, drawable installed Setup. App suite 5307/3 -> 5321/3 (+14, 0 regressions). Runtime 1735/0 unchanged. Launcher.Core.Tests 337/0 and Launcher.Tests 67/0 unchanged (first build of the merged tree carrying the #406 launcher merge). Full solution: 14508 total / 14504 passed / 4 skipped / 0 failed, dotnet test exit code 0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
0b05b58514
commit
63bf64c934
9 changed files with 866 additions and 103 deletions
|
|
@ -24,6 +24,59 @@ What does NOT go here:
|
|||
- Every session: scan OPEN issues at start; promote/close anything we touched during the session before ending.
|
||||
- Promoting to a Phase: mark as `DONE (promoted to Phase X)` + commit SHA where the Phase entry landed.
|
||||
|
||||
## #409 — Client-wide UI tooltip system is unshipped (GF-16, deferred out of Campaign CC gate round 1)
|
||||
|
||||
**Status:** OPEN
|
||||
**Severity:** LOW-MEDIUM (cosmetic/discoverability — no gameplay impact, but retail shows a tooltip on hover for ~253 authored elements client-wide and acdream shows none)
|
||||
|
||||
Found during Campaign CC gate round 1's Batch D root-cause investigation
|
||||
(`docs/research/2026-08-16-campaign-cc-gate-round1-findings.md`, GF-16
|
||||
"Hover tooltips missing on all pages"). Explicitly out of Batch D's own
|
||||
scope — Batch D fixed the chargen 3D preview backdrop (GF-7/GF-14) only;
|
||||
GF-16 is a CLIENT-WIDE mechanism, not a chargen-scoped one, and needs its
|
||||
own gate round the same way GF-12's frame carve-out and #408's
|
||||
importer-wide honor did.
|
||||
|
||||
Retail's tooltip pipeline (decomp anchors from the Batch D
|
||||
investigation):
|
||||
|
||||
- `UIElement::StartTooltipAtMouse @0x00460D70` — the per-element entry
|
||||
point; fired from mouse-hover dispatch.
|
||||
- `UIElementManager::StartTooltip @0x0045DE90` and a second call site
|
||||
`@0x00459700` — the manager-level owner that actually builds/positions
|
||||
the tooltip popup element and starts its show/delay timer.
|
||||
- Layout DID `0x21000041` — the authored tooltip popup LayoutDesc (not yet
|
||||
imported/mounted by `LayoutImporter`/`RetailUiRuntime`).
|
||||
- Element properties `P0x47`/`P0x48`/`P0x49`/`P0x4A`/`P0x4B` — the five
|
||||
per-element tooltip-text/behavior properties `UIElement::OnSetAttribute`
|
||||
reads (exact semantics per property still need re-derivation when this
|
||||
issue is picked up — the investigation only confirmed the property IDs,
|
||||
not their individual meanings).
|
||||
- Measured **~253 authored elements client-wide** carry at least one of
|
||||
those five properties (a scope comparable to #408's 1,083-element sweep,
|
||||
though a different property family).
|
||||
- User-facing config: `Misc_TooltipEnable`/`Misc_TooltipDelay` prefs (the
|
||||
Options-panel-adjacent settings that gate whether tooltips show at all
|
||||
and how long the hover dwell is before one appears).
|
||||
|
||||
Fix direction, mirroring #408's own "own gate round" shape: (1) grep-named
|
||||
first on all four decomp anchors above and re-derive the exact show/hide/
|
||||
position/delay state machine (`StartTooltipAtMouse` → `StartTooltip` →
|
||||
popup lifecycle) before writing any pseudocode; (2) import/mount layout
|
||||
`0x21000041` through the existing `LayoutImporter`/`RetailUiRuntime`
|
||||
pipeline; (3) wire client-wide mouse-hover dispatch (likely through the
|
||||
existing `InputDispatcher`/`UiRoot` hover-tracking, if any already exists,
|
||||
or a new hover-timer owner otherwise) to read the five P0x47-P0x4B
|
||||
properties per hovered element; (4) honor `Misc_TooltipEnable`/
|
||||
`Misc_TooltipDelay` from `RuntimeCharacterOptionsState`/
|
||||
`CharacterOptionTable` (Campaign OP's existing option-storage owner); (5)
|
||||
a live-DAT sweep of the ~253 elements (same shape as #408's per-LayoutDesc
|
||||
enumeration) before claiming full coverage, since a partial per-page
|
||||
implementation would repeat the "accumulate a bigger partial table"
|
||||
mistake #306 already named for a different subsystem; (6) its own
|
||||
connected visual gate — hovering a representative sample across multiple
|
||||
screens (chargen, main game UI, chat, Options) side-by-side with retail.
|
||||
|
||||
## #408 — General importer-wide honor of dat property 0x3B (Invisible) is unshipped (1,083 elements client-wide)
|
||||
|
||||
**Status:** OPEN
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue