feat(streaming): PhysicsDatBundle on LoadedLandblock (datLock fix scaffold)

Carries the parsed dat objects ApplyLoadedTerrainLocked needs so the worker
can pre-read them and the apply can run lock-free. Optional field (default
null) keeps existing LoadedLandblock construction back-compatible.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-23 09:31:26 +02:00
parent 5ab5d3910e
commit 3a0e349c6e
3 changed files with 50 additions and 1 deletions

View file

@ -5,4 +5,5 @@ namespace AcDream.Core.World;
public sealed record LoadedLandblock(
uint LandblockId,
LandBlock Heightmap,
IReadOnlyList<WorldEntity> Entities);
IReadOnlyList<WorldEntity> Entities,
PhysicsDatBundle? PhysicsDats = null);

View file

@ -0,0 +1,30 @@
using System.Collections.Generic;
using DatReaderWriter.DBObjs;
// Environment collides with System.Environment under implicit usings — alias it.
using DatEnvironment = DatReaderWriter.DBObjs.Environment;
namespace AcDream.Core.World;
/// <summary>
/// The parsed dat objects <c>ApplyLoadedTerrainLocked</c> needs, pre-read by the
/// streaming worker under <c>_datLock</c> so the apply makes ZERO DatCollection
/// calls and the update thread never blocks on the worker's lock (the FPS
/// 30↔200 swing was that lock-wait). Keyed by the same dat id the apply would
/// have passed to <c>_dats.Get&lt;T&gt;</c>.
/// </summary>
public sealed record PhysicsDatBundle(
LandBlockInfo? Info,
IReadOnlyDictionary<uint, EnvCell> EnvCells,
IReadOnlyDictionary<uint, DatEnvironment> Environments,
IReadOnlyDictionary<uint, Setup> Setups,
IReadOnlyDictionary<uint, GfxObj> GfxObjs)
{
/// <summary>Empty bundle for far-tier landblocks (no cells / buildings /
/// entities) and for non-streaming <see cref="LoadedLandblock"/> construction.</summary>
public static readonly PhysicsDatBundle Empty = new(
null,
new Dictionary<uint, EnvCell>(),
new Dictionary<uint, DatEnvironment>(),
new Dictionary<uint, Setup>(),
new Dictionary<uint, GfxObj>());
}

View file

@ -0,0 +1,18 @@
using AcDream.Core.World;
using Xunit;
namespace AcDream.Core.Tests.World;
public class PhysicsDatBundleTests
{
[Fact]
public void Empty_ReturnsNullInfoAndEmptyMaps()
{
var b = PhysicsDatBundle.Empty;
Assert.Null(b.Info);
Assert.Empty(b.EnvCells);
Assert.Empty(b.Environments);
Assert.Empty(b.Setups);
Assert.Empty(b.GfxObjs);
}
}