Block Swapper

Block Swapper

152k Downloads

Blacklist

Reaviik opened this issue ยท 1 comments

commented

Please make the blacklist bidirectional, currently it only works for the block to be swapped and not the one it will replace
If it's not too much trouble, a world blacklist would also be welcome <3

commented

I got a little carried away, I hope you get mad about it, I really liked your mod.

I added a function for multiple swapping, but I really wanted to know how to make the player place the block and not the server because that caused me some problems ^^

Spoiler ` public class SwapperInteraction {
@SubscribeEvent
public static void swapperMainHandInteraction(PlayerInteractEvent.RightClickBlock event) {
    processSwapperInteraction(event, true);
}

@SubscribeEvent
public static void swapperOffhandInteraction(PlayerInteractEvent.RightClickBlock event) {
    processSwapperInteraction(event, false);
}


private static void processSwapperInteraction(PlayerInteractEvent.RightClickBlock event, boolean isMainHand) {
    if(event.isCanceled()){ return;}
    Player player = event.getEntity();
    if(!(player instanceof ServerPlayer serverPlayer)){ return;}
    Direction facing = event.getFace();
    BlockPos pos = event.getPos();
    Level world = event.getLevel();

    ItemStack swapperStack = isMainHand ? player.getMainHandItem() : player.getOffhandItem();
    ItemStack blockStack = isMainHand ? player.getOffhandItem() : player.getMainHandItem();

    if (!swapperStack.is(ItemsInit.COPPER_BLOCK_SWAPPER.get())
        || !blockStack.is(ItemsInit.COPPER_BLOCK_SWAPPER.get())
        || !swapperStack.is(ItemsInit.NETHERITE_BLOCK_SWAPPER.get())
        || !blockStack.is(ItemsInit.NETHERITE_BLOCK_SWAPPER.get())) {
        return;
    }

    BlockState oldBlockState = world.getBlockState(pos);
    BlockState newBlockState = Blocks.AIR.defaultBlockState();

    SoundType oldSound = oldBlockState.getSoundType();

    boolean facingBlock = (facing != null);
    boolean playerCanEditBlock = player.mayUseItemAt(pos.offset(facing.getNormal()), facing, swapperStack);
    boolean creative = player.isCreative() && ServerConfig.doesCreativeAffect();
    boolean canMine = creative;
    boolean notEntity = !oldBlockState.hasBlockEntity();
    boolean extended = swapperStack.getOrCreateTag().getBoolean("Extended");

    if (swapperStack.is(ItemsInit.COPPER_BLOCK_SWAPPER.get())) {
        if (Items.STONE_AXE.isCorrectToolForDrops(oldBlockState) ||
                Items.STONE_PICKAXE.isCorrectToolForDrops(oldBlockState) ||
                Items.STONE_SHOVEL.isCorrectToolForDrops(oldBlockState) ||
                Items.STONE_SWORD.isCorrectToolForDrops(oldBlockState) ||
                Items.STONE_HOE.isCorrectToolForDrops(oldBlockState) ||
                Items.SHEARS.isCorrectToolForDrops(oldBlockState)) {
            canMine = true;
        }
    } else if (swapperStack.is(ItemsInit.NETHERITE_BLOCK_SWAPPER.get())) {
        if (Items.DIAMOND_AXE.isCorrectToolForDrops(oldBlockState) ||
                Items.DIAMOND_PICKAXE.isCorrectToolForDrops(oldBlockState) ||
                Items.DIAMOND_SHOVEL.isCorrectToolForDrops(oldBlockState) ||
                Items.DIAMOND_SWORD.isCorrectToolForDrops(oldBlockState) ||
                Items.DIAMOND_HOE.isCorrectToolForDrops(oldBlockState) ||
                Items.SHEARS.isCorrectToolForDrops(oldBlockState)) {
            canMine = true;
        }
    } else return;

    if (blockStack.getItem() instanceof BlockItem blockItem) {
        if (ServerConfig.getSwapDisabled(blockItem.getBlock())) {
            world.playSound(player, pos, oldSound.getBreakSound(), SoundSource.BLOCKS, oldSound.getVolume(), oldSound.getPitch());
            event.setCanceled(true);
            event.setCancellationResult(InteractionResult.SUCCESS);
            return;
        }
        newBlockState = blockItem.getBlock().withPropertiesOf(oldBlockState);
    } else if (swapperStack.getEnchantmentLevel(EnchantmentsInit.EXCAVATING.get()) > 0 || creative) {
        if (ServerConfig.getExcavateDisabled(oldBlockState.getBlock()) && !creative) {
            world.playSound(player, pos, oldSound.getBreakSound(), SoundSource.BLOCKS, oldSound.getVolume(), oldSound.getPitch());
            event.setCanceled(true);
            event.setCancellationResult(InteractionResult.SUCCESS);
            return;
        }
    } else return;

    if (ServerConfig.getSwapDisabled(oldBlockState.getBlock())) canMine = false;
    if (player.hasEffect(MobEffect.byId(4)) && ServerConfig.doesFatigueAffect()) canMine = false;

    if (!facingBlock || !playerCanEditBlock || !notEntity) return;
    if (newBlockState.equals(oldBlockState) || (!canMine && !creative)) {
        world.playSound(player, pos, oldSound.getBreakSound(), SoundSource.BLOCKS, oldSound.getVolume(), oldSound.getPitch());
        event.setCanceled(true);
        event.setCancellationResult(InteractionResult.SUCCESS);
        return;
    }

    List<BlockPos> blocksToReplace = (extended && player.isShiftKeyDown()) ?
            findConnectedBlocks(world, pos, oldBlockState, 64) :
            Collections.singletonList(pos);

    int maxToReplace = blocksToReplace.size();
    if (!creative && blockStack.getItem() instanceof BlockItem) {
        maxToReplace = Math.min(maxToReplace, blockStack.getCount());
    }

    if (maxToReplace <= 0) {
        world.playSound(player, pos, oldSound.getBreakSound(), SoundSource.BLOCKS, oldSound.getVolume(), oldSound.getPitch());
        event.setCanceled(true);
        event.setCancellationResult(InteractionResult.SUCCESS);
        return;
    }

    int finalMaxToReplace = maxToReplace;
    world.playSound(player, pos, oldSound.getBreakSound(), SoundSource.BLOCKS, oldSound.getVolume(), oldSound.getPitch());
    if (!world.isClientSide()) {
        BlockState finalNewBlockState = newBlockState;
        AtomicInteger replacedBlocks = new AtomicInteger(0);

        blocksToReplace.subList(0, finalMaxToReplace).forEach(currentPos -> {
            if (player.mayUseItemAt(currentPos.offset(facing.getNormal()), facing, swapperStack)) {

                boolean destroyed = serverPlayer.gameMode.destroyBlock(currentPos);
                BlockState currentState = world.getBlockState(currentPos);

                if (!destroyed || !currentState.isAir()) {
                    return;
                }

                BlockState placementState = finalNewBlockState;
                if (placementState.hasProperty(BlockStateProperties.PERSISTENT) &&
                        !currentState.hasProperty(BlockStateProperties.PERSISTENT)) {
                    placementState = placementState.setValue(BlockStateProperties.PERSISTENT, true);
                }

                world.setBlock(currentPos, placementState, 11);
                world.gameEvent(GameEvent.BLOCK_CHANGE, currentPos, GameEvent.Context.of(player, placementState));

                replacedBlocks.incrementAndGet();
            }
        });

        int actuallyReplaced = replacedBlocks.get();

        if (!player.isCreative() && blockStack.getItem() instanceof BlockItem) {
            blockStack.shrink(actuallyReplaced);
        }

        swapperStack.hurtAndBreak(actuallyReplaced, player, pl ->
                pl.broadcastBreakEvent(isMainHand ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND));
    }

    SoundType newSound = newBlockState.getSoundType();
    world.playSound(player, pos, newSound.getPlaceSound(), SoundSource.BLOCKS, newSound.getVolume(), newSound.getPitch());

    if (!isMainHand) {
        player.swing(InteractionHand.OFF_HAND);
    }

    event.setCanceled(true);
    event.setCancellationResult(InteractionResult.SUCCESS);
}

private static List<BlockPos> findConnectedBlocks(Level world, BlockPos startPos, BlockState targetState, int maxBlocks) {
    List<BlockPos> connected = new ArrayList<>();
    Queue<BlockPos> queue = new LinkedList<>();
    Set<BlockPos> visited = new HashSet<>();

    queue.add(startPos);
    visited.add(startPos);

    while (!queue.isEmpty() && connected.size() < maxBlocks) {
        BlockPos current = queue.poll();
        connected.add(current);

        for (Direction dir : Direction.values()) {
            BlockPos neighbor = current.relative(dir);
            if (!visited.contains(neighbor)) {
                BlockState neighborState = world.getBlockState(neighbor);
                if (neighborState.equals(targetState)) {
                    visited.add(neighbor);
                    queue.add(neighbor);
                    if (connected.size() + queue.size() >= maxBlocks) {
                        break;
                    }
                }
            }
        }
    }
    return connected.subList(0, Math.min(connected.size(), maxBlocks));
}

}`