fix(app,runtime,headless): Campaign CC slice CC4 review-fix round — F1-F12
Dual-lens review of CC4 (0e71d3b8) returned architectural FAIL (F1, F6)
and retail-fidelity PASS-with-reservations (F2, F3, F4), plus LOW
findings F5, F7-F12. F13 (TS-82's merge collision with campaign-cc6a) is
merge mechanics for the orchestrator, not addressed here.
F1 (HIGH, blocking): CharacterCreationUiController never released
UiRoot.FixedCanvasSize, on a FALSE premise that CharacterManagementUi-
Controller does a per-tick set (it does not — it sets once on activation
and nulls on Deactivate/Dispose). Root cause: RuntimeCharacterCreation-
State had no CompleteEnter() analogue to RuntimeCharacterSelectionState's,
so the creation view reported IsActive=true for an entire in-world
session. Added CompleteEnter(), wired at both LiveSessionController
in-world edges (StartCore, EnterHighlightedCore); made Open/Close/
Deactivate/Dispose set/null the canvas symmetrically; corrected the false
comment and ledger claim; added FixedCanvasSize test coverage.
F2 (MEDIUM-HIGH, blocking): the attribute-slider scalar mapping was not
retail's. Fixed display to value/100f (UpdateAttributeValues @
0x0048251d) and the drag inverse to truncate+clamp-low-only, no rescale
(ListenToElementMessage @ 0x004829c0, independently re-verified against
the decomp). Added tests at scalar 0.5/0.0 plus a display-direction test.
F3 (MEDIUM, blocking): ported the unported heritage-button tab-restore
arm (ListenToElementMessage @ 0x004e9450) — SHOW/HIDE id sets independently
re-derived from the decomp, including the genuine Lugian (0x100005f1)
no-restore quirk, reproduced faithfully. Wired via a new HeritagePage
click callback; added restore + quirk tests.
F4 (MEDIUM): ported SetTown's (@ 0x0047c360) separate per-town page-root
state literal (Holtburg->0x10000034 etc.), independently re-derived from
the decomp's tail-merged branches; wired via the existing
IUiDatStateful.TrySetRetailState seam; added a test.
F5 (MEDIUM): softened AD-103's unmeasured pixel-equivalence claim.
F6 (MEDIUM, blocking): DECISION — install ChargenOptions in the headless
content path (chosen over marking headless creation out-of-scope).
HeadlessSessionHost now calls InstallOptions off the shared content
lease's Dats, beside the existing InstallSpellMetadata call.
F7: AP-213 already named the label format and click/double-click
substitution explicitly on inspection — no edit needed.
F8: AP-212 now names all six DoRandom primitives with a known landing site.
F9: AD-101 retirement corrected to precede CC5's Finish un-ghosting.
F10: merged ItemAppraisalTextFormatter's duplicate <summary> block.
F11: fixed TS-82's wrong AP-211 cross-reference.
F12: cached the chargen DatStringResolver once per composition instead of
per ResolveText call.
Runtime 1713/0, App 5125/13 skips (+8 new tests), Headless 165/0, full
solution Release build green. Live-DAT probes 7/7 under
ACDREAM_PROBE_LIVE_MOUNT=1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
0e71d3b829
commit
ec854db045
12 changed files with 419 additions and 30 deletions
|
|
@ -915,6 +915,9 @@ public sealed class LiveSessionController
|
|||
_inWorld = true;
|
||||
_activeSelection = selection;
|
||||
CharacterSelectionState.CompleteEnter(selection.CharacterId);
|
||||
// CC4 review-fix F1: same in-world edge as selection's own
|
||||
// CompleteEnter above.
|
||||
CharacterCreationState.CompleteEnter();
|
||||
host.ApplyEnteredWorld(selection);
|
||||
if (!IsCurrent(scope, generation))
|
||||
return new LiveSessionStartResult(LiveSessionStartStatus.Deferred);
|
||||
|
|
@ -1206,6 +1209,10 @@ public sealed class LiveSessionController
|
|||
_inWorld = true;
|
||||
_activeSelection = selection;
|
||||
CharacterSelectionState.CompleteEnter(character.CharacterId);
|
||||
// CC4 review-fix F1: covers BOTH callers of this shared core
|
||||
// (EnterSelectedCore and EnterCreatedCharacterCore) — the same
|
||||
// in-world edge as selection's own CompleteEnter above.
|
||||
CharacterCreationState.CompleteEnter();
|
||||
scope.Host.ApplyEnteredWorld(selection);
|
||||
if (!IsCurrent(scope, generation))
|
||||
return CharacterSelectionResult(RuntimeCommandStatus.Inactive);
|
||||
|
|
|
|||
|
|
@ -400,6 +400,39 @@ public sealed class RuntimeCharacterCreationState : IDisposable
|
|||
Publish(RuntimeCharacterCreationDeltaKind.Reset);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Campaign CC slice CC4 review-fix round (F1): the character-creation
|
||||
/// analogue of <see cref="RuntimeCharacterSelectionState.CompleteEnter"/>.
|
||||
/// Unlike selection (whose <c>IsActive</c> is computed from a
|
||||
/// <c>Lifecycle</c> enum that already has an <c>InWorld</c> state),
|
||||
/// creation has no lifecycle enum — this flips <see cref="_active"/>
|
||||
/// (and therefore <see cref="RuntimeCharacterCreationSnapshot.IsActive"/>)
|
||||
/// straight to <see langword="false"/>, mirroring selection's OBSERVABLE
|
||||
/// effect at the same call sites (<c>LiveSessionController.StartCore</c>
|
||||
/// and <c>EnterHighlightedCore</c>, both already call
|
||||
/// <c>CharacterSelectionState.CompleteEnter</c> at the exact point the
|
||||
/// session transitions in-world). Session field data (heritage/gender/
|
||||
/// name/etc.) is left untouched — only <see cref="Reset"/> clears it,
|
||||
/// matching selection's own CompleteEnter, which does not clear its
|
||||
/// roster either. Before this fix, nothing ever cleared
|
||||
/// <see cref="_active"/> between <see cref="Begin"/> and the NEXT
|
||||
/// <see cref="Reset"/>/<see cref="Dispose"/>, so the creation view
|
||||
/// reported active for an entire in-world session — the CC4 review's
|
||||
/// F1 finding (a permanently re-pinned <c>UiRoot.FixedCanvasSize</c>
|
||||
/// once the chargen screen had ever been opened).
|
||||
/// </summary>
|
||||
internal void CompleteEnter()
|
||||
{
|
||||
lock (_gate)
|
||||
{
|
||||
if (_disposed || !_active)
|
||||
return;
|
||||
_active = false;
|
||||
_revision++;
|
||||
}
|
||||
Publish(RuntimeCharacterCreationDeltaKind.StateChanged);
|
||||
}
|
||||
|
||||
internal void Reset(RuntimeGenerationToken generation)
|
||||
{
|
||||
lock (_gate)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue