refactor(apply): read dats from the bundle, not DatCollection (no lock change yet)

ApplyLoadedTerrainLocked's six Get<T> sites now read from lb.PhysicsDats via
TryGetValue (loud-fail on a gather/apply id mismatch). Zero _dats.Get calls
remain in the apply. Behavior identical: same ids -> same cached dat objects
-> same surfaces/BSP/ShadowObjects. Lock removal is the next commit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-06-23 09:36:09 +02:00
parent 4a99b55a73
commit 81a5605ff4

View file

@ -6790,6 +6790,11 @@ public sealed class GameWindow : IDisposable
// _heightTable still needed for physics TerrainSurface below. // _heightTable still needed for physics TerrainSurface below.
if (_terrain is null || _dats is null || _heightTable is null) return; if (_terrain is null || _dats is null || _heightTable is null) return;
// datLock fix: every dat the apply needs was pre-read by the worker into
// lb.PhysicsDats. Read from the bundle — NO _dats.Get here, so this method
// (and its caller) need no _datLock.
var datBundle = lb.PhysicsDats ?? AcDream.Core.World.PhysicsDatBundle.Empty;
uint lbXu = (lb.LandblockId >> 24) & 0xFFu; uint lbXu = (lb.LandblockId >> 24) & 0xFFu;
uint lbYu = (lb.LandblockId >> 16) & 0xFFu; uint lbYu = (lb.LandblockId >> 16) & 0xFFu;
int lbX = (int)lbXu; int lbX = (int)lbXu;
@ -6864,21 +6869,18 @@ public sealed class GameWindow : IDisposable
var cellSurfaces = new List<AcDream.Core.Physics.CellSurface>(); var cellSurfaces = new List<AcDream.Core.Physics.CellSurface>();
var portalPlanes = new List<AcDream.Core.Physics.PortalPlane>(); var portalPlanes = new List<AcDream.Core.Physics.PortalPlane>();
var lbInfo = _dats.Get<DatReaderWriter.DBObjs.LandBlockInfo>( var lbInfo = datBundle.Info;
(lb.LandblockId & 0xFFFF0000u) | 0xFFFEu);
if (lbInfo is not null && lbInfo.NumCells > 0) if (lbInfo is not null && lbInfo.NumCells > 0)
{ {
uint firstCellId = (lb.LandblockId & 0xFFFF0000u) | 0x0100u; uint firstCellId = (lb.LandblockId & 0xFFFF0000u) | 0x0100u;
for (uint offset = 0; offset < lbInfo.NumCells; offset++) for (uint offset = 0; offset < lbInfo.NumCells; offset++)
{ {
uint envCellId = firstCellId + offset; uint envCellId = firstCellId + offset;
var envCell = _dats.Get<DatReaderWriter.DBObjs.EnvCell>(envCellId); if (!datBundle.EnvCells.TryGetValue(envCellId, out var envCell)) continue;
if (envCell is null) continue;
if (envCell.EnvironmentId == 0) continue; if (envCell.EnvironmentId == 0) continue;
var environment = _dats.Get<DatReaderWriter.DBObjs.Environment>( if (!datBundle.Environments.TryGetValue(
0x0D000000u | envCell.EnvironmentId); 0x0D000000u | envCell.EnvironmentId, out var environment)) continue;
if (environment is null) continue;
if (!environment.Cells.TryGetValue(envCell.CellStructure, out var cellStruct)) continue; if (!environment.Cells.TryGetValue(envCell.CellStructure, out var cellStruct)) continue;
// Transform CellStruct vertices from cell-local to world space. // Transform CellStruct vertices from cell-local to world space.
@ -6991,7 +6993,7 @@ public sealed class GameWindow : IDisposable
// _dats is non-null on every streaming-drain path // _dats is non-null on every streaming-drain path
// (the GfxObj physics cache loop below dereferences // (the GfxObj physics cache loop below dereferences
// it unconditionally). // it unconditionally).
var bldSetup = _dats!.Get<DatReaderWriter.DBObjs.Setup>(building.ModelId); datBundle.Setups.TryGetValue(building.ModelId, out var bldSetup);
shellPart0 = bldSetup is not null && bldSetup.Parts.Count > 0 shellPart0 = bldSetup is not null && bldSetup.Parts.Count > 0
? bldSetup.Parts[0] ? bldSetup.Parts[0]
: 0u; : 0u;
@ -7067,8 +7069,7 @@ public sealed class GameWindow : IDisposable
foreach (var meshRef in entity.MeshRefs) foreach (var meshRef in entity.MeshRefs)
{ {
if ((meshRef.GfxObjId & 0xFF000000u) != 0x01000000u) continue; if ((meshRef.GfxObjId & 0xFF000000u) != 0x01000000u) continue;
var gfx = _dats.Get<DatReaderWriter.DBObjs.GfxObj>(meshRef.GfxObjId); if (!datBundle.GfxObjs.TryGetValue(meshRef.GfxObjId, out var gfx)) continue;
if (gfx is null) continue;
_physicsDataCache.CacheGfxObj(meshRef.GfxObjId, gfx); _physicsDataCache.CacheGfxObj(meshRef.GfxObjId, gfx);
} }
} }
@ -7104,7 +7105,7 @@ public sealed class GameWindow : IDisposable
uint src = entity.SourceGfxObjOrSetupId; uint src = entity.SourceGfxObjOrSetupId;
if ((src & 0xFF000000u) == 0x02000000u) if ((src & 0xFF000000u) == 0x02000000u)
{ {
var datSetup = _dats.Get<DatReaderWriter.DBObjs.Setup>(src); datBundle.Setups.TryGetValue(src, out var datSetup);
if (datSetup is not null && datSetup.Lights.Count > 0) if (datSetup is not null && datSetup.Lights.Count > 0)
{ {
var loaded = AcDream.Core.Lighting.LightInfoLoader.Load( var loaded = AcDream.Core.Lighting.LightInfoLoader.Load(