Solved Run BukkitRunnable onDisable

Discussion in 'Plugin Development' started by xDeeKay, Jan 14, 2015.

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

    xDeeKay

    This issue has been bugging me for a few days now. I've got a few BukkitRunnable classes to handle MySQL queries and writing data to the database on a PlayerQuitEvent. The problem is, a server restart doesn't fire the PlayerQuitEvent or PlayerKickEvent (like I previously presumed it would).

    Simply running the scheduler on onDisable doesn't seem to work, and throws me: IllegalPluginAccessException: Plugin attempted to register task while disabled

    There was a thread made about this today, but it didn't seem to answer my question specifically. Here's the thread: http://bukkit.org/threads/playerquitevent-on-server-shutdown.335287/

    Here's an example of my BukkitRunnable classes:
    Code:
    package net.dkcraft.opticore.listeners.stats;
    
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    import net.dkcraft.opticore.Main;
    
    import org.bukkit.Bukkit;
    import org.bukkit.scheduler.BukkitRunnable;
    
    public class BlockPlaceHandler extends BukkitRunnable {
    
        private final Main plugin;
    
        public BlockPlaceHandler(Main instance, String playerName, String uuid) {
            this.plugin = instance;
            this.playerName = playerName;
            this.uuid = uuid;
        }
       
        private String playerName;
        private String uuid;
    
        @Override
        public void run() {
            if (plugin.playerDataContainsUUID(uuid)) {
                if (Main.statsBlockPlace.containsKey(playerName) && Main.statsBlockPlace.get(playerName) != 0) {
                    try {
                        int previousBlocksPlaced = 0;
    
                        PreparedStatement sql = Main.connection
                                .prepareStatement("SELECT blocks_placed FROM `player_stats` WHERE uuid=?;");
                        sql.setString(1, uuid);
    
                        ResultSet result = sql.executeQuery();
                        result.next();
    
                        previousBlocksPlaced = result.getInt("blocks_placed");
    
                        PreparedStatement placedUpdate = Main.connection
                                .prepareStatement("UPDATE `player_stats` SET blocks_placed=? WHERE uuid=?;");
                        placedUpdate.setInt(1, previousBlocksPlaced + Main.statsBlockPlace.get(playerName));
                        placedUpdate.setString(2, uuid);
                        placedUpdate.executeUpdate();
    
                        placedUpdate.close();
                        sql.close();
                        result.close();
    
                        Bukkit.getConsoleSender().sendMessage("Writing " + Main.statsBlockPlace.get(playerName) + " blocks to " + playerName + "'s data");
    
                        Main.statsBlockPlace.remove(playerName);
                        Bukkit.getConsoleSender().sendMessage("Removing BlockPlace Hashmap for " + playerName);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    Main.statsBlockPlace.remove(playerName);
                    Bukkit.getConsoleSender().sendMessage("Removing BlockPlace Hashmap for " + playerName);
                }
            }
        }
    }
    Here's what I run on a PlayerQuitEvent, and what I tried to use on onDisable (with no luck)
    Code:
    new BlockPlaceHandler(this.plugin, playerName, uuid).runTaskAsynchronously(this.plugin);
    Here's the attempted onDisable:
    Code:
        public void onDisable() {
            new BlockPlaceHandler(this, playerName, uuid).runTaskAsynchronously(this);
    
            try {
                if (connection != null && !connection.isClosed())
                    closeConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    So, how can I run such scheduler on onDisable to ensure all data is written?
     
  2. Offline

    timtower Administrator Administrator Moderator

    @xDeeKay Just do it in the onDisable itself without using a runnable for that. There are no players to notice it anyways.
     
  3. Offline

    xDeeKay

    @timtower How do I run it on onDisable without directly using the runnable class? That's why I made the classes, so I could simply call the runnable in any place I needed. Unless I'm missing something?
     
  4. Offline

    timtower Administrator Administrator Moderator

    @xDeeKay
    new BlockPlaceHandler(this, playerName, uuid).run()
     
  5. Baring in mind that this will be running on the main thread, which for shutdown won't necessarily be a problem, but it will be if your plugin is disabled when not shutting down.
     
  6. Offline

    xDeeKay

    @timtower No errors this time, but it didn't seem to be run either.
     
  7. Offline

    timtower Administrator Administrator Moderator

    @AdamQpzm I am fully aware of that.
    @xDeeKay Where do the playername and uuid coming from?
     
  8. timtower likes this.
  9. Offline

    xDeeKay

    Thanks @AdamQpzm, I will definitely keep that in mind.
    @timtower Variables in the Main class for playerName and uuid.
     
  10. Offline

    timtower Administrator Administrator Moderator

    @xDeeKay Why do you have fields in the main class instead of in a list? Now you can only save 1 person
     
  11. Offline

    xDeeKay

    @timtower I'm unsure as to how that works, do you mean to loop through online players?
     
  12. Offline

    timtower Administrator Administrator Moderator

  13. Offline

    xDeeKay

    @timtower Would that work in the onDisable though? Wouldn't there technically be no players online once onDisable is run?
     
  14. Offline

    timtower Administrator Administrator Moderator

  15. Offline

    xDeeKay

    @timtower But what about stopping the server? That's when I need the data to be saved.
     
  16. Offline

    timtower Administrator Administrator Moderator

    @xDeeKay Then you get a hashmap with all the storage.
     
  17. Offline

    xDeeKay

  18. Offline

    timtower Administrator Administrator Moderator

    @xDeeKay Make a hashmap with uuid and blocks broken ( or what kind of data you store )
    Then you can save that asynch always ( on a timer or something )
    And you can save it onDisable.
     
  19. Offline

    xDeeKay

    @timtower I'm already storing blocks broken and blocks placed in their own hashmaps, and a scheduler class is writing that data on a PlayerQuitEvent (examples are in the original post). The issue is I can't run the class onDisable like I can on the PlayerQuitEvent.
     
  20. Offline

    timtower Administrator Administrator Moderator

    @xDeeKay You can call the run method directly instead of with run later
     
  21. Offline

    Lolmewn

  22. Offline

    xDeeKay

    @Lolmewn Thanks, I'll take a look. I thought storing the info in hashmaps would save me a lot of time and trouble, but now I've hit this problem of not being able to write any of the stored info to the database because of server stops.

    It would be nice if the PlayerQuitEvent or PlayerKickEvent were fired when players are disconnected, that would make things so much simpler.

    @timtower I've already got that there, I'm just unsure how to actually run it properly on onDisable and how to get the player names. For example, the PlayerQuitEvent is obviously fired when a player quits, and gets their name that way, but not on onDisable.
     
    Last edited: Jan 15, 2015
Thread Status:
Not open for further replies.

Share This Page