Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
9693c4d
add jumping to place block above head, add toggle for said jumping, a…
UndercoverGoose Nov 24, 2025
c1c5faa
add option to prioritize the strongest block to block in with
UndercoverGoose Nov 25, 2025
6991355
fix: ignore bed prox state does not persist
UndercoverGoose Nov 25, 2025
6b6d524
reorder the options to make more sense
UndercoverGoose Nov 25, 2025
29d4c9e
remove ignore prox toggle in favor of setting the prox slider to 0
UndercoverGoose Nov 25, 2025
4368daf
move block switcher to BedwarsAgent so it can be used elsewhere
UndercoverGoose Nov 25, 2025
e1e1deb
feat: place weak blocks on player non-adjacent positions
UndercoverGoose Nov 25, 2025
17fff13
fix: block-in trys to place on beds and ladders which arent full cubes
UndercoverGoose Nov 25, 2025
01e2040
fix: water interference
UndercoverGoose Nov 25, 2025
770fbc5
fix: entity interference and being able to start the block-in while n…
UndercoverGoose Nov 25, 2025
47c1431
feat: make block-in 0.05 seconds faster
UndercoverGoose Nov 26, 2025
27f3de9
add option to tp to the center of the block so alignment is perfect e…
UndercoverGoose Nov 28, 2025
e94080d
update tp to center to teleport to the closest edge inside the block …
UndercoverGoose Nov 28, 2025
7437662
Merge branch 'main' into fix/bedwars/block-in-jump
UndercoverGoose Nov 28, 2025
3bb3c19
Merge branch 'main' into fix/bedwars/block-in-jump
UndercoverGoose Nov 28, 2025
0f67309
continually run the module until the key is released
UndercoverGoose Nov 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/main/java/dev/cigarette/agent/BedwarsAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
}
}
162 changes: 130 additions & 32 deletions src/main/java/dev/cigarette/module/bedwars/AutoBlockIn.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -25,38 +26,67 @@ public class AutoBlockIn extends TickModule<ToggleWidget, Boolean> {

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<TextWidget, BaseWidget.Stateless> 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;
Expand All @@ -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;
Expand All @@ -95,67 +131,129 @@ 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
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) {
}
}
Loading