我的世界1.16.5版本Forge模组开发(简单的一键挖矿)

一、分析如何实现一键挖矿

  1. 监听方块被破坏事件
  2. 通过广度优先搜索周边相同方块
  3. 通过默认配置和工具耐久确定连锁破坏范围
  4. 执行破坏方块指令

二、代码编写

@Mod.EventBusSubscriber(modid = Constants.MODID)
public class BlockBreakEvent {

    private static final Integer MAX_SEARCH_NUM = 50;

    @SubscribeEvent
    public static void blockBreakEvent(BlockEvent.BreakEvent event) {
        handleBlockBreakEvent(event);
    }

    /**
     * 处理方块被破坏事件
     */
    private static void handleBlockBreakEvent(BlockEvent.BreakEvent event) {
        // 玩家实体
        PlayerEntity player = event.getPlayer();
        // 当前世界
        World world = player.getCommandSenderWorld();
        // 被破坏方块的坐标
        BlockPos pos = event.getPos();
        // 被破坏方块信息
        BlockState state = event.getState();
        // 玩家主手工具
        ItemStack handItem = player.getMainHandItem();
        // 查找可以连锁的方块
        Set<BlockPos> blocksToMine = findBlocksToMine(world, pos, state, handItem.getDamageValue() == 0 ? MAX_SEARCH_NUM : handItem.getDamageValue());
        for (BlockPos p : blocksToMine) {
            // 破坏方块
            world.destroyBlock(p, true, player);
        }
        if (handItem.getDamageValue() != 0) {
            // 减少主手工具耐久值
            handItem.setDamageValue(Math.min(handItem.getDamageValue() + blocksToMine.size(), handItem.getMaxDamage()));
        }
    }

    /**
     * 通过广度优先搜索获取可破坏的方块
     */
    private static Set<BlockPos> findBlocksToMine(World world, BlockPos pos, BlockState originalState, int damageValue) {
        Set<BlockPos> blocksToMine = new HashSet<>();
        Queue<BlockPos> queue = new ArrayDeque<>();
        queue.add(pos);
        while (!queue.isEmpty()) {
            BlockPos currentPos = queue.poll();
            if (blocksToMine.contains(currentPos)) {
                continue;
            }
            BlockState currentState = world.getBlockState(currentPos);
            if (currentState.getBlock() == originalState.getBlock()) {
                blocksToMine.add(currentPos);
                for (BlockPos adjacentPos : getAdjacentPositions(currentPos)) {
                    if (!queue.contains(adjacentPos)) {
                        queue.add(adjacentPos);
                    }
                }
            }
            if (blocksToMine.size() >= damageValue) {
                return blocksToMine;
            }
        }
        return blocksToMine;
    }

    /**
     * 获取被破坏方块周围方块,共26个
     */
    private static Set<BlockPos> getAdjacentPositions(BlockPos pos) {
        Set<BlockPos> adjacentPositions = new HashSet<>();
        adjacentPositions.add(pos.north());
        adjacentPositions.add(pos.south());
        adjacentPositions.add(pos.east());
        adjacentPositions.add(pos.west());
        adjacentPositions.add(pos.above());
        adjacentPositions.add(pos.below());
        adjacentPositions.add(pos.north().above());
        adjacentPositions.add(pos.above().south());
        adjacentPositions.add(pos.south().below());
        adjacentPositions.add(pos.below().north());
        adjacentPositions.add(pos.north().east());
        adjacentPositions.add(pos.east().south());
        adjacentPositions.add(pos.south().west());
        adjacentPositions.add(pos.west().north());
        adjacentPositions.add(pos.north().east());
        adjacentPositions.add(pos.east().south());
        adjacentPositions.add(pos.south().west());
        adjacentPositions.add(pos.west().north());
        adjacentPositions.add(pos.above().north().west());
        adjacentPositions.add(pos.above().north().east());
        adjacentPositions.add(pos.above().south().west());
        adjacentPositions.add(pos.above().south().east());
        adjacentPositions.add(pos.below().north().west());
        adjacentPositions.add(pos.below().north().east());
        adjacentPositions.add(pos.below().south().west());
        adjacentPositions.add(pos.below().south().east());
        return adjacentPositions;
    }

}

 注:上述代码只是一个简单的实现,如getAdjacentPositions()方法可以有更好的写法,方块的破坏逻辑和拣取逻辑也可以做更好的优化。

三、运行效果

四、优化实现

        从上面的运行效果可以看出来物品掉落非常零散,拣取很不方便,因此可以通过如下代码替换实现物品掉落的合并以及更好的掉落效果。

    private static void handleBlockBreakEvent(BlockEvent.BreakEvent event) {
        PlayerEntity player = event.getPlayer();
        Direction direction = player.getDirection();
        World world = player.getCommandSenderWorld();
        BlockPos pos = event.getPos();
        BlockState state = event.getState();
        ItemStack handItem = player.getMainHandItem();
        List<ItemStack> drops = new ArrayList<>();
        LootContext.Builder lootContextBuilder = new LootContext.Builder((ServerWorld)world)
                .withRandom(world.random)
                .withParameter(LootParameters.ORIGIN, Vector3d.atCenterOf(pos))
                .withParameter(LootParameters.TOOL, handItem)
                .withOptionalParameter(LootParameters.THIS_ENTITY, player);
        Set<BlockPos> blocksToMine = findBlocksToMine(world, pos, state, direction, handItem.getDamageValue() == 0 ? MAX_SEARCH_NUM : handItem.getDamageValue());
        for (BlockPos p : blocksToMine) {
            BlockState blockState = world.getBlockState(p);
            List<ItemStack> blockDrops = blockState.getDrops(lootContextBuilder);
            drops.addAll(blockDrops);
            world.removeBlock(p, false);
        }
        // 在中心位置生成所有掉落物
        for (ItemStack drop : drops) {
            ItemEntity itemEntity = new ItemEntity(world, pos.getX() + 0.1, pos.getY() + 0.1, pos.getZ() + 0.1, drop);
            world.addFreshEntity(itemEntity);
        }
        if (!handItem.equals(ItemStack.EMPTY)) {
            handItem.setDamageValue(Math.min(handItem.getDamageValue() + blocksToMine.size(), handItem.getMaxDamage()));
        }
    }

        优化后的运行效果如下,具体的实现逻辑也比较简单,感兴趣的可以自己探索一番。

注:本文仅用于学习参考,不参与任何商业行为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值