From e514f0495776f06205153a664cb28a8a3f989854 Mon Sep 17 00:00:00 2001 From: Old Chum <57156982+Old-Chum@users.noreply.github.com> Date: Thu, 30 Mar 2023 21:19:40 -0700 Subject: [PATCH 1/5] Rewrite Nuker#getClosestBlock(), also adds settings for future packet mode --- .../impl/module/world/NukerModule.java | 201 +++++++++--------- 1 file changed, 106 insertions(+), 95 deletions(-) diff --git a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java index b483bb1..78777e8 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java +++ b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java @@ -16,24 +16,36 @@ import net.minecraft.client.Minecraft; import net.minecraft.init.Blocks; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import team.stiff.pomelo.impl.annotated.handler.annotation.Listener; +import java.util.HashMap; +import java.util.Map; + /** * Author Seth * 6/10/2019 @ 2:31 PM. */ public final class NukerModule extends Module { - public final Value mode = new Value("Mode", new String[]{"Mode", "M"}, "The nuker mode to use.", Mode.SELECTION); + public final Value mode = new Value("Mode", new String[]{"M"}, "The nuker mode to use.", Mode.SELECTION); + public final Value mineMode = new Value("MineMode", new String[]{"MM"}, "The way that nuker mines blocks", MineMode.NORMAL); public final Value distance = new Value("Distance", new String[]{"Dist", "D"}, "Maximum distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value fixed = new Value("FixedDistance", new String[]{"Fixed", "fdist", "F"}, "Use vertical and horizontal distances in blocks instead of distances relative to the camera", false); public final Value vDistance = new Value("VerticalDistance", new String[]{"Vertical", "vdist", "VD"}, "Maximum vertical distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value hDistance = new Value("HorizontalDistance", new String[]{"Horizontal", "hist", "HD"}, "Maximum horizontal distance in blocks the nuker will reach", 3f, 0.0f, 5.0f, 0.1f); + + public final Value timeout = new Value("Timeout", new String[]{"TO, t"}, "How long to wait (in ms) until trying to break a specific block again (PACKET Mode)", 1000, 0, Integer.MAX_VALUE, 1); + public final Value minMineSpeed = new Value("MinMineSpeed", new String[]{"Min", "Speed", "MineSpeed"}, "How fast you should be able to mine a block for nuker to attempt to mine it (0-1, 0 to allow all blocks, 1 to only allow instantly minable blocks)", 0.2f, 0f, 1.0f, 0.1f); + private final RotationTask rotationTask = new RotationTask("NukerTask", 2); + private Block selected = null; private BlockPos currentPos = null; + private Map attemptedBreaks = new HashMap<>(); + public NukerModule() { super("Nuker", new String[]{"Nuke"}, "Automatically mines blocks within reach", "NONE", -1, ModuleType.WORLD); } @@ -63,67 +75,63 @@ public final class NukerModule extends Module { switch (event.getStage()) { case PRE: - this.currentPos = null; + if (this.mineMode.getValue() == MineMode.PACKET) { + // PACKET mode does not need to rotate. The few servers it works on probably don't care about rotation. + // It also tries to break more than one block per event, and I am not sure how to handle that using the + // rotation task. - switch (this.mode.getValue()) { - case SELECTION: - this.currentPos = this.getClosestBlock(true); - break; - case ALL: - this.currentPos = this.getClosestBlock(false); - break; - } + } else { + this.currentPos = this.getClosestBlock(); - if (this.currentPos != null) { - Seppuku.INSTANCE.getRotationManager().startTask(this.rotationTask); - if (this.rotationTask.isOnline()) { - final float[] angle = MathUtil.calcAngle(mc.player.getPositionEyes(mc.getRenderPartialTicks()), new Vec3d(this.currentPos.getX() + 0.5f, this.currentPos.getY() + 0.5f, this.currentPos.getZ() + 0.5f)); - Seppuku.INSTANCE.getRotationManager().setPlayerRotations(angle[0], angle[1]); + if (this.currentPos != null) { + Seppuku.INSTANCE.getRotationManager().startTask(this.rotationTask); + if (this.rotationTask.isOnline()) { + final float[] angle = MathUtil.calcAngle(mc.player.getPositionEyes(mc.getRenderPartialTicks()), new Vec3d(this.currentPos.getX() + 0.5f, this.currentPos.getY() + 0.5f, this.currentPos.getZ() + 0.5f)); + Seppuku.INSTANCE.getRotationManager().setPlayerRotations(angle[0], angle[1]); + } } } + break; case POST: if (this.mode.getValue().equals(Mode.CREATIVE)) { if (mc.player.capabilities.isCreativeMode) { /* the amazing creative 'nuker' straight from the latch hacked client */ - for (double y = Math.round(mc.player.posY - 1) + this.vDistance.getValue(); y > Math.round(mc.player.posY - 1); y -= 1.0D) { - for (double x = mc.player.posX - this.hDistance.getValue(); x < mc.player.posX + this.hDistance.getValue(); x += 1.0D) { - for (double z = mc.player.posZ - this.hDistance.getValue(); z < mc.player.posZ + this.hDistance.getValue(); z += 1.0D) { - final BlockPos blockPos = new BlockPos(x, y, z); - final Block block = BlockUtil.getBlock(blockPos); - if (block == Blocks.AIR || !mc.world.getBlockState(blockPos).isFullBlock()) - continue; + // TODO: Test moving to the iterable didn't break this + Iterable itr = getBoxIterable(); + for (BlockPos blockPos : itr) { + final Block block = BlockUtil.getBlock(blockPos); + if (block == Blocks.AIR || !mc.world.getBlockState(blockPos).isFullBlock()) + continue; - final Vec3d eyesPos = new Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight(), mc.player.posZ); - final Vec3d posVec = new Vec3d(blockPos).add(0.5f, 0.5f, 0.5f); - double distanceSqPosVec = eyesPos.squareDistanceTo(posVec); + final Vec3d eyesPos = new Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight(), mc.player.posZ); + final Vec3d posVec = new Vec3d(blockPos).add(0.5f, 0.5f, 0.5f); + double distanceSqPosVec = eyesPos.squareDistanceTo(posVec); - for (EnumFacing side : EnumFacing.values()) { - final Vec3d hitVec = posVec.add(new Vec3d(side.getDirectionVec()).scale(0.5f)); - double distanceSqHitVec = eyesPos.squareDistanceTo(hitVec); + for (EnumFacing side : EnumFacing.values()) { + final Vec3d hitVec = posVec.add(new Vec3d(side.getDirectionVec()).scale(0.5f)); + double distanceSqHitVec = eyesPos.squareDistanceTo(hitVec); - // check if hitVec is within range (6 blocks) - if (distanceSqHitVec > 36) - continue; + // check if hitVec is within range (6 blocks) + if (distanceSqHitVec > 36) + continue; - // check if side is facing towards player - if (distanceSqHitVec >= distanceSqPosVec) - continue; + // check if side is facing towards player + if (distanceSqHitVec >= distanceSqPosVec) + continue; - // face block - final float[] rotations = EntityUtil.getRotations(hitVec.x, hitVec.y, hitVec.z); - Seppuku.INSTANCE.getRotationManager().setPlayerRotations(rotations[0], rotations[1]); + // face block + final float[] rotations = EntityUtil.getRotations(hitVec.x, hitVec.y, hitVec.z); + Seppuku.INSTANCE.getRotationManager().setPlayerRotations(rotations[0], rotations[1]); - // damage block - if (mc.playerController.onPlayerDamageBlock(blockPos, side)) { - mc.player.swingArm(EnumHand.MAIN_HAND); - } - } + // damage block + if (mc.playerController.onPlayerDamageBlock(blockPos, side)) { + mc.player.swingArm(EnumHand.MAIN_HAND); } } } } - } else { + } else if (this.mineMode.getValue() != MineMode.PACKET) { if (this.currentPos != null) { if (this.rotationTask.isOnline()) { if (SpeedMineModule.autoPos != null) { @@ -160,74 +168,77 @@ public final class NukerModule extends Module { private boolean canBreak(BlockPos pos) { final IBlockState blockState = Minecraft.getMinecraft().world.getBlockState(pos); final Block block = blockState.getBlock(); - return block.getBlockHardness(blockState, Minecraft.getMinecraft().world, pos) != -1; + return block.getBlockHardness(blockState, Minecraft.getMinecraft().world, pos) >= minMineSpeed.getValue(); } - private BlockPos getClosestBlock(boolean selection) { + private boolean shouldBreak(BlockPos pos) { final Minecraft mc = Minecraft.getMinecraft(); - BlockPos ret = null; + // TODO: Might want to double check that the block is within the distance value (getAllInBox is generous) + + // TODO: Replace SELECTION with a filter? + if (this.mode.getValue() == Mode.SELECTION) { + if (this.selected != null && !mc.world.getBlockState(pos).getBlock().equals(this.selected)) { + return false; + } + } + + return mc.world.getBlockState(pos).getBlock() != Blocks.AIR && + !(mc.world.getBlockState(pos).getBlock() instanceof BlockLiquid) && + this.canBreak(pos) && + !pos.equals(SpeedMineModule.autoPos); + } + + private Iterable getBoxIterable () { + final Minecraft mc = Minecraft.getMinecraft(); + AxisAlignedBB bb; if (this.fixed.getValue()) { - float maxVDist = this.vDistance.getValue(); - float maxHDist = this.hDistance.getValue(); - for (float x = 0; x <= maxHDist; x++) { - for (float y = 0; y <= maxVDist; y++) { - for (float z = 0; z <= maxHDist; z++) { - for (int revX = 0; revX <= 1; revX++, x = -x) { - for (int revZ = 0; revZ <= 1; revZ++, z = -z) { - final BlockPos pos = new BlockPos(mc.player.posX + x, mc.player.posY + y, mc.player.posZ + z); - if (pos.equals(SpeedMineModule.autoPos)) { - continue; - } - if ((mc.world.getBlockState(pos).getBlock() != Blocks.AIR && - !(mc.world.getBlockState(pos).getBlock() instanceof BlockLiquid)) && - this.canBreak(pos)) { - if (selection) { - if ((this.selected == null) || !mc.world.getBlockState(pos).getBlock().equals(this.selected)) { - continue; - } - } - - ret = pos; - } - } - } - } - } - } + bb = new AxisAlignedBB( + (int) mc.player.posX - hDistance.getValue(), + (int) mc.player.posY - vDistance.getValue(), + (int) mc.player.posZ - hDistance.getValue(), + (int) mc.player.posX + hDistance.getValue(), + (int) mc.player.posY + vDistance.getValue(), + (int) mc.player.posZ + hDistance.getValue()); } else { - float maxDist = this.distance.getValue(); - for (float x = maxDist; x >= -maxDist; x--) { - for (float y = maxDist; y >= -maxDist; y--) { - for (float z = maxDist; z >= -maxDist; z--) { - final BlockPos pos = new BlockPos(mc.player.posX + x, mc.player.posY + y, mc.player.posZ + z); - final double dist = mc.player.getDistance(pos.getX(), pos.getY(), pos.getZ()); - if (pos.equals(SpeedMineModule.autoPos)) { - continue; - } - if (dist <= maxDist && (mc.world.getBlockState(pos).getBlock() != Blocks.AIR && !(mc.world.getBlockState(pos).getBlock() instanceof BlockLiquid)) && canBreak(pos)) { - if (selection) { - if ((this.selected == null) || !mc.world.getBlockState(pos).getBlock().equals(this.selected)) { - continue; - } - } + bb = new AxisAlignedBB( + (int) mc.player.posX - distance.getValue(), + (int) mc.player.posY - distance.getValue(), + (int) mc.player.posZ - distance.getValue(), + (int) mc.player.posX + distance.getValue(), + (int) mc.player.posY + distance.getValue(), + (int) mc.player.posZ + distance.getValue()); + } - if (pos.getY() < mc.player.posY) - continue; + return BlockPos.getAllInBox((int) bb.minX, (int) bb.minY, (int) bb.minZ, (int) bb.maxX, (int) bb.maxY, (int) bb.maxZ); + } - maxDist = (float) dist; - ret = pos; - } - } + private BlockPos getClosestBlock() { + final Minecraft mc = Minecraft.getMinecraft(); + Iterable itr = getBoxIterable(); + + BlockPos closest = null; + double closestDist = Double.POSITIVE_INFINITY; + for (BlockPos pos : itr) { + double dist = pos.distanceSqToCenter(mc.player.posX, mc.player.getEyeHeight(), mc.player.posZ); + + if (shouldBreak(pos)) { + if (dist < closestDist) { + closestDist = dist; + closest = pos; } } } - return ret; + + return closest; } private enum Mode { SELECTION, ALL, CREATIVE } + private enum MineMode { + NORMAL, PACKET + } } From bf8d91e2346f48f9bbb1508976942a41da9194d0 Mon Sep 17 00:00:00 2001 From: Old Chum <57156982+Old-Chum@users.noreply.github.com> Date: Thu, 30 Mar 2023 21:56:52 -0700 Subject: [PATCH 2/5] Added nuker PACKET mode functionality --- .../impl/module/world/NukerModule.java | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java index 78777e8..8ff8195 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java +++ b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java @@ -13,7 +13,9 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.block.state.IBlockState; import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.init.Blocks; +import net.minecraft.network.play.client.CPacketPlayerDigging; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.math.AxisAlignedBB; @@ -21,8 +23,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import team.stiff.pomelo.impl.annotated.handler.annotation.Listener; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * Author Seth @@ -30,7 +31,7 @@ import java.util.Map; */ public final class NukerModule extends Module { - public final Value mode = new Value("Mode", new String[]{"M"}, "The nuker mode to use.", Mode.SELECTION); + public final Value mode = new Value("Mode", new String[]{"M"}, "The nuker mode to use", Mode.SELECTION); public final Value mineMode = new Value("MineMode", new String[]{"MM"}, "The way that nuker mines blocks", MineMode.NORMAL); public final Value distance = new Value("Distance", new String[]{"Dist", "D"}, "Maximum distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value fixed = new Value("FixedDistance", new String[]{"Fixed", "fdist", "F"}, "Use vertical and horizontal distances in blocks instead of distances relative to the camera", false); @@ -79,7 +80,31 @@ public final class NukerModule extends Module { // PACKET mode does not need to rotate. The few servers it works on probably don't care about rotation. // It also tries to break more than one block per event, and I am not sure how to handle that using the // rotation task. + List blocks = getSortedBlocks(); + for (BlockPos pos : blocks) { + IBlockState state = mc.world.getBlockState(pos); + + if (shouldBreak(pos)) { + if (!this.attemptedBreaks.containsKey(pos)) { + mc.player.connection.sendPacket(new CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, pos, EnumFacing.NORTH)); + mc.player.connection.sendPacket(new CPacketPlayerDigging(CPacketPlayerDigging.Action.STOP_DESTROY_BLOCK, pos, EnumFacing.NORTH)); + + this.attemptedBreaks.put(pos, System.currentTimeMillis()); + } + } + } + + List toRemove = new ArrayList<>(); + for (BlockPos pos : attemptedBreaks.keySet()) { + if (System.currentTimeMillis() - attemptedBreaks.get(pos) >= timeout.getValue()) { + toRemove.add(pos); + } + } + + for (BlockPos pos : toRemove) { + attemptedBreaks.remove(pos); + } } else { this.currentPos = this.getClosestBlock(); @@ -98,8 +123,7 @@ public final class NukerModule extends Module { if (mc.player.capabilities.isCreativeMode) { /* the amazing creative 'nuker' straight from the latch hacked client */ // TODO: Test moving to the iterable didn't break this - Iterable itr = getBoxIterable(); - for (BlockPos blockPos : itr) { + for (BlockPos blockPos : getBoxIterable()) { final Block block = BlockUtil.getBlock(blockPos); if (block == Blocks.AIR || !mc.world.getBlockState(blockPos).isFullBlock()) continue; @@ -216,11 +240,10 @@ public final class NukerModule extends Module { private BlockPos getClosestBlock() { final Minecraft mc = Minecraft.getMinecraft(); - Iterable itr = getBoxIterable(); BlockPos closest = null; double closestDist = Double.POSITIVE_INFINITY; - for (BlockPos pos : itr) { + for (BlockPos pos : getBoxIterable()) { double dist = pos.distanceSqToCenter(mc.player.posX, mc.player.getEyeHeight(), mc.player.posZ); if (shouldBreak(pos)) { @@ -234,6 +257,24 @@ public final class NukerModule extends Module { return closest; } + /* + * Not very good performance wise. A better way to do this would be to directly iterate from the player's head, + * but that is difficult, and we don't expect SUPER huge input for this. At most the player would probably have a + * cube of 'radius' 6, +1 if the bounding box is aligned right, so we would have around 13^3 = 2197 blocks to + * iterate and sort. + */ + private List getSortedBlocks() { + EntityPlayerSP player = Minecraft.getMinecraft().player; + List ret = new ArrayList<>(); + + for (BlockPos pos : getBoxIterable()) { + ret.add(new BlockPos(pos)); + } + + ret.sort(Comparator.comparingDouble(o -> o.distanceSqToCenter(player.posX, player.posY, player.posZ))); + return ret; + } + private enum Mode { SELECTION, ALL, CREATIVE } From 859a6733d6605f15b25f440934e6ea5668a72dba Mon Sep 17 00:00:00 2001 From: Old Chum <57156982+Old-Chum@users.noreply.github.com> Date: Thu, 30 Mar 2023 22:01:16 -0700 Subject: [PATCH 3/5] Added flatten option to nuker --- .../me/rigamortis/seppuku/impl/module/world/NukerModule.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java index 8ff8195..e01fdce 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java +++ b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java @@ -35,6 +35,7 @@ public final class NukerModule extends Module { public final Value mineMode = new Value("MineMode", new String[]{"MM"}, "The way that nuker mines blocks", MineMode.NORMAL); public final Value distance = new Value("Distance", new String[]{"Dist", "D"}, "Maximum distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value fixed = new Value("FixedDistance", new String[]{"Fixed", "fdist", "F"}, "Use vertical and horizontal distances in blocks instead of distances relative to the camera", false); + public final Value flatten = new Value("Flatten", new String[]{"flat"}, "Ensures nuker does not mine blocks below your feet", false); public final Value vDistance = new Value("VerticalDistance", new String[]{"Vertical", "vdist", "VD"}, "Maximum vertical distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value hDistance = new Value("HorizontalDistance", new String[]{"Horizontal", "hist", "HD"}, "Maximum horizontal distance in blocks the nuker will reach", 3f, 0.0f, 5.0f, 0.1f); @@ -220,7 +221,7 @@ public final class NukerModule extends Module { if (this.fixed.getValue()) { bb = new AxisAlignedBB( (int) mc.player.posX - hDistance.getValue(), - (int) mc.player.posY - vDistance.getValue(), + (int) (this.flatten.getValue() ? mc.player.posY : mc.player.posY - vDistance.getValue()), (int) mc.player.posZ - hDistance.getValue(), (int) mc.player.posX + hDistance.getValue(), (int) mc.player.posY + vDistance.getValue(), @@ -228,7 +229,7 @@ public final class NukerModule extends Module { } else { bb = new AxisAlignedBB( (int) mc.player.posX - distance.getValue(), - (int) mc.player.posY - distance.getValue(), + (int) (this.flatten.getValue() ? mc.player.posY : mc.player.posY - vDistance.getValue()), (int) mc.player.posZ - distance.getValue(), (int) mc.player.posX + distance.getValue(), (int) mc.player.posY + distance.getValue(), From dfbd97ef9d2d7e74ceba3baad2aea3a0e035e80d Mon Sep 17 00:00:00 2001 From: Old Chum <57156982+Old-Chum@users.noreply.github.com> Date: Thu, 30 Mar 2023 22:56:32 -0700 Subject: [PATCH 4/5] Replaced Nuker's SELECTION mode with a block filter --- .../impl/command/NukerFilterCommand.java | 169 ++++++++++++++++++ .../impl/config/NukerFilterConfig.java | 64 +++++++ .../impl/management/CommandManager.java | 1 + .../impl/management/ConfigManager.java | 1 + .../impl/module/world/NukerModule.java | 116 +++++++----- 5 files changed, 308 insertions(+), 43 deletions(-) create mode 100644 src/main/java/me/rigamortis/seppuku/impl/command/NukerFilterCommand.java create mode 100644 src/main/java/me/rigamortis/seppuku/impl/config/NukerFilterConfig.java diff --git a/src/main/java/me/rigamortis/seppuku/impl/command/NukerFilterCommand.java b/src/main/java/me/rigamortis/seppuku/impl/command/NukerFilterCommand.java new file mode 100644 index 0000000..301fc30 --- /dev/null +++ b/src/main/java/me/rigamortis/seppuku/impl/command/NukerFilterCommand.java @@ -0,0 +1,169 @@ +package me.rigamortis.seppuku.impl.command; + +import me.rigamortis.seppuku.Seppuku; +import me.rigamortis.seppuku.api.command.Command; +import me.rigamortis.seppuku.api.util.StringUtil; +import me.rigamortis.seppuku.impl.config.NukerFilterConfig; +import me.rigamortis.seppuku.impl.module.world.NukerModule; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.util.text.Style; +import net.minecraft.util.text.TextComponentString; +import net.minecraft.util.text.event.HoverEvent; + +/** + * @author Old Chum + * @since 3/30/2023 + */ +public class NukerFilterCommand extends Command { + + private final String[] addAlias = new String[]{"Add", "A"}; + private final String[] removeAlias = new String[]{"Remove", "Rem", "R", "Delete", "Del", "D"}; + private final String[] listAlias = new String[]{"List", "Lst"}; + private final String[] clearAlias = new String[]{"Clear", "C"}; + + public NukerFilterCommand() { + super("NukerFilter", new String[]{"NukerF", "FilterN"}, "Allows you to change what blocks nuker mines", + "NukerFilter Add \n" + + "NukerFilter Add \n" + + "NukerFilter Remove \n" + + "NukerFilter Remove \n" + + "NukerFilter List\n" + + "NukerFilter Clear"); + } + + @Override + public void exec(String input) { + if (!this.clamp(input, 2, 3)) { + this.printUsage(); + return; + } + + final String[] split = input.split(" "); + + final NukerModule nuker = (NukerModule) Seppuku.INSTANCE.getModuleManager().find(NukerModule.class); + + if (nuker != null) { + if (equals(addAlias, split[1])) { + if (!this.clamp(input, 3, 3)) { + this.printUsage(); + return; + } + + if (StringUtil.isInt(split[2])) { + final int id = Integer.parseInt(split[2]); + + if (id > 0) { + final Block block = Block.getBlockById(id); + + if (nuker.contains(block)) { + Seppuku.INSTANCE.logChat("Nuker already contains " + block.getLocalizedName()); + } else { + nuker.add(Block.getIdFromBlock(block)); + + Seppuku.INSTANCE.getConfigManager().save(NukerFilterConfig.class); + Seppuku.INSTANCE.logChat("Added " + block.getLocalizedName() + " to nuker"); + } + } else { + Seppuku.INSTANCE.errorChat("Cannot add Air to nuker"); + } + } else { + final Block block = Block.getBlockFromName(split[2].toLowerCase()); + + if (block != null) { + if (block == Blocks.AIR) { + Seppuku.INSTANCE.errorChat("Cannot add Air to nuker"); + } else { + if (nuker.contains(block)) { + Seppuku.INSTANCE.logChat("Nuker already contains " + block.getLocalizedName()); + } else { + nuker.add(Block.getIdFromBlock(block)); + + Seppuku.INSTANCE.getConfigManager().save(NukerFilterConfig.class); + Seppuku.INSTANCE.logChat("Added " + block.getLocalizedName() + " to nuker"); + } + } + } else { + Seppuku.INSTANCE.logChat("\247c" + split[2] + "\247f is not a valid block"); + } + } + } else if (equals(removeAlias, split[1])) { + if (!this.clamp(input, 3, 3)) { + this.printUsage(); + return; + } + + if (StringUtil.isInt(split[2])) { + final int id = Integer.parseInt(split[2]); + + if (id > 0) { + final Block block = Block.getBlockById(id); + + if (nuker.contains(block)) { + nuker.remove(Block.getIdFromBlock(block)); + + Seppuku.INSTANCE.getConfigManager().save(NukerFilterConfig.class); + Seppuku.INSTANCE.logChat("Removed " + block.getLocalizedName() + " from nuker"); + } else { + Seppuku.INSTANCE.logChat("Nuker doesn't contain " + block.getLocalizedName()); + } + } else { + Seppuku.INSTANCE.errorChat("Cannot remove Air from nuker"); + } + } else { + final Block block = Block.getBlockFromName(split[2].toLowerCase()); + + if (block != null) { + if (block == Blocks.AIR) { + Seppuku.INSTANCE.errorChat("Cannot remove Air from nuker"); + } else { + if (nuker.contains(block)) { + nuker.remove(Block.getIdFromBlock(block)); + + Seppuku.INSTANCE.getConfigManager().save(NukerFilterConfig.class); + Seppuku.INSTANCE.logChat("Removed " + block.getLocalizedName() + " from nuker"); + } else { + Seppuku.INSTANCE.logChat("Nuker doesn't contain " + block.getLocalizedName()); + } + } + } else { + Seppuku.INSTANCE.logChat("\247c" + split[2] + "\247f is not a valid block"); + } + } + } else if (equals(listAlias, split[1])) { + if (!this.clamp(input, 2, 2)) { + this.printUsage(); + return; + } + + if (nuker.getFilter().getValue().size() > 0) { + final TextComponentString msg = new TextComponentString("\2477Nuker IDs: "); + + for (Block block : nuker.getFilter().getValue()) { + msg.appendSibling(new TextComponentString("\2477[\247a" + Block.getIdFromBlock(block) + "\2477] ") + .setStyle(new Style() + .setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(block.getLocalizedName()))))); + } + + Seppuku.INSTANCE.logcChat(msg); + } else { + Seppuku.INSTANCE.logChat("You don't have any nuker ids"); + } + } else if (equals(clearAlias, split[1])) { + if (!this.clamp(input, 2, 2)) { + this.printUsage(); + return; + } + nuker.clear(); + + Seppuku.INSTANCE.getConfigManager().save(NukerFilterConfig.class); + Seppuku.INSTANCE.logChat("Cleared all blocks from nuker"); + } else { + Seppuku.INSTANCE.errorChat("Unknown input " + "\247f\"" + input + "\""); + this.printUsage(); + } + } else { + Seppuku.INSTANCE.errorChat("Nuker not present"); + } + } +} diff --git a/src/main/java/me/rigamortis/seppuku/impl/config/NukerFilterConfig.java b/src/main/java/me/rigamortis/seppuku/impl/config/NukerFilterConfig.java new file mode 100644 index 0000000..76a1944 --- /dev/null +++ b/src/main/java/me/rigamortis/seppuku/impl/config/NukerFilterConfig.java @@ -0,0 +1,64 @@ +package me.rigamortis.seppuku.impl.config; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import me.rigamortis.seppuku.Seppuku; +import me.rigamortis.seppuku.api.config.Configurable; +import me.rigamortis.seppuku.api.util.FileUtil; +import me.rigamortis.seppuku.impl.module.world.NukerModule; +import net.minecraft.block.Block; + +import java.io.File; + +/** + * @author Old Chum + * @since 3/30/2023 + */ +public class NukerFilterConfig extends Configurable { + private final NukerModule nukerModule; + + public NukerFilterConfig(File dir) { + super(FileUtil.createJsonFile(dir, "NukerFilter")); + this.nukerModule = (NukerModule) Seppuku.INSTANCE.getModuleManager().find("Nuker"); + } + + @Override + public void onLoad() { + super.onLoad(); + + if (this.nukerModule == null) + return; + + JsonArray xrayIdsJsonArray = null; + + final JsonElement blockIds = this.getJsonObject().get("NukerFilterIds"); + if (blockIds != null) + xrayIdsJsonArray = blockIds.getAsJsonArray(); + + final NukerModule nukerModule = (NukerModule) Seppuku.INSTANCE.getModuleManager().find("Nuker"); + if (nukerModule != null) { + if (xrayIdsJsonArray != null) { + for (JsonElement jsonElement : xrayIdsJsonArray) { + nukerModule.add(jsonElement.getAsInt()); + } + } + } + } + + @Override + public void onSave() { + if (this.nukerModule == null) + return; + + JsonObject save = new JsonObject(); + + JsonArray xrayIdsJsonArray = new JsonArray(); + for (Block block : this.nukerModule.getFilter().getValue()) + xrayIdsJsonArray.add(Block.getIdFromBlock(block)); + + save.add("NukerFilterIds", xrayIdsJsonArray); + + this.saveJsonObjectToFile(save); + } +} diff --git a/src/main/java/me/rigamortis/seppuku/impl/management/CommandManager.java b/src/main/java/me/rigamortis/seppuku/impl/management/CommandManager.java index 16ea61c..dc0b267 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/management/CommandManager.java +++ b/src/main/java/me/rigamortis/seppuku/impl/management/CommandManager.java @@ -76,6 +76,7 @@ public final class CommandManager { this.commandList.add(new LocateFeatureCommand()); this.commandList.add(new MainMenuCommand()); this.commandList.add(new ConfigCommand()); + this.commandList.add(new NukerFilterCommand()); //create commands for every value within every module loadValueCommands(); diff --git a/src/main/java/me/rigamortis/seppuku/impl/management/ConfigManager.java b/src/main/java/me/rigamortis/seppuku/impl/management/ConfigManager.java index f240fa4..cd23fe2 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/management/ConfigManager.java +++ b/src/main/java/me/rigamortis/seppuku/impl/management/ConfigManager.java @@ -100,6 +100,7 @@ public final class ConfigManager { this.configurableList.add(new IgnoreConfig(configDir)); this.configurableList.add(new AutoIgnoreConfig(configDir)); this.configurableList.add(new AltConfig(configDir)); + this.configurableList.add(new NukerFilterConfig(configDir)); if (this.firstLaunch) { this.saveAll(); diff --git a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java index e01fdce..0c0918f 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java +++ b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java @@ -1,11 +1,9 @@ package me.rigamortis.seppuku.impl.module.world; import me.rigamortis.seppuku.Seppuku; -import me.rigamortis.seppuku.api.event.player.EventRightClickBlock; import me.rigamortis.seppuku.api.event.player.EventUpdateWalkingPlayer; import me.rigamortis.seppuku.api.module.Module; import me.rigamortis.seppuku.api.task.rotation.RotationTask; -import me.rigamortis.seppuku.api.util.BlockUtil; import me.rigamortis.seppuku.api.util.EntityUtil; import me.rigamortis.seppuku.api.util.MathUtil; import me.rigamortis.seppuku.api.value.Value; @@ -31,22 +29,23 @@ import java.util.*; */ public final class NukerModule extends Module { - public final Value mode = new Value("Mode", new String[]{"M"}, "The nuker mode to use", Mode.SELECTION); - public final Value mineMode = new Value("MineMode", new String[]{"MM"}, "The way that nuker mines blocks", MineMode.NORMAL); + public final Value mode = new Value("Mode", new String[]{"M"}, "The way that nuker mines blocks", Mode.NORMAL); public final Value distance = new Value("Distance", new String[]{"Dist", "D"}, "Maximum distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value fixed = new Value("FixedDistance", new String[]{"Fixed", "fdist", "F"}, "Use vertical and horizontal distances in blocks instead of distances relative to the camera", false); public final Value flatten = new Value("Flatten", new String[]{"flat"}, "Ensures nuker does not mine blocks below your feet", false); public final Value vDistance = new Value("VerticalDistance", new String[]{"Vertical", "vdist", "VD"}, "Maximum vertical distance in blocks the nuker will reach", 4.5f, 0.0f, 5.0f, 0.1f); public final Value hDistance = new Value("HorizontalDistance", new String[]{"Horizontal", "hist", "HD"}, "Maximum horizontal distance in blocks the nuker will reach", 3f, 0.0f, 5.0f, 0.1f); - public final Value timeout = new Value("Timeout", new String[]{"TO, t"}, "How long to wait (in ms) until trying to break a specific block again (PACKET Mode)", 1000, 0, Integer.MAX_VALUE, 1); + public final Value timeout = new Value("Timeout", new String[]{"TO, t"}, "How long to wait (in ms) until trying to break a specific block again (PACKET Mode)", 1000, 0, 5000, 10); public final Value minMineSpeed = new Value("MinMineSpeed", new String[]{"Min", "Speed", "MineSpeed"}, "How fast you should be able to mine a block for nuker to attempt to mine it (0-1, 0 to allow all blocks, 1 to only allow instantly minable blocks)", 0.2f, 0f, 1.0f, 0.1f); + public final Value filterMode = new Value("FilterMode", new String[]{"fm", "fmode"}, "Controls how blocks should be checked against the filter", FilterMode.WHITE); + public final Value> filter = new Value>("Filter", new String[]{}, "Controls what block id's nuker will mine"); + private final RotationTask rotationTask = new RotationTask("NukerTask", 2); - private Block selected = null; private BlockPos currentPos = null; - private Map attemptedBreaks = new HashMap<>(); + private final Map attemptedBreaks = new HashMap<>(); public NukerModule() { super("Nuker", new String[]{"Nuke"}, "Automatically mines blocks within reach", "NONE", -1, ModuleType.WORLD); @@ -55,7 +54,7 @@ public final class NukerModule extends Module { @Override public void onToggle() { super.onToggle(); - this.selected = null; + this.filter.setValue(new ArrayList<>()); } @Override @@ -77,15 +76,13 @@ public final class NukerModule extends Module { switch (event.getStage()) { case PRE: - if (this.mineMode.getValue() == MineMode.PACKET) { + if (this.mode.getValue() == Mode.PACKET) { // PACKET mode does not need to rotate. The few servers it works on probably don't care about rotation. // It also tries to break more than one block per event, and I am not sure how to handle that using the // rotation task. List blocks = getSortedBlocks(); for (BlockPos pos : blocks) { - IBlockState state = mc.world.getBlockState(pos); - if (shouldBreak(pos)) { if (!this.attemptedBreaks.containsKey(pos)) { mc.player.connection.sendPacket(new CPacketPlayerDigging(CPacketPlayerDigging.Action.START_DESTROY_BLOCK, pos, EnumFacing.NORTH)); @@ -120,13 +117,11 @@ public final class NukerModule extends Module { break; case POST: - if (this.mode.getValue().equals(Mode.CREATIVE)) { + if (this.mode.getValue() == Mode.CREATIVE) { if (mc.player.capabilities.isCreativeMode) { /* the amazing creative 'nuker' straight from the latch hacked client */ - // TODO: Test moving to the iterable didn't break this for (BlockPos blockPos : getBoxIterable()) { - final Block block = BlockUtil.getBlock(blockPos); - if (block == Blocks.AIR || !mc.world.getBlockState(blockPos).isFullBlock()) + if (!shouldBreak(blockPos) || !mc.world.getBlockState(blockPos).isFullBlock()) continue; final Vec3d eyesPos = new Vec3d(mc.player.posX, mc.player.posY + mc.player.getEyeHeight(), mc.player.posZ); @@ -156,7 +151,7 @@ public final class NukerModule extends Module { } } } - } else if (this.mineMode.getValue() != MineMode.PACKET) { + } else if (this.mode.getValue() == Mode.NORMAL) { if (this.currentPos != null) { if (this.rotationTask.isOnline()) { if (SpeedMineModule.autoPos != null) { @@ -178,18 +173,6 @@ public final class NukerModule extends Module { } } - @Listener - public void clickBlock(EventRightClickBlock event) { - if (this.mode.getValue() == Mode.SELECTION) { - final Block block = Minecraft.getMinecraft().world.getBlockState(event.getPos()).getBlock(); - if (block != this.selected) { - this.selected = block; - Seppuku.INSTANCE.logChat("Nuker block set to " + block.getLocalizedName()); - event.setCanceled(true); - } - } - } - private boolean canBreak(BlockPos pos) { final IBlockState blockState = Minecraft.getMinecraft().world.getBlockState(pos); final Block block = blockState.getBlock(); @@ -199,19 +182,17 @@ public final class NukerModule extends Module { private boolean shouldBreak(BlockPos pos) { final Minecraft mc = Minecraft.getMinecraft(); - // TODO: Might want to double check that the block is within the distance value (getAllInBox is generous) - - // TODO: Replace SELECTION with a filter? - if (this.mode.getValue() == Mode.SELECTION) { - if (this.selected != null && !mc.world.getBlockState(pos).getBlock().equals(this.selected)) { - return false; - } + boolean isFiltered = false; + if (this.filterMode.getValue() != FilterMode.DISABLED) { + // Did a truth table for this and this just so happens to be a XOR + isFiltered = this.filter.getValue().contains(mc.world.getBlockState(pos).getBlock()) ^ this.filterMode.getValue() == FilterMode.WHITE; } - return mc.world.getBlockState(pos).getBlock() != Blocks.AIR && - !(mc.world.getBlockState(pos).getBlock() instanceof BlockLiquid) && - this.canBreak(pos) && - !pos.equals(SpeedMineModule.autoPos); + return mc.world.getBlockState(pos).getBlock() != Blocks.AIR + && !(mc.world.getBlockState(pos).getBlock() instanceof BlockLiquid) + && this.canBreak(pos) + && !pos.equals(SpeedMineModule.autoPos) + && !isFiltered; } private Iterable getBoxIterable () { @@ -276,11 +257,60 @@ public final class NukerModule extends Module { return ret; } - private enum Mode { - SELECTION, ALL, CREATIVE + public Value> getFilter() { + return filter; } - private enum MineMode { - NORMAL, PACKET + public boolean contains(Block block) { + return this.filter.getValue().contains(block); + } + + public void add(int id) { + final Block blockFromID = Block.getBlockById(id); + if (!contains(blockFromID)) { + this.filter.getValue().add(blockFromID); + } + } + + public void add(String name) { + final Block blockFromName = Block.getBlockFromName(name); + if (blockFromName != null) { + if (!contains(blockFromName)) { + this.filter.getValue().add(blockFromName); + } + } + } + + public void remove(int id) { + for (Block block : this.filter.getValue()) { + final int blockID = Block.getIdFromBlock(block); + if (blockID == id) { + this.filter.getValue().remove(block); + break; + } + } + } + + public void remove(String name) { + final Block blockFromName = Block.getBlockFromName(name); + if (blockFromName != null) { + if (contains(blockFromName)) { + this.filter.getValue().remove(blockFromName); + } + } + } + + public int clear() { + final int count = this.filter.getValue().size(); + this.filter.getValue().clear(); + return count; + } + + private enum Mode { + NORMAL, PACKET, CREATIVE + } + + private enum FilterMode { + WHITE, BLACK, DISABLED } } From 773b9e3201c73382fa92001e5fbf992d115f26ee Mon Sep 17 00:00:00 2001 From: Old Chum <57156982+Old-Chum@users.noreply.github.com> Date: Thu, 30 Mar 2023 23:00:52 -0700 Subject: [PATCH 5/5] Documented bug --- .../me/rigamortis/seppuku/impl/module/world/NukerModule.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java index 0c0918f..ca1eac1 100644 --- a/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java +++ b/src/main/java/me/rigamortis/seppuku/impl/module/world/NukerModule.java @@ -39,6 +39,7 @@ public final class NukerModule extends Module { public final Value timeout = new Value("Timeout", new String[]{"TO, t"}, "How long to wait (in ms) until trying to break a specific block again (PACKET Mode)", 1000, 0, 5000, 10); public final Value minMineSpeed = new Value("MinMineSpeed", new String[]{"Min", "Speed", "MineSpeed"}, "How fast you should be able to mine a block for nuker to attempt to mine it (0-1, 0 to allow all blocks, 1 to only allow instantly minable blocks)", 0.2f, 0f, 1.0f, 0.1f); + // TODO: FilterMode does not show up in the gui (noil's fault). public final Value filterMode = new Value("FilterMode", new String[]{"fm", "fmode"}, "Controls how blocks should be checked against the filter", FilterMode.WHITE); public final Value> filter = new Value>("Filter", new String[]{}, "Controls what block id's nuker will mine");