You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bukkit中EntityExplosionEvent#blockList()失效问题求助

解决EntityExplosionEvent获取blockList全为AIR的问题

嘿,我之前正好碰到过一模一样的问题!让我给你捋清楚原因和解决办法:

问题根源

你遇到的核心问题是:EntityExplosionEvent触发时,游戏已经完成了方块的摧毁逻辑,此时event.blockList()返回的是爆炸后会被替换成空气的方块实例(也就是已经被标记为AIR的对象),而不是爆炸前的原始方块。这就是为什么你拿到的全是AIR类型。

正确解决思路:手动获取爆炸范围内的原始方块

我们需要绕过blockList(),直接通过爆炸的中心点和半径,遍历范围内的所有方块,筛选出会被爆炸破坏的目标,记录它们的状态后再进行恢复。下面是具体的代码示例:

@EventHandler
public void onTNTExplosion(EntityExplosionEvent event) {
    // 如果你想完全自定义爆炸效果,先取消默认的破坏行为
    event.setCancelled(true);

    // 获取爆炸的核心参数:中心点和半径
    Location explosionCenter = event.getLocation();
    float explosionRadius = event.getRadius();

    // 存储需要恢复的方块快照(包含所有状态信息)
    List<BlockSnapshot> blocksToRestore = new ArrayList<>();

    // 遍历爆炸覆盖的立方体范围(取半径的整数上限)
    int radiusInt = (int) Math.ceil(explosionRadius);
    for (int x = -radiusInt; x <= radiusInt; x++) {
        for (int y = -radiusInt; y <= radiusInt; y++) {
            for (int z = -radiusInt; z <= radiusInt; z++) {
                Location blockLoc = explosionCenter.clone().add(x, y, z);
                Block block = blockLoc.getBlock();

                // 跳过空气方块和防爆方块(比如基岩、黑曜石)
                if (block.getType().isAir() || !block.getType().isDestroyableByExplosion()) {
                    continue;
                }

                // 判断方块是否在爆炸有效半径内(用平方距离减少计算开销)
                double distance = blockLoc.distanceSquared(explosionCenter);
                if (distance > explosionRadius * explosionRadius) {
                    continue;
                }

                // 记录方块的完整快照(包含类型、数据、NBT等)
                blocksToRestore.add(block.getSnapshot());
            }
        }
    }

    // 模拟爆炸的视觉和音效(如果取消了默认爆炸)
    explosionCenter.getWorld().createExplosion(explosionCenter, explosionRadius, false, false);

    // 延迟恢复方块(示例为10秒后,20ticks=1秒)
    Bukkit.getScheduler().runTaskLater(yourPluginInstance, () -> {
        for (BlockSnapshot snapshot : blocksToRestore) {
            // 将快照恢复到原位置
            snapshot.update(true, false);
        }
    }, 200L);
}

额外注意事项

  • 用BlockSnapshot保存状态:这个类能完整保存方块的所有状态(比如箱子里的物品、熔炉进度、告示牌文字等),比单纯记录Material要可靠得多。
  • 性能优化:用distanceSquared代替distance可以减少开根号的计算开销,提升遍历效率;如果爆炸半径很大,可以考虑缩小遍历范围。
  • 灵活调整逻辑:如果不需要取消默认爆炸,直接去掉event.setCancelled(true)即可——游戏会先显示方块被炸毁,之后再自动恢复,视觉效果更自然。
  • 主线程操作:所有方块操作必须在主线程执行,所以恢复逻辑要用runTaskLater而不是异步任务。

内容的提问来源于stack exchange,提问作者Kiligo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:05:13