fix(app): Phase A.1 — run StreamingController.Tick before WorldSession.Tick
Fourth Phase A.1 hotfix. Terrain rendered correctly after the 0xFFFF
fix and the canonicalize fix, but live NPCs and weenies remained
invisible. Root cause: in OnUpdate the live session was draining its
incoming-message queue BEFORE the streaming controller had a chance
to load the initial 5×5 window. The first frame's order was:
1. _liveSession.Tick() — drains the post-login CreateObject flood
(40+ NPCs + items at the player's spawn landblock)
2. _streamingController.Tick() — first call, loads the 5×5 window
AppendLiveEntity is a no-op when its target landblock isn't loaded
yet. So all 40+ spawns landed in step 1 before any landblock existed
in GpuWorldState, were silently dropped, and never came back even
after the landblocks finished loading in step 2.
Fix: swap the order. Streaming runs first so the initial window
exists in GpuWorldState before any CreateObject events drain. This is
correct because the streaming Tick is now synchronous (per the
531c9f9 hotfix) — by the time it returns, all landblocks in the
window are loaded and ready for AppendLiveEntity to find them.
A more robust solution would be a pending-spawn list inside
GpuWorldState that backfills entities when their landblock loads
later. That stays as a future improvement; the simple reorder is
correct for the dominant case (login → flood of spawns into the
already-known initial landblock).
212 tests green.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8941447204
commit
4b01c95ecb
1 changed files with 13 additions and 8 deletions
|
|
@ -1238,14 +1238,13 @@ public sealed class GameWindow : IDisposable
|
|||
|
||||
private void OnUpdate(double dt)
|
||||
{
|
||||
// Drain any pending live-session traffic. Non-blocking — returns
|
||||
// immediately if no datagrams are in the kernel buffer. Fires
|
||||
// EntitySpawned events synchronously on this thread.
|
||||
_liveSession?.Tick();
|
||||
|
||||
// Phase A.1: advance the streaming controller. Computes the observer's
|
||||
// current landblock coordinates and feeds new load/unload diffs to the
|
||||
// streamer, then drains any completed landblocks into GpuWorldState.
|
||||
// Phase A.1: advance the streaming controller FIRST so the initial
|
||||
// landblocks are loaded into GpuWorldState before live-session
|
||||
// CreateObject events drain. The earlier order (live tick first,
|
||||
// streaming tick second) caused the initial CreateObject flood from
|
||||
// login to land before any landblock was loaded; AppendLiveEntity
|
||||
// is a no-op for unloaded landblocks, so all 40+ NPCs/weenies were
|
||||
// silently dropped on the first frame and never rendered.
|
||||
if (_streamingController is not null && _cameraController is not null)
|
||||
{
|
||||
int observerCx = _liveCenterX;
|
||||
|
|
@ -1274,6 +1273,12 @@ public sealed class GameWindow : IDisposable
|
|||
_streamingController.Tick(observerCx, observerCy);
|
||||
}
|
||||
|
||||
// Drain pending live-session traffic AFTER streaming so any incoming
|
||||
// CreateObject events find their landblock already loaded in
|
||||
// GpuWorldState. Non-blocking — returns immediately if no datagrams
|
||||
// are in the kernel buffer. Fires EntitySpawned events synchronously.
|
||||
_liveSession?.Tick();
|
||||
|
||||
if (_cameraController is null || _input is null) return;
|
||||
if (!_cameraController.IsFlyMode) return;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue