refactor(streaming): compose landblock presentation transaction

Own render, physics, DAT-static presentation, and retained static-resource rebinds behind retryable receipts so a failed publication resumes its exact unfinished suffix without replaying retail create-time defaults.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-21 21:45:16 +02:00
parent e1110f7e54
commit ea0da8c8ae
15 changed files with 1744 additions and 89 deletions

View file

@ -24,6 +24,7 @@ public sealed class LandblockPhysicsPublication
internal object Owner { get; }
internal LandblockBuild Build { get; }
internal bool BeginCommitted { get; set; }
internal bool CompletionCommitted { get; set; }
public uint LandblockId => Build.Landblock.LandblockId;
@ -127,6 +128,20 @@ public sealed class LandblockPhysicsPublisher
/// </summary>
public LandblockPhysicsPublication BeginPublication(
LandblockRenderPublication renderPublication)
{
LandblockPhysicsPublication publication = PreparePublication(
renderPublication);
BeginPublication(publication);
return publication;
}
/// <summary>
/// Captures the exact render receipt before physics mutation begins. The
/// coordinator retains this receipt and can retry the idempotent exact
/// replacement when a cache/backend operation fails.
/// </summary>
public LandblockPhysicsPublication PreparePublication(
LandblockRenderPublication renderPublication)
{
ArgumentNullException.ThrowIfNull(renderPublication);
LandblockBuild build = renderPublication.Build;
@ -134,7 +149,25 @@ public sealed class LandblockPhysicsPublisher
if (!IsFinite(origin))
throw new ArgumentOutOfRangeException(nameof(renderPublication));
return new LandblockPhysicsPublication(
_receiptOwner,
build,
origin);
}
/// <summary>
/// Advances the exact terrain/cell/building physics replacement from a
/// retained receipt.
/// </summary>
public void BeginPublication(LandblockPhysicsPublication publication)
{
ValidateReceipt(publication);
if (publication.BeginCommitted)
return;
long started = Stopwatch.GetTimestamp();
LandblockBuild build = publication.Build;
Vector3 origin = publication.Origin;
LoadedLandblock landblock = build.Landblock;
PhysicsDatBundle datBundle =
landblock.PhysicsDats ?? PhysicsDatBundle.Empty;
@ -286,12 +319,9 @@ public sealed class LandblockPhysicsPublisher
_cellSurfaceCount += cellSurfaces.Count;
_portalPlaneCount += portalPlanes.Count;
_buildingCount += buildingCount;
publication.BeginCommitted = true;
_beginCount++;
_basePublishTicks += Stopwatch.GetTimestamp() - started;
return new LandblockPhysicsPublication(
_receiptOwner,
build,
origin);
}
/// <summary>
@ -304,11 +334,10 @@ public sealed class LandblockPhysicsPublisher
LandblockPhysicsPublication publication,
Action<WorldEntity>? beforeStaticCollision = null)
{
ArgumentNullException.ThrowIfNull(publication);
if (!ReferenceEquals(publication.Owner, _receiptOwner))
throw new ArgumentException(
"The physics publication receipt belongs to another publisher.",
nameof(publication));
ValidateReceipt(publication);
if (!publication.BeginCommitted)
throw new InvalidOperationException(
"Physics publication cannot complete before its prefix commits.");
if (publication.CompletionCommitted)
return;
@ -651,4 +680,15 @@ public sealed class LandblockPhysicsPublisher
float.IsFinite(value.X)
&& float.IsFinite(value.Y)
&& float.IsFinite(value.Z);
private void ValidateReceipt(LandblockPhysicsPublication publication)
{
ArgumentNullException.ThrowIfNull(publication);
if (!ReferenceEquals(publication.Owner, _receiptOwner))
{
throw new ArgumentException(
"The physics publication receipt belongs to another publisher.",
nameof(publication));
}
}
}