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

@ -4,14 +4,23 @@ using AcDream.Core.World;
namespace AcDream.App.Streaming;
/// <summary>
/// Read-only presentation state needed by render traversal and diagnostics.
/// Keeping this projection on the pipeline prevents the composition root from
/// retaining each concrete publication owner independently.
/// </summary>
public readonly record struct LandblockPresentationDiagnostics(
LandblockRenderPublisherDiagnostics Render,
LandblockPhysicsPublisherDiagnostics Physics,
LandblockStaticPresentationDiagnostics Statics);
/// <summary>
/// Render-thread transaction coordinator for one accepted landblock streaming
/// result. Streaming policy (desired tier, generation, priority, and apply
/// budget) remains in <see cref="StreamingController"/>; spatial buckets remain
/// in <see cref="GpuWorldState"/>. This owner fixes the presentation ordering
/// independently of those policies so the concrete render, physics, and static
/// publishers can be extracted behind it without returning callbacks to the
/// game window.
/// independently of those policies. The concrete render, physics, and static
/// publishers remain private implementation participants behind this boundary.
/// </summary>
/// <remarks>
/// Retail establishes cells/buildings before static objects in
@ -19,9 +28,9 @@ namespace AcDream.App.Streaming;
/// <c>CLandBlock::release_all @ 0x0052FCF0</c> (objects and visible cells) from
/// later destruction in <c>CLandBlock::Destroy @ 0x0052FAA0</c> (static objects
/// and buildings). Acdream's detach-first retry ledger is the existing
/// asynchronous lifetime adaptation. The injected publication operation
/// currently contains the already-shipped production transaction; later
/// Slice-5 checkpoints replace it with focused publishers.
/// asynchronous lifetime adaptation. Production always uses the focused owner
/// graph; the internal delegate constructor exists only for hermetic policy and
/// retry characterization tests.
/// </remarks>
public sealed class LandblockPresentationPipeline
{
@ -63,7 +72,7 @@ public sealed class LandblockPresentationPipeline
private readonly Dictionary<LandblockStreamResult, PublicationTransaction> _publications =
new(ReferenceEqualityComparer.Instance);
public LandblockPresentationPipeline(
internal LandblockPresentationPipeline(
Action<LandblockBuild, LandblockMeshData> publishBeforeSpatialCommit,
GpuWorldState state,
Action<uint>? onLandblockLoaded = null,
@ -137,6 +146,21 @@ public sealed class LandblockPresentationPipeline
retirementOwner.Advance);
}
/// <summary>
/// Building visibility registries published by the render owner. Legacy
/// test pipelines have no render owner and therefore expose an empty view.
/// </summary>
public IReadOnlyCollection<BuildingRegistry> BuildingRegistries =>
_renderPublisher?.BuildingRegistries ?? Array.Empty<BuildingRegistry>();
/// <summary>
/// Cumulative diagnostics from the three concrete presentation owners.
/// </summary>
public LandblockPresentationDiagnostics Diagnostics => new(
_renderPublisher?.Diagnostics ?? default,
_physicsPublisher?.Diagnostics ?? default,
_staticPublisher?.Diagnostics ?? default);
public int PendingRetirementCount => _retirements.PendingCount;
public int PendingPublicationCount => _publications.Count;