Skip to content

Commit 37f0964

Browse files
committed
Updated TunnelHoleStairESP
1 parent d473fc9 commit 37f0964

1 file changed

Lines changed: 120 additions & 8 deletions

File tree

src/main/java/net/wurstclient/hacks/TunnelHoleStairEspHack.java

Lines changed: 120 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ public final class TunnelHoleStairEspHack extends Hack
9191
"Periodically re-queue all chunks in range so stale detections refresh\n"
9292
+ "without toggling the hack.",
9393
10, 0, 60, 1, ValueDisplay.INTEGER.withSuffix(" s"));
94+
private final CheckboxSetting adaptiveMovementScan = new CheckboxSetting(
95+
"Adaptive movement scan",
96+
"Adjusts scan area and throughput based on your movement speed.\n"
97+
+ "Standing still keeps your selected area. Moving/flying tightens area\n"
98+
+ "and boosts nearby scan speed.",
99+
true);
100+
private final SliderSetting nearbyPriorityRadius = new SliderSetting(
101+
"Nearby priority radius",
102+
"Always prioritize chunks in this radius around you each tick.\n"
103+
+ "Higher values discover nearby tunnels faster, but can cost more CPU.",
104+
2, 0, 12, 1, ValueDisplay.INTEGER.withSuffix(" chunks"));
94105
private final CheckboxSetting airOnly = new CheckboxSetting("Air only",
95106
"Only treat pure air as passable. Turning this off will also treat\n"
96107
+ "other non-solid blocks as passable.",
@@ -213,6 +224,7 @@ public final class TunnelHoleStairEspHack extends Hack
213224
private int scanConfigHash;
214225
private int refreshTimerTicks;
215226
private Level activeLevel;
227+
private Vec3 lastPlayerPos;
216228

217229
public TunnelHoleStairEspHack()
218230
{
@@ -225,6 +237,8 @@ public TunnelHoleStairEspHack()
225237
addSetting(chunksPerTick);
226238
addSetting(scanTimeBudgetMs);
227239
addSetting(refreshInterval);
240+
addSetting(adaptiveMovementScan);
241+
addSetting(nearbyPriorityRadius);
228242
addSetting(airOnly);
229243
addSetting(minYOffset);
230244
addSetting(maxYOffset);
@@ -283,6 +297,7 @@ protected void onEnable()
283297
refreshTimerTicks = 0;
284298
lastAreaSelection = area.getSelected();
285299
activeLevel = null;
300+
lastPlayerPos = null;
286301
clearRuntimeState();
287302
EVENTS.add(UpdateListener.class, this);
288303
EVENTS.add(RenderListener.class, this);
@@ -298,6 +313,7 @@ protected void onDisable()
298313
EVENTS.remove(CameraTransformViewBobbingListener.class, this);
299314
EVENTS.remove(PacketInputListener.class, this);
300315
activeLevel = null;
316+
lastPlayerPos = null;
301317
clearRuntimeState();
302318
}
303319

@@ -324,6 +340,7 @@ public void onUpdate()
324340
refreshTimerTicks = 0;
325341
lastAreaSelection = area.getSelected();
326342
scanConfigHash = getScanConfigHash();
343+
lastPlayerPos = null;
327344
clearRuntimeState();
328345
}
329346

@@ -349,11 +366,14 @@ public void onUpdate()
349366
clearRuntimeState();
350367
}
351368

352-
HashSet<ChunkPos> areaChunks = getAreaChunks();
369+
ScanProfile profile = getScanProfile();
370+
HashSet<ChunkPos> areaChunks = getAreaChunks(profile.range);
353371
boolean changed = syncToArea(areaChunks);
354372
enqueueDirtyChunks(areaChunks);
355373
enqueuePeriodicRefresh(areaChunks);
356-
changed |= processQueuedScans(areaChunks);
374+
promoteNearbyChunks(areaChunks, profile.nearbyRadius);
375+
changed |=
376+
processQueuedScans(areaChunks, profile.scans, profile.budgetNs);
357377

358378
if(changed)
359379
rebuildRenderCache();
@@ -518,7 +538,7 @@ private boolean isEnabledInCurrentDimension()
518538
return true;
519539
}
520540

521-
private HashSet<ChunkPos> getAreaChunks()
541+
private HashSet<ChunkPos> getAreaChunks(int chunkRange)
522542
{
523543
ChunkPos center = getAreaCenterChunk();
524544
ChunkAreaSetting.ChunkArea selection = area.getSelected();
@@ -528,7 +548,6 @@ private HashSet<ChunkPos> getAreaChunks()
528548
// requiring
529549
// a hack toggle or area change.
530550
areaChunkCache.clear();
531-
int chunkRange = getChunkRange(selection);
532551
for(int x = center.x() - chunkRange; x <= center.x() + chunkRange; x++)
533552
for(int z = center.z() - chunkRange; z <= center.z()
534553
+ chunkRange; z++)
@@ -592,15 +611,44 @@ private void enqueueDirtyChunks(HashSet<ChunkPos> areaChunks)
592611

593612
if(queuedChunks.add(pos))
594613
scanQueue.addFirst(pos);
614+
else if(scanQueue.remove(pos))
615+
scanQueue.addFirst(pos);
595616

596617
promoted++;
597618
}
598619
}
599620

600-
private boolean processQueuedScans(HashSet<ChunkPos> areaChunks)
621+
private void promoteNearbyChunks(HashSet<ChunkPos> areaChunks,
622+
int nearbyRadius)
623+
{
624+
ChunkPos center = getAreaCenterChunk();
625+
ArrayList<ChunkPos> nearby = new ArrayList<>();
626+
int radius = Math.min(getChunkRange(area.getSelected()), nearbyRadius);
627+
628+
for(int dx = -radius; dx <= radius; dx++)
629+
for(int dz = -radius; dz <= radius; dz++)
630+
{
631+
ChunkPos pos = new ChunkPos(center.x() + dx, center.z() + dz);
632+
if(areaChunks.contains(pos))
633+
nearby.add(pos);
634+
}
635+
636+
nearby.sort(
637+
Comparator.comparingInt(pos -> getChunkDistance(pos, center)));
638+
// Push nearest chunks to the front so "standing on it" updates fast.
639+
for(int i = nearby.size() - 1; i >= 0; i--)
640+
{
641+
ChunkPos pos = nearby.get(i);
642+
if(queuedChunks.add(pos))
643+
scanQueue.addFirst(pos);
644+
else if(scanQueue.remove(pos))
645+
scanQueue.addFirst(pos);
646+
}
647+
}
648+
649+
private boolean processQueuedScans(HashSet<ChunkPos> areaChunks, int scans,
650+
long budgetNs)
601651
{
602-
int scans = Math.max(1, chunksPerTick.getValueI());
603-
long budgetNs = Math.max(1L, scanTimeBudgetMs.getValueI()) * 1_000_000L;
604652
long startNs = System.nanoTime();
605653
boolean changed = false;
606654

@@ -623,6 +671,52 @@ private boolean processQueuedScans(HashSet<ChunkPos> areaChunks)
623671
return changed;
624672
}
625673

674+
private ScanProfile getScanProfile()
675+
{
676+
int baseRange = getChunkRange(area.getSelected());
677+
int baseScans = Math.max(1, chunksPerTick.getValueI());
678+
long baseBudgetNs =
679+
Math.max(1L, scanTimeBudgetMs.getValueI()) * 1_000_000L;
680+
int baseNearby = nearbyPriorityRadius.getValueI();
681+
682+
if(MC.player == null)
683+
return new ScanProfile(baseRange, baseScans, baseBudgetNs,
684+
baseNearby);
685+
686+
Vec3 currentPos = MC.player.position();
687+
double speed = 0;
688+
if(lastPlayerPos != null)
689+
speed = currentPos.subtract(lastPlayerPos).horizontalDistance();
690+
lastPlayerPos = currentPos;
691+
692+
if(!adaptiveMovementScan.isChecked())
693+
return new ScanProfile(baseRange, baseScans, baseBudgetNs,
694+
baseNearby);
695+
696+
boolean flying =
697+
MC.player.getAbilities().flying || MC.player.isFallFlying();
698+
if(flying || speed >= 0.9)
699+
{
700+
int range = Math.min(baseRange, 6);
701+
int scans = Math.max(baseScans, 16);
702+
long budgetNs = Math.max(baseBudgetNs, 16_000_000L);
703+
int nearby = Math.min(Math.max(baseNearby, 3), 6);
704+
return new ScanProfile(range, scans, budgetNs, nearby);
705+
}
706+
707+
if(speed >= 0.25)
708+
{
709+
int range = Math.min(baseRange, 12);
710+
int scans = Math.max(baseScans, 10);
711+
long budgetNs = Math.max(baseBudgetNs, 10_000_000L);
712+
int nearby = Math.min(Math.max(baseNearby, 3), 8);
713+
return new ScanProfile(range, scans, budgetNs, nearby);
714+
}
715+
716+
// Standing/slow movement: keep full selected area and user throughput.
717+
return new ScanProfile(baseRange, baseScans, baseBudgetNs, baseNearby);
718+
}
719+
626720
private ChunkDetections scanChunk(ChunkPos chunkPos)
627721
{
628722
ChunkDetections result = new ChunkDetections();
@@ -1373,7 +1467,8 @@ private int getScanConfigHash()
13731467
minLadderHeight.getValueI(), detectBubbleColumns.isChecked(),
13741468
minBubbleColumnHeight.getValueI(), detectWaterColumns.isChecked(),
13751469
minWaterColumnHeight.getValueI(), maxPerChunk.getValueI(),
1376-
refreshInterval.getValueI(), naturalWallsOnly.isChecked(),
1470+
refreshInterval.getValueI(), adaptiveMovementScan.isChecked(),
1471+
nearbyPriorityRadius.getValueI(), naturalWallsOnly.isChecked(),
13771472
naturalWallRatio.getValue(), overworld.isChecked(),
13781473
nether.isChecked(), end.isChecked());
13791474
}
@@ -1421,6 +1516,23 @@ private static final class ChunkDetections
14211516
private final ArrayList<AABB> waterColumns = new ArrayList<>();
14221517
}
14231518

1519+
private static final class ScanProfile
1520+
{
1521+
private final int range;
1522+
private final int scans;
1523+
private final long budgetNs;
1524+
private final int nearbyRadius;
1525+
1526+
private ScanProfile(int range, int scans, long budgetNs,
1527+
int nearbyRadius)
1528+
{
1529+
this.range = range;
1530+
this.scans = scans;
1531+
this.budgetNs = budgetNs;
1532+
this.nearbyRadius = nearbyRadius;
1533+
}
1534+
}
1535+
14241536
private enum DetectionMode
14251537
{
14261538
ALL("All"),

0 commit comments

Comments
 (0)