diff --git a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java index dff1982..c4eff76 100644 --- a/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java +++ b/src/main/java/land/chipmunk/chipmunkmod/modules/CommandCore.java @@ -1,11 +1,13 @@ package land.chipmunk.chipmunkmod.modules; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import land.chipmunk.chipmunkmod.ChipmunkMod; import land.chipmunk.chipmunkmod.listeners.Listener; import land.chipmunk.chipmunkmod.listeners.ListenerManager; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.CommandBlock; +import net.minecraft.block.FallingBlock; import net.minecraft.block.entity.CommandBlockBlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; @@ -23,17 +25,18 @@ import net.minecraft.network.packet.c2s.play.CreativeInventoryActionC2SPacket; import net.minecraft.network.packet.c2s.play.UpdateCommandBlockC2SPacket; import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; import net.minecraft.registry.Registries; +import net.minecraft.registry.tag.BlockTags; import net.minecraft.state.property.Property; import net.minecraft.util.Hand; +import net.minecraft.util.Pair; import net.minecraft.util.Util; import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.math.BlockBox; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.*; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.dimension.DimensionType; +import java.util.Collections; +import java.util.Map; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.CompletableFuture; @@ -51,8 +54,10 @@ public class CommandCore implements Listener { public boolean runFillCommand = true; public boolean alreadyFilled = false; + private final Map pendingSetBlockCommands = Collections.synchronizedMap(new Object2ObjectArrayMap<>()); private Timer timer; private boolean shouldRefill = false; + private int refillTriesUsingPlaceBlock = 0; private DimensionType oldDimension; public CommandCore (final MinecraftClient client) { @@ -103,7 +108,30 @@ public class CommandCore implements Listener { check(); - if (!shouldRefill) return; + if (!shouldRefill) { + refillTriesUsingPlaceBlock = 0; + synchronized (pendingSetBlockCommands) { + if (pendingSetBlockCommands.isEmpty()) return; + for (final Map.Entry entry : pendingSetBlockCommands.entrySet()) { + final BlockPos blockPos = entry.getKey(); + final String block = entry.getValue(); + + run( + String.format( + "setblock %d %d %d %s", + + blockPos.getX(), + blockPos.getY(), + blockPos.getZ(), + + block + ) + ); + } + pendingSetBlockCommands.clear(); + } + return; + } refill(); @@ -189,8 +217,17 @@ public class CommandCore implements Listener { public void refill () { final ClientPlayNetworkHandler networkHandler = client.getNetworkHandler(); + final ClientPlayerEntity player = client.player; - if (!runFillCommand || client.world == null || networkHandler == null || withPos == null) return; + if ( + !runFillCommand + || player == null + || !player.isInCreativeMode() + || !player.hasPermissionLevel(2) + || client.world == null + || networkHandler == null + || withPos == null + ) return; final Chunk chunk = client.world.getChunk(withPos.getCenter()); @@ -208,7 +245,13 @@ public class CommandCore implements Listener { withPos.getMaxZ() ); - runPlaceBlock(command); + if (refillTriesUsingPlaceBlock > 5) { + networkHandler.sendChatCommand(command); + refillTriesUsingPlaceBlock = 0; + } else { + runPlaceBlock(command); + refillTriesUsingPlaceBlock++; + } } public void incrementCurrentBlock () { @@ -360,29 +403,24 @@ public class CommandCore implements Listener { final DimensionType dimensionType = world.getDimension(); + final ClientPlayerInteractionManager interactionManager = client.interactionManager; + if (interactionManager == null) return; + + // stolen from two five hundred million dollars + + final Pair pair = findBlockLocation(); + if ( - player.getPos().getY() < dimensionType.minY() - || player.getPos().getY() > dimensionType.height() + dimensionType.minY() + pair == null + || pair.getLeft().getY() < dimensionType.minY() + || pair.getLeft().getY() > dimensionType.height() + dimensionType.minY() ) { networkHandler.sendChatCommand(command); return; } - final ClientPlayerInteractionManager interactionManager = client.interactionManager; - if (interactionManager == null) return; - - final float yaw = player.getYaw(); - final float pitch = player.getPitch(); - - // Anti Block when flying around - final BlockPos position = player.getBlockPos().add( - (int) Math.round(3 * Math.cos(Math.toRadians(yaw))), - 3 * (pitch < 0 ? -1 : 1), - (int) Math.round(3 * Math.sin(Math.toRadians(yaw))) - ); - - // stolen from two five hundred million dollars - final BlockState oldBlockState = world.getBlockState(position); + final BlockPos position = pair.getLeft(); + final BlockState oldBlockState = pair.getRight(); final int freeHotBarSlot = player.getInventory().getEmptySlot(); final int slot = 36 + freeHotBarSlot; @@ -430,43 +468,57 @@ public class CommandCore implements Listener { } connection.send(new CreativeInventoryActionC2SPacket(slot, oldStack)); - final Timer timer = new Timer(); + final StringBuilder oldBlockString = new StringBuilder(Registries.BLOCK.getId(oldBlockState.getBlock()).toString()); + if (!oldBlockState.getProperties().isEmpty()) { + oldBlockString.append('['); - final TimerTask task = new TimerTask() { - @Override - public void run () { - final StringBuilder command = new StringBuilder( - String.format( - "setblock %d %d %d %s", - - position.getX(), - position.getY(), - position.getZ(), - - Registries.BLOCK.getId(oldBlockState.getBlock()) - ) - ); - - if (!oldBlockState.getProperties().isEmpty()) { - command.append('['); - - for (final Property property : oldBlockState.getProperties()) { - command.append(property.getName()) - .append('=') - .append(Util.getValueAsString(property, property.getValues().getLast())) // water[level=15] instead of water[level=0,level=1,....,level=15] - .append(','); - } - - command.deleteCharAt(command.length() - 1); - - command.append(']'); - } - - CommandCore.this.run(command.toString()); + for (final Property property : oldBlockState.getProperties()) { + oldBlockString.append(property.getName()) + .append('=') + .append(Util.getValueAsString(property, property.getValues().getLast())) // water[level=15] instead of water[level=0,level=1,....,level=15] + .append(','); } - }; - timer.schedule(task, 100); // assuming the core has already been filled at this point + oldBlockString.deleteCharAt(oldBlockString.length() - 1); + + oldBlockString.append(']'); + } + + pendingSetBlockCommands.put(position, oldBlockString.toString()); + } + + // also from two five hundred million dollars + private Pair findBlockLocation () { + final ClientPlayerEntity player = client.player; + if (player == null) return null; + final BlockPos position = player.getBlockPos(); + final Box boundingBox = player.getBoundingBox(); + boundingBox.expand(1.0); + for (int x = position.getX() - 2; x <= position.getX() + 2; x++) { + for (int y = position.getY() - 2; y <= position.getY() + 2; y++) { + for (int z = position.getZ() - 2; z <= position.getZ() + 2; z++) { + final BlockPos blockPos = new BlockPos(x, y, z); + if (!player.canInteractWithBlockAt(blockPos, 1.0)) continue; + // we don't want to place a block inside ourselves + if (boundingBox.intersects(new Vec3d(blockPos), new Vec3d(blockPos))) continue; + final BlockState blockState = player.getWorld().getBlockState(blockPos); + if (blockState.getBlock() instanceof FallingBlock) continue; + final boolean replaceable = blockState.isIn(BlockTags.REPLACEABLE); + if ( + !replaceable + && !blockState.isIn(BlockTags.AXE_MINEABLE) + && !blockState.isIn(BlockTags.HOE_MINEABLE) + && !blockState.isIn(BlockTags.SHOVEL_MINEABLE) + && !blockState.isIn(BlockTags.PICKAXE_MINEABLE) + ) { + continue; + } + return new Pair<>(blockPos, blockState); + } + } + } + + return null; } public void cleanup () {