From cb01be4b4715641b6a6e67b3270d30e6edb23a6d Mon Sep 17 00:00:00 2001 From: TudbuT Date: Wed, 19 Jun 2024 18:15:10 +0200 Subject: [PATCH] implement Fill module --- .../java/de/com/baseband/client/Setup.java | 1 + .../client/event/remote/RemoteEventBus.java | 6 +- .../client/feature/modules/ingame/Fill.java | 172 ++++++++++++++++++ .../client/feature/modules/ingame/Select.java | 15 +- .../client/util/interact/BlockUtils.java | 137 ++++++++++++++ 5 files changed, 326 insertions(+), 5 deletions(-) create mode 100644 Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Fill.java diff --git a/Client/src/main/java/de/com/baseband/client/Setup.java b/Client/src/main/java/de/com/baseband/client/Setup.java index 06ad744..374f5ae 100644 --- a/Client/src/main/java/de/com/baseband/client/Setup.java +++ b/Client/src/main/java/de/com/baseband/client/Setup.java @@ -56,6 +56,7 @@ public class Setup { new ElytraFly(), new ElytraBot(), new ESP(), + new Fill(), new Freecam(), new Help(), new HUD(), diff --git a/Client/src/main/java/de/com/baseband/client/event/remote/RemoteEventBus.java b/Client/src/main/java/de/com/baseband/client/event/remote/RemoteEventBus.java index f73f4ee..ae5b5e4 100644 --- a/Client/src/main/java/de/com/baseband/client/event/remote/RemoteEventBus.java +++ b/Client/src/main/java/de/com/baseband/client/event/remote/RemoteEventBus.java @@ -201,6 +201,10 @@ public class RemoteEventBus { } public void onTick() { + if(!isConnected()) { + toProcess.addAll(toSend); + toSend.clear(); + } while(!toProcess.isEmpty()) { RemoteEvent event = toProcess.poll(); if(event instanceof RemoteInitEvent) { @@ -211,8 +215,6 @@ public class RemoteEventBus { BaseBand.EVENT_BUS.publish(event); } } - if(!isConnected()) - toSend.clear(); } public int getID() { diff --git a/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Fill.java b/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Fill.java new file mode 100644 index 0000000..bf7a16a --- /dev/null +++ b/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Fill.java @@ -0,0 +1,172 @@ +package de.com.baseband.client.feature.modules.ingame; + +import de.com.baseband.client.BaseBand; +import de.com.baseband.client.feature.Feature; +import de.com.baseband.client.feature.category.Ingame; +import de.com.baseband.client.registry.annotation.*; +import de.com.baseband.client.util.interact.BlockUtils; +import de.com.baseband.client.util.interact.InventoryUtils; +import de.com.baseband.client.util.interact.ServerDataManager; +import de.tudbut.tools.Lock; +import net.minecraft.block.state.IBlockState; +import net.minecraft.inventory.Slot; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; + +import java.util.HashMap; + +@Ingame +@Requires(Select.class) +public class Fill extends Feature { + + public enum Mode { + Break, + Place, + } + + @Config("Mode") + public Mode mode = Mode.Break; + + @Config("Iterations") + @Description("Functions as a multiplier for speed: Runs the module multiple times per tick.") + @Range("1..5") + public int iterations = 1; + + @Config("Rotate") + @Description("Faces the block that is being acted on.") + public boolean rotate = false; + + @KeyBound("Use break") + public void useBreak() { + mode = Mode.Break; + handle.poll("Mode"); + BaseBand.notify(this + " is now in break mode."); + } + @KeyBound("Use place") + public void usePlace() { + mode = Mode.Place; + handle.poll("Mode"); + BaseBand.notify(this + " is now in place mode."); + } + @KeyBound("Switch mode") + public void switchMode() { + if(mode == Mode.Break) + usePlace(); + else + useBreak(); + } + + int iterationsLeft = 0; + + @Override + public void onTick() { + if(Select.selection == null) + return; + + iterationsLeft = iterations; + + // loop through intersection of box around player and the selection + BlockPos eyePos = new BlockPos(mc.player.getPositionEyes(1)); + BlockPos pBoxMin = eyePos.add(-5, -5, -5); + BlockPos pBoxMax = eyePos.add(5, 5, 5); + BlockPos selectMin = Select.selection.pos1; + BlockPos selectMax = Select.selection.pos2; + int minX = Math.max(pBoxMin.getX(), selectMin.getX()), maxX = Math.min(pBoxMax.getX(), selectMax.getX()); + int minY = Math.max(pBoxMin.getY(), selectMin.getY()), maxY = Math.min(pBoxMax.getY(), selectMax.getY()); + int minZ = Math.max(pBoxMin.getZ(), selectMin.getZ()), maxZ = Math.min(pBoxMax.getZ(), selectMax.getZ()); + try { + for (int y = minY; y <= maxY; y++) { + for (int x = minX; x <= maxX; x++) { + for (int z = minZ; z <= maxZ; z++) { + if (doBlock(x, y, z)) + return; + } + } + } + } catch (NoItem ignored) {} + } + + private boolean doBlock(int x, int y, int z) throws NoItem { + while (iterationsLeft > 0) { + if (mode == Mode.Break) + if(!doBreak(x, y, z)) + break; + if (mode == Mode.Place) + if(!doPlace(x, y, z)) + break; + iterationsLeft--; + } + return iterationsLeft == 0; + } + + private boolean doBreak(int x, int y, int z) { + BlockPos pos = new BlockPos(x,y,z); + + // TODO find optimal tool + + IBlockState block = mc.world.getBlockState(pos); + if(block.getMaterial().isReplaceable()) { + return false; + } + + if(block.getBlockHardness(mc.world, pos) == -1) { + return false; + } + + BlockUtils.breakBlock(pos, rotate); + return true; + } + + HashMap placeCache = new HashMap<>(); + Item lastPlacedItem = null; + boolean doPlace(int x, int y, int z) throws NoItem { + BlockPos pos = new BlockPos(x,y,z); + if (placeCache.containsKey(pos)) { + if (placeCache.get(pos).isLocked()) { + return false; + } + else { + placeCache.remove(pos); + } + } + if(!mc.world.getBlockState(pos).getMaterial().isReplaceable()) { + return false; + } + + ItemStack curItem = mc.player.inventoryContainer.getSlot(36 + InventoryUtils.getCurrentSlot()).getStack(); + if(curItem.isEmpty()) { + a: + { + for (Slot inventorySlot : mc.player.inventoryContainer.inventorySlots) { + if (!inventorySlot.getStack().isEmpty() && inventorySlot.getStack().getItem() == lastPlacedItem) { + InventoryUtils.swapWithHB(inventorySlot.getSlotIndex(), InventoryUtils.getCurrentSlot()); + break a; + } + } + throw new NoItem(); + } + } + + if(!BlockUtils.placeBlock(pos, EnumHand.MAIN_HAND, rotate, true)) { + return false; + } + + Lock value = new Lock(); + value.lock(Math.max(0, (int) (ServerDataManager.ping * 2))); + placeCache.put(pos, value); + lastPlacedItem = curItem.getItem(); + + return true; + } + + @Override + public String toString() { + return "Fill"; + } + + private static class NoItem extends Throwable { + + } +} diff --git a/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Select.java b/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Select.java index 14e0140..40c3e06 100644 --- a/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Select.java +++ b/Client/src/main/java/de/com/baseband/client/feature/modules/ingame/Select.java @@ -5,6 +5,8 @@ import de.com.baseband.client.event.Priority; import de.com.baseband.client.event.events.SelectEvent; import de.com.baseband.client.feature.Feature; import de.com.baseband.client.feature.category.Ingame; +import de.com.baseband.client.registry.annotation.KeyBound; +import de.com.baseband.client.registry.annotation.Trigger; import de.com.baseband.client.util.type.Selection; import net.minecraft.util.math.BlockPos; @@ -16,11 +18,9 @@ public class Select extends Feature { public static void select(BlockPos b) { if(end != null || begin == null) { + reset(); begin = b; - end = null; - BaseBand.notify("Selection reset."); BaseBand.notify("Position 1: " + b.getX() + " " + b.getY() + " " + b.getZ()); - BaseBand.publish(new SelectEvent(null)); return; } end = b; @@ -41,6 +41,15 @@ public class Select extends Feature { meta = "0 Blocks"; } + @Trigger("Reset") + @KeyBound + public static void reset() { + begin = end = null; + BaseBand.publish(new SelectEvent(null)); + BaseBand.notify("Selection reset."); + } + + @Override public String toString() { return "Select"; diff --git a/Client/src/main/java/de/com/baseband/client/util/interact/BlockUtils.java b/Client/src/main/java/de/com/baseband/client/util/interact/BlockUtils.java index a1c4f27..5c7ccd6 100644 --- a/Client/src/main/java/de/com/baseband/client/util/interact/BlockUtils.java +++ b/Client/src/main/java/de/com/baseband/client/util/interact/BlockUtils.java @@ -1,12 +1,75 @@ package de.com.baseband.client.util.interact; import de.com.baseband.client.util.type.Selection; +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.init.Blocks; +import net.minecraft.network.play.client.CPacketEntityAction; +import net.minecraft.network.play.client.CPacketPlayer; +import net.minecraft.network.play.client.CPacketPlayerTryUseItemOnBlock; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec2f; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static de.com.baseband.client.BaseBand.mc; + public class BlockUtils { + + // Sneak! + public static ArrayList sneakList = new ArrayList<>(Arrays.asList( + Blocks.ENDER_CHEST, + Blocks.CHEST, + Blocks.TRAPPED_CHEST, + Blocks.CRAFTING_TABLE, + Blocks.ANVIL, + Blocks.BREWING_STAND, + Blocks.HOPPER, + Blocks.DROPPER, + Blocks.DISPENSER, + Blocks.TRAPDOOR, + Blocks.ENCHANTING_TABLE, + Blocks.POWERED_COMPARATOR, + Blocks.UNPOWERED_COMPARATOR, + Blocks.POWERED_REPEATER, + Blocks.UNPOWERED_REPEATER, + Blocks.CAKE, + Blocks.STANDING_SIGN, + Blocks.WALL_SIGN, + Blocks.OAK_DOOR, + Blocks.SPRUCE_DOOR, + Blocks.BIRCH_DOOR, + Blocks.DARK_OAK_DOOR, + Blocks.IRON_DOOR, + Blocks.JUNGLE_DOOR, + Blocks.ACACIA_DOOR, + Blocks.IRON_TRAPDOOR + )); + public static ArrayList shulkerList = new ArrayList<>(Arrays.asList( + Blocks.WHITE_SHULKER_BOX, + Blocks.ORANGE_SHULKER_BOX, + Blocks.MAGENTA_SHULKER_BOX, + Blocks.LIGHT_BLUE_SHULKER_BOX, + Blocks.YELLOW_SHULKER_BOX, + Blocks.LIME_SHULKER_BOX, + Blocks.PINK_SHULKER_BOX, + Blocks.GRAY_SHULKER_BOX, + Blocks.SILVER_SHULKER_BOX, + Blocks.CYAN_SHULKER_BOX, + Blocks.PURPLE_SHULKER_BOX, + Blocks.BLUE_SHULKER_BOX, + Blocks.BROWN_SHULKER_BOX, + Blocks.GREEN_SHULKER_BOX, + Blocks.RED_SHULKER_BOX, + Blocks.BLACK_SHULKER_BOX + )); + // returned amount may be smaller! public static Selection[] splitSelection1D(Selection selection, int amount) { Vec3i size = selection.size(); @@ -39,4 +102,78 @@ public class BlockUtils { return new Vec2f((float) ((yaw + Math.PI) % (Math.PI * 2) - Math.PI), (float) (pitch)); } + + public static boolean placeBlock(BlockPos pos, EnumHand hand, boolean rotate, boolean packet) { + EnumFacing side = getFirstFacing(pos); + if (side == null) { + return false; + } + + BlockPos neighbour = pos.offset(side); + EnumFacing sidePlacedOn = side.getOpposite(); + // middle of the selected face + Vec3d hitVec = new Vec3d(neighbour).add(0.5, 0.5, 0.5).add(new Vec3d(sidePlacedOn.getDirectionVec()).scale(0.5)); + + Block neighbourBlock = mc.world.getBlockState(neighbour).getBlock(); + + if (!mc.player.isSneaking() && (sneakList.contains(neighbourBlock) || shulkerList.contains(neighbourBlock))) { + mc.player.connection.sendPacket(new CPacketEntityAction(mc.player, CPacketEntityAction.Action.START_SNEAKING)); + mc.player.setSneaking(true); + } + + if (rotate) { + Vec2f rotations = lookTo(mc.player.getPositionEyes(1), hitVec); + mc.player.connection.sendPacket(new CPacketPlayer.Rotation(rotations.x, rotations.y, mc.player.onGround)); + } + + rightClickBlock(neighbour, hitVec, hand, sidePlacedOn, packet); + + if (mc.player.isSneaking()) { + mc.player.connection.sendPacket(new CPacketEntityAction(mc.player, CPacketEntityAction.Action.STOP_SNEAKING)); + mc.player.setSneaking(false); + } + return true; + } + + public static void rightClickBlock(BlockPos pos, Vec3d vec, EnumHand hand, EnumFacing direction, boolean packet) { + if (packet) { + float f = (float) (vec.x - (double) pos.getX()); + float f1 = (float) (vec.y - (double) pos.getY()); + float f2 = (float) (vec.z - (double) pos.getZ()); + mc.player.connection.sendPacket(new CPacketPlayerTryUseItemOnBlock(pos, direction, hand, f, f1, f2)); + } else { + mc.playerController.processRightClickBlock(mc.player, mc.world, pos, direction, vec, hand); + } + mc.player.swingArm(EnumHand.MAIN_HAND); + } + + public static List getSidesFacing(BlockPos pos, boolean allowSneak) { + List facings = new ArrayList<>(); + for (EnumFacing side : EnumFacing.values()) { + BlockPos neighbor = pos.offset(side); + Block neighborBlock = mc.world.getBlockState(neighbor).getBlock(); + if (neighborBlock.canCollideCheck(mc.world.getBlockState(neighbor), false)) { + IBlockState blockState = mc.world.getBlockState(neighbor); + if (!blockState.getMaterial().isReplaceable() && (allowSneak || !(sneakList.contains(neighborBlock) || shulkerList.contains(neighborBlock)))) { + facings.add(side); + } + } + } + return facings; + } + + public static EnumFacing getFirstFacing(BlockPos pos) { + return getSidesFacing(pos, false).stream().findFirst().orElse(getSidesFacing(pos, true).stream().findFirst().orElse(null)); + } + + public static void breakBlock(BlockPos pos, boolean rotate) { + if (rotate) { + Vec2f rotations = lookTo(mc.player.getPositionEyes(1), new Vec3d(pos).add(0.5, 0.5, 0.5)); + mc.player.connection.sendPacket(new CPacketPlayer.Rotation(rotations.x, rotations.y, mc.player.onGround)); + } + if(mc.playerController.onPlayerDamageBlock(pos, EnumFacing.DOWN)) { + mc.effectRenderer.addBlockHitEffects(pos, EnumFacing.DOWN); + mc.player.swingArm(EnumHand.MAIN_HAND); + } + } }