1818import net .wurstclient .SearchTags ;
1919import net .wurstclient .WurstRenderLayers ;
2020import net .wurstclient .events .RenderListener ;
21+ import net .wurstclient .events .CameraTransformViewBobbingListener ;
2122import net .wurstclient .events .UpdateListener ;
2223import net .wurstclient .hack .Hack ;
2324import net .wurstclient .settings .BlockListSetting ;
25+ import net .wurstclient .settings .CheckboxSetting ;
2426import net .wurstclient .settings .ColorSetting ;
27+ import net .wurstclient .settings .SliderSetting ;
2528import net .wurstclient .util .BlockUtils ;
2629import net .wurstclient .util .BlockVertexCompiler ;
2730import net .wurstclient .util .ChatUtils ;
3033import net .wurstclient .util .RenderUtils ;
3134
3235@ SearchTags ({"base finder" , "factions" })
33- public final class BaseFinderHack extends Hack
34- implements UpdateListener , RenderListener
36+ public final class BaseFinderHack extends Hack implements UpdateListener ,
37+ RenderListener , CameraTransformViewBobbingListener
3538{
3639 private final BlockListSetting naturalBlocks = new BlockListSetting (
3740 "Natural Blocks" ,
@@ -180,12 +183,33 @@ public final class BaseFinderHack extends Hack
180183 private final ColorSetting color = new ColorSetting ("Color" ,
181184 "Man-made blocks will be highlighted in this color." , Color .RED );
182185
186+ // Y limit controls
187+ private final SliderSetting minY = new SliderSetting ("Min Y" , 0 , -64 , 384 ,
188+ 1 , SliderSetting .ValueDisplay .INTEGER );
189+ private final SliderSetting maxY = new SliderSetting ("Max Y" , 319 , -64 , 384 ,
190+ 1 , SliderSetting .ValueDisplay .INTEGER );
191+
192+ // Tracer option
193+ private final net .wurstclient .settings .CheckboxSetting showTracers =
194+ new net .wurstclient .settings .CheckboxSetting ("Tracers" ,
195+ "Draw tracer lines from your view to found blocks." , false );
196+
197+ // Static area (sticky) option
198+ private final CheckboxSetting stickyArea = new CheckboxSetting (
199+ "Sticky area" ,
200+ "Off: Re-centers every scan around your position.\n On: Keeps results anchored so you can path back to them." ,
201+ false );
202+ private BlockPos scanCenter ;
203+ private boolean lastSticky ;
204+
183205 private ArrayList <String > blockNames ;
184206 private java .util .Set <String > naturalExactIds ;
185207 private String [] naturalKeywords ;
186208
187209 private final HashSet <BlockPos > matchingBlocks = new HashSet <>();
188210 private ArrayList <int []> vertices = new ArrayList <>();
211+ private java .util .ArrayList <net .minecraft .world .phys .Vec3 > tracerEnds =
212+ new java .util .ArrayList <>();
189213 private EasyVertexBuffer vertexBuffer ;
190214
191215 private int messageTimer = 0 ;
@@ -199,6 +223,10 @@ public BaseFinderHack()
199223 setCategory (Category .RENDER );
200224 addSetting (naturalBlocks );
201225 addSetting (color );
226+ addSetting (minY );
227+ addSetting (maxY );
228+ addSetting (showTracers );
229+ addSetting (stickyArea );
202230 }
203231
204232 @ Override
@@ -227,23 +255,29 @@ protected void onEnable()
227255 messageTimer = 0 ;
228256 blockNames = new ArrayList <>(naturalBlocks .getBlockNames ());
229257 rebuildNaturalCaches ();
258+ scanCenter = BlockPos .containing (MC .player .getX (), 0 , MC .player .getZ ());
259+ lastSticky = stickyArea .isChecked ();
230260
231261 EVENTS .add (UpdateListener .class , this );
232262 EVENTS .add (RenderListener .class , this );
263+ EVENTS .add (CameraTransformViewBobbingListener .class , this );
233264 }
234265
235266 @ Override
236267 protected void onDisable ()
237268 {
238269 EVENTS .remove (UpdateListener .class , this );
239270 EVENTS .remove (RenderListener .class , this );
271+ EVENTS .remove (CameraTransformViewBobbingListener .class , this );
240272 matchingBlocks .clear ();
241273 vertices .clear ();
274+ tracerEnds .clear ();
242275
243276 if (vertexBuffer != null )
244277 vertexBuffer .close ();
245278 vertexBuffer = null ;
246279 lastRegion = null ;
280+ scanCenter = null ;
247281 }
248282
249283 @ Override
@@ -263,11 +297,64 @@ public void onRender(PoseStack matrixStack, float partialTicks)
263297 color .getColorF (), 0.25F );
264298
265299 matrixStack .popPose ();
300+
301+ // Tracers (world-space, no regional offset) using last compiled set
302+ if (showTracers .isChecked () && !tracerEnds .isEmpty ())
303+ {
304+ int lineColor = color .getColorI (0x80 );
305+ RenderUtils .drawTracers (matrixStack , partialTicks , tracerEnds ,
306+ lineColor , false );
307+ }
308+ }
309+
310+ @ Override
311+ public void onCameraTransformViewBobbing (
312+ CameraTransformViewBobbingEvent event )
313+ {
314+ if (showTracers .isChecked ())
315+ event .cancel ();
266316 }
267317
268318 @ Override
269319 public void onUpdate ()
270320 {
321+ // Detect block list changes without toggling the hack
322+ java .util .ArrayList <String > current =
323+ new java .util .ArrayList <>(naturalBlocks .getBlockNames ());
324+ if (!current .equals (blockNames ))
325+ {
326+ blockNames = current ;
327+ rebuildNaturalCaches ();
328+ matchingBlocks .clear ();
329+ vertices .clear ();
330+ tracerEnds .clear ();
331+ if (vertexBuffer != null )
332+ {
333+ vertexBuffer .close ();
334+ vertexBuffer = null ;
335+ }
336+ lastRegion = null ;
337+ }
338+
339+ // Update scan center based on sticky toggle
340+ boolean sticky = stickyArea .isChecked ();
341+ if (sticky != lastSticky )
342+ {
343+ matchingBlocks .clear ();
344+ vertices .clear ();
345+ tracerEnds .clear ();
346+ if (vertexBuffer != null )
347+ {
348+ vertexBuffer .close ();
349+ vertexBuffer = null ;
350+ }
351+ lastRegion = null ;
352+ lastSticky = sticky ;
353+ }
354+ if (!sticky || scanCenter == null )
355+ scanCenter =
356+ BlockPos .containing (MC .player .getX (), 0 , MC .player .getZ ());
357+
271358 int modulo = MC .player .tickCount % 64 ;
272359 RegionPos region = RenderUtils .getCameraRegion ();
273360
@@ -290,12 +377,18 @@ public void onUpdate()
290377 if (modulo == 0 )
291378 matchingBlocks .clear ();
292379
293- int stepSize = MC .level .getHeight () / 64 ;
294- int startY = MC .level .getMaxY () - 1 - modulo * stepSize ;
295- int endY = startY - stepSize ;
380+ int cfgMin = (int )Math .min (minY .getValue (), maxY .getValue ());
381+ int cfgMax = (int )Math .max (minY .getValue (), maxY .getValue ());
382+ int worldMin = MC .level .getMinY ();
383+ int worldMax = MC .level .getMaxY () - 1 ;
384+ int scanMin = Math .max (worldMin , cfgMin );
385+ int scanMax = Math .min (worldMax , cfgMax );
386+ int heightRange = Math .max (1 , scanMax - scanMin + 1 );
387+ int stepSize = Math .max (1 , heightRange / 64 );
388+ int startY = scanMax - modulo * stepSize ;
389+ int endY = Math .max (scanMin , startY - stepSize );
296390
297- BlockPos playerPos =
298- BlockPos .containing (MC .player .getX (), 0 , MC .player .getZ ());
391+ BlockPos playerPos = scanCenter ;
299392
300393 // search matching blocks
301394 loop : for (int y = startY ; y > endY ; y --)
@@ -365,6 +458,11 @@ public void onUpdate()
365458
366459 // calculate vertices
367460 vertices = BlockVertexCompiler .compile (matchingBlocks );
461+ // update stable tracer end points until next compile
462+ tracerEnds = new java .util .ArrayList <>(matchingBlocks .size ());
463+ for (BlockPos p : matchingBlocks )
464+ tracerEnds .add (new net .minecraft .world .phys .Vec3 (p .getX () + 0.5 ,
465+ p .getY () + 0.5 , p .getZ () + 0.5 ));
368466 }
369467
370468 private void rebuildNaturalCaches ()
0 commit comments