diff --git a/src/AcDream.App/Streaming/LandblockStreamer.cs b/src/AcDream.App/Streaming/LandblockStreamer.cs index a3416de..0811c8e 100644 --- a/src/AcDream.App/Streaming/LandblockStreamer.cs +++ b/src/AcDream.App/Streaming/LandblockStreamer.cs @@ -177,11 +177,19 @@ public sealed class LandblockStreamer : IDisposable switch (job) { case LandblockStreamJob.Load load: - // TODO(A.5 T16): route by load.Kind. LoadFar will skip - // LandBlockInfo + scenery generation; PromoteToNear will skip - // mesh build (terrain already on GPU). Today every Kind takes - // the full-load path via _loadLandblock, which matches today's - // single-tier semantics. + // A.5 T26 follow-up (Bug A): far-tier LBs must NOT contribute + // entities to GpuWorldState — that defeats the whole purpose of + // the two-tier split. The factory still builds the full entity + // layer (LandblockLoader + scenery generation + interior cells) + // regardless of Kind because it doesn't know about JobKind today. + // We strip Entities here for far-tier results so the render- + // thread dispatcher walks only near-tier (~10K) entities, not + // all (~71K) entities at radius=12. + // + // Wasted worker-thread CPU is acceptable (it's off the render + // thread). A future optimization (TODO N.6 or A.6) plumbs Kind + // through BuildLandblockForStreaming so the dat read + scenery + // generation are skipped entirely for far-tier. try { var lb = _loadLandblock(load.LandblockId); @@ -200,6 +208,14 @@ public sealed class LandblockStreamer : IDisposable } var tier = load.Kind == LandblockStreamJobKind.LoadFar ? LandblockStreamTier.Far : LandblockStreamTier.Near; + if (tier == LandblockStreamTier.Far && lb.Entities.Count > 0) + { + // Strip entities — far-tier ships terrain only. + lb = new LoadedLandblock( + lb.LandblockId, + lb.Heightmap, + System.Array.Empty()); + } _outbox.Writer.TryWrite(new LandblockStreamResult.Loaded( load.LandblockId, tier, lb, mesh)); }