revert(teleport): drop the Slice 2 outdoor readiness-gate hold

User-tested: the Slice 2 'hold outdoor until landblock loaded' gate made
EVERY outdoor teleport a ~10 s freeze, because the destination landblock
does NOT load fast during the hold (lbs=0 the whole time — the #138
streaming gap + _datLock starvation from the CreateObject flood). The hold
was band-aiding a broken/slow foundation rather than fixing it, and it never
actually prevented the #145 edge cascade anyway (it force-snapped onto
NO-LANDBLOCK after the timeout regardless).

Reverts ad8c24e..c880973 to the pre-Slice-2 state (00ef47e): outdoor places
immediately again (fast teleports). The genuine bug found along the way —
IsLandblockLoaded queried the wrong key form (& 0xFFFF0000 vs the stored
| 0xFFFF) — is preserved in the history (c880973) and will be re-applied when
we re-introduce a proper hold ON A FIXED FOUNDATION.

Decision (user, 2026-06-21): fix the foundation FIRST — fast/complete
streaming during teleport (#138), the post-teleport lost-collision bug, and
the FPS leak (Work item C) — then revisit the teleport-flow animation. Slice 1
(the pure TeleportAnimSequencer) stays in (dormant, unwired, harmless).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-21 21:46:24 +02:00
parent c8809735f3
commit dd2eb8b39d
6 changed files with 43 additions and 195 deletions

View file

@ -5471,7 +5471,6 @@ public sealed class GameWindow : IDisposable
// impossible claim / timeout. PortalSpace keeps input frozen meanwhile.
EnsureTeleportArrivalController();
_pendingTeleportRot = rot;
_lastArrivalVerdict = AcDream.App.World.ArrivalReadiness.NotReady; // reset probe state for each new hold
_teleportArrival!.BeginArrival(newWorldPos, p.LandblockId);
}
}
@ -5482,8 +5481,6 @@ public sealed class GameWindow : IDisposable
// runtime deps are wired by then).
private AcDream.App.World.TeleportArrivalController? _teleportArrival;
private System.Numerics.Quaternion _pendingTeleportRot = System.Numerics.Quaternion.Identity;
// §3.4 arrival-gate probe: tracks previous verdict so we log only the flip.
private AcDream.App.World.ArrivalReadiness _lastArrivalVerdict = AcDream.App.World.ArrivalReadiness.NotReady;
// #145: the LANDBLOCK-relative (cell-local) position used to SEED the player
// body's cell-relative CellPosition. This is the ONE place the streaming center
@ -5512,36 +5509,24 @@ public sealed class GameWindow : IDisposable
// Reuses the #107 login readiness triplet (GameWindow.cs:1010-1024), evaluated
// against the teleport's (destPos, destCell): an impossible indoor claim short-
// circuits to immediate placement; otherwise hold until terrain is sampled and,
// for an indoor cell, the cell struct has hydrated. For an outdoor cell, hold
// until the physics landblock is registered (§3.4 #145 residual fix).
// for an indoor cell, the cell struct has hydrated.
private AcDream.App.World.ArrivalReadiness TeleportArrivalReadiness(
System.Numerics.Vector3 destPos, uint destCell)
{
bool claimUnhydratable = IsSpawnClaimUnhydratable(destCell);
// #135: an INDOOR destination (sealed dungeon / building interior) gates on the
// EnvCell FLOOR hydrating. Retail places on the cell floor. An OUTDOOR destination
// places immediately on the server-authoritative position — see TeleportArrivalRules
// (#145: holding is futile because streaming doesn't progress during a PortalSpace
// hold; the stale source landblock is dropped at recenter so the resolve trusts the
// server cell until the destination streams in).
bool indoor = (destCell & 0xFFFFu) >= 0x0100u;
bool indoorCellReady = indoor && !claimUnhydratable
&& _physicsEngine.IsSpawnCellReady(destCell);
// §3.4: for outdoor arrivals, gate on the physics landblock being resident.
// The landblock id is the high 16 bits of the cell id (i.e. destCell & 0xFFFF0000).
// Streaming progresses during the hold because the streaming controller runs before
// TeleportArrivalController.Tick. The 10 s _maxHoldFrames safety-net remains active.
bool outdoorReady = !indoor
&& _physicsEngine.IsLandblockLoaded(destCell & 0xFFFF0000u);
var verdict = AcDream.App.World.TeleportArrivalRules.Decide(
claimUnhydratable, indoor, indoorCellReady, outdoorReady);
if (AcDream.Core.Physics.PhysicsDiagnostics.ProbeArrivalGateEnabled
&& verdict != _lastArrivalVerdict
&& verdict != AcDream.App.World.ArrivalReadiness.NotReady)
{
Console.WriteLine(System.FormattableString.Invariant(
$"[arrival-gate] destCell=0x{destCell:X8} landblock=0x{(destCell & 0xFFFF0000u):X8} verdict={verdict} indoor={indoor} landblockCount={_physicsEngine.LandblockCount}"));
}
_lastArrivalVerdict = verdict;
return verdict;
return AcDream.App.World.TeleportArrivalRules.Decide(
claimUnhydratable, indoor, indoorCellReady);
}
// The deferred snap (the original OnLivePositionUpdated steps 2-5), now run only