使用Java插件的dataFolder时遇问题:无法找到文件存储位置
我需要将Minecraft玩家的坐标输出保存到以玩家用户名命名的.log文件(例如用户名为abce时,文件名为abce.log),但在远程Shockbyte服务器的plugins文件夹中找不到该文件,它并未出现在我预期的路径里。以下是相关信息:
插件代码
package newestfile.here.newestplugin; import java.util.UUID; import java.nio.charset.StandardCharsets; import java.nio.file.StandardOpenOption; 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; import java.nio.file.Files; public class Main extends JavaPlugin implements Listener { boolean stopRepeater; HashMap<UUID, BukkitTask> tasks = new HashMap<>(); private File dataFolder; public void onEnable() { Bukkit.getServer().getPluginManager().registerEvents(this,this); getLogger().info("HELLO! WELCOME TO THE TRACKER PLUGIN"); dataFolder = new File(getDataFolder(), "data"); dataFolder.mkdirs(); } @EventHandler public void onLogin(final PlayerJoinEvent event) { final Player thePlayer = event.getPlayer(); this.stopRepeater = true; final Location playerSpawnLocation = thePlayer.getLocation(); getLogger().info("Welcome " + thePlayer.getName() + ". Your current position is: " + playerSpawnLocation); BukkitTask task = getServer().getScheduler().runTaskTimer(this, () -> { if(this.stopRepeater) { this.logToFile(thePlayer, thePlayer.getLocation()); } }, 0L, 20L); tasks.put(thePlayer.getUniqueId(),task);} @EventHandler public void onQuit(final PlayerQuitEvent event) { Player thePlayer = event.getPlayer(); if(!thePlayer.isOnline()) { this.stopRepeater = false; getLogger().info(String.valueOf(event.getPlayer().getName()) + " has left the game"); BukkitTask task = tasks.remove(thePlayer.getUniqueId()); if(task != null) { task.cancel(); } } } public void logToFile(final Player currentPlayer, final Location playerCurrentLocation) { try { String content = String.valueOf(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date())) + " CurrentLocation(x,y,z): " + playerCurrentLocation.getBlockX() + " " + playerCurrentLocation.getBlockY() + " " + playerCurrentLocation.getBlockZ() + "\n"; final File file = new File(dataFolder, currentPlayer.getName() + ".log"); if (!file.exists()) { file.createNewFile(); } Files.write(file.toPath(),content.getBytes(StandardCharsets.UTF_8),StandardOpenOption.APPEND); } catch (Exception e) { e.printStackTrace(); } } }
预期存储路径说明
预期路径为plugins/NewestPlugin/data文件夹,当前该文件夹为空。
latest.log输出说明
日志显示插件已正常加载(输出HELLO! WELCOME TO THE TRACKER PLUGIN),玩家加入时会记录坐标(例如Welcome Caledonian26. Your current position is: Location{world=CraftWorld{name=world},x=...,y=...,z=...,pitch=...,yaw=...}),玩家退出时也有对应日志记录(例如Caledonian26 has left the game)。
问题排查与解决方案
1. 日志文件实际存储位置
代码中getDataFolder()返回的是插件专属数据文件夹,路径为plugins/你的插件jar包名/(比如插件jar是NewestPlugin.jar,则路径为plugins/NewestPlugin/data/)。你需要进入plugins下对应插件的子文件夹,而非plugins根目录。
2. 代码逻辑修复
- 全局变量
stopRepeater会导致多玩家在线时,一个玩家退出就停止所有玩家的日志记录,需改为按玩家UUID单独维护状态:
// 替换原全局变量stopRepeater HashMap<UUID, Boolean> playerTrackingStatus = new HashMap<>(); // 修改onLogin方法 @EventHandler public void onLogin(final PlayerJoinEvent event) { final Player thePlayer = event.getPlayer(); playerTrackingStatus.put(thePlayer.getUniqueId(), true); final Location playerSpawnLocation = thePlayer.getLocation(); getLogger().info("Welcome " + thePlayer.getName() + ". Your current position is: " + playerSpawnLocation); BukkitTask task = getServer().getScheduler().runTaskTimer(this, () -> { if(playerTrackingStatus.getOrDefault(thePlayer.getUniqueId(), false)) { this.logToFile(thePlayer, thePlayer.getLocation()); } }, 0L, 20L); tasks.put(thePlayer.getUniqueId(),task); } // 修改onQuit方法 @EventHandler public void onQuit(final PlayerQuitEvent event) { Player thePlayer = event.getPlayer(); playerTrackingStatus.remove(thePlayer.getUniqueId()); getLogger().info(event.getPlayer().getName() + " has left the game"); BukkitTask task = tasks.remove(thePlayer.getUniqueId()); if(task != null) { task.cancel(); } }
onQuit方法中的if(!thePlayer.isOnline())判断多余,PlayerQuitEvent触发时玩家已离线,可直接移除该判断。
3. Shockbyte服务器文件访问
登录Shockbyte控制面板,进入文件管理器,找到plugins文件夹后进入对应插件的子目录,即可在data文件夹中找到玩家日志文件。若仍找不到,可通过服务器控制台查看插件加载日志,确认数据文件夹的实际路径。
内容的提问来源于stack exchange,提问作者Caledonian26

