refactor(streaming): complete landblock presentation cutover

Remove the legacy GameWindow apply path and make the concrete render, physics, and static publishers the only production owner graph. Serialize full-window retirement with shared-origin teleport and session boundaries so old coordinate-frame resources cannot survive into a new world or login.
This commit is contained in:
Erik 2026-07-21 22:47:30 +02:00
parent 801d8a189c
commit c79d0a49da
12 changed files with 1373 additions and 402 deletions

View file

@ -129,8 +129,8 @@ public sealed class LandblockBuildFactory
// Hydrate the stabs: same logic as the old OnLoad preload. Each stab
// entity from LandblockLoader carries a SourceGfxObjOrSetupId that we
// expand into per-part MeshRefs via SetupMesh.Flatten / GfxObjMesh.Build.
// GPU upload (EnsureUploaded) happens on the render thread in
// ApplyLoadedTerrain — NOT here.
// GPU upload happens later through the render-thread presentation
// pipeline, never in this worker-side build.
var hydrated = new List<AcDream.Core.World.WorldEntity>(baseLoaded.Entities.Count);
foreach (var e in baseLoaded.Entities)
{
@ -364,7 +364,8 @@ public sealed class LandblockBuildFactory
if (gfx is not null)
{
_physicsDataCache.CacheGfxObj(spawn.ObjectId, gfx);
// Sub-meshes pre-built CPU-side; upload deferred to ApplyLoadedTerrain.
// Sub-meshes are CPU-built here; the presentation pipeline
// defers upload to the render thread.
_ = AcDream.Core.Meshing.GfxObjMesh.Build(gfx, _dats);
var pb = AcDream.Core.Meshing.GfxObjBounds.Get(gfx);
if (pb is not null) sceneryBounds.Add(scaleMat, pb.Value);
@ -417,9 +418,8 @@ public sealed class LandblockBuildFactory
// _physicsEngine.SampleTerrainZ(worldPx) query was structurally racy: at
// build time this landblock is NOT registered in physics yet, so that query
// could only return null (→ this same own-heightmap) or a STALE neighbor's
// height — the previous location's terrain, still registered after a teleport
// recenter (which drops only the single stale CENTER landblock, GameWindow
// :5444) until streaming unloads it — planting scenery at the old location's
// height — the previous location's terrain before the full old-window
// recenter retirement converges — planting scenery at the old location's
// altitude (trees-in-sky, deltaZ up to +500m; confirmed via the
// [scenery-z-stale] probe 2026-06-22). Own-heightmap is correct in every
// case, so the global query is removed (also drops its per-spawn cost).
@ -526,7 +526,7 @@ public sealed class LandblockBuildFactory
/// Portal cells and drawable shell placements are accumulated in the
/// transaction-local <paramref name="envCellBuild"/>. The render thread
/// cannot observe this landblock until the streaming completion carries the
/// finished transaction to ApplyLoadedTerrain.
/// finished transaction to <c>LandblockPresentationPipeline</c>.
///
/// Ported from pre-streaming preload lines 407-565.
/// </summary>
@ -683,8 +683,8 @@ public sealed class LandblockBuildFactory
// Setup carries real Lights — a "light attach point" fixture (e.g. the Town
// Network fountain room's ceiling light, Setup 0x02000365). Track the dat
// Setup's Lights.Count here so the meshRefs==0 gate below doesn't also drop
// the entity that would otherwise carry those lights to the registration
// pass (GameWindow.cs ~7900).
// the entity that otherwise carries those lights to the static
// presentation publisher.
int stabLightCount = 0;
if ((stab.Id & 0xFF000000u) == 0x01000000u)
{