Using Bukkit and Java to create a 'repeating task' code on a Minecraft spigot plugin

Discussion in 'Plugin Development' started by caledonian26, Nov 22, 2022.

Thread Status:
Not open for further replies.
  1. Offline

    caledonian26

    I am in the process of creating a spigot plugin (using Java and Bukkit language) that will allow me to store the coordinates of players in minecraft (Java edition) in real time.

    I want to use a 'scheduler' to do this with a 'repeating task' structure.

    I have the following code:

    Code:
    Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin)this, (Runnable)new Runnable() {
    @Override
    public void run() {
    if (main.this.stopRepeater) {
    main.this.logToFile(thePlayer, thePlayer.getLocation());
                  }
              }
         }, 0L, 20L);
    }
    However, I am not 100% sure what role the '@Override' and 'new Runnable()' parts of the code are actually playing here. This is the first time I'm using Java/Bukkit/Spigot for a project.

    I am aware that 'new Runnable()' is used to create a new runnable thread of code, and that '@Override' method is used to override the parent class - but what is the 'parent class' in this case above?

    I haven't been able to find a clear explanation for this as different sites say different things.

    I would be so grateful if somebody could clarify this for me!
     
  2. Offline

    timtower Administrator Administrator Moderator

    @caledonian26
    Code:
    new BukkitRunnable(){
       @Override
       public void run() {
         if (main.this.stopRepeater) {
           main.this.logToFile(thePlayer, thePlayer.getLocation());
         }
       }
    }.runTaskTimer(plugin, 0, 20)
    
     
  3. Offline

    caledonian26

    Thanks so much - how does it know that the 'plugin' in runTaskTimer is referring to 'this ' plugin? Should it not be .runTaskTimer((Plugin)this,0,20)?
     
  4. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 No, then you would be casting, casting is not needed if the type is already correct.
     
  5. Offline

    caledonian26

    Ok perfect thanks, so the:

    Code:
    Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask((Plugin)this, (Runnable)new Runnable() {
    part is no longer needed and can be entirely replaced by the following?

    Code:
    new BukkitRunnable(){
       @Override
       public void run() {
        if (main.this.stopRepeater) {
          main.this.logToFile(thePlayer, thePlayer.getLocation());
                }
            }
       }.runTaskTimer(Plugin, 0, 20)
     
  6. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 Yes, but you can't do "Plugin" there as that is not a variable probably
     
  7. Offline

    caledonian26

    so would you replace 'plugin' for 'this'? or how would I refer to the plugin I defined earlier:

    Code:
    public void onEnable() {
            Bukkit.getServer().getPluginManager().registerEvents((Listener)this, (Plugin)this);
     
  8. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 Again, remove the casting, you don't need it.
    And post the full class, can't see it with just single lines, don't know where everything is located.
     
  9. Offline

    caledonian26

    @timtower thanks so much - so if I replace '(Listener)this' for 'listener', and '(Plugin)this' for 'plugin', that should work?

    Here is the fuller code:

    Code:
    public class main extends JavaPlugin implements Listener
    {
        Logger trackerLogger;
        boolean stopRepeater;
      
        public main() {
            this.trackerLogger = Bukkit.getLogger();
            this.stopRepeater = true;
        }
    
      public void onEnable() {
            Bukkit.getServer().getPluginManager().registerEvents(Listener, Plugin);
            this.trackerLogger.info("HELLO! WELCOME TO THE TRACKER PLUGIN");
            if(!this.getDataFolder().exists())
            {
                this.getDataFolder().mkdir();
            }
        }
      
        public void onDisable() {
            this.trackerLogger.info("SHUTTING DOWN!");
        }
    
    new BukkitRunnable(){
    @Override
    public void run() {
    if (main.this.stopRepeater) {
    main.this.logToFile(thePlayer, thePlayer.getLocation());
           }
         }
      }.runTaskTimer(Plugin, 0, 20)
    
    
     
  10. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 Can't start a runnable outside of a class.
    Can't have a constructor like that in your code.
    Don't need your own logger, just use "getLogger()"
    Can't register using Listener and Plugin, use "this" for both.
    Don't log your own plugins please.
     
  11. Offline

    caledonian26

    @timtower - I would like to log my own plugins so I can store the output for later analysis.

    When you say I don't need my own logger, why is this? :)

    I have now placed a runnable inside the class.

    When you say 'you can't have a constructor like that in your code', which constructor do you mean?

    Code:
    public class main extends JavaPlugin implements Listener
    {
        Logger trackerLogger;
        boolean stopRepeater;
    
        public main() {
            this.trackerLogger = Bukkit.getLogger();
            this.stopRepeater = true;
        }
    
      public void onEnable() {
            Bukkit.getServer().getPluginManager().registerEvents(this, this);
            this.trackerLogger.info("HELLO! WELCOME TO THE TRACKER PLUGIN");
            if(!this.getDataFolder().exists())
            {
                this.getDataFolder().mkdir();
            }
        }
    
        public void onDisable() {
            this.trackerLogger.info("SHUTTING DOWN!");
        }
    
        @EventHandler
        public void onLogin(final PlayerJoinEvent event) {
               new BukkitRunnable(){
                  @Override
                   public void run() {
                            if (main.this.stopRepeater) {
                                        main.this.logToFile(thePlayer, thePlayer.getLocation());
                                     }
                            }
                  }.runTaskTimer(this, 0, 20)
    
    
     
  12. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 You don't need to say that it is starting and shutting down, Bukkit does that for you.
    And you don't need your own logger as every plugin already has one by calling getLogger
     
  13. Offline

    caledonian26

    @timtower thank you for confirming - so the code above should still work? (now that I have made amendments)
     
  14. Offline

    timtower Administrator Administrator Moderator

    Yes, and best way to find out is by trying.
     
  15. Offline

    caledonian26

    Thank you for all your support @timtower! :)

    I have the following code. I am trying to store the coordinates of players on a Minecraft (Java edition) server every second (20 ticks).

    The server is a 'paper' server (hosted externally by Shockbyte), and the code was created using a Bukkit API with the Maven tool and the Java programming language.

    The coordinates will be stored in the file 'saveTo' (i.e., where the data recorded by the plugin is stored).

    Although my code runs fine (with no errors) on eclipse - the software I am using to amend the code - when I try export it as a jar file and then upload it onto my server (in the plugins folder), it doesn't seem to work and I'm not sure why.

    I would be so grateful for a helping hand!

    Code:
    package newestfile.here.newestplugin;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.FileWriter;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    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 java.util.logging.Logger;
    import org.bukkit.event.Listener;
    import org.bukkit.plugin.java.JavaPlugin;
    import org.bukkit.scheduler.BukkitRunnable;
    
    public class Main extends JavaPlugin implements Listener
    {
        Logger trackerLogger;
        boolean stopRepeater;
       
        public Main() {
            this.trackerLogger = Bukkit.getLogger();
            this.stopRepeater = true;
        }
       
        public void onEnable() {
            Bukkit.getServer().getPluginManager().registerEvents(this,this);
            this.trackerLogger.info("HELLO! WELCOME TO THE TRACKER PLUGIN");
            if(!this.getDataFolder().exists())
            {
                this.getDataFolder().mkdir();
            }
        }
       
        public void onDisable() {
            this.trackerLogger.info("SHUTTING DOWN!");
        }
       
        @EventHandler
        public void onLogin(final PlayerJoinEvent event) {
            final Player thePlayer = event.getPlayer();
            this.stopRepeater = true;
            final Location playerSpawnLocation = new Location(thePlayer.getWorld(), (double)thePlayer.getLocation().getBlockX(), (double)thePlayer.getLocation().getBlockY(), (double)thePlayer.getLocation().getBlockZ());
            this.trackerLogger.info(String.valueOf(thePlayer.getPlayer().getName()) + " is logging in!");
            this.trackerLogger.info("Welcome " + thePlayer.getPlayer().getName() + ". Your current position is: " + playerSpawnLocation);
           
            new BukkitRunnable(){
                   public void run() {
                    if (Main.this.stopRepeater) {
                      Main.this.logToFile(thePlayer, thePlayer.getLocation());
                            }
                        }
                   }.runTaskTimer(this, 0, 20);}
       
        @EventHandler
        public void onQuit(final PlayerQuitEvent event) {
            this.stopRepeater = false;
            this.trackerLogger.info(String.valueOf(event.getPlayer().getName()) + " has left the game");
        }
       
        public void logToFile(final Player currentPlayer, final Location playerCurrentLocation) {
            try {
                final File dataFolder = new File(this.getDataFolder() + File.separator + currentPlayer.getPlayer().getName());
                if (!dataFolder.exists()) {
                    dataFolder.mkdir();
                }
                final File saveTo = new File(dataFolder, String.valueOf(currentPlayer.getPlayer().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();
            }
        }
    }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Nov 23, 2022
  16. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 So, here I see a logger.
    Logging lines in the onEnable and onDisable
    A constructor.

    Yet you said you would fix all those things.
    What went wrong?
     
  17. Offline

    caledonian26

    @timtower - do you mean that I can change lines of code containing 'trackerLogger':

    Code:
    this.trackerLogger.info(String.valueOf(event.getPlayer().getName()) + " has left the game");
        }
    To this:

    Code:
    Bukkit.getServer().getLogger().info(String.valueOf(event.getPlayer().getName()) + " has left the game");
        }
    And when you say constructor, are you saying that this constructor can be removed:

    Code:
    public Main() {
    this.trackerLogger = Bukkit.getLogger();
    this.stopRepeater = true;
    }
     
  18. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 Constructor: yes, that can be removed.
    For the logger:
    Code:
    getLogger().info(String.valueOf(event.getPlayer().getName()) + " has left the game");
    That is enough, every plugin has its own logger.
     
  19. Offline

    caledonian26

    Thanks! But then what about 'this.stopRepeater' - if I remove the constructor, I would have to replace this with something else?
     
  20. Offline

    timtower Administrator Administrator Moderator

    Initialize it in the declaration?
     
  21. Offline

    caledonian26

    You mean like this? (I've taken out the logger part as we discussed above)

    Code:
    public class Main extends JavaPlugin implements Listener
    {
        boolean stopRepeater;
       
        public Main() {
     
  22. Offline

    timtower Administrator Administrator Moderator

  23. Offline

    caledonian26

    Sure - so then how should I change this line:

    Code:
    this.stopRepeater = true;
    My code currently looks like this (with errors next to the 'this.stopRepeater' lines:

    Code:
    package newestfile.here.newestplugin;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.FileWriter;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    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 java.util.logging.Logger;
    import org.bukkit.event.Listener;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class Main extends JavaPlugin implements Listener
    {
    
        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);
            Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
                if(this.stopRepeater) {
                    this.logToFile(thePlayer, thePlayer.getLocation());
                }
            }, 0L, 20L);}
      
        @EventHandler
        public void onQuit(final PlayerQuitEvent event) {
            Player thePlayer = event.getPlayer();
            if(!thePlayer.isOnline()) {
                this.stopRepeater = false;
                int taskID = Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
                    if(this.stopRepeater) {
                        this.logToFile(thePlayer, thePlayer.getLocation());
                    }
                }, 0L, 20L);
                Bukkit.getScheduler().cancelTask(taskID);
                getLogger().info(String.valueOf(event.getPlayer().getName()) + " has left the game");
            }
        }
      
        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();
            }
        }
    }
     
  24. Offline

    timtower Administrator Administrator Moderator

    @caledonian26 Why do you remove the
    boolean stopRepeater; line?
     
  25. Offline

    caledonian26

    Yes sorry - I accidentally removed that :) have added it back in. My current code now looks like this (no errors):

    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();
            }
        }
    }
     
  26. Offline

    caledonian26

    @timtower does that code look ok to you? :)
     
  27. Offline

    timtower Administrator Administrator Moderator

    Does it work?

    And as long as these exists, no:
    Code:
    getLogger().info("HELLO! WELCOME TO THE TRACKER PLUGIN");
    getLogger().info("SHUTTING DOWN!");
    
     
  28. Offline

    caledonian26

    Although the code seems to run without any errors, I cannot see a '.log' file in the plugins directory on my server. I would be so grateful for a helping hand! @timtower

    If I remove this, I will not be able to then print a display message on the screen? :)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Dec 5, 2022
  29. Offline

    timtower Administrator Administrator Moderator

    You don't need to either.
    Because everything is in the latest.log, in the logs folder.
     
  30. Offline

    caledonian26

    When I check the latest.log, the coordinates do not seem to be in there.

    Shall I put the 'public void logToFile' part of the code above the 'publicvoid onQuit' part of the code?
     
Thread Status:
Not open for further replies.

Share This Page