fix(render): harden portal exit handoff
This commit is contained in:
parent
ddbd7e4096
commit
82e4b4cb6d
17 changed files with 896 additions and 119 deletions
|
|
@ -555,7 +555,20 @@ internal sealed class LocalPlayerTeleportPresentation
|
|||
var (snapshot, events) = _animation.Tick(
|
||||
deltaSeconds,
|
||||
worldReady,
|
||||
CurrentTunnelFrame);
|
||||
CurrentTunnelFrame,
|
||||
holdInTunnel: StreamingDiagnostics.TunnelFreezeFrame.HasValue);
|
||||
|
||||
// Retail hides portal space before publishing the WorldFadeIn view
|
||||
// plane (gmSmartBoxUI::UseTime @ 0x004D73D3). Keep that viewport
|
||||
// swap inside the presentation update: the controller's exit event
|
||||
// performs host work, and allowing the terminal projection to escape
|
||||
// while the tunnel remains visible exposes the finite portal mesh as
|
||||
// a one-frame faceted disk. Hiding first is also safe if a render
|
||||
// boundary lands between these two writes: the destination world is
|
||||
// already materialized and receives the old outgoing projection.
|
||||
if (!snapshot.ShowTunnel && _tunnel.IsVisible)
|
||||
_tunnel.Exit();
|
||||
|
||||
_viewPlane.Update(snapshot);
|
||||
return (snapshot, events);
|
||||
}
|
||||
|
|
@ -1228,16 +1241,19 @@ internal sealed class LocalPlayerTeleportController
|
|||
return;
|
||||
break;
|
||||
case TeleportAnimEvent.PlayExitSound:
|
||||
// gmSmartBoxUI::UseTime @ 0x004D6E30 releases destination
|
||||
// cell blocking at the exact portal/world viewport swap.
|
||||
// LoginComplete remains one WorldFadeIn second later.
|
||||
// Retail first hides portal space, then shows the world,
|
||||
// and only afterwards plays Sound_UI_ExitPortal
|
||||
// (gmSmartBoxUI::UseTime @ 0x004D73D3..0x004D7405).
|
||||
// ExitTunnel is idempotent: the production presentation
|
||||
// normally retired it before publishing this snapshot,
|
||||
// while this call enforces the same order for every host.
|
||||
_presentation.ExitTunnel();
|
||||
if (!IsCurrentLifetime(generation, sequence))
|
||||
return;
|
||||
_worldReveal.RevealWorldViewport();
|
||||
if (!IsCurrentLifetime(generation, sequence))
|
||||
return;
|
||||
_presentation.PlayExitCue();
|
||||
if (!IsCurrentLifetime(generation, sequence))
|
||||
return;
|
||||
_presentation.ExitTunnel();
|
||||
if (!IsCurrentLifetime(generation, sequence))
|
||||
return;
|
||||
break;
|
||||
|
|
@ -1707,17 +1723,16 @@ internal sealed class LocalPlayerTeleportController
|
|||
return;
|
||||
break;
|
||||
case TeleportAnimEvent.PlayExitSound:
|
||||
// Release destination cell blocking at the exact
|
||||
// portal/world viewport swap — same edge as the teleport
|
||||
// pump (gmSmartBoxUI::UseTime @ 0x004D6E30), with
|
||||
// Sound_UI_ExitPortal @ 0x004D7405.
|
||||
// Identical retail viewport order to the teleport pump:
|
||||
// hide portal, show/release the destination world, then
|
||||
// play Sound_UI_ExitPortal @ 0x004D7405.
|
||||
_presentation.ExitTunnel();
|
||||
if (!IsCurrentLoginLifetime(generation, revealGeneration))
|
||||
return;
|
||||
_worldReveal.RevealWorldViewport();
|
||||
if (!IsCurrentLoginLifetime(generation, revealGeneration))
|
||||
return;
|
||||
_presentation.PlayExitCue();
|
||||
if (!IsCurrentLoginLifetime(generation, revealGeneration))
|
||||
return;
|
||||
_presentation.ExitTunnel();
|
||||
if (!IsCurrentLoginLifetime(generation, revealGeneration))
|
||||
return;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue