diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/Nuker.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/Nuker.java index 7245c5f0e1..2ac884d29f 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/world/Nuker.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/world/Nuker.java @@ -5,7 +5,10 @@ package meteordevelopment.meteorclient.systems.modules.world; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import meteordevelopment.meteorclient.events.entity.player.BlockBreakingCooldownEvent; +import meteordevelopment.meteorclient.events.meteor.KeyEvent; +import meteordevelopment.meteorclient.events.meteor.MouseButtonEvent; import meteordevelopment.meteorclient.events.render.Render3DEvent; import meteordevelopment.meteorclient.events.world.TickEvent; import meteordevelopment.meteorclient.renderer.ShapeMode; @@ -13,6 +16,10 @@ import meteordevelopment.meteorclient.systems.modules.Categories; import meteordevelopment.meteorclient.systems.modules.Module; import meteordevelopment.meteorclient.utils.Utils; +import meteordevelopment.meteorclient.utils.misc.Keybind; +import meteordevelopment.meteorclient.utils.misc.Names; +import meteordevelopment.meteorclient.utils.misc.input.KeyAction; +import meteordevelopment.meteorclient.utils.player.PlayerUtils; import meteordevelopment.meteorclient.utils.player.Rotations; import meteordevelopment.meteorclient.utils.render.RenderUtils; import meteordevelopment.meteorclient.utils.render.color.SettingColor; @@ -21,15 +28,21 @@ import meteordevelopment.orbit.EventHandler; import meteordevelopment.orbit.EventPriority; import net.minecraft.block.Block; +import net.minecraft.network.packet.c2s.play.HandSwingC2SPacket; import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RaycastContext; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import java.util.Set; public class Nuker extends Module { private final SettingGroup sgGeneral = settings.getDefaultGroup(); @@ -39,211 +52,241 @@ public class Nuker extends Module { // General private final Setting shape = sgGeneral.add(new EnumSetting.Builder() - .name("shape") - .description("The shape of nuking algorithm.") - .defaultValue(Shape.Sphere) - .build() + .name("shape") + .description("The shape of nuking algorithm.") + .defaultValue(Shape.Sphere) + .build() ); private final Setting mode = sgGeneral.add(new EnumSetting.Builder() - .name("mode") - .description("The way the blocks are broken.") - .defaultValue(Nuker.Mode.Flatten) - .build() + .name("mode") + .description("The way the blocks are broken.") + .defaultValue(Nuker.Mode.Flatten) + .build() ); private final Setting range = sgGeneral.add(new DoubleSetting.Builder() - .name("range") - .description("The break range.") - .defaultValue(4) - .min(0) - .visible(() -> shape.get() != Shape.Cube) - .build() + .name("range") + .description("The break range.") + .defaultValue(4) + .min(0) + .visible(() -> shape.get() != Shape.Cube) + .build() ); private final Setting range_up = sgGeneral.add(new IntSetting.Builder() - .name("up") - .description("The break range.") - .defaultValue(1) - .min(0) - .visible(() -> shape.get() == Shape.Cube) - .build() + .name("up") + .description("The break range.") + .defaultValue(1) + .min(0) + .visible(() -> shape.get() == Shape.Cube) + .build() ); private final Setting range_down = sgGeneral.add(new IntSetting.Builder() - .name("down") - .description("The break range.") - .defaultValue(1) - .min(0) - .visible(() -> shape.get() == Shape.Cube) - .build() + .name("down") + .description("The break range.") + .defaultValue(1) + .min(0) + .visible(() -> shape.get() == Shape.Cube) + .build() ); private final Setting range_left = sgGeneral.add(new IntSetting.Builder() - .name("left") - .description("The break range.") - .defaultValue(1) - .min(0) - .visible(() -> shape.get() == Shape.Cube) - .build() + .name("left") + .description("The break range.") + .defaultValue(1) + .min(0) + .visible(() -> shape.get() == Shape.Cube) + .build() ); private final Setting range_right = sgGeneral.add(new IntSetting.Builder() - .name("right") - .description("The break range.") - .defaultValue(1) - .min(0) - .visible(() -> shape.get() == Shape.Cube) - .build() + .name("right") + .description("The break range.") + .defaultValue(1) + .min(0) + .visible(() -> shape.get() == Shape.Cube) + .build() ); private final Setting range_forward = sgGeneral.add(new IntSetting.Builder() - .name("forward") - .description("The break range.") - .defaultValue(1) - .min(0) - .visible(() -> shape.get() == Shape.Cube) - .build() + .name("forward") + .description("The break range.") + .defaultValue(1) + .min(0) + .visible(() -> shape.get() == Shape.Cube) + .build() ); private final Setting range_back = sgGeneral.add(new IntSetting.Builder() - .name("back") - .description("The break range.") - .defaultValue(1) - .min(0) - .visible(() -> shape.get() == Shape.Cube) - .build() + .name("back") + .description("The break range.") + .defaultValue(1) + .min(0) + .visible(() -> shape.get() == Shape.Cube) + .build() + ); + + private final Setting wallsRange = sgGeneral.add(new DoubleSetting.Builder() + .name("walls-range") + .description("Range in which to break when behind blocks.") + .defaultValue(4.0) + .min(0) + .sliderMax(6) + .build() ); private final Setting delay = sgGeneral.add(new IntSetting.Builder() - .name("delay") - .description("Delay in ticks between breaking blocks.") - .defaultValue(0) - .build() + .name("delay") + .description("Delay in ticks between breaking blocks.") + .defaultValue(0) + .build() ); private final Setting maxBlocksPerTick = sgGeneral.add(new IntSetting.Builder() - .name("max-blocks-per-tick") - .description("Maximum blocks to try to break per tick. Useful when insta mining.") - .defaultValue(1) - .min(1) - .sliderRange(1, 6) - .build() + .name("max-blocks-per-tick") + .description("Maximum blocks to try to break per tick. Useful when insta mining.") + .defaultValue(1) + .min(1) + .build() ); private final Setting sortMode = sgGeneral.add(new EnumSetting.Builder() - .name("sort-mode") - .description("The blocks you want to mine first.") - .defaultValue(Nuker.SortMode.Closest) - .build() + .name("sort-mode") + .description("The blocks you want to mine first.") + .defaultValue(Nuker.SortMode.Closest) + .build() + ); + + private final Setting packetMine = sgGeneral.add(new BoolSetting.Builder() + .name("packet-mine") + .description("Attempt to instamine everything at once.") + .defaultValue(false) + .build() ); - private final Setting swingHand = sgGeneral.add(new BoolSetting.Builder() - .name("swing-hand") - .description("Swing hand client side.") - .defaultValue(true) - .build() + private final Setting suitableTools = sgGeneral.add(new BoolSetting.Builder() + .name("only-suitable-tools") + .description("Only mines when using an appropriate for the block.") + .defaultValue(false) + .build() ); - private final Setting packetMine = sgGeneral.add(new BoolSetting.Builder() - .name("packet-mine") - .description("Attempt to instamine everything at once.") - .defaultValue(false) - .build() + private final Setting interact = sgGeneral.add(new BoolSetting.Builder() + .name("interact") + .description("Interacts with the block instead of mining.") + .defaultValue(false) + .build() ); private final Setting rotate = sgGeneral.add(new BoolSetting.Builder() - .name("rotate") - .description("Rotates server-side to the block being mined.") - .defaultValue(true) - .build() + .name("rotate") + .description("Rotates server-side to the block being mined.") + .defaultValue(true) + .build() ); // Whitelist and blacklist private final Setting listMode = sgWhitelist.add(new EnumSetting.Builder() - .name("list-mode") - .description("Selection mode.") - .defaultValue(ListMode.Blacklist) - .build() + .name("list-mode") + .description("Selection mode.") + .defaultValue(ListMode.Blacklist) + .build() ); private final Setting> blacklist = sgWhitelist.add(new BlockListSetting.Builder() - .name("blacklist") - .description("The blocks you don't want to mine.") - .visible(() -> listMode.get() == ListMode.Blacklist) - .build() + .name("blacklist") + .description("The blocks you don't want to mine.") + .visible(() -> listMode.get() == ListMode.Blacklist) + .build() ); private final Setting> whitelist = sgWhitelist.add(new BlockListSetting.Builder() - .name("whitelist") - .description("The blocks you want to mine.") - .visible(() -> listMode.get() == ListMode.Whitelist) - .build() + .name("whitelist") + .description("The blocks you want to mine.") + .visible(() -> listMode.get() == ListMode.Whitelist) + .build() + ); + + private final Setting selectBlockBind = sgWhitelist.add(new KeybindSetting.Builder() + .name("select-block-bind") + .description("Adds targeted block to list when this button is pressed.") + .defaultValue(Keybind.none()) + .build() ); // Rendering + private final Setting swing = sgRender.add(new BoolSetting.Builder() + .name("swing") + .description("Whether to swing hand client-side.") + .defaultValue(true) + .build() + ); + private final Setting enableRenderBounding = sgRender.add(new BoolSetting.Builder() - .name("bounding-box") - .description("Enable rendering bounding box for Cube and Uniform Cube.") - .defaultValue(true) - .build() + .name("bounding-box") + .description("Enable rendering bounding box for Cube and Uniform Cube.") + .defaultValue(true) + .build() ); private final Setting shapeModeBox = sgRender.add(new EnumSetting.Builder() - .name("nuke-box-mode") - .description("How the shape for the bounding box is rendered.") - .defaultValue(ShapeMode.Both) - .build() + .name("nuke-box-mode") + .description("How the shape for the bounding box is rendered.") + .defaultValue(ShapeMode.Both) + .build() ); private final Setting sideColorBox = sgRender.add(new ColorSetting.Builder() - .name("side-color") - .description("The side color of the bounding box.") - .defaultValue(new SettingColor(16,106,144, 100)) - .build() + .name("side-color") + .description("The side color of the bounding box.") + .defaultValue(new SettingColor(16,106,144, 100)) + .build() ); private final Setting lineColorBox = sgRender.add(new ColorSetting.Builder() - .name("line-color") - .description("The line color of the bounding box.") - .defaultValue(new SettingColor(16,106,144, 255)) - .build() + .name("line-color") + .description("The line color of the bounding box.") + .defaultValue(new SettingColor(16,106,144, 255)) + .build() ); private final Setting enableRenderBreaking = sgRender.add(new BoolSetting.Builder() - .name("broken-blocks") - .description("Enable rendering bounding box for Cube and Uniform Cube.") - .defaultValue(true) - .build() + .name("broken-blocks") + .description("Enable rendering bounding box for Cube and Uniform Cube.") + .defaultValue(true) + .build() ); private final Setting shapeModeBreak = sgRender.add(new EnumSetting.Builder() - .name("nuke-block-mode") - .description("How the shapes for broken blocks are rendered.") - .defaultValue(ShapeMode.Both) - .visible(enableRenderBreaking::get) - .build() + .name("nuke-block-mode") + .description("How the shapes for broken blocks are rendered.") + .defaultValue(ShapeMode.Both) + .visible(enableRenderBreaking::get) + .build() ); private final Setting sideColor = sgRender.add(new ColorSetting.Builder() - .name("side-color") - .description("The side color of the target block rendering.") - .defaultValue(new SettingColor(255, 0, 0, 80)) - .visible(enableRenderBreaking::get) - .build() + .name("side-color") + .description("The side color of the target block rendering.") + .defaultValue(new SettingColor(255, 0, 0, 80)) + .visible(enableRenderBreaking::get) + .build() ); private final Setting lineColor = sgRender.add(new ColorSetting.Builder() - .name("line-color") - .description("The line color of the target block rendering.") - .defaultValue(new SettingColor(255, 0, 0, 255)) - .visible(enableRenderBreaking::get) - .build() + .name("line-color") + .description("The line color of the target block rendering.") + .defaultValue(new SettingColor(255, 0, 0, 255)) + .visible(enableRenderBreaking::get) + .build() ); private final List blocks = new ArrayList<>(); + private final Set interacted = new ObjectOpenHashSet<>(); private boolean firstBlock; private final BlockPos.Mutable lastBlockPos = new BlockPos.Mutable(); @@ -265,6 +308,7 @@ public void onActivate() { firstBlock = true; timer = 0; noBlockTimer = 0; + interacted.clear(); } @EventHandler @@ -283,6 +327,16 @@ private void onRender(Render3DEvent event) { } } + @EventHandler + private void onMouseButton(MouseButtonEvent event) { + if (event.action == KeyAction.Press) addTargetedBlockToList(); + } + + @EventHandler + private void onKey(KeyEvent event) { + if (event.action == KeyAction.Press) addTargetedBlockToList(); + } + @EventHandler private void onTickPre(TickEvent.Pre event) { // Update timer @@ -292,48 +346,44 @@ private void onTickPre(TickEvent.Pre event) { } // Calculate some stuff - double pX = mc.player.getX(); - double pY = mc.player.getY(); - double pZ = mc.player.getZ(); - + double pX = mc.player.getX(), pY = mc.player.getY(), pZ = mc.player.getZ(); double rangeSq = Math.pow(range.get(), 2); + BlockPos playerBlockPos = mc.player.getBlockPos(); if (shape.get() == Shape.UniformCube) range.set((double) Math.round(range.get())); - // Some render stuff - double pX_ = pX; double pZ_ = pZ; int r = (int) Math.round(range.get()); if (shape.get() == Shape.UniformCube) { - pX_ += 1; // weired position stuff + pX_ += 1; // weird position stuff pos1.set(pX_ - r, pY - r + 1, pZ - r + 1); // down pos2.set(pX_ + r - 1, pY + r, pZ + r); // up + maxh = 0; + maxv = 0; } else { - int direction = Math.round((mc.player.getRotationClient().y % 360) / 90); - direction = Math.floorMod(direction, 4); - - // direction == 1 - pos1.set(pX_ - range_forward.get(), Math.ceil(pY) - range_down.get(), pZ_ - range_right.get()); // down - pos2.set(pX_ + range_back.get() + 1, Math.ceil(pY + range_up.get() + 1), pZ_ + range_left.get() + 1); // up - // Only change me if you want to mess with 3D rotations: // I messed with it + Direction direction = mc.player.getHorizontalFacing(); switch (direction) { - case 0 -> { + case Direction.SOUTH -> { pZ_ += 1; pX_ += 1; pos1.set(pX_ - (range_right.get() + 1), Math.ceil(pY) - range_down.get(), pZ_ - (range_back.get() + 1)); // down pos2.set(pX_ + range_left.get(), Math.ceil(pY + range_up.get() + 1), pZ_ + range_forward.get()); // up } - case 2 -> { + case Direction.WEST -> { + pos1.set(pX_ - range_forward.get(), Math.ceil(pY) - range_down.get(), pZ_ - range_right.get()); // down + pos2.set(pX_ + range_back.get() + 1, Math.ceil(pY + range_up.get() + 1), pZ_ + range_left.get() + 1); // up + } + case Direction.NORTH -> { pX_ += 1; pZ_ += 1; pos1.set(pX_ - (range_left.get() + 1), Math.ceil(pY) - range_down.get(), pZ_ - (range_forward.get() + 1)); // down pos2.set(pX_ + range_right.get(), Math.ceil(pY + range_up.get() + 1), pZ_ + range_back.get()); // up } - case 3 -> { + case Direction.EAST -> { pX_ += 1; pos1.set(pX_ - (range_back.get() + 1), Math.ceil(pY) - range_down.get(), pZ_ - range_left.get()); // down pos2.set(pX_ + range_forward.get(), Math.ceil(pY + range_up.get() + 1), pZ_ + range_right.get() + 1); // up @@ -345,38 +395,47 @@ private void onTickPre(TickEvent.Pre event) { maxv = 1 + Math.max(range_up.get(), range_down.get()); } - if (mode.get() == Mode.Flatten) { - pos1.setY((int) Math.floor(pY)); - } + // Flatten + if (mode.get() == Mode.Flatten) pos1.setY((int) Math.floor(pY + 0.5)); + Box box = new Box(pos1.toCenterPos(), pos2.toCenterPos()); // Find blocks to break BlockIterator.register(Math.max((int) Math.ceil(range.get() + 1), maxh), Math.max((int) Math.ceil(range.get()), maxv), (blockPos, blockState) -> { - // Check for air, unbreakable blocks and distance + Vec3d center = blockPos.toCenterPos(); switch (shape.get()) { case Sphere -> { - if (Utils.squaredDistance(pX, pY, pZ, blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5) > rangeSq) return; + if (Utils.squaredDistance(pX, pY, pZ, center.getX(), center.getY(), center.getZ()) > rangeSq) return; } case UniformCube -> { - if (chebyshevDist(mc.player.getBlockPos().getX(), mc.player.getBlockPos().getY(), mc.player.getBlockPos().getZ(), blockPos.getX(), blockPos.getY(), blockPos.getZ()) >= range.get()) return; + if (chebyshevDist(playerBlockPos.getX(), playerBlockPos.getY(), playerBlockPos.getZ(), blockPos.getX(), blockPos.getY(), blockPos.getZ()) >= range.get()) return; } case Cube -> { - if (!box.contains(Vec3d.ofCenter(blockPos))) return; + if (!box.contains(center)) return; } } - if (!BlockUtils.canBreak(blockPos, blockState)) return; - // Flatten - if (mode.get() == Mode.Flatten && blockPos.getY() < Math.floor(mc.player.getY())) return; + if (mode.get() == Mode.Flatten && blockPos.getY() + 0.5 < pY) return; // Smash if (mode.get() == Mode.Smash && blockState.getHardness(mc.world, blockPos) != 0) return; + // Use only optimal tools + if (suitableTools.get() && !interact.get() && !mc.player.getMainHandStack().isSuitableFor(blockState)) return; + + // Block must be breakable + if (!BlockUtils.canBreak(blockPos, blockState) && !interact.get()) return; + + // Raycast to block + if (isOutOfRange(blockPos)) return; + // Check whitelist or blacklist if (listMode.get() == ListMode.Whitelist && !whitelist.get().contains(blockState.getBlock())) return; if (listMode.get() == ListMode.Blacklist && blacklist.get().contains(blockState.getBlock())) return; + if (interact.get() && interacted.contains(blockPos)) return; + // Add block blocks.add(blockPos.toImmutable()); }); @@ -391,6 +450,7 @@ else if (sortMode.get() != SortMode.None) // Check if some block was found if (blocks.isEmpty()) { + interacted.clear(); // If no block was found for long enough then set firstBlock flag to true to not wait before breaking another again if (noBlockTimer++ >= delay.get()) firstBlock = true; return; @@ -435,12 +495,52 @@ else if (sortMode.get() != SortMode.None) } private void breakBlock(BlockPos blockPos) { - if (packetMine.get()) { + if (interact.get()) { + // Interact mode + BlockUtils.interact(new BlockHitResult(blockPos.toCenterPos(), BlockUtils.getDirection(blockPos), blockPos, true), Hand.MAIN_HAND, swing.get()); + interacted.add(blockPos); + } else if (packetMine.get()) { + // Packet mine mode mc.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.START_DESTROY_BLOCK, blockPos, BlockUtils.getDirection(blockPos))); - mc.player.swingHand(Hand.MAIN_HAND); + + if (swing.get()) mc.player.swingHand(Hand.MAIN_HAND); + else mc.getNetworkHandler().sendPacket(new HandSwingC2SPacket(Hand.MAIN_HAND)); + mc.getNetworkHandler().sendPacket(new PlayerActionC2SPacket(PlayerActionC2SPacket.Action.STOP_DESTROY_BLOCK, blockPos, BlockUtils.getDirection(blockPos))); } else { - BlockUtils.breakBlock(blockPos, swingHand.get()); + // Legit mine mode + BlockUtils.breakBlock(blockPos, swing.get()); + } + } + + private boolean isOutOfRange(BlockPos blockPos) { + Vec3d pos = blockPos.toCenterPos(); + RaycastContext raycastContext = new RaycastContext(mc.player.getEyePos(), pos, RaycastContext.ShapeType.COLLIDER, RaycastContext.FluidHandling.NONE, mc.player); + BlockHitResult result = mc.world.raycast(raycastContext); + if (result == null || !result.getBlockPos().equals(blockPos)) + return !PlayerUtils.isWithin(pos, wallsRange.get()); + + return false; + } + + private void addTargetedBlockToList() { + if (!selectBlockBind.get().isPressed() || mc.currentScreen != null) return; + + HitResult hitResult = mc.crosshairTarget; + if (hitResult == null || hitResult.getType() != HitResult.Type.BLOCK) return; + + BlockPos pos = ((BlockHitResult) hitResult).getBlockPos(); + Block targetBlock = mc.world.getBlockState(pos).getBlock(); + + List list = listMode.get() == ListMode.Whitelist ? whitelist.get() : blacklist.get(); + String modeName = listMode.get().name(); + + if (list.contains(targetBlock)) { + list.remove(targetBlock); + info("Removed " + Names.get(targetBlock) + " from " + modeName); + } else { + list.add(targetBlock); + info("Added " + Names.get(targetBlock) + " to " + modeName); } }