Bukkit插件Scoreboard配置scheduler后仍不更新且控制台报错求助
问题根因
- 你创建了
damage团队,但没有将团队对应的条目添加到计分板的显示列表中,反而直接用了固定文本的伤害行,导致团队本身没有和计分板绑定,后续更新的是团队前缀自然不会生效。 - 每次调用
showScoreboard方法都会生成新的计分板、重复注册定时任务,同一个玩家可能对应多个定时任务同时运行,当玩家计分板被替换后,旧的定时任务访问旧计分板的团队就会抛出空异常。 - 没有对定时任务做生命周期管理,玩家退出服务器后任务仍会继续运行,访问离线玩家的计分板也会触发异常。
修复方案
调整核心逻辑,删除固定文本的伤害行、改用团队对应的条目作为显示项,新增任务ID缓存避免重复注册,简化异常处理逻辑:
public class PlayerScoreboard { private static Plugin plugin; // 存储玩家对应的定时任务ID,避免重复注册 private static final Map<UUID, Integer> taskMap = new HashMap<>(); public static void setPlugin(Plugin plugin) { PlayerScoreboard.plugin = plugin; } public static void showScoreboard(Player player) { ScoreboardManager manager = Bukkit.getScoreboardManager(); if (manager == null) return; Scoreboard board = manager.getNewScoreboard(); Objective objective = board.registerNewObjective("servername", "dummy", ChatColor.translateAlternateColorCodes('&', "&e&lRAY'S &b&lSERVER")); objective.setDisplaySlot(DisplaySlot.SIDEBAR); objective.getScore("————————————————").setScore(4); objective.getScore("").setScore(3); // 替换原有固定伤害行为团队对应条目 String damageEntry = ChatColor.DARK_RED + "" + ChatColor.BLUE; objective.getScore(damageEntry).setScore(2); objective.getScore(" ").setScore(1); Team damage = board.registerNewTeam("damage"); damage.addEntry(damageEntry); damage.setPrefix(ChatColor.RED + "Damage dealt: " + ChatColor.GREEN + player.getStatistic(Statistic.DAMAGE_DEALT)); player.setScoreboard(board); // 取消玩家之前的旧任务,避免重复运行 UUID playerUuid = player.getUniqueId(); if (taskMap.containsKey(playerUuid)) { Bukkit.getScheduler().cancelTask(taskMap.get(playerUuid)); } // 注册新任务并存储ID int taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -> { // 玩家离线则清理任务 if (!player.isOnline()) { Bukkit.getScheduler().cancelTask(taskMap.get(playerUuid)); taskMap.remove(playerUuid); return; } updateDamage(player); }, 0L, 20L); taskMap.put(playerUuid, taskId); } public static void updateDamage(Player player) { Scoreboard board = player.getScoreboard(); Team team = board.getTeam("damage"); if (team == null) { // 团队不存在直接重建,避免报错 team = board.registerNewTeam("damage"); String damageEntry = ChatColor.DARK_RED + "" + ChatColor.BLUE; team.addEntry(damageEntry); } team.setPrefix(ChatColor.RED + "Damage dealt: " + ChatColor.GREEN + player.getStatistic(Statistic.DAMAGE_DEALT)); } // 玩家退出时调用,清理无效任务 public static void onPlayerQuit(Player player) { UUID uuid = player.getUniqueId(); if (taskMap.containsKey(uuid)) { Bukkit.getScheduler().cancelTask(taskMap.get(uuid)); taskMap.remove(uuid); } } }
补充说明
在插件的玩家退出事件监听器中调用PlayerScoreboard.onPlayerQuit(player),可以避免内存泄漏和无效任务占用服务器资源。
内容的提问来源于stack exchange,提问作者amxyargaming
相关产品推荐
相关产品推荐

