@@ -234,18 +234,16 @@ private void init(Visitor visitor,
234
234
this .initOutsideWorldHeight (queue , viewport , searchDistance , frame ,
235
235
this .level .getMaxSectionY (), GraphDirection .UP );
236
236
} else {
237
- this .initWithinWorld (visitor , queue , viewport , useOcclusionCulling , frame );
237
+ var originSection = this .sections .get (origin .asLong ());
238
+ if (originSection != null ) {
239
+ this .initAtExistingSection (visitor , queue , originSection , useOcclusionCulling , frame );
240
+ } else {
241
+ this .initAtNonExistingSection (visitor , queue , viewport , useOcclusionCulling , searchDistance , frame );
242
+ }
238
243
}
239
244
}
240
245
241
- private void initWithinWorld (Visitor visitor , WriteQueue <RenderSection > queue , Viewport viewport , boolean useOcclusionCulling , int frame ) {
242
- var origin = viewport .getChunkCoord ();
243
- var section = this .getRenderSection (origin .getX (), origin .getY (), origin .getZ ());
244
-
245
- if (section == null ) {
246
- return ;
247
- }
248
-
246
+ private void initAtExistingSection (Visitor visitor , WriteQueue <RenderSection > queue , RenderSection section , boolean useOcclusionCulling , int frame ) {
249
247
section .setLastVisibleFrame (frame );
250
248
section .setIncomingDirections (GraphDirectionSet .NONE );
251
249
@@ -265,6 +263,68 @@ private void initWithinWorld(Visitor visitor, WriteQueue<RenderSection> queue, V
265
263
visitNeighbors (queue , section , outgoing , frame );
266
264
}
267
265
266
+ private void initAtNonExistingSection (Visitor visitor , WriteQueue <RenderSection > queue , Viewport viewport , boolean useOcclusionCulling , float searchDistance , int frame ) {
267
+ var origin = viewport .getChunkCoord ();
268
+ var minY = this .level .getMinSectionY ();
269
+ var maxY = this .level .getMaxSectionY ();
270
+ var originX = origin .getX ();
271
+ var originY = origin .getY ();
272
+ var originZ = origin .getZ ();
273
+
274
+ // iterate shells until one is found with a loaded and visible section
275
+ var foundAny = false ;
276
+ var radius = 1 ;
277
+ while (!foundAny ) {
278
+ // iterate a shell around the origin
279
+ var bigStep = radius * 2 ;
280
+ for (var dy = -radius ; dy <= radius ; dy ++) {
281
+ var y = originY + dy ;
282
+ // skip layers outside the world's y range
283
+ if (y < minY || y > maxY ) {
284
+ continue ;
285
+ }
286
+
287
+ // iterate only the perimeter with the current radius
288
+ var notYFace = !(dy == -radius || dy == radius );
289
+ for (var dx = -radius ; dx <= radius ; dx ++) {
290
+ var zStep = notYFace && (dx == -radius || dx == radius ) ? bigStep : 1 ;
291
+ for (var dz = -radius ; dz <= radius ; dz += zStep ) {
292
+ var x = originX + dx ;
293
+ var z = originZ + dz ;
294
+
295
+ // visit loaded visible sections and queue their neighbors
296
+ var section = this .getRenderSection (x , y , z );
297
+ if (section != null && isSectionVisible (section , viewport , searchDistance )) {
298
+ foundAny = true ;
299
+
300
+ // use all directions as incoming, using just some yields a broken result
301
+ var incoming = GraphDirectionSet .ALL ;
302
+ section .setIncomingDirections (incoming );
303
+ section .setLastVisibleFrame (frame );
304
+
305
+ visitor .visit (section , true );
306
+
307
+ // reduce set of neighbors to visit based on visibility connections
308
+ int connections = getOutwardDirections (origin , section );
309
+ if (useOcclusionCulling ) {
310
+ connections &= VisibilityEncoding .getConnections (section .getVisibilityData (), incoming );
311
+ }
312
+
313
+ visitNeighbors (queue , section , connections , frame );
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ radius ++;
320
+
321
+ // don't exceed the search distance with the init search
322
+ if (radius << 4 > searchDistance ) {
323
+ break ;
324
+ }
325
+ }
326
+ }
327
+
268
328
// Enqueues sections that are inside the viewport using diamond spiral iteration to avoid sorting and ensure a
269
329
// consistent order. Innermost layers are enqueued first. Within each layer, iteration starts at the northernmost
270
330
// section and proceeds counterclockwise (N->W->S->E).
0 commit comments