如何在Bukkit插件中于ArrayList移除玩家时触发重新启用摔落伤害的逻辑
实现方案
第一步:修复列表作用域问题
你当前把nofalldmg定义在命令执行方法内部,每次触发命令都会创建新的空列表,之前存储的玩家数据会完全丢失,需要把它改成插件主类的全局成员,建议用HashSet替代ArrayList,查询/删除效率更高:
// 放在你的插件主类中,作为全局静态变量 public static HashSet<Player> noFallDmgImmune = new HashSet<>();
第二步:注册摔落伤害拦截监听器
在主类onEnable方法中注册事件监听器,逻辑为:只要玩家在免疫列表内,就取消摔落伤害事件:
@EventHandler public void onPlayerFallDamage(EntityDamageEvent event) { // 仅处理摔落伤害、且受伤害对象为玩家的场景 if (event.getCause() != EntityDamageEvent.DamageCause.FALL || !(event.getEntity() instanceof Player)) { return; } Player player = (Player) event.getEntity(); if (你的主类名.noFallDmgImmune.contains(player)) { event.setCancelled(true); } }
第三步:调整延迟任务逻辑
只要玩家被移出免疫列表,监听器就不会再拦截他的摔落伤害,自动恢复默认逻辑。如果需要避免移除瞬间玩家因为之前累计的掉落高度掉血,可以额外清理掉落距离:
// 你原有的命令逻辑调整后 Player p = (Player) sender; if (p.hasPermission("custome.fly")) { if (p.isFlying()) { p.setAllowFlight(false); p.setFlying(false); 你的主类名.noFallDmgImmune.add(p); Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { @Override public void run() { 你的主类名.noFallDmgImmune.remove(p); // 清理累计掉落距离,避免移除瞬间掉血 p.setFallDistance(0); } }, 60); } }
补充优化建议
- 加一个玩家退出事件的监听器,玩家下线时自动从免疫列表移除,避免内存泄漏
- 如果你使用的是1.17+版本的Spigot API,可以直接调用
p.setFallDamageImmuneTicks(60),不需要自己维护免疫列表,逻辑更简洁
内容的提问来源于stack exchange,提问作者Zavage
相关产品推荐
相关产品推荐

