diff --git a/src/AcDream.App/Rendering/Walk/WalkProductionWorldData.cs b/src/AcDream.App/Rendering/Walk/WalkProductionWorldData.cs index 17392765..a9ef6195 100644 --- a/src/AcDream.App/Rendering/Walk/WalkProductionWorldData.cs +++ b/src/AcDream.App/Rendering/Walk/WalkProductionWorldData.cs @@ -65,14 +65,17 @@ internal sealed class WalkProductionWorldData : IWalkFrameWorldData foreach (List bucket in _shellsByAnchor.Values) bucket.Clear(); - int count; - while (true) + // CopyIndexTo THROWS on an undersized destination (ArchRenderScene + // validates up front — the first connected gate run of the FW3.2b-2 + // cutover crashed on exactly this at Aerlinthe's 5,040 outdoor + // statics), so presize from the query's own index counts. + int required = _scene.IndexCounts.For(RenderSceneIndex.OutdoorStatic); + if (required > _sweepScratch.Length) { - count = _scene.CopyIndexTo(RenderSceneIndex.OutdoorStatic, _sweepScratch); - if (count < _sweepScratch.Length) - break; - _sweepScratch = new RenderProjectionRecord[_sweepScratch.Length * 2]; + _sweepScratch = new RenderProjectionRecord[ + Math.Max(required, _sweepScratch.Length * 2)]; } + int count = _scene.CopyIndexTo(RenderSceneIndex.OutdoorStatic, _sweepScratch); for (int i = 0; i < count; i++) { ref readonly RenderProjectionRecord record = ref _sweepScratch[i]; @@ -111,14 +114,15 @@ internal sealed class WalkProductionWorldData : IWalkFrameWorldData { if (_cellCache.TryGetValue(cellId, out WalkFrameStaticRecords cached)) return cached; - int count; - while (true) + // Same up-front-validation contract as CopyIndexTo: presize from the + // query's own count rather than probing with an undersized span. + int required = _scene.GetCellStaticCount(cellId); + if (required > _cellScratch.Length) { - count = _scene.CopyCellStaticsTo(cellId, _cellScratch); - if (count < _cellScratch.Length) - break; - _cellScratch = new RenderProjectionRecord[_cellScratch.Length * 2]; + _cellScratch = new RenderProjectionRecord[ + Math.Max(required, _cellScratch.Length * 2)]; } + int count = _scene.CopyCellStaticsTo(cellId, _cellScratch); WalkFrameStaticRecords records = count == 0 ? WalkFrameStaticRecords.Empty with { TupleLandblockId = _tupleLandblockId } : new WalkFrameStaticRecords(_cellScratch[..count], _tupleLandblockId);