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

Bukkit枪械插件递归方法无限调用致StackOverflowError求助

Bukkit枪械插件弹药逻辑问题解决

问题分析

  1. 递归栈溢出:原Ammo.moveFrom()方法仅在命中沙子时终止递归,未命中则无限调用自身,直接触发StackOverflowError。
  2. 循环版本失效:修改后的循环逻辑向量计算错误——每次都重新获取玩家当前视角方向并叠加固定向量,导致弹药无法沿发射方向直线前进,位置混乱;同时缺少射程限制,可能陷入死循环。

核心修正点

  • 改用Bukkit异步调度+循环实现弹药飞行(避免卡住服务器主线程)
  • 修正向量计算:基于发射瞬间的初始方向,按固定步长递增位置
  • 添加最大射程限制,防止无限循环
  • 扩展碰撞检测:命中所有非空气方块时执行摧毁逻辑

修正后的代码

重构后的Ammo类

package fr.laponie.ShooterPlugin;

import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;

import net.minecraft.server.v1_8_R3.EnumParticle;
import net.minecraft.server.v1_8_R3.PacketPlayOutWorldParticles;

public class Ammo {
    private final Player p;
    private final Weapon w;
    private Location currentLoc;
    private final Vector direction;
    private final double step = 0.4; // 每次移动步长
    private final int maxRange = 50; // 最大射程(方块数)
    private int traveledTicks = 0;

    public Ammo(Player p, Weapon w) {
        this.p = p;
        this.w = w;
        this.currentLoc = p.getEyeLocation().clone();
        // 初始化发射方向:标准化后乘以步长,移除错误的(1,1,1)叠加
        this.direction = currentLoc.getDirection().normalize().multiply(step);
    }

    // 启动弹药飞行逻辑
    public void launch() {
        new BukkitRunnable() {
            @Override
            public void run() {
                traveledTicks++;
                // 更新当前位置
                currentLoc.add(direction);
                Block targetBlock = currentLoc.getBlock();

                // 发送飞行粒子特效
                sendParticle(currentLoc);

                // 终止条件:超出射程或命中非空气方块
                if (traveledTicks >= maxRange || targetBlock.getType() != Material.AIR) {
                    if (targetBlock.getType() != Material.AIR) {
                        p.sendMessage(ChatColor.DARK_AQUA + "" + ChatColor.BOLD + "命中方块:" + targetBlock.getType().name());
                        targetBlock.setType(Material.AIR);
                    }
                    this.cancel();
                    return;
                }
            }
        }.runTaskTimer(w.getPlugin(), 0, 1); // 每1tick执行一次(20tick=1秒)
    }

    // 封装粒子发送逻辑
    private void sendParticle(Location loc) {
        EnumParticle trail = EnumParticle.CRIT;
        PacketPlayOutWorldParticles packParticle = new PacketPlayOutWorldParticles(
                trail, false,
                (float) loc.getX(), (float) loc.getY(), (float) loc.getZ(),
                0, 0, 0, 0, 0, null
        );
        ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packParticle);
    }
}

修正后的PlayerInteractEvent处理

@EventHandler
public void onRightClickWeapon(PlayerInteractEvent e) {
    Player p = e.getPlayer();
    Action a = e.getAction();

    ItemStack current = p.getItemInHand();
    ItemStack rifle = new AssaultRifle().mat;

    if ((a == Action.RIGHT_CLICK_AIR || a == Action.RIGHT_CLICK_BLOCK) && current != null) {
        // 匹配枪械类型与名称
        if (current.getType() == rifle.getType() && current.hasItemMeta() 
            && current.getItemMeta().getDisplayName().equalsIgnoreCase(rifle.getItemMeta().getDisplayName())) {
            
            Ammo ammo = new Ammo(p, this);
            ammo.launch(); // 启动弹药飞行逻辑
        }
    }
}

关键改进说明

  1. 异步调度:用BukkitRunnable实现非阻塞循环,避免拖慢服务器
  2. 直线飞行逻辑:基于发射瞬间的方向向量,保证弹药沿直线前进
  3. 安全限制:通过maxRange防止无限循环,同时避免弹药飞出地图边界
  4. 通用碰撞处理:命中所有非空气方块都触发摧毁,满足需求
  5. 代码解耦:将粒子发送逻辑抽为独立方法,提升代码可维护性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:05:59