@@ -147,6 +147,11 @@ private static enum Mode
147147 private boolean visibleBoxesUpToDate = false ;
148148 private java .util .List <Box > visibleBoxes = new java .util .ArrayList <>();
149149
150+ // Debounce to avoid flashing when coordinator updates rapidly (e.g., on
151+ // right-click or fast movement). Measured in milliseconds.
152+ private static final long COORDINATOR_DEBOUNCE_MS = 200L ;
153+ private long lastCoordinatorChangeMs = 0L ;
154+
150155 public XRayHack ()
151156 {
152157 super ("X-Ray" );
@@ -284,6 +289,11 @@ public void onUpdate()
284289 {
285290 highlightPositionsUpToDate = false ;
286291 visibleBoxesUpToDate = false ;
292+ // Record change timestamp and DO NOT immediately clear cached
293+ // boxes.
294+ // This avoids flicker during quick user actions; boxes will be
295+ // refreshed when new data arrives or after debounce.
296+ lastCoordinatorChangeMs = System .currentTimeMillis ();
287297 }
288298
289299 // force gamma to 16 so that ores are bright enough to see
@@ -382,24 +392,47 @@ public void onUpdate()
382392 @ Override
383393 public void onRender (MatrixStack matrices , float partialTicks )
384394 {
385- // Ensure we have visible boxes computed from known positions
386- if (!visibleBoxesUpToDate )
387- rebuildVisibleBoxes ();
395+ long now = System .currentTimeMillis ();
388396
389- if (visibleBoxes .isEmpty ())
397+ // If coordinator finished, refresh highlight positions immediately.
398+ if (!highlightPositionsUpToDate && coordinator .isDone ())
399+ {
400+ highlightPositions .clear ();
401+ coordinator .getMatches ()
402+ .forEach (r -> highlightPositions .add (r .pos ()));
403+ highlightPositionsUpToDate = true ;
404+ visibleBoxesUpToDate = false ;
405+ }
406+
407+ // Rebuild visible boxes if needed. Use debounce to avoid flicker: if
408+ // rebuild would create an empty set but the coordinator just changed
409+ // recently, keep existing boxes until debounce expires.
410+ if (!visibleBoxesUpToDate )
390411 {
391- // If we have no positions yet but coordinator is done, populate
392- if (! highlightPositionsUpToDate && coordinator . isDone () )
412+ java . util . List < Box > newBoxes = new java . util . ArrayList <>();
413+ for ( BlockPos p : highlightPositions )
393414 {
394- highlightPositions .clear ();
395- coordinator .getMatches ()
396- .forEach (r -> highlightPositions .add (r .pos ()));
397- highlightPositionsUpToDate = true ;
398- rebuildVisibleBoxes ();
415+ if (onlyExposed .isChecked () && !isExposed (p ))
416+ continue ;
417+ newBoxes .add (new Box (p ));
418+ }
419+
420+ // If newBoxes empty but coordinator changed very recently, skip
421+ // replacing to avoid flicker.
422+ if (newBoxes .isEmpty ()
423+ && now - lastCoordinatorChangeMs < COORDINATOR_DEBOUNCE_MS )
424+ {
425+ // keep previous visibleBoxes until debounce expires
426+ }else
427+ {
428+ visibleBoxes = newBoxes ;
429+ visibleBoxesUpToDate = true ;
399430 }
400- return ;
401431 }
402432
433+ if (visibleBoxes .isEmpty ())
434+ return ;
435+
403436 int color = getHighlightColorWithAlpha ();
404437 if (highlightFill .isChecked ())
405438 {
0 commit comments