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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 21:30:47