fix(streaming): #138-B avatar vanishes after teleporting out — don't relocate during PortalSpace
After a teleport-OUT the per-frame avatar-sync (GameWindow ~:8018) called GpuWorldState.RelocateEntity with the player controller's cell — which stays the FROZEN SOURCE cell until PlaceTeleportArrival materializes the destination. So mid-transit it dragged the avatar (which the teleport's rescue/re-inject had correctly placed at the destination center) back into the now-UNLOADED source landblock's pending bucket, where nothing recovers it (RelocateEntity only scans _loaded). Net: the avatar vanished after teleporting out and stayed gone. Fix: skip the per-frame relocate while the player is in PortalSpace. The teleport machinery (DrainRescued + PlaceTeleportArrival) owns the avatar's landblock during transit; per-frame relocation resumes at FireLoginComplete (InWorld). Live-verified with a new env-gated avatar-lifecycle probe (ACDREAM_PROBE_ENT / EntityVanishProbe; [ent] draw-set transitions + [dyn] cull check): pre-fix the trace showed `[ent] APPEND lb=0x0007FFFF(source) -> PENDING -> DRAWSET ABSENT` never recovering; post-fix every teleport goes RESCUE -> ABSENT -> APPEND(destination) -> PRESENT and stays drawn (4 teleports incl. to Holtburg, session ended PRESENT). Suites green: Core 1568(+2 skip), App 468(+2 skip), UI 425, Net 317. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
57e79dc679
commit
afd5f2a012
4 changed files with 111 additions and 1 deletions
|
|
@ -726,6 +726,10 @@ public sealed class RetailPViewRenderer
|
|||
{
|
||||
EntitySphere(e, out var c, out float r);
|
||||
bool indoor = InteriorEntityPartition.IsIndoorCellId(e.ParentCellId);
|
||||
// TEMP (#138-B): trace the avatar's survival through this cull.
|
||||
bool isProbePlayer = AcDream.App.Streaming.EntityVanishProbe.Enabled
|
||||
&& AcDream.App.Streaming.EntityVanishProbe.PlayerGuid != 0
|
||||
&& e.ServerGuid == AcDream.App.Streaming.EntityVanishProbe.PlayerGuid;
|
||||
// #118: under an interior root, outdoor-classified dynamics drew in
|
||||
// the outside stage (pre-clear, seal-protected) — retail draws them
|
||||
// via LScape::draw's per-landcell DrawSortCell, never in the
|
||||
|
|
@ -734,10 +738,18 @@ public sealed class RetailPViewRenderer
|
|||
// seal. Indoor dynamics (incl. exit-portal straddlers, which drew
|
||||
// in BOTH stages) stay — this pass is retail's loop C.
|
||||
if (!rootIsOutdoor && !indoor)
|
||||
{
|
||||
if (isProbePlayer)
|
||||
AcDream.App.Streaming.EntityVanishProbe.LogPlayerDynOnChange(
|
||||
$"cell=0x{(e.ParentCellId ?? 0):X8} indoor=False rootOutdoor={rootIsOutdoor} -> CULLED(outside-stage)");
|
||||
continue;
|
||||
}
|
||||
bool visible = indoor
|
||||
? viewcone.SphereVisibleInCell(e.ParentCellId!.Value, c, r)
|
||||
: viewcone.SphereVisibleOutside(c, r);
|
||||
if (isProbePlayer)
|
||||
AcDream.App.Streaming.EntityVanishProbe.LogPlayerDynOnChange(
|
||||
$"cell=0x{(e.ParentCellId ?? 0):X8} indoor={indoor} rootOutdoor={rootIsOutdoor} viewcone={visible} -> {(visible ? "DRAWN" : "CULLED(viewcone)")}");
|
||||
if (visible)
|
||||
_dynamicsScratch.Add(e);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue