Bukkit/Spigot插件无法保存Minecraft玩家坐标至.log文件问题
问题分析与解决方案
核心问题
你找不到日志文件的直接原因是文件生成路径不符合预期,同时代码存在多玩家冲突的逻辑错误:
1. 文件路径错误
你的代码会在插件专属的data目录下创建以玩家名为名的子文件夹,再在其中生成日志文件,实际路径是:plugins/你的插件文件夹名/abce/abce.log
而非你预期的plugins/abce.log。
2. 多玩家逻辑冲突
全局变量stopRepeater是单个布尔值,当多个玩家同时在线时:
- 新玩家登录会将
stopRepeater设为true,覆盖之前的状态 - 任意玩家退出会将
stopRepeater设为false,导致所有在线玩家的坐标记录任务停止
3. 冗余判断
PlayerQuitEvent触发时玩家必然已离线,!thePlayer.isOnline()判断完全多余。
修正后的代码
package newestfile.here.newestplugin; import java.io.IOException; import java.util.UUID; import java.io.PrintWriter; import java.io.FileWriter; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.io.File; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.EventHandler; import org.bukkit.entity.Player; import org.bukkit.Location; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.Bukkit; import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitTask; public class Main extends JavaPlugin implements Listener { // 用HashMap存储每个玩家的任务状态,避免多玩家冲突 private final HashMap<UUID, Boolean> playerTrackingStatus = new HashMap<>(); private final HashMap<UUID, BukkitTask> tasks = new HashMap<>(); @Override public void onEnable() { Bukkit.getPluginManager().registerEvents(this, this); getLogger().info("HELLO! WELCOME TO THE TRACKER PLUGIN"); // 确保插件data目录存在 if (!getDataFolder().exists()) { getDataFolder().mkdir(); } } @Override public void onDisable() { getLogger().info("SHUTTING DOWN!"); // 关闭所有正在运行的任务 for (BukkitTask task : tasks.values()) { task.cancel(); } tasks.clear(); playerTrackingStatus.clear(); } @EventHandler public void onLogin(final PlayerJoinEvent event) { final Player thePlayer = event.getPlayer(); UUID playerId = thePlayer.getUniqueId(); // 标记该玩家的追踪状态为开启 playerTrackingStatus.put(playerId, true); final Location playerSpawnLocation = thePlayer.getLocation(); getLogger().info(thePlayer.getName() + " is logging in!"); getLogger().info("Welcome " + thePlayer.getName() + ". Your current position is: " + playerSpawnLocation); BukkitTask task = getServer().getScheduler().runTaskTimer(this, () -> { // 仅当该玩家的追踪状态为开启时记录 if (playerTrackingStatus.getOrDefault(playerId, false)) { logToFile(thePlayer, thePlayer.getLocation()); } }, 0L, 20L); tasks.put(playerId, task); } @EventHandler public void onQuit(final PlayerQuitEvent event) { Player thePlayer = event.getPlayer(); UUID playerId = thePlayer.getUniqueId(); getLogger().info(event.getPlayer().getName() + " has left the game"); // 取消该玩家的任务并移除状态记录 BukkitTask task = tasks.remove(playerId); if (task != null) { task.cancel(); } playerTrackingStatus.remove(playerId); } public void logToFile(final Player currentPlayer, final Location playerCurrentLocation) { try { // 直接在plugins目录下生成日志文件(若想保留原路径,可改回getDataFolder()相关代码) File saveTo = new File(Bukkit.getPluginsFolder(), currentPlayer.getName() + ".log"); if (!saveTo.exists()) { saveTo.createNewFile(); } final Date nowDate = new Date(); final SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); final FileWriter fw = new FileWriter(saveTo, true); final PrintWriter pw = new PrintWriter(fw); pw.println(format.format(nowDate) + " CurrentLocation(x,y,z): " + playerCurrentLocation.getBlockX() + " " + playerCurrentLocation.getBlockY() + " " + playerCurrentLocation.getBlockZ()); pw.close(); } catch (IOException e) { e.printStackTrace(); getLogger().severe("Failed to write log for player " + currentPlayer.getName()); } } }
关键修改说明
- 修复多玩家冲突:用
HashMap<UUID, Boolean>替代全局stopRepeater,每个玩家独立维护追踪状态 - 调整文件路径:将日志文件直接生成在
plugins目录下(若想保留原路径,可改回getDataFolder()相关代码) - 清理冗余逻辑:移除
PlayerQuitEvent中多余的离线判断 - 优化插件关闭逻辑:在
onDisable中统一取消所有任务并清理数据 - 增强错误日志:添加日志提示写入失败的玩家,便于排查问题
内容的提问来源于stack exchange,提问作者Caledonian26
相关产品推荐
相关产品推荐

