0

I have created a plugin using the Bukkit/Spigot API.

The aim of the plugin is to save player coordinates every second on Minecraft and store this in a '.log' file.

If my username on minecraft is 'abce', then there should be a file in the plugins folder of my server that is saved called 'abce.log' that stores my coordinates.

However, I am unable to find the file 'abce.log' file in my plugins folder on my server.

I have the following code :

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
{
    boolean stopRepeater;
    HashMap<UUID, BukkitTask> tasks = new HashMap<>();
 
    public void onEnable() {
        Bukkit.getServer().getPluginManager().registerEvents(this,this);
        getLogger().info("HELLO! WELCOME TO THE TRACKER PLUGIN");
        if(!this.getDataFolder().exists())
        {
            this.getDataFolder().mkdir();
        }
    }
    
    public void onDisable() {
        getLogger().info("SHUTTING DOWN!");
    }
    
    @EventHandler
    public void onLogin(final PlayerJoinEvent event) {
        final Player thePlayer = event.getPlayer();
        this.stopRepeater = true;
        final Location playerSpawnLocation = thePlayer.getLocation();
        getLogger().info(String.valueOf(thePlayer.getName()) + " is logging in!");
        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 {
            final File dataFolder = new File(this.getDataFolder() + File.separator + currentPlayer.getName());
            if (!dataFolder.exists()) {
                dataFolder.mkdir();
            }
            final File saveTo = new File(dataFolder, String.valueOf(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(String.valueOf(format.format(nowDate)) + " CurrentLocation(x,y,z): " + playerCurrentLocation.getBlockX() + " " + playerCurrentLocation.getBlockY() + " " + playerCurrentLocation.getBlockZ());
            pw.close();
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}
Elikill58
  • 4,050
  • 24
  • 23
  • 45
Caledonian26
  • 727
  • 1
  • 10
  • 27
  • Don't include unrevelant tag. [tag:eclipse] and [tag:maven] are not useful here such as your issue isn't on eclipse itself. For your issue, do you have error ? What is created ? Does a folder is created ? – Elikill58 Dec 05 '22 at 18:43
  • Make sure the `FileWriter` is properly closed. You might desire to use a `try/catch/finally` expression in order to ensure this happens. Otherwise, the only oddity I'm seeing is that you're making a folder per-player, in addition to the logfile per-player (e.g. `plugins/PluginName/abcd/abcd.log`). If there are exceptions in the server log, then those should be addressed. Note as well `stopRepeater` will apply to _all players_, so if one player quits then all logging stops. If a player joins, all logging resumes. – Rogue Dec 05 '22 at 18:48
  • @Elikill58 a folder sadly is not created! – Caledonian26 Dec 05 '22 at 19:19
  • @Rogue thanks so much for your help! I thought that using a hash map would ensure that the logging would only stop for that particular player (which is what I want), not for all players - how can I change my code to allow this? :) Also, how can I change my code to creating a different file per player but not a different folder? – Caledonian26 Dec 05 '22 at 19:23

1 Answers1

1

There is easier way to add content file.

But, before adding content to file, you should create them. For this, you should do like:

private File dataFolder;

@Override
public void onEnable() {
    dataFolder = new File(getDataFolder(), "data"); // get folder "plugins/MyPlugin/data"
    dataFolder.mkdirs(); // create folder if not exists
}

Then, to edit file, do:

public void logToFile(final Player currentPlayer, final Location loc) {
   try {
       String content = String.valueOf(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(new Date()))
               + " CurrentLocation(x,y,z): " + loc.getBlockX() + " " + loc.getBlockY() + " " + loc.getBlockZ() + "\n";
  
       File file = new File(dataFolder, currentPlayer.getName() + ".log");
       if(!file.exists()) { // if file is not present
           file.createNewFile(); // create
       }
       // append to file
       Files.write(file.toPath(), content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND);
   } catch (Exception e) {
       e.printStackTrace();
   }
}

Also, actually, if multiple player join then one join, they will all be stopped from checking (because of change of stopRepeater). I think you should change the logic for timers, but it's another discussion which is off-topic for this question.

Elikill58
  • 4,050
  • 24
  • 23
  • 45
  • Thanks so much for the advice - it is asking me to rename the 'onEnable()' as I already have an 'onEnable()' higher up in my code - should I rename it? And is the '@override' necessary? – Caledonian26 Dec 06 '22 at 17:16
  • The `onEnable` method that I show is only example, and this content should be in your own actual `onEnable` method – Elikill58 Dec 06 '22 at 17:47
  • ok perfect - could you confirm: 1. why file data folder is a 'private' variable 2. why the variable 'files' hasn't been defined? Shouldn't I add this line - Files files = new Files();? – Caledonian26 Dec 06 '22 at 18:41
  • 1. It's a reflex with those types of variables. It's not necessary. 2. `files` isn't a variable but a class, [here](https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html) is javadoc – Elikill58 Dec 06 '22 at 18:57
  • ok thanks so much for clarifying - I get the error: the method write(byte[], File) in the type Files is not applicable for the arguments (Path, byte[], StandardOpenOption) - not sure why! – Caledonian26 Dec 06 '22 at 19:06
  • https://stackoverflow.com/questions/74707941/the-method-writebyte-file-in-the-type-files-is-not-applicable-for-the-argum – Caledonian26 Dec 06 '22 at 19:13
  • Seems to be fixed – Elikill58 Dec 06 '22 at 19:59