feat(chargen): Campaign CC slice CC6b-MOUNT — Appearance page + preview mount
The page-mount half CC6b-PRE deferred: CharacterCreationAppearancePage (gender buttons, Face/Clothes sub-tabs, nine spin controls with retail's decrement/increment/select-as-current-part OnClickAt zones, nine color swatches, shade scrollbar, zoom/rotate wiring) plus ChargenPreviewController, which bridges the ChargenPreviewRenderer/ChargenPreviewZoomController camera-injection gap CC6a/CC6b-PRE left open and mounts as the third private creature viewport beside paperdoll/creature-appraisal. Color-wheel scouting (campaign risk item 4): live-DAT probe found every color-wheel-family id resolves through existing DatWidgetFactory mappings (Button/Scrollbar/generic fallback) — no new widget type needed. The @140355 gender-flip-on-init oddity (risk item 5): resolved via decomp alone — gmCharGenMainUI's own ctor calls CharGenState::RandomizeCharacter before any page constructs, so retail's chargen screen is never actually blank on open; the Appearance page's gender-flip code always fires against a real, randomly-rolled gender. Filed AP-214 (acdream doesn't port RandomizeCharacter this round, so it opens honestly blank instead) and AP-215 (two narrow visual substitutions: swatch .Selected highlight vs retail's separate overlay, ordinal labels vs retail's icon-only spins). AD-101 retired: the Heritage page's auto-gender-select interim default is deleted now that the Appearance page's real gender buttons exist. TS-82 narrowed to Summary-only. Scope addendum: ChargenPreviewRotationController's parameterless-constructor default changes from 0f to a new RetailDefaultHeadingDegrees=180f constant (retail's InitializePage override, not the ctor's raw 0) — every real gmCG3DView owner converges on 180 before its first frame, so a controller defaulting to 0 was a trap for future consumers. Runtime 1713/0, Core 4786/1 skip, Content 147/0, App 5220/3 skips (Release, ACDREAM_PROBE_LIVE_MOUNT=1) — zero failures across two clean full-solution runs; the one Core.Net.Tests NakEmissionTests flake observed on a third run is the same pre-existing, previously-documented timing flake (zero files under src/AcDream.Core.Net/ touched, passes 100% in isolation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
11374484dc
commit
34c6fceab0
20 changed files with 2109 additions and 57 deletions
|
|
@ -32,6 +32,11 @@ public sealed record CharacterCreationRuntimeBindings(
|
|||
Func<int, RuntimeCommandResult> SelectStartArea,
|
||||
Func<bool, RuntimeCommandResult> Finish,
|
||||
Action RequestExit,
|
||||
/// <summary>Campaign CC slice CC6b-MOUNT: the Appearance page's nine
|
||||
/// spin controls and nine color swatches.</summary>
|
||||
Func<ChargenAppearanceSlot, uint, RuntimeCommandResult>? SetAppearanceIndex = null,
|
||||
/// <summary>CC6b-MOUNT: the Appearance page's shade scrollbar.</summary>
|
||||
Func<ChargenShadeSlot, double, RuntimeCommandResult>? SetShade = null,
|
||||
/// <summary>DAT string lookup (table <c>0x23000002</c>, the SAME table
|
||||
/// every other <c>ID_CharGen_*</c>/<c>ID_Character*</c> key resolves
|
||||
/// through) — used by the Heritage page's composed description text.
|
||||
|
|
@ -130,6 +135,7 @@ internal sealed class CharacterCreationUiController : IDisposable
|
|||
private readonly CharacterCreationProfessionPage _professionPage;
|
||||
private readonly CharacterCreationSkillsPage _skillsPage;
|
||||
private readonly CharacterCreationTownPage _townPage;
|
||||
private readonly CharacterCreationAppearancePage _appearancePage;
|
||||
|
||||
private Vector2 _authoredCanvas;
|
||||
private RuntimeGenerationToken _lastGeneration;
|
||||
|
|
@ -218,6 +224,7 @@ internal sealed class CharacterCreationUiController : IDisposable
|
|||
_professionPage = new CharacterCreationProfessionPage(professionPageRoot, bindings);
|
||||
_skillsPage = new CharacterCreationSkillsPage(skillsPageRoot, bindings, templateResolver);
|
||||
_townPage = new CharacterCreationTownPage(townPageRoot, bindings);
|
||||
_appearancePage = new CharacterCreationAppearancePage(appearancePageRoot, bindings);
|
||||
|
||||
// gmCharGenMainUI::ListenToElementMessage @ 0x004e9450.
|
||||
_back.OnClick = OnBack;
|
||||
|
|
@ -247,6 +254,30 @@ internal sealed class CharacterCreationUiController : IDisposable
|
|||
|
||||
internal UiElement Root => _layout.Root;
|
||||
|
||||
/// <summary>The authored Appearance-page viewport (<c>0x100003bb</c>) —
|
||||
/// CC6b-MOUNT's composition root assigns its <c>Renderer</c> once the
|
||||
/// graphics backend exists (mirrors the paperdoll's own late
|
||||
/// <c>viewport.Renderer = ...</c> assignment).</summary>
|
||||
internal UiViewport? AppearanceViewport => _appearancePage.Viewport;
|
||||
|
||||
/// <summary>CC6b-MOUNT: the late-bound zoom/rotate control surface —
|
||||
/// see <see cref="AcDream.App.Rendering.IChargenPreviewControl"/>'s own
|
||||
/// doc comment for why this is assigned after construction rather than
|
||||
/// threaded through the ctor.</summary>
|
||||
internal AcDream.App.Rendering.IChargenPreviewControl? AppearancePreviewControl
|
||||
{
|
||||
get => _appearancePage.PreviewControl;
|
||||
set => _appearancePage.PreviewControl = value;
|
||||
}
|
||||
|
||||
/// <summary>Gates the Appearance preview's per-frame work on whether
|
||||
/// that specific page — AND the whole chargen screen — is the one
|
||||
/// currently showing. <c>Close()</c> only ever hides <see cref="Root"/>,
|
||||
/// not the individual page roots, so a page-root-only check would stay
|
||||
/// true after the screen closes on the Appearance page. Mirrors the
|
||||
/// paperdoll's own outer-inventory-frame gate.</summary>
|
||||
internal bool IsAppearancePageVisible => Root.Visible && _appearancePageRoot.Visible;
|
||||
|
||||
internal static CharacterCreationUiController? CreateDetached(
|
||||
UiRoot host,
|
||||
ImportedLayout layout,
|
||||
|
|
@ -370,6 +401,7 @@ internal sealed class CharacterCreationUiController : IDisposable
|
|||
_professionPage.Refresh(view, snapshot);
|
||||
_skillsPage.Refresh(view, snapshot);
|
||||
_townPage.Refresh(view, snapshot);
|
||||
_appearancePage.Refresh(view, snapshot);
|
||||
_lastGeneration = snapshot.Generation;
|
||||
_lastRevision = snapshot.Revision;
|
||||
}
|
||||
|
|
@ -437,6 +469,7 @@ internal sealed class CharacterCreationUiController : IDisposable
|
|||
_professionPage.Dispose();
|
||||
_skillsPage.Dispose();
|
||||
_townPage.Dispose();
|
||||
_appearancePage.Dispose();
|
||||
_host.RemoveChild(Root);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue