fix(G.3): recenter streaming onto the spawn landblock at login (#133)

A character saved inside a far dungeon hung at the #107 auto-entry hold because
the streaming center was fixed at the startup default and the login spawn never
recentered it, so the dungeon never streamed. Mirror the teleport-arrival
recenter on the login player-spawn path: when the player's spawn landblock
differs from the current center, recenter before translating the spawn position
(landblock-local -> new-center frame). No-op for a same-landblock (normal
Holtburg) login.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-13 19:00:14 +02:00
parent 95d9dab4bb
commit 47ae237e7b

View file

@ -2436,6 +2436,40 @@ public sealed class GameWindow : IDisposable
// landblock; each neighbor landblock is offset by 192 units per step.
int lbX = (int)((p.LandblockId >> 24) & 0xFFu);
int lbY = (int)((p.LandblockId >> 16) & 0xFFu);
// G.3 (#133): recenter streaming onto the player's spawn landblock at
// login. The streaming center (_liveCenterX/_liveCenterY) is pinned to
// the startup default (Holtburg, 0xA9B4) and is otherwise only moved by
// the teleport-arrival path (OnLivePositionUpdated, ~line 4901). A
// character saved INSIDE a far dungeon spawns with that dungeon's
// landblock id, but the center never followed it, so the dungeon (tens
// of km away in world space) never streamed and the #107 auto-entry
// gate's SampleTerrainZ(pe.Position) waited forever — the player hung
// frozen at login. Mirror the teleport-arrival recenter HERE, for the
// PLAYER's spawn only, BEFORE the world-space translation below: when
// the spawn landblock differs from the current center, move the center
// onto it so the spawn maps to (PositionX, PositionY, PositionZ) in the
// new center frame (identical to the teleport path's
// `newWorldPos = new Vector3(p.PositionX, p.PositionY, p.PositionZ)`),
// and the next StreamingController.Tick observes the new center and
// streams the spawn landblock.
//
// No-op for a normal Holtburg login: the saved spawn landblock equals
// the default center, so the guard is false and origin/worldPos are
// byte-identical to the pre-fix path. Gated on the player guid so NPC /
// object spawns never move the center. Idempotent + thrash-free: a
// re-sent CreateObject for the same spawn landblock leaves the center
// already-equal, so the guard is false on every repeat.
if (spawn.Guid == _playerServerGuid
&& (lbX != _liveCenterX || lbY != _liveCenterY))
{
Console.WriteLine(
$"live: login spawn — recentering streaming from ({_liveCenterX},{_liveCenterY}) " +
$"to ({lbX},{lbY}) for player spawn @0x{p.LandblockId:X8}");
_liveCenterX = lbX;
_liveCenterY = lbY;
}
var origin = new System.Numerics.Vector3(
(lbX - _liveCenterX) * 192f,
(lbY - _liveCenterY) * 192f,