fix(render) Campaign FW3 visual gate: sweep-fail frames root on the PLAYER cell

Owner report: floor openings (stairs down) briefly covered by outside
terrain at camera in/out crossings - the historic #119 family
transition arm. Root cause: at a doorway graze the camera collision
sweep can transiently fail; retail total-failure fallback
set_viewer(&player->m_position, 1) (update_viewer @0x00453fad, and the
cell==0 bail @0x00453d1d) copies the WHOLE player Position - objcell_id
included - so retail roots those frames on the player interior cell.
Our fallback left ViewerCellId = 0, which the walk reads as an OUTDOOR
root while the eye is inside: full-screen terrain with the look-in
gates correctly refusing from the interior side - grass over the
stairwell for exactly the failing frames. The fallback now inherits
the pivot/player cell, matching retail byte-for-byte.

Suites: full Release build 0 warnings; hermetic 6,758/0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-08-30 17:45:18 +02:00
parent 77fd40771b
commit f3cb4b6cc9

View file

@ -252,12 +252,23 @@ public sealed class RetailChaseCamera : ICamera
var swept = CollisionProbe.SweepEye(pivotWorld, _soughtEye, cellId, selfEntityId, playerPosition);
publishedEye = swept.Eye;
ViewerCellId = swept.ViewerCellId;
// Total-failure fallback = retail set_viewer(player_pos, reset_sought=1)
// (update_viewer :92886 and the cell==0 bail :92775 — both surface here as
// ViewerCellId == 0): the sought resets to the returned position and
// re-extends from there.
// Total-failure fallback = retail set_viewer(&player->m_position,
// reset_sought=1) (update_viewer @0x00453fad and the cell==0 bail
// @0x00453d1d — both surface here as ViewerCellId == 0): the
// sought resets to the returned position and re-extends, AND the
// viewer INHERITS THE PLAYER'S POSITION CELL — set_viewer copies
// the whole Position, objcell_id included, so retail ROOTS ON THE
// PLAYER'S (interior) CELL for these frames. Leaving 0 here made
// the walk read the frame as OUTDOOR-rooted while the eye was
// inside a doorway graze: full-screen terrain with the look-in
// gates correctly refusing from the interior side — the FW3
// visual gate's "grass briefly covers the stairwell at the
// crossing" report (the historic #119 family's transition arm).
if (swept.ViewerCellId == 0)
{
_soughtEye = swept.Eye;
ViewerCellId = cellId;
}
}
// Retail viewer — the base of next frame's interpolation (step 5).
_publishedEye = publishedEye;