Skip to content

Commit c256f64

Browse files
committed
Nuker improvements for non-anarchy
- Adds Smooth Rotate option - Adds ClosestToLast sort - Adds random face point targeting - Makes method isOutOfRange() smarter (but likely much slower) - Includes/supercedes my fix (MeteorDevelopment#6169) to prevent Nuker switching from a block it's already mining to a new one with higher sort priority (SEMI-UNTESTED) Intended to make nuker mining less suspicious for use on non-anarchy servers such as Hypixel Skyblock, Prison servers, Box Servers
1 parent f18ec5f commit c256f64

4 files changed

Lines changed: 266 additions & 36 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
.settings
44
.project
55
.classpath
6+
.vscode
67
build
78
out
89
run

src/main/java/meteordevelopment/meteorclient/systems/modules/world/Nuker.java

Lines changed: 174 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@
1919
import meteordevelopment.meteorclient.utils.misc.Keybind;
2020
import meteordevelopment.meteorclient.utils.misc.Names;
2121
import meteordevelopment.meteorclient.utils.misc.input.KeyAction;
22-
import meteordevelopment.meteorclient.utils.player.PlayerUtils;
2322
import meteordevelopment.meteorclient.utils.player.Rotations;
2423
import meteordevelopment.meteorclient.utils.render.RenderUtils;
24+
import meteordevelopment.meteorclient.utils.render.color.Color;
2525
import meteordevelopment.meteorclient.utils.render.color.SettingColor;
2626
import meteordevelopment.meteorclient.utils.world.BlockIterator;
2727
import meteordevelopment.meteorclient.utils.world.BlockUtils;
2828
import meteordevelopment.orbit.EventHandler;
2929
import meteordevelopment.orbit.EventPriority;
3030
import net.minecraft.block.Block;
31+
import net.minecraft.block.BlockState;
3132
import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket;
3233
import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket;
3334
import net.minecraft.util.Hand;
@@ -36,14 +37,21 @@
3637
import net.minecraft.util.math.BlockPos;
3738
import net.minecraft.util.math.Box;
3839
import net.minecraft.util.math.Direction;
40+
import net.minecraft.util.math.MathHelper;
3941
import net.minecraft.util.math.Vec3d;
42+
import net.minecraft.util.shape.VoxelShape;
4043
import net.minecraft.world.RaycastContext;
4144

4245
import java.util.ArrayList;
4346
import java.util.Comparator;
4447
import java.util.List;
4548
import java.util.Set;
4649

50+
import org.joml.Random;
51+
52+
import com.google.common.collect.HashMultimap;
53+
import com.google.common.collect.Multimap;
54+
4755
public class Nuker extends Module {
4856
private final SettingGroup sgGeneral = settings.getDefaultGroup();
4957
private final SettingGroup sgWhitelist = settings.createGroup("Whitelist");
@@ -187,6 +195,14 @@ public class Nuker extends Module {
187195
.build()
188196
);
189197

198+
private final Setting<Boolean> smoothRotate = sgGeneral.add(new BoolSetting.Builder()
199+
.name("smooth-rotate")
200+
.description("Smoothes rotation according to delay.")
201+
.defaultValue(true)
202+
.visible(() -> rotate.get() && maxBlocksPerTick.get() <= 1)
203+
.build()
204+
);
205+
190206
// Whitelist and blacklist
191207

192208
private final Setting<ListMode> listMode = sgWhitelist.add(new EnumSetting.Builder<ListMode>()
@@ -285,15 +301,54 @@ public class Nuker extends Module {
285301
.build()
286302
);
287303

304+
private final Setting<Boolean> enableRenderDebug = sgRender.add(new BoolSetting.Builder()
305+
.name("debug-visuals")
306+
.description("Enable debug rendering.")
307+
.defaultValue(false)
308+
.build()
309+
);
310+
288311
private final List<BlockPos> blocks = new ArrayList<>();
312+
private BlockPos currentBlock = null;
289313
private final Set<BlockPos> interacted = new ObjectOpenHashSet<>();
290314

291315
private boolean firstBlock;
292316
private final BlockPos.Mutable lastBlockPos = new BlockPos.Mutable();
293317

294318
private int timer;
319+
private int timerMax;
320+
private double startYaw = 0;
321+
private double startPitch = 0;
322+
private Vec3d randomOffsetOnFace;
295323
private int noBlockTimer;
296324

325+
private void resetOffsetOnFace(BlockPos blockPos) {
326+
// Check if the offset has already been reset for this block
327+
if (lastBlockPos.equals(blockPos)) return;
328+
329+
// Select a random visible side of the block
330+
ArrayList<Direction> sideList = new ArrayList<>(visibleFaceMap.get(blockPos));
331+
Direction side = sideList.get(new Random().nextInt(sideList.size()));
332+
333+
// <narakomii> this seems to break when i remove this scope, i probably did something dumb and didn't notice - i'm too lazy to fix it rn
334+
{
335+
// Select a random offset
336+
double x = Math.random();
337+
double y = Math.random();
338+
double z = Math.random();
339+
340+
// Clamp the offset to the selected side
341+
if (side.getOffsetX() == 1) x = 1;
342+
else if (side.getOffsetX() == -1) x = 0;
343+
else if (side.getOffsetY() == 1) y = 1;
344+
else if (side.getOffsetY() == -1) y = 0;
345+
else if (side.getOffsetZ() == 1) z = 1;
346+
else if (side.getOffsetZ() == -1) z = 0;
347+
348+
randomOffsetOnFace = new Vec3d(x, y, z);
349+
}
350+
}
351+
297352
private final BlockPos.Mutable pos1 = new BlockPos.Mutable(); // Rendering for cubes
298353
private final BlockPos.Mutable pos2 = new BlockPos.Mutable();
299354
int maxh = 0;
@@ -305,9 +360,11 @@ public Nuker() {
305360

306361
@Override
307362
public void onActivate() {
363+
currentBlock = null;
308364
firstBlock = true;
309365
timer = 0;
310366
noBlockTimer = 0;
367+
lastBlockPos.set((int) Math.floor(mc.player.getEyePos().x), (int) Math.floor(mc.player.getEyePos().y), (int) Math.floor(mc.player.getEyePos().z));
311368
interacted.clear();
312369
}
313370

@@ -342,10 +399,13 @@ private void onTickPre(TickEvent.Pre event) {
342399
// Update timer
343400
if (timer > 0) {
344401
timer--;
345-
return;
346402
}
347403

404+
visibleFaceMap.clear();
405+
348406
// Calculate some stuff
407+
boolean smoothRotateEnabled = rotate.get() && maxBlocksPerTick.get() <= 1 && smoothRotate.get();
408+
349409
double pX = mc.player.getX(), pY = mc.player.getY(), pZ = mc.player.getZ();
350410
double rangeSq = Math.pow(range.get(), 2);
351411
BlockPos playerBlockPos = mc.player.getBlockPos();
@@ -427,15 +487,15 @@ private void onTickPre(TickEvent.Pre event) {
427487
// Block must be breakable
428488
if (!BlockUtils.canBreak(blockPos, blockState) && !interact.get()) return;
429489

430-
// Raycast to block
431-
if (isOutOfRange(blockPos)) return;
432-
433490
// Check whitelist or blacklist
434491
if (listMode.get() == ListMode.Whitelist && !whitelist.get().contains(blockState.getBlock())) return;
435492
if (listMode.get() == ListMode.Blacklist && blacklist.get().contains(blockState.getBlock())) return;
436493

437494
if (interact.get() && interacted.contains(blockPos)) return;
438495

496+
// Raycast to block
497+
if (isOutOfRange(blockPos, blockState)) return;
498+
439499
// Add block
440500
blocks.add(blockPos.toImmutable());
441501
});
@@ -445,28 +505,53 @@ private void onTickPre(TickEvent.Pre event) {
445505
// Sort blocks
446506
if (sortMode.get() == SortMode.TopDown)
447507
blocks.sort(Comparator.comparingDouble(value -> -value.getY()));
448-
else if (sortMode.get() != SortMode.None)
449-
blocks.sort(Comparator.comparingDouble(value -> Utils.squaredDistance(pX, pY, pZ, value.getX() + 0.5, value.getY() + 0.5, value.getZ() + 0.5) * (sortMode.get() == SortMode.Closest ? 1 : -1)));
450-
451-
// Check if some block was found
508+
else if (sortMode.get() == SortMode.ClosestToLast && noBlockTimer <= 0) {
509+
// Sort by closest to last mined block, then closest to player
510+
blocks.sort(Comparator.comparingDouble(value ->
511+
Utils.squaredDistance((double) lastBlockPos.getX() + 0.5, (double) lastBlockPos.getY() + 0.5, (double) lastBlockPos.getZ() + 0.5, (double) value.getX() + 0.5, (double) value.getY() + 0.5, (double) value.getZ() + 0.5)
512+
+ Utils.squaredDistance(pX, pY, pZ, (double) value.getX() + 0.5, (double) value.getY() + 0.5, (double) value.getZ() + 0.5) / 262144
513+
));
514+
} else if (sortMode.get() != SortMode.None)
515+
blocks.sort(Comparator.comparingDouble(value -> Utils.squaredDistance(pX, pY, pZ, value.getX() + 0.5, value.getY() + 0.5, value.getZ() + 0.5) * (sortMode.get() == SortMode.Furthest ? -1 : 1)));
516+
517+
// Check if no block was found
452518
if (blocks.isEmpty()) {
453-
interacted.clear();
454519
// If no block was found for long enough then set firstBlock flag to true to not wait before breaking another again
455-
if (noBlockTimer++ >= delay.get()) firstBlock = true;
520+
if (!smoothRotateEnabled && noBlockTimer++ >= delay.get()) firstBlock = true;
521+
522+
// Reset some values
523+
currentBlock = null;
524+
interacted.clear();
525+
startYaw = mc.player.getYaw();
526+
startPitch = mc.player.getPitch();
456527
return;
457528
}
458529
else {
459530
noBlockTimer = 0;
460531
}
461532

533+
// Check if a block is already being mined
534+
if (currentBlock != null) {
535+
// Check if it's still valid
536+
if (!BlockUtils.canInstaBreak(currentBlock) && !packetMine.get() && blocks.contains(currentBlock)) {
537+
// Move it to the start of the list (will be iterated first)
538+
blocks.remove(currentBlock);
539+
blocks.addFirst(currentBlock);
540+
} else {
541+
currentBlock = null;
542+
}
543+
}
544+
462545
// Update timer
463546
if (!firstBlock && !lastBlockPos.equals(blocks.getFirst())) {
464-
timer = delay.get();
547+
timer = timerMax = delay.get();
465548

466549
firstBlock = false;
467-
lastBlockPos.set(blocks.getFirst());
468550

469-
if (timer > 0) return;
551+
// Try to reset random face offset
552+
resetOffsetOnFace(blocks.getFirst());
553+
554+
lastBlockPos.set(blocks.getFirst());
470555
}
471556

472557
// Break
@@ -477,12 +562,43 @@ else if (sortMode.get() != SortMode.None)
477562

478563
boolean canInstaMine = BlockUtils.canInstaBreak(block);
479564

480-
if (rotate.get()) Rotations.rotate(Rotations.getYaw(block), Rotations.getPitch(block), () -> breakBlock(block));
481-
else breakBlock(block);
565+
resetOffsetOnFace(block);
566+
// Add the offset to the block's position
567+
Vec3d lookPos = new Vec3d(block).add(randomOffsetOnFace);
568+
569+
if (enableRenderDebug.get()) {
570+
// Display currently targeted point
571+
RenderUtils.renderTickingPoint(lookPos, Color.GREEN, 1, false);
572+
}
573+
574+
if (timer <= 0) {
575+
// If delay is over, mine the block
576+
if (rotate.get())
577+
Rotations.rotate(startYaw = Rotations.getYaw(lookPos), startPitch = Rotations.getPitch(lookPos), () -> breakBlock(block));
578+
else
579+
breakBlock(block);
580+
} else if (smoothRotateEnabled) {
581+
// If not and smooth rotate is enabled, lerp to the target
582+
double endYaw = Rotations.getYaw(lookPos);
583+
double endPitch = Rotations.getPitch(lookPos);
584+
double delta = 1 - ((double) timer) / timerMax;
585+
586+
// Weird easing hybrid of EaseOutQuart and modified EaseOutBack
587+
final double c = 0.37;
588+
delta = (1 + (c + 1) * Math.pow(delta - 1, 3) + c * Math.pow(delta - 1, 2)) * (1 - Math.pow(1 - delta, 4));
589+
590+
double yaw = MathHelper.lerpAngleDegrees(delta, startYaw, endYaw);
591+
double pitch = MathHelper.lerpAngleDegrees(delta, startPitch, endPitch);
592+
593+
Rotations.rotate(yaw, pitch);
594+
break;
595+
}
482596

483597
if (enableRenderBreaking.get()) RenderUtils.renderTickingBlock(block, sideColor.get(), lineColor.get(), shapeModeBreak.get(), 0, 8, true, false);
484598
lastBlockPos.set(block);
485599

600+
currentBlock = block;
601+
486602
count++;
487603
if (!canInstaMine && !packetMine.get() /* With packet mine attempt to break everything possible at once */) break;
488604
}
@@ -513,14 +629,46 @@ private void breakBlock(BlockPos blockPos) {
513629
}
514630
}
515631

516-
private boolean isOutOfRange(BlockPos blockPos) {
517-
Vec3d pos = blockPos.toCenterPos();
518-
RaycastContext raycastContext = new RaycastContext(mc.player.getEyePos(), pos, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player);
519-
BlockHitResult result = mc.world.raycast(raycastContext);
520-
if (result == null || !result.getBlockPos().equals(blockPos))
521-
return !PlayerUtils.isWithin(pos, wallsRange.get());
632+
private Multimap<BlockPos, Direction> visibleFaceMap = HashMultimap.create();
633+
634+
private static final double boxShrink = Math.pow(2, -16);
635+
636+
private boolean isOutOfRange(BlockPos blockPos, BlockState blockState) {
637+
boolean allOutOfRange = true;
638+
639+
VoxelShape shape = blockState.getOutlineShape(mc.player.getEntityWorld(), blockPos);
640+
641+
// Iterate over each cuboid of the block's interaction box
642+
for (Box box : shape.getBoundingBoxes()) {
643+
// Shrink cuboid by a tiny amount to avoid false misses, but preserve accuracy
644+
// Then offset by block position
645+
box = box.contract(boxShrink).offset(blockPos);
646+
647+
// Iterate over each corner of the adjusted cuboid
648+
for (Vec3d corner : Utils.getBoxCorners(box)) {
649+
// Raycast to the corner
650+
RaycastContext raycastContext = new RaycastContext(mc.player.getEyePos(), corner, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player);
651+
BlockHitResult result = mc.world.raycast(raycastContext);
652+
653+
boolean outOfRange = result == null || !result.getBlockPos().equals(blockPos);
654+
655+
if (!outOfRange) {
656+
// If raycast hit, add the block face to the map
657+
visibleFaceMap.put(blockPos.toImmutable(), result.getSide());
658+
659+
// Then, if debug rendering is disabled: break and return false immediately
660+
// If enabled: set return value to false and draw the corner
661+
if (!enableRenderDebug.get()) {
662+
return false;
663+
} else {
664+
allOutOfRange = false;
665+
RenderUtils.renderTickingPoint(corner, Color.BLUE, 1, false);
666+
}
667+
}
668+
}
669+
}
522670

523-
return false;
671+
return allOutOfRange;
524672
}
525673

526674
private void addTargetedBlockToList() {
@@ -564,7 +712,8 @@ public enum SortMode {
564712
None,
565713
Closest,
566714
Furthest,
567-
TopDown
715+
TopDown,
716+
ClosestToLast
568717
}
569718

570719
public enum Shape {
@@ -580,4 +729,4 @@ public static int chebyshevDist(int x1, int y1, int z1, int x2, int y2, int z2)
580729
int dZ = Math.abs(z2 - z1);
581730
return Math.max(Math.max(dX, dY), dZ);
582731
}
583-
}
732+
}

src/main/java/meteordevelopment/meteorclient/utils/Utils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,14 @@
5555
import net.minecraft.util.DyeColor;
5656
import net.minecraft.util.collection.DefaultedList;
5757
import net.minecraft.util.math.BlockPos;
58+
import net.minecraft.util.math.Box;
5859
import net.minecraft.util.math.MathHelper;
60+
import net.minecraft.util.math.RotationAxis;
5961
import net.minecraft.util.math.Vec3d;
6062
import net.minecraft.world.chunk.Chunk;
6163
import org.apache.commons.io.IOUtils;
6264
import org.apache.commons.lang3.StringUtils;
65+
import org.apache.commons.lang3.tuple.Pair;
6366
import org.jetbrains.annotations.Range;
6467
import org.joml.Vector3d;
6568

@@ -645,6 +648,21 @@ public static Vector3d set(Vector3d vec, Entity entity, double tickDelta) {
645648
return vec;
646649
}
647650

651+
public static List<Vec3d> getBoxCorners(Box box) {
652+
List<Vec3d> list = new ArrayList<>();
653+
654+
list.add(new Vec3d(box.minX, box.minY, box.minZ));
655+
list.add(new Vec3d(box.minX, box.minY, box.maxZ));
656+
list.add(new Vec3d(box.minX, box.maxY, box.minZ));
657+
list.add(new Vec3d(box.minX, box.maxY, box.maxZ));
658+
list.add(new Vec3d(box.maxX, box.minY, box.minZ));
659+
list.add(new Vec3d(box.maxX, box.minY, box.maxZ));
660+
list.add(new Vec3d(box.maxX, box.maxY, box.minZ));
661+
list.add(new Vec3d(box.maxX, box.maxY, box.maxZ));
662+
663+
return list;
664+
}
665+
648666
// Filters
649667

650668
public static boolean nameFilter(String text, char character) {

0 commit comments

Comments
 (0)