fix(chargen): Campaign CC gate round 1 closeout — Group 3: round review fixes (F4-F11, F14, F16)

The remaining code-bearing findings from the round review, F4-F16 minus
the doc-only items (batched separately):

- F4: three client-wide UiButton corpus sweeps (LabelBox path — exactly
  the 4 Town buttons, confined to chargen; conflicting custom-selection-
  pair + standard Normal/Highlight media — zero found, no gate
  tightening needed; per-state label-color map — 209 matches beyond
  chargen, confirming AP-222's mechanism has always been broadly active
  since it shipped generically in DatWidgetFactory).
- F5/F6: LayoutImporter's Batch C un-consumed-children carve-out now
  honors a child's own AuthoredInvisible flag (a narrow honor scoped to
  exactly that carve-out, not the general #408 client-wide one) — the
  chat transcript's new-text indicator (0x1000048C) was building as a
  visible phantom element retail never shows; verified both directions
  against the gold-frame pieces, which do not author Invisible.
- F7: BoundedProcessOutputCapture.AppendLine combines the line text and
  its trailing newline into one buffer and one file open/write/close
  instead of two.
- F9: corrected a stale comment in RuntimeSettingsTargets — #407 split
  DisplayModeCatalog's Resolutions/WindowedResolutions in two, so the
  fullscreen validator's own narrower list is now DELIBERATELY different
  from the Config dropdown's fuller offering, not the "must match" bug
  the comment described.
- F10: documented (not changed) why the LabelBox path's default 3px
  inset and the face-relative +4px gap in DatWidgetFactory.BuildButton
  are deliberately different numbers — neither carries a retail
  citation, and moving either to match the other would be an unfounded
  guess on a button that currently works correctly.
- F11: Heritage/Profession/Summary/Town description pages now compose
  DatRichText.Compose's result ONCE inside their already revision-gated
  Refresh, caching the built line list instead of re-wrapping on every
  draw call.
- F14: documented (not changed) why PrivateEntityViewportRenderer's
  _animatedIds set carrying a reserved-but-never-drawn backdrop id is
  harmless — BuildDrawEntities already excludes a null/empty backdrop
  from the actual draw list, so the id is never looked up.
- F16: the Summary preview now uses its own render-id pair
  (SummaryPreviewRenderId/SummaryPreviewBackdropRenderId, 0xDA11D035/
  0xDA11D036) instead of sharing the Appearance page's
  (0xDA11D032/0xDA11D034) — confirmed by tracing
  FixedEntityTextureOwnerLease through TextureCache to
  CompositeTextureArrayCache's shared owner tracker that both pages'
  previews share ONE process-wide TextureCache, so sharing render ids
  was a real cross-page texture-release collision (either page's own
  re-dress or disposal could release the OTHER page's still-active
  textures), not a theoretical one.

F3's own register bookkeeping (AP-229 addendum) and F12's register/AD
header-count corrections land in the docs-only commit alongside F15.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-16 15:34:07 +02:00
parent 0fed5fdd91
commit bd359d5181
17 changed files with 636 additions and 37 deletions

View file

@ -1071,6 +1071,15 @@ internal sealed class LivePresentationCompositionPhase
chargenCatalog,
d.DatLock);
interaction.RetainedUi.Runtime.ChargenPreviewControl = chargenPreviewController;
// Campaign CC gate round 1 closeout (Group 1, R2-5): the two
// Batch G STOPPED items land here — chargenCatalog already
// implements all three color-wheel seams (TryGetPalSet/
// TryGetClothingTable/TryGetColor), same instance as the
// preview control just above, same one-shot composition-time
// assignment.
interaction.RetainedUi.Runtime.ChargenPalSetSource = chargenCatalog;
interaction.RetainedUi.Runtime.ChargenClothingTableSource = chargenCatalog;
interaction.RetainedUi.Runtime.ChargenPaletteColorSource = chargenCatalog;
bindings.AdoptRelease(
"chargen preview control",
() =>
@ -1142,7 +1151,17 @@ internal sealed class LivePresentationCompositionPhase
foundation.SceneLighting!,
foundation.TextureCache,
foundation.MeshAdapter!,
camera: summaryCamera),
camera: summaryCamera,
// F16 (Campaign CC gate round 1 closeout): the Summary
// page's OWN render-id pair — see
// ChargenPreviewEntityBuilder.SummaryPreviewRenderId's
// own doc for why sharing the Appearance page's pair
// (the pre-existing default) is a real cross-page
// texture-release collision, not merely untidy, since
// both pages share the SAME foundation.TextureCache
// passed one line above.
renderId: AcDream.App.Rendering.ChargenPreviewEntityBuilder.SummaryPreviewRenderId,
backdropRenderId: AcDream.App.Rendering.ChargenPreviewEntityBuilder.SummaryPreviewBackdropRenderId),
static value => value.Dispose());
IUiViewportRenderer? previousSummaryRenderer = summaryViewport.Renderer;
summaryViewport.Renderer = summaryPreviewLease.Resource;
@ -1170,7 +1189,15 @@ internal sealed class LivePresentationCompositionPhase
// OUT full-body framing (gmCGSummaryPage::InitializePage @
// 0x0047bbf0), not the Appearance page's zoomed-in default —
// see ChargenPreviewController's own ctor doc comment.
useZoomedOutEye: true);
useZoomedOutEye: true,
// F16 (Campaign CC gate round 1 closeout): MUST match the
// renderId/backdropRenderId pair given to summaryPreviewLease's
// own ChargenPreviewRenderer above — see
// ChargenPreviewEntityBuilder.SummaryPreviewRenderId's own
// doc for why sharing the Appearance page's pair here would
// be a real cross-page TextureCache collision.
renderId: AcDream.App.Rendering.ChargenPreviewEntityBuilder.SummaryPreviewRenderId,
backdropRenderId: AcDream.App.Rendering.ChargenPreviewEntityBuilder.SummaryPreviewBackdropRenderId);
interaction.RetainedUi.Runtime.SummaryPreviewControl = summaryPreviewController;
bindings.AdoptRelease(
"summary preview control",