diff --git a/src/AcDream.App/Rendering/GameWindow.cs b/src/AcDream.App/Rendering/GameWindow.cs index 393f4e1e..d9b7ed0d 100644 --- a/src/AcDream.App/Rendering/GameWindow.cs +++ b/src/AcDream.App/Rendering/GameWindow.cs @@ -6790,6 +6790,11 @@ public sealed class GameWindow : IDisposable // _heightTable still needed for physics TerrainSurface below. 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 lbYu = (lb.LandblockId >> 16) & 0xFFu; int lbX = (int)lbXu; @@ -6864,21 +6869,18 @@ public sealed class GameWindow : IDisposable var cellSurfaces = new List(); var portalPlanes = new List(); - var lbInfo = _dats.Get( - (lb.LandblockId & 0xFFFF0000u) | 0xFFFEu); + var lbInfo = datBundle.Info; if (lbInfo is not null && lbInfo.NumCells > 0) { uint firstCellId = (lb.LandblockId & 0xFFFF0000u) | 0x0100u; for (uint offset = 0; offset < lbInfo.NumCells; offset++) { uint envCellId = firstCellId + offset; - var envCell = _dats.Get(envCellId); - if (envCell is null) continue; + if (!datBundle.EnvCells.TryGetValue(envCellId, out var envCell)) continue; if (envCell.EnvironmentId == 0) continue; - var environment = _dats.Get( - 0x0D000000u | envCell.EnvironmentId); - if (environment is null) continue; + if (!datBundle.Environments.TryGetValue( + 0x0D000000u | envCell.EnvironmentId, out var environment)) continue; if (!environment.Cells.TryGetValue(envCell.CellStructure, out var cellStruct)) continue; // 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 // (the GfxObj physics cache loop below dereferences // it unconditionally). - var bldSetup = _dats!.Get(building.ModelId); + datBundle.Setups.TryGetValue(building.ModelId, out var bldSetup); shellPart0 = bldSetup is not null && bldSetup.Parts.Count > 0 ? bldSetup.Parts[0] : 0u; @@ -7067,8 +7069,7 @@ public sealed class GameWindow : IDisposable foreach (var meshRef in entity.MeshRefs) { if ((meshRef.GfxObjId & 0xFF000000u) != 0x01000000u) continue; - var gfx = _dats.Get(meshRef.GfxObjId); - if (gfx is null) continue; + if (!datBundle.GfxObjs.TryGetValue(meshRef.GfxObjId, out var gfx)) continue; _physicsDataCache.CacheGfxObj(meshRef.GfxObjId, gfx); } } @@ -7104,7 +7105,7 @@ public sealed class GameWindow : IDisposable uint src = entity.SourceGfxObjOrSetupId; if ((src & 0xFF000000u) == 0x02000000u) { - var datSetup = _dats.Get(src); + datBundle.Setups.TryGetValue(src, out var datSetup); if (datSetup is not null && datSetup.Lights.Count > 0) { var loaded = AcDream.Core.Lighting.LightInfoLoader.Load(