fix(streaming): commit EnvCell landblocks atomically (#214)
Carry one complete cell payload with each streaming completion and publish visibility, physics, and render state on the render thread. Remove the obsolete post-readiness login reload that triggered a duplicate dungeon build. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
85980fe13f
commit
b0c175afc0
26 changed files with 973 additions and 617 deletions
|
|
@ -52,7 +52,7 @@ public sealed class LandblockStreamer : IDisposable
|
|||
/// </summary>
|
||||
public const int DefaultDrainBatchSize = 4;
|
||||
|
||||
private readonly Func<uint, LandblockStreamJobKind, LoadedLandblock?> _loadLandblock;
|
||||
private readonly Func<uint, LandblockStreamJobKind, LandblockBuild?> _loadLandblock;
|
||||
private readonly Func<uint, LoadedLandblock?, AcDream.Core.Terrain.LandblockMeshData?> _buildMeshOrNull;
|
||||
private readonly Channel<LandblockStreamJob> _inbox;
|
||||
private readonly Channel<LandblockStreamResult> _outbox;
|
||||
|
|
@ -68,7 +68,7 @@ public sealed class LandblockStreamer : IDisposable
|
|||
/// <c>LandBlockInfo</c> + <c>SceneryGenerator</c> work.
|
||||
/// </summary>
|
||||
public LandblockStreamer(
|
||||
Func<uint, LandblockStreamJobKind, LoadedLandblock?> loadLandblock,
|
||||
Func<uint, LandblockStreamJobKind, LandblockBuild?> loadLandblock,
|
||||
Func<uint, LoadedLandblock?, AcDream.Core.Terrain.LandblockMeshData?>? buildMeshOrNull = null)
|
||||
{
|
||||
_loadLandblock = loadLandblock;
|
||||
|
|
@ -81,6 +81,22 @@ public sealed class LandblockStreamer : IDisposable
|
|||
new UnboundedChannelOptions { SingleReader = true, SingleWriter = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compatibility constructor for loaders that have no App-owned cell payload.
|
||||
/// Production uses the <see cref="LandblockBuild"/> overload so render state
|
||||
/// remains attached to the exact streaming completion that produced it.
|
||||
/// </summary>
|
||||
public LandblockStreamer(
|
||||
Func<uint, LandblockStreamJobKind, LoadedLandblock?> loadLandblock,
|
||||
Func<uint, LoadedLandblock?, AcDream.Core.Terrain.LandblockMeshData?>? buildMeshOrNull = null)
|
||||
: this(
|
||||
(id, kind) => loadLandblock(id, kind) is { } landblock
|
||||
? new LandblockBuild(landblock)
|
||||
: null,
|
||||
buildMeshOrNull)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Back-compat overload — wraps a kind-agnostic factory so existing test code
|
||||
/// that doesn't care about the JobKind branch keeps compiling. The wrapper
|
||||
|
|
@ -90,7 +106,11 @@ public sealed class LandblockStreamer : IDisposable
|
|||
public LandblockStreamer(
|
||||
Func<uint, LoadedLandblock?> loadLandblock,
|
||||
Func<uint, LoadedLandblock?, AcDream.Core.Terrain.LandblockMeshData?>? buildMeshOrNull = null)
|
||||
: this((id, _) => loadLandblock(id), buildMeshOrNull)
|
||||
: this(
|
||||
(id, _) => loadLandblock(id) is { } landblock
|
||||
? new LandblockBuild(landblock)
|
||||
: null,
|
||||
buildMeshOrNull)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -311,13 +331,14 @@ public sealed class LandblockStreamer : IDisposable
|
|||
// factory returns far-tier with entities anyway.
|
||||
try
|
||||
{
|
||||
var lb = _loadLandblock(load.LandblockId, load.Kind);
|
||||
if (lb is null)
|
||||
var build = _loadLandblock(load.LandblockId, load.Kind);
|
||||
if (build is null)
|
||||
{
|
||||
_outbox.Writer.TryWrite(new LandblockStreamResult.Failed(
|
||||
load.LandblockId, "LandblockLoader.Load returned null"));
|
||||
break;
|
||||
}
|
||||
var lb = build.Landblock;
|
||||
if (load.Kind == LandblockStreamJobKind.PromoteToNear)
|
||||
{
|
||||
var promotedMesh = _buildMeshOrNull(load.LandblockId, lb);
|
||||
|
|
@ -328,7 +349,7 @@ public sealed class LandblockStreamer : IDisposable
|
|||
break;
|
||||
}
|
||||
_outbox.Writer.TryWrite(new LandblockStreamResult.Promoted(
|
||||
load.LandblockId, lb, promotedMesh));
|
||||
load.LandblockId, build, promotedMesh));
|
||||
break;
|
||||
}
|
||||
var mesh = _buildMeshOrNull(load.LandblockId, lb);
|
||||
|
|
@ -351,9 +372,10 @@ public sealed class LandblockStreamer : IDisposable
|
|||
lb.LandblockId,
|
||||
lb.Heightmap,
|
||||
System.Array.Empty<AcDream.Core.World.WorldEntity>());
|
||||
build = new LandblockBuild(lb);
|
||||
}
|
||||
_outbox.Writer.TryWrite(new LandblockStreamResult.Loaded(
|
||||
load.LandblockId, tier, lb, mesh));
|
||||
load.LandblockId, tier, build, mesh));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue