Development Assistance Clicks Per Second Plugin

Discussion in 'Plugin Help/Development/Requests' started by tribuns, Jan 22, 2015.

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

    tribuns

    Hey Forums!

    I am currently working on a clicks per second plugin that after starting a countdown, counts the clicks per second of a player. This was a throw together of a bunch of sources, and I just barely got it to work.

    The problem is that my server keeps getting a "Can't keep up" error and doesn't log the clicks. It would also be greatly appreciated if someone could help me with saving the hashmaps to a file.

    I use HashMaps to store the variables.
    Here is my code, listener and onCommand in the same file:

    Code:
    package me.tribunsofdestiny.pvp;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.HashMap;
    import java.util.UUID;
    import java.util.logging.Logger;
    
    import me.tribunsofdestiny.pvp.Permissions;
    
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.Material;
    //import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.Action;
    import org.bukkit.event.player.PlayerInteractEvent;
    import org.bukkit.plugin.PluginDescriptionFile;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class PVP extends JavaPlugin implements CommandExecutor, Listener {
    
        public static Logger logger = Logger.getLogger("Minecraft");
        public static PVP plugin;
    
        HashMap<UUID, Boolean> isReady = new HashMap<UUID, Boolean>();
        HashMap<UUID, Integer> clickCount = new HashMap<UUID, Integer>();
        HashMap<UUID, Double> clickRate = new HashMap<UUID, Double>();
    
        @SuppressWarnings("unchecked")
        @Override
        public void onEnable() {
            PluginDescriptionFile pdffile = getDescription();
            logger.info(pdffile.getName() + " v" + pdffile.getVersion()
                    + " has been enabled!");
            getLogger().info("Make a backup everyday!");
            this.getServer().getPluginManager().registerEvents(this, this);
            saveDefaultConfig();
            updateRates();
    
            File yml = new File(this.getDataFolder().getPath() + File.separator    + "clickRate.yml");
            if (!yml.exists()) {
                try {
                    yml.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                ObjectInputStream input = new ObjectInputStream(
                        new FileInputStream(this.getDataFolder().getPath()
                                + File.separator + "clickRate.yml"));
                clickRate = (HashMap<UUID, Double>) input.readObject();
                input.close();
            } catch (IOException | ClassNotFoundException e) {
                this.getLogger().info(
                        "Error: Something went wrong reading the file");
            }
    
        }
    
        public void onDisable() {
            PluginDescriptionFile pdffile = getDescription();
            logger.info(pdffile.getName() + " has been disabled!");
    
            try {
                ObjectOutputStream output = new ObjectOutputStream(
                        new FileOutputStream(this.getDataFolder().getPath()
                                + File.separator + "clickRate.yml"));
                output.writeObject(clickRate);
                output.close();
            } catch (IOException e) {
                this.getLogger().info("File could not be saved");
            }
        }
    
        public boolean onCommand(CommandSender sender, Command cmd,
                String commandLabel, String[] args) {
            Player player = (Player) sender;
            if (commandLabel.equalsIgnoreCase("pvptest")) {
                cmd.getAliases();
            }
            if (args.length == 0) {
                player.sendMessage(ChatColor.RED
                        + "[PVP] Type /pvptest help for help!");
            }
            if (args.length == 1) {
                if (args[0].equalsIgnoreCase("help")) {
                    player.sendMessage(ChatColor.AQUA
                            + "[PVP] Type '/pvptest start' to start. After the countdown, hit the sign as fast as you can! View your rate by typing '/pvptest rate'!");
                } else if (args[0].equalsIgnoreCase("start")) {
                    if (sender.hasPermission(new Permissions().start)) {
                        try {
                            player.sendMessage(ChatColor.GOLD + "[PVP] Starts in 10 seconds!");
                            Thread.sleep(5000); // 1000 milliseconds is one second.
                        } catch (InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }
                        try {
                            player.sendMessage(ChatColor.GOLD + "[PVP] Starts in 5 seconds!");
                            Thread.sleep(5000); // 1000 milliseconds is one second.
                        } catch (InterruptedException ex) {
                            Thread.currentThread().interrupt();
                        }
                        isReady.remove(player.getUniqueId());
                        isReady.put(player.getUniqueId(), true);
    
                        if (isReady.get(player.getUniqueId())) {
                            player.sendMessage(ChatColor.GREEN + "[PVP] GO!!!");
                            Boolean isReadyB = isReady.get(player.getUniqueId());
                            player.sendMessage(ChatColor.GREEN + "[PVP] isReady is " + isReadyB);
                        }
                    }
                } else if (args[0].equalsIgnoreCase("cps") || args[0].equalsIgnoreCase("rate")) {
                    if (sender.hasPermission(new Permissions().rate)) {
                        @SuppressWarnings("unused")
                        UUID target = player.getUniqueId();
    
                        //double rate = 0;
                        //if (clickRate.get(target) != null) {
                        //    rate = clickRate.get(target);
                        // }
                        player.sendMessage(ChatColor.GOLD + "Your click rate is " + clickRate.get(player.getUniqueId()) + " clicks per second!");
                        return false;
                    }
                }
            }
            return false;
        }
    
        @EventHandler
        public void clickBlock(PlayerInteractEvent e) {
            // this will be called automatically by bukkit whenever a player
            // interacts
            Player player = e.getPlayer();
            if (e.getAction() == (Action.LEFT_CLICK_BLOCK)) {
                Material m = e.getClickedBlock().getType(); // get the block type clicked
                if (m.equals(Material.SIGN) || (m.equals(Material.SIGN_POST))) {
                    if (isReady.get(player.getName())) {
                        int newCount = 1;
                        if (clickCount.get(e.getPlayer().getUniqueId()) != null) {      
                            newCount = newCount    + clickCount.get(e.getPlayer().getUniqueId());
                        }
                        clickCount.put(e.getPlayer().getUniqueId(), newCount);
                    }
                }
            }
        }
        // This method updates the click rate for every online player every 20
        // seconds
        private void updateRates() {
            // We need to schedule a repeating task to do this.
            Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
                public void run() {
                    // We need to perform the code that follows for each online
                    // player.
                    // This is done via an enhanced for-loop
                    for (Player p : Bukkit.getOnlinePlayers()) {
                        // Check whether the player has clicked yet to avoid a
                        // NullPointerExpection
                        if (clickCount.containsKey(p.getUniqueId())) {
                            // Getting their click count. It is required to cast to
                            // a double to get a fractional answer
                            double count = (double) clickCount.get(p.getUniqueId());
    
                            // Divide the count by 20 to get a rate in clicks per
                            // second
                            double rate = count / 20;
    
                            // Put this rate in our clickRate HashMap
                            clickRate.put(p.getUniqueId(), rate);
    
                            // Reset the clickCount to 0
                            clickCount.put(p.getUniqueId(), 0);
                        }
                    }
                }
                // We have an initial delay of 0 seconds, and then the task repeats
                // at an interval of 20 seconds
                // As there are 20 ticks in a second, this can be written as below.
                // I could have done 400L, but this way just makes it easier to read
                // at a glance later on.
            }, 0L, 400L);
        }
    }
    
    Thanks in advance!!
     
  2. Offline

    pie_flavor

    @tribuns You should use runTaskLater() instead of Thread.sleep() as it is safer, and perhaps that is what is causing the problem. Also, in the latest version of Bukkit, Scheduler is deprecated. Use BukkitRunnable and just create the new object, then call the method runTaskTimer on it.
     
  3. Offline

    tribuns

    Ok thanks. By latest version of bukkit, do you mean 1.7.10? I'm using 1.7.9 and it didn't tell me it was deprecated.

    I get null clicks per second. Server still can't keep up. This is my new code:

    Code:
    package me.tribunsofdestiny.pvp;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.util.HashMap;
    import java.util.UUID;
    import java.util.logging.Logger;
    
    import me.tribunsofdestiny.pvp.Permissions;
    
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.Material;
    //import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.Action;
    import org.bukkit.event.player.PlayerInteractEvent;
    import org.bukkit.plugin.PluginDescriptionFile;
    import org.bukkit.plugin.java.JavaPlugin;
    
    public class PVP extends JavaPlugin implements CommandExecutor, Listener {
    
        public static Logger logger = Logger.getLogger("Minecraft");
        public static PVP plugin;
    
        HashMap<UUID, Boolean> isReady = new HashMap<UUID, Boolean>();
        HashMap<UUID, Integer> clickCount = new HashMap<UUID, Integer>();
        HashMap<UUID, Double> clickRate = new HashMap<UUID, Double>();
    
        @SuppressWarnings("unchecked")
        @Override
        public void onEnable() {
            PluginDescriptionFile pdffile = getDescription();
            logger.info(pdffile.getName() + " v" + pdffile.getVersion()
                    + " has been enabled!");
            getLogger().info("Make a backup everyday!");
            this.getServer().getPluginManager().registerEvents(this, this);
            saveDefaultConfig();
            updateRates();
    
            File yml = new File(this.getDataFolder().getPath() + File.separator    + "clickRate.yml");
            if (!yml.exists()) {
                try {
                    yml.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                ObjectInputStream input = new ObjectInputStream(
                        new FileInputStream(this.getDataFolder().getPath()
                                + File.separator + "clickRate.yml"));
                clickRate = (HashMap<UUID, Double>) input.readObject();
                input.close();
            } catch (IOException | ClassNotFoundException e) {
                this.getLogger().info(
                        "Error: Something went wrong reading the file");
            }
    
        }
    
        public void onDisable() {
            PluginDescriptionFile pdffile = getDescription();
            logger.info(pdffile.getName() + " has been disabled!");
    
            try {
                ObjectOutputStream output = new ObjectOutputStream(
                        new FileOutputStream(this.getDataFolder().getPath()
                                + File.separator + "clickRate.yml"));
                output.writeObject(clickRate);
                output.close();
            } catch (IOException e) {
                this.getLogger().info("File could not be saved");
            }
        }
    
        public boolean onCommand(CommandSender sender, Command cmd,
                String commandLabel, String[] args) {
            final Player player = (Player) sender;
            if (commandLabel.equalsIgnoreCase("pvptest")) {
                cmd.getAliases();
            }
            if (args.length == 0) {
                player.sendMessage(ChatColor.RED
                        + "[PVP] Type /pvptest help for help!");
            }
            if (args.length == 1) {
                if (args[0].equalsIgnoreCase("help")) {
                    player.sendMessage(ChatColor.AQUA
                            + "[PVP] Type '/pvptest start' to start. After the countdown, hit the sign as fast as you can! View your rate by typing '/pvptest rate'!");
                } else if (args[0].equalsIgnoreCase("start")) {
                    if (sender.hasPermission(new Permissions().start)) {
                        player.sendMessage(ChatColor.GOLD + "[PVP] Starts in 10 seconds!");
                        Bukkit.getScheduler().runTaskLater(this, new Runnable() {
                            @Override
                            public void run() {
                                player.sendMessage(ChatColor.GOLD + "[PVP] Starts in 5 seconds!");
                            }
                        }, 100L);
                        Bukkit.getScheduler().runTaskLater(this, new Runnable() {
                            @Override
                            public void run() {
                                isReady.remove(player.getUniqueId());
                                isReady.put(player.getUniqueId(), true);
                            }
                        }, 100L);
    
                        if (isReady.get(player.getUniqueId())) {
                            player.sendMessage(ChatColor.GREEN + "[PVP] GO!!!");
                            Boolean isReadyB = isReady.get(player.getUniqueId());
                            player.sendMessage(ChatColor.GREEN + "[PVP] isReady is " + isReadyB);
                        }
                    }
                } else if (args[0].equalsIgnoreCase("cps") || args[0].equalsIgnoreCase("rate")) {
                    if (sender.hasPermission(new Permissions().rate)) {
                        @SuppressWarnings("unused")
                        UUID target = player.getUniqueId();
    
                        //double rate = 0;
                        //if (clickRate.get(target) != null) {
                        //    rate = clickRate.get(target);
                        // }
                        player.sendMessage(ChatColor.GOLD + "Your click rate is " + clickRate.get(player.getUniqueId()) + " clicks per second!");
                        return false;
                    }
                }
            }
            return false;
        }
    
        @EventHandler
        public void clickBlock(PlayerInteractEvent e) {
            // this will be called automatically by bukkit whenever a player
            // interacts
            Player player = e.getPlayer();
            if (e.getAction() == (Action.LEFT_CLICK_BLOCK)) {
                Material m = e.getClickedBlock().getType(); // get the block type clicked
                if (m.equals(Material.SIGN) || (m.equals(Material.SIGN_POST))) {
                    if (isReady.get(player.getName())) {
                        int newCount = 1;
                        // We check whether the player has clicked yet (i.e. whether their
                        // click count is null or not)
                        if (clickCount.get(e.getPlayer().getUniqueId()) != null) {
                            // If it is not null, we add this to their newCount
                            newCount = newCount    + clickCount.get(e.getPlayer().getUniqueId());
                        }
                        // We set their clickCount to their newCount in the HashMap
                        clickCount.put(e.getPlayer().getUniqueId(), newCount);
                    }
                }
            }
        }
        // This method updates the click rate for every online player every 20
        // seconds
        private void updateRates() {
            // We need to schedule a repeating task to do this.
            Bukkit.getScheduler().runTaskTimer(this, new Runnable() {
                public void run() {
                    // We need to perform the code that follows for each online
                    // player.
                    // This is done via an enhanced for-loop
                    for (Player p : Bukkit.getOnlinePlayers()) {
                        // Check whether the player has clicked yet to avoid a
                        // NullPointerExpection
                        if (clickCount.containsKey(p.getUniqueId())) {
                            // Getting their click count. It is required to cast to
                            // a double to get a fractional answer
                            double count = (double) clickCount.get(p.getUniqueId());
    
                            // Divide the count by 20 to get a rate in clicks per
                            // second
                            double rate = count / 20;
    
                            // Put this rate in our clickRate HashMap
                            clickRate.put(p.getUniqueId(), rate);
    
                            // Reset the clickCount to 0
                            clickCount.put(p.getUniqueId(), 0);
                        }
                    }
                }
                // We have an initial delay of 0 seconds, and then the task repeats
                // at an interval of 20 seconds
                // As there are 20 ticks in a second, this can be written as below.
                // I could have done 400L, but this way just makes it easier to read
                // at a glance later on.
            }, 0L, 400L);
        }
    
    
    }
    
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 13, 2016
  4. Offline

    teej107

    @tribuns
    1. Don't ever sleep the server. It will make the server lag.
    2. Delete all of your code and start from scratch. BZBroz is a bad tutorial to learn from and/or throwing a bunch of code together from sources (that are terrible) is not good either.
    3. Knowledge of Java is a requirement to develop Bukkit plugins.
    Here is how to achieve clicks-per-second
    1. Create a Map with Player (something to represent one) as key and a Collection (Set/List, etc) as the value.
    2. That Collection will contain long values taken from the system's time.
    3. When a player performs a click, add the System's current time to the Collection.
    4. When you want to calculate the clicks per second, average the long values in the Collection.
    5. You may create a separate class with a Collection and the methods to add values and to calculate the average in place of using a Collection as the value in the Map as said in step 1.
     
  5. Offline

    pie_flavor

  6. Offline

    tribuns

    Ok, thanks for the starting tips.
     
Thread Status:
Not open for further replies.

Share This Page