diff --git a/src/main/java/dev/cigarette/agent/BedwarsAgent.java b/src/main/java/dev/cigarette/agent/BedwarsAgent.java index 9545c280..b08ff2c4 100644 --- a/src/main/java/dev/cigarette/agent/BedwarsAgent.java +++ b/src/main/java/dev/cigarette/agent/BedwarsAgent.java @@ -126,6 +126,36 @@ public static boolean switchToNextStackOfBlocks(ClientPlayerEntity player) { return false; } + public static boolean switchToNextStackOfBlocks(@NotNull ClientPlayerEntity player, BlockConfig config) { + if (config.selectFirst && isBlock(player.getMainHandStack())) return true; + int bestSlot = 0; + BlockPriority bestBlock = null; + for (int i = 0; i < 9; i++) { + BlockPriority block = BlockPriority.fromStack(player.getInventory().getStack(i)); + if (!block.isBedwarsBlock()) continue; + if (config.selectFirst) { + player.getInventory().setSelectedSlot(i); + return true; + } + if (block == BlockPriority.OBSIDIAN && !config.enableObsidian) continue; + if (block == BlockPriority.ENDSTONE && !config.enableEndstone) continue; + if (block == BlockPriority.WOOD && !config.enableWood) continue; + if (block == BlockPriority.CLAY && !config.enableClay) continue; + if (block == BlockPriority.WOOL && !config.enableWool) continue; + if (block == BlockPriority.GLASS && !config.enableGlass) continue; + + if (bestBlock == null || (block.strongerThan(bestBlock) == config.orderStrongest)) { + bestSlot = i; + bestBlock = block; + } + } + if (bestBlock != null) { + player.getInventory().setSelectedSlot(bestSlot); + return true; + } + return false; + } + @Override public boolean inValidGame() { return GameDetector.rootGame == GameDetector.ParentGame.BEDWARS; @@ -159,4 +189,38 @@ public boolean contains(BlockPos pos) { return this.head.equals(pos) || this.foot.equals(pos); } } + + private enum BlockPriority { + OBSIDIAN(10), ENDSTONE(8), WOOD(6), CLAY(4), WOOL(2), GLASS(1), NONE(0); + + private final int id; + + BlockPriority(int id) { + this.id = id; + } + + public boolean isBedwarsBlock() { + return this != NONE; + } + + public boolean strongerThan(BlockPriority other) { + return this.id > other.id; + } + + public static BlockPriority fromStack(ItemStack item) { + if (item.getItem() instanceof BlockItem blockItem) { + BlockState state = blockItem.getBlock().getDefaultState(); + if (BedwarsAgent.isObsidian(state)) return OBSIDIAN; + if (BedwarsAgent.isEndStone(state)) return ENDSTONE; + if (BedwarsAgent.isWood(state)) return WOOD; + if (BedwarsAgent.isClay(state)) return CLAY; + if (BedwarsAgent.isWool(state)) return WOOL; + if (BedwarsAgent.isGlass(state)) return GLASS; + } + return NONE; + } + } + + public record BlockConfig(boolean enableObsidian, boolean enableEndstone, boolean enableWood, boolean enableClay, boolean enableWool, boolean enableGlass, boolean orderStrongest, boolean selectFirst) { + } } diff --git a/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java b/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java index d1f25523..970e4672 100644 --- a/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java +++ b/src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java @@ -2,21 +2,22 @@ import dev.cigarette.GameDetector; import dev.cigarette.agent.BedwarsAgent; -import dev.cigarette.gui.widget.KeybindWidget; -import dev.cigarette.gui.widget.SliderWidget; -import dev.cigarette.gui.widget.ToggleWidget; +import dev.cigarette.gui.widget.*; import dev.cigarette.helper.KeybindHelper; import dev.cigarette.lib.PlayerEntityL; +import dev.cigarette.lib.Raycast; import dev.cigarette.module.TickModule; import dev.cigarette.precomputed.BlockIn; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.ShapeContext; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; import net.minecraft.item.ItemStack; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; -import net.minecraft.util.math.Vec3i; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,38 +26,67 @@ public class AutoBlockIn extends TickModule { private final KeybindWidget keybind = new KeybindWidget("Keybind", "A key to trigger the block in module."); private final SliderWidget speed = new SliderWidget("Speed", "The higher the speed, the less time spent between adjusting the camera and placing blocks.").withBounds(0, 12, 15); - private final SliderWidget proximityToBeds = new SliderWidget("Max Proximity", "How many blocks close you need to be to any beds for the module to be allowed to activate.").withBounds(1, 5, 9); + private final SliderWidget proximityToBeds = new SliderWidget("Max Proximity", "How many blocks close you need to be to any beds for the module to be allowed to activate. Set to 0 to remove the proximity requirement entirely, allowing you to block-in anywhere.").withBounds(0, 5, 9); private final ToggleWidget switchToBlocks = new ToggleWidget("Switch to Blocks", "Automatically switches to blocks once activated.").withDefaultState(true); private final ToggleWidget switchToTool = new ToggleWidget("Switch to Tools", "Automatically switches to a tool once finished.").withDefaultState(true); private final SliderWidget variation = new SliderWidget("Variation", "Applies randomness to the delay between block places.").withBounds(0, 1, 4); + private final ToggleWidget jumpEnabled = new ToggleWidget("Jump", "Jumps immediately to ensure the block above you is placed.").withDefaultState(true); + private final ToggleWidget tpToCenter = new ToggleWidget("TP to Center", "Risky option that teleports you to the center of the block when activating the module to ensure proper placement.").withDefaultState(false); + + private final TextWidget allowedBlocksText = new TextWidget("Block Config", "Configure which blocks can be used by the module.").centered(false); + private final DropdownWidget allowedBlocks = new DropdownWidget<>("", null); + private final ToggleWidget prioritizeStrongest = new ToggleWidget("Prioritize Strongest", "Prioritizes stronger blocks over weaker ones when placing.\nOrder: Obsidian > Endstone > Wood > Clay > Wool > Glass").withDefaultState(true); + private final ToggleWidget weakNonAdjacent = new ToggleWidget("Weak Non-Adjacent", "Places the weakest blocks on positions not immediately next to or above the player.").withDefaultState(true); + private final ToggleWidget enableObsidian = new ToggleWidget("Use Obsidian", "Allows the module to use obsidian blocks.").withDefaultState(false); + private final ToggleWidget enableEndstone = new ToggleWidget("Use Endstone", "Allows the module to use endstone blocks.").withDefaultState(true); + private final ToggleWidget enableWood = new ToggleWidget("Use Wood", "Allows the module to use wood blocks.").withDefaultState(true); + private final ToggleWidget enableClay = new ToggleWidget("Use Clay", "Allows the module to use clay blocks.").withDefaultState(true); + private final ToggleWidget enableWool = new ToggleWidget("Use Wool", "Allows the module to use wool blocks.").withDefaultState(true); + private final ToggleWidget enableGlass = new ToggleWidget("Use Glass", "Allows the module to use glass blocks.").withDefaultState(false); private boolean running = false; private BlockPos originalPos = null; + private Vec3d originalPosVec = null; private float originalYaw = 0; private float originalPitch = 0; private Vec3d previousVector = null; private int cooldownTicks = 0; + private boolean hasJumped = false; private AutoBlockIn(String id, String name, String tooltip) { super(ToggleWidget::module, id, name, tooltip); - this.setChildren(keybind, speed, proximityToBeds, switchToBlocks, switchToTool, variation); + allowedBlocks.setHeader(allowedBlocksText); + allowedBlocks.setChildren(prioritizeStrongest, weakNonAdjacent, enableObsidian, enableEndstone, enableWood, enableClay, enableWool, enableGlass); + this.setChildren(keybind, allowedBlocks, switchToBlocks, switchToTool, jumpEnabled, tpToCenter, speed, variation, proximityToBeds); keybind.registerConfigKey(id + ".key"); speed.registerConfigKey(id + ".speed"); proximityToBeds.registerConfigKey(id + ".proximity"); switchToBlocks.registerConfigKey(id + ".switchblocks"); switchToTool.registerConfigKey(id + ".switchtool"); variation.registerConfigKey(id + ".variation"); + prioritizeStrongest.registerConfigKey(id + ".prioritizestrongest"); + tpToCenter.registerConfigKey(id + ".tptocenter"); + weakNonAdjacent.registerConfigKey(id + ".weaknonadjacent"); + enableObsidian.registerConfigKey(id + ".allow.obsidian"); + enableEndstone.registerConfigKey(id + ".allow.endstone"); + enableWood.registerConfigKey(id + ".allow.wood"); + enableClay.registerConfigKey(id + ".allow.clay"); + enableWool.registerConfigKey(id + ".allow.wool"); + enableGlass.registerConfigKey(id + ".allow.glass"); } - private void enable(@NotNull ClientPlayerEntity player) { + private void enable(@NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { running = true; + hasJumped = false; originalPos = player.getBlockPos(); + originalPosVec = player.getPos(); originalYaw = player.getYaw(); originalPitch = player.getPitch(); } private void disable(@NotNull ClientPlayerEntity player) { running = false; + hasJumped = false; player.setYaw(originalYaw); player.setPitch(originalPitch); previousVector = null; @@ -75,17 +105,23 @@ private void disableAndSwitch(@NotNull ClientPlayerEntity player) { } } + private boolean blockBlockedByEntity(@NotNull ClientWorld world, @NotNull ClientPlayerEntity player, @NotNull BlockPos pos) { + return !world.getOtherEntities(player, new Box(pos)).isEmpty(); + } + private @Nullable ReachableNeighbor getReachableNeighbor(@NotNull ClientWorld world, @NotNull ClientPlayerEntity player, BlockPos pos) { ReachableNeighbor closest = null; double closestDistance = 0; for (Vec3i offset : BlockIn.BLOCK_NEIGHBORS) { BlockPos neighborPos = pos.add(offset); - if (world.getBlockState(neighborPos).isAir()) continue; + BlockState state = world.getBlockState(neighborPos); + if (state.isAir() || state.isOf(Blocks.WATER) || BedwarsAgent.isBed(state) || state.isOf(Blocks.LADDER)) continue; + Vec3d faceCenter = neighborPos.toCenterPos().subtract(new Vec3d(offset).multiply(0.5f)); Vec3d eye = player.getEyePos(); double distance = faceCenter.distanceTo(eye); - if (distance > 3) continue; + if (distance > 4) continue; Direction face = Direction.fromVector(offset, Direction.UP).getOpposite(); if (face == Direction.UP && eye.getY() <= faceCenter.getY()) continue; @@ -95,60 +131,119 @@ private void disableAndSwitch(@NotNull ClientPlayerEntity player) { if (face == Direction.EAST && eye.getX() <= faceCenter.getX()) continue; if (face == Direction.WEST && eye.getX() >= faceCenter.getX()) continue; + HitResult res = Raycast.raycast(eye, faceCenter, ShapeContext.absent()); + if (res.getType() == BlockHitResult.Type.BLOCK) { + if (!((BlockHitResult) res).getBlockPos().equals(neighborPos)) continue; + } else if (res.getType() == HitResult.Type.ENTITY) { + continue; + } + if (closest == null || distance < closestDistance) { - closest = new ReachableNeighbor(neighborPos, face, faceCenter); + closest = new ReachableNeighbor(neighborPos, face, faceCenter, distance); closestDistance = distance; } } return closest; } - private @Nullable Vec3d getNextBlockPlaceVector(@NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { - if (!player.getBlockPos().equals(originalPos)) return null; + private @Nullable NextVector getNextBlockPlaceVector(@NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { + BlockPos newBlockPos = player.getBlockPos(); + if (newBlockPos.getX() != originalPos.getX() || newBlockPos.getZ() != originalPos.getZ() || Math.abs(newBlockPos.getY() - originalPos.getY()) > 2) return null; + ReachableNeighbor closest = null; + Vec3i closestOffset = null; + ReachableNeighbor jumpNeighbor = null; for (Vec3i offset : BlockIn.PLAYER_NEIGHBORS) { BlockPos pos = originalPos.add(offset); - if (!world.getBlockState(pos).isAir()) continue; + + BlockState state = world.getBlockState(pos); + if (!state.isAir() && !state.isOf(Blocks.WATER)) continue; + if (blockBlockedByEntity(world, player, pos)) continue; ReachableNeighbor neighbor = getReachableNeighbor(world, player, pos); if (neighbor == null) continue; - return neighbor.faceCenter().subtract(player.getEyePos()).normalize(); + if (offset.getX() == 0 && offset.getZ() == 0) { + jumpNeighbor = neighbor; + continue; + } + if (closest == null || neighbor.distance < closest.distance) { + closest = neighbor; + closestOffset = offset; + } + } + if (closest != null) { + return new NextVector(closest.faceCenter().subtract(player.getEyePos()).normalize(), false, BlockIn.isPlayerAdjacent(closestOffset)); + } + if (jumpNeighbor != null) { + return new NextVector(jumpNeighbor.faceCenter().subtract(player.getEyePos()).normalize(), true, true); } return null; } + private boolean switchToNextStackOfBlocks(@NotNull ClientPlayerEntity player) { + return BedwarsAgent.switchToNextStackOfBlocks(player, new BedwarsAgent.BlockConfig(enableObsidian.getRawState(), enableEndstone.getRawState(), enableWood.getRawState(), enableClay.getRawState(), enableWool.getRawState(), enableGlass.getRawState(), prioritizeStrongest.getRawState(), !prioritizeStrongest.getRawState())); + } + + private boolean switchToWeakestBlocks(@NotNull ClientPlayerEntity player) { + return BedwarsAgent.switchToNextStackOfBlocks(player, new BedwarsAgent.BlockConfig(enableObsidian.getRawState(), enableEndstone.getRawState(), enableWood.getRawState(), enableClay.getRawState(), enableWool.getRawState(), enableGlass.getRawState(), false, false)); + } + @Override protected void onEnabledTick(MinecraftClient client, @NotNull ClientWorld world, @NotNull ClientPlayerEntity player) { if (!running) { - if (!keybind.getKeybind().wasPhysicallyPressed()) return; - BlockPos pos = player.getBlockPos(); - for (BedwarsAgent.PersistentBed bed : BedwarsAgent.getVisibleBeds()) { - if (bed.head().isWithinDistance(pos, proximityToBeds.getRawState()) || bed.foot().isWithinDistance(pos, proximityToBeds.getRawState())) { - enable(player); - return; + if (!keybind.getKeybind().isPhysicallyPressed()) return; + double xDecimal = player.getX() - Math.floor(player.getX()); + double zDecimal = player.getZ() - Math.floor(player.getZ()); + if (xDecimal < 0.3 || xDecimal > 0.7 || zDecimal < 0.3 || zDecimal > 0.7) { + if (!tpToCenter.getRawState()) return; + double xCorrection = (xDecimal < 0.3 ? (0.3 + Math.random() * 0.069) : Math.min(xDecimal, 0.7 - Math.random() * 0.069)) - xDecimal; + double zCorrection = (zDecimal < 0.3 ? 0.3 + Math.random() * 0.069 : Math.min(zDecimal, 0.7 - Math.random() * 0.069)) - zDecimal; + player.updatePosition(player.getX() + xCorrection, player.getY(), player.getZ() + zCorrection); + } + + enableChecks: + if (proximityToBeds.getRawState() == 0) { + enable(world, player); + } else { + BlockPos pos = player.getBlockPos(); + for (BedwarsAgent.PersistentBed bed : BedwarsAgent.getVisibleBeds()) { + if (bed.head().isWithinDistance(pos, proximityToBeds.getRawState()) || bed.foot().isWithinDistance(pos, proximityToBeds.getRawState())) { + enable(world, player); + break enableChecks; + } } + return; } - return; } if (--cooldownTicks > 0) return; - if (!BedwarsAgent.isBlock(player.getMainHandStack()) && (!switchToBlocks.getRawState() || !BedwarsAgent.switchToNextStackOfBlocks(player))) { - disable(player); + NextVector next = getNextBlockPlaceVector(world, player); + if (next == null || (previousVector != null && previousVector.equals(next.lookVector))) { + if (jumpEnabled.getRawState() && player.getPos().getY() > originalPosVec.getY()) { + return; + } + disableAndSwitch(player); return; } + previousVector = next.lookVector; - Vec3d nextLookVector = getNextBlockPlaceVector(world, player); - if (nextLookVector == null || (previousVector != null && previousVector.equals(nextLookVector))) { - disableAndSwitch(player); + if (!switchToBlocks.getRawState() || !(next.isAdjacent || !weakNonAdjacent.getRawState() ? switchToNextStackOfBlocks(player) : switchToWeakestBlocks(player))) { + disable(player); return; } - previousVector = nextLookVector; - PlayerEntityL.setRotationVector(player, nextLookVector); + PlayerEntityL.setRotationVector(player, next.lookVector); KeybindHelper.KEY_USE_ITEM.press(); int rand = variation.getRawState().intValue() > 0 ? (int) (Math.random() * variation.getRawState().intValue()) : 0; cooldownTicks = 16 - speed.getRawState().intValue() + rand; + + if (jumpEnabled.getRawState() && !hasJumped && !next.aboveHead) { + if (world.getBlockState(BlockPos.ofFloored(player.getPos().add(0, 2, 0))).isAir()) { + KeybindHelper.KEY_JUMP.holdForTicks(1); + hasJumped = true; + } + } } @Override @@ -156,6 +251,9 @@ public boolean inValidGame() { return GameDetector.rootGame == GameDetector.ParentGame.BEDWARS && GameDetector.subGame == GameDetector.ChildGame.INSTANCED_BEDWARS; } - private record ReachableNeighbor(BlockPos pos, Direction side, Vec3d faceCenter) { + private record ReachableNeighbor(BlockPos pos, Direction side, Vec3d faceCenter, double distance) { + } + + private record NextVector(Vec3d lookVector, boolean aboveHead, boolean isAdjacent) { } } diff --git a/src/main/java/dev/cigarette/precomputed/BlockIn.java b/src/main/java/dev/cigarette/precomputed/BlockIn.java index 2e3503b0..fb0f8a32 100644 --- a/src/main/java/dev/cigarette/precomputed/BlockIn.java +++ b/src/main/java/dev/cigarette/precomputed/BlockIn.java @@ -3,6 +3,14 @@ import net.minecraft.util.math.Vec3i; public class BlockIn { - public static final Vec3i[] PLAYER_NEIGHBORS = new Vec3i[]{new Vec3i(1, 0, 0), new Vec3i(-1, 0, 0), new Vec3i(1, -1, 0), new Vec3i(-1, -1, 0), new Vec3i(0, 0, 1), new Vec3i(0, 0, -1), new Vec3i(0, -1, 1), new Vec3i(0, -1, -1), new Vec3i(1, 1, 0), new Vec3i(-1, 1, 0), new Vec3i(0, 1, 1), new Vec3i(0, 1, -1), new Vec3i(0, 2, 0)}; + public static final Vec3i[] PLAYER_NEIGHBORS = new Vec3i[]{new Vec3i(1, 0, 0), new Vec3i(-1, 0, 0), new Vec3i(1, -1, 0), new Vec3i(-1, -1, 0), new Vec3i(1, -2, 0), new Vec3i(-1, -2, 0), new Vec3i(0, 0, 1), new Vec3i(0, 0, -1), new Vec3i(0, -1, 1), new Vec3i(0, -1, -1), new Vec3i(0, -2, 1), new Vec3i(0, -2, -1), new Vec3i(1, 1, 0), new Vec3i(-1, 1, 0), new Vec3i(0, 1, 1), new Vec3i(0, 1, -1), new Vec3i(1, 2, 0), new Vec3i(-1, 2, 0), new Vec3i(0, 2, 1), new Vec3i(0, 2, -1), new Vec3i(0, 2, 0)}; public static final Vec3i[] BLOCK_NEIGHBORS = new Vec3i[]{new Vec3i(1, 0, 0), new Vec3i(-1, 0, 0), new Vec3i(0, 0, 1), new Vec3i(0, 0, -1), new Vec3i(0, 1, 0), new Vec3i(0, -1, 0)}; + public static final Vec3i[] PLAYER_ADJACENT = new Vec3i[]{new Vec3i(1, 0, 0), new Vec3i(-1, 0, 0), new Vec3i(0, 0, 1), new Vec3i(0, 0, -1), new Vec3i(1, 1, 0), new Vec3i(-1, 1, 0), new Vec3i(0, 1, 1), new Vec3i(0, 1, -1), new Vec3i(0, -1, 0), new Vec3i(0, 2, 0)}; + + public static boolean isPlayerAdjacent(Vec3i offset) { + for (Vec3i adj : PLAYER_ADJACENT) { + if (adj.equals(offset)) return true; + } + return false; + } }