From 47ae237e7b0dee87ff3c9def1fd40111077cbc71 Mon Sep 17 00:00:00 2001 From: Erik Date: Sat, 13 Jun 2026 19:00:14 +0200 Subject: [PATCH] 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) --- src/AcDream.App/Rendering/GameWindow.cs | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 1c1db412..16956ac4 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -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,