Spigot 1.19中PlayerJoinEvent封禁玩家踢人逻辑失效问题求助
问题分析与修复方案
核心问题点
- 条件分支逻辑错误:前两个
if/else if已覆盖所有玩家情况(首次加入/非首次加入),导致封禁判断的分支永远不会执行。 - MongoDB查询条件错误:用
Player对象作为查询条件,而数据库中存储的是玩家名字字符串,无法匹配到目标数据。 - 资源泄漏:每次触发事件都新建
MongoClient,会快速耗尽数据库连接资源。 - 封禁状态判断脱节:依赖Bukkit内置的
isBanned(),但自定义封禁数据存在MongoDB中,两者状态可能不同步。
修复后的代码
package xyz.foresthosting.testplugin.events; import com.mongodb.client.MongoCollection; import org.bson.Document; import xyz.foresthosting.testplugin.TestPlugin; import org.bukkit.ChatColor; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; public class PlayerJoin implements Listener { private final TestPlugin plugin; private final MongoCollection<Document> bansCollection; // 构造函数传入预初始化的Mongo集合,避免重复创建连接 public PlayerJoin(TestPlugin plugin, MongoCollection<Document> bansCollection) { this.plugin = plugin; this.bansCollection = bansCollection; } @EventHandler public void onPlayerJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); String playerName = player.getName(); // 优先检查封禁记录 Document banRecord = bansCollection.find(new Document("name", playerName)).first(); if (banRecord != null) { String staff = banRecord.getString("staff"); String reason = banRecord.getString("reason"); // 执行踢人并终止后续逻辑 player.kickPlayer(ChatColor.RED + "你已被服务器封禁!\n原因: " + reason + "\n执行人员: " + staff); event.setJoinMessage(null); return; } // 处理欢迎消息逻辑 if (!player.hasPlayedBefore()) { event.setJoinMessage(ChatColor.GREEN + "欢迎加入服务器 " + playerName + "!祝你游戏愉快。"); } else { event.setJoinMessage(ChatColor.GREEN + "欢迎回来 " + playerName + "!"); } } }
额外优化建议
- 复用MongoDB连接:在插件主类中仅初始化一次
MongoClient和集合,通过构造函数传递给监听器:// 主类示例代码 private MongoCollection<Document> bansCollection; @Override public void onEnable() { // 初始化MongoDB连接(仅执行一次) MongoClient mongoClient = new MongoClient("mongodb://admin:<nopasswordforyou>@185.209.223.136:2002"); MongoDatabase database = mongoClient.getDatabase("test"); this.bansCollection = database.getCollection("bans"); // 注册监听器时传入集合实例 getServer().getPluginManager().registerEvents(new PlayerJoin(this, bansCollection), this); } - 异步处理数据库查询:数据库操作属于阻塞操作,建议用Bukkit异步任务执行,避免卡住服务器主线程:
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> { Document banRecord = bansCollection.find(new Document("name", playerName)).first(); // 踢人、消息设置必须回到主线程执行 plugin.getServer().getScheduler().runTask(plugin, () -> { if (banRecord != null) { String staff = banRecord.getString("staff"); String reason = banRecord.getString("reason"); player.kickPlayer(ChatColor.RED + "你已被服务器封禁!\n原因: " + reason + "\n执行人员: " + staff); event.setJoinMessage(null); } else { if (!player.hasPlayedBefore()) { event.setJoinMessage(ChatColor.GREEN + "欢迎加入服务器 " + playerName + "!祝你游戏愉快。"); } else { event.setJoinMessage(ChatColor.GREEN + "欢迎回来 " + playerName + "!"); } } }); }); - 添加异常捕获:给MongoDB操作增加异常处理,避免插件因数据库连接失败而崩溃。
内容的提问来源于stack exchange,提问作者Knife worm
相关产品推荐
相关产品推荐

