How to reset a thread.sleep cooldown

Discussion in 'Plugin Development' started by tizrain, Sep 11, 2015.

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

    tizrain

    Hello. I've recently coded a combatlog system and it works like a charm, but I'm not sure how to code so when you get hit again it resets the cooldown back to it's original time.

    My code:

    Code:
    package at.craftopia.theepicex.event.player;
    
    import java.util.ArrayList;
    
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityDamageByEntityEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.inventory.ItemStack;
    
    import at.craftopia.theepicex.Arrays;
    import at.craftopia.theepicex.Main;
    
    public class CombatLog implements Listener {
       
        private Main plugin;
    
        public ArrayList<Player> combatLogged = (new Arrays().combatLogged);
       
        public CombatLog(Main instance) {
           
            plugin = instance;
        }
       
        @SuppressWarnings("deprecation")
        @EventHandler (priority = EventPriority.NORMAL)
        public void onPlayerDamage(EntityDamageByEntityEvent e) {
            if (((e.getDamager() instanceof Player) && (e.getEntity() instanceof Player))) {
                final Player p = (Player) e.getEntity();
                final Player t = (Player) e.getDamager();
               
                if ((!combatLogged.contains(p)) && (!combatLogged.contains(t))) {
                    combatLogged.add(p);
                    combatLogged.add(t);
                    p.sendMessage(plugin.getConfig().getString("messages.combatlog").replaceAll("&", "§").replaceAll("%player%", t.getDisplayName()));
                    t.sendMessage(plugin.getConfig().getString("messages.combatlog").replaceAll("&", "§").replaceAll("%player%", p.getDisplayName()));
                   
                    Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin,
                    new Runnable() {
                        public void run() {
                            int combatLog = plugin.getConfig().getInt("combatlogged");
                            try {
                                Thread.sleep(combatLog * 1000);
                                if ((combatLogged.contains(p)) && (combatLogged.contains(t))) {
                                    combatLogged.remove(p);
                                    combatLogged.remove(t);
                                    t.sendMessage(ChatColor.GREEN + "You can now log out safely.");
                                    p.sendMessage(ChatColor.GREEN + "You can now log out safely.");
                                }
                            } catch (Exception ignored) { }
                        }
                    });
                }
            }
        }
       
        @EventHandler (priority = EventPriority.NORMAL)
        public void onPlayerQuit(PlayerQuitEvent e) {
            Player p = e.getPlayer();
            if (combatLogged.contains(p)) {
                if (plugin.getConfig().getBoolean("broadcastcombatlog") == true) {
                    Bukkit.broadcastMessage(plugin.getConfig().getString("messages.broadcastcombatlog").replaceAll("&", "§").replaceAll("%player%", p.getDisplayName()));
                }
                for (ItemStack i : p.getInventory().getContents()) {
                    if (i != null) {
                        p.getWorld().dropItemNaturally(p.getLocation(), i);
                        p.getInventory().remove(i);
                    }
                }
            }
        }
    }
    
    (Made sure to give you the whole class if anything u need otherwise would be missing). Thanks in advance.
     
  2. Offline

    Gamesareme

    @tizrain Hmm, not sure that is the best use of Thread sleeps.
    I would recommend that you use a HashMap, and store the player unique id and the time he has remaning in combate. Then in your runable keep taking from the players time in the hashmap, until it is 0 or smaller. If the player enters into combate after the count down has started just keep resetting the players number in the HashMap.

    Something like this.

    Code:
    @Override
                public void run() {
                    if(hashmap.get(player id) > 0){
                         hashmap get player remove 1;
                     }else{
                          cancle in combate the time has run out;
                     }
    
                }
            }.runTaskLater(this.plugin, 20);//This will run once every secon so all you need to do is add a number into the hashma the corilates to the amount of time you want to the player to be in comabte for.
    then if the player enters comabate just reset the number in the hashmap.
     
  3. Offline

    tizrain

    @Gamesareme I'm not as familiar in using Hashmaps as I am with using Arrays. But I do consider learning it since I know it's easier and better once you've got a hang of it. But there is no specific way in using it with the code I have now?
     
  4. Offline

    mythbusterma

    @tizrain

    Never ever sleep the thread in a Bukkit plugin. There is NO reason to do it.

    Use scheduled tasks instead. Don't use the word "aysnc" unless you actually know what you're doing (i.e. can define "visibility" and "atomicity" as they refer concurrency).

    Arrays (even though you meant "ArrayList" [which is extremely different]) and Maps serve completely different purposes. Arrays (and Lists) are used to store an ordered set of values. Maps are used to associate one value with another (this is the equivalent of a "dictionary" in other languages). For posterity's sake, Sets are used to store an unordered grouping of values.

    Also, don't save references to Players in Collections unless you're absolutely 100% certain they will be removed. You will leak memory otherwise.

    As for the reason you should use a Map, you can create a Map that associates UUIDs and Longs, then store in the Map the last time (in milliseconds) the player PVP'd. When they log out, check for them in the Map, seeing if a certain amount of time has elapsed.

    If you want to show them a message, schedule a task that runs every few seconds that checks the contents of the Map, seeing if there are any players that should be shown a message and removed from the Map.
     
    DoggyCode™, bwfcwalshy and rbrick like this.
  5. Offline

    tizrain

    @mythbusterma I actually got the thread.sleep part from a tutorial I was watching. But the creator of the tutorial may be as wrong as me. I'm not very skilled in Java coding and I'm just creating this plugin for a friends server, which doesn't require too much things in it. Though I'm not very sure how to rearrange my code to make this work, based on what you explained to me.
     
  6. Offline

    mythbusterma

    @tizrain

    That's fine, some tutorials are quite awful.

    So the idea is that you know the last time they where hit, when they leave, check to see if it's been long enough.
     
  7. Offline

    tizrain

    @mythbusterna and the easiest way to do this is checking if they're in a HashMap?
     
  8. Offline

    mythbusterma

    @tizrain

    And then checking if the time since they were hit has been long enough.
     
  9. Offline

    tizrain

    @mythbusterna Here's my code so far. Now I'm kind of stuck though :/

    Code:
    package at.craftopia.theepicex.event.player;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.UUID;
    
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityDamageByEntityEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.inventory.ItemStack;
    
    import at.craftopia.theepicex.Main;
    
    public class CombatLog implements Listener {
     
        private Main plugin;
    
        public HashMap<UUID, ArrayList<Player>> combatLogged = new HashMap<UUID, ArrayList<Player>>();
     
        public CombatLog(Main instance) {
         
            plugin = instance;
        }
     
        @SuppressWarnings("deprecation")
        @EventHandler (priority = EventPriority.NORMAL)
        public void onPlayerDamage(EntityDamageByEntityEvent e) {
            if (((e.getDamager() instanceof Player) && (e.getEntity() instanceof Player))) {
                final Player p = (Player) e.getEntity();
                final Player t = (Player) e.getDamager();
             
                if ((!combatLogged.containsKey(p.getUniqueId())) && (!combatLogged.containsKey(t.getUniqueId()))) {
                    combatLogged.put(p.getUniqueId(), null);
                    combatLogged.put(t.getUniqueId(), null);
                    p.sendMessage(plugin.getConfig().getString("messages.combatlog").replaceAll("&", "§").replaceAll("%player%", t.getDisplayName()));
                    t.sendMessage(plugin.getConfig().getString("messages.combatlog").replaceAll("&", "§").replaceAll("%player%", p.getDisplayName()));
                 
                    Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin,
                    new Runnable() {
                        public void run() {
                            int combatLog = plugin.getConfig().getInt("combatlogged");
                            try {
                                Thread.sleep(combatLog * 1000);
                                if ((combatLogged.containsKey(p.getUniqueId())) && (combatLogged.containsKey(t.getUniqueId()))) {
                                    combatLogged.remove(p);
                                    combatLogged.remove(t);
                                    t.sendMessage(ChatColor.GREEN + "You can now log out safely.");
                                    p.sendMessage(ChatColor.GREEN + "You can now log out safely.");
                                }
                            } catch (Exception ignored) { }
                        }
                    });
                }
            }
        }
     
        @EventHandler (priority = EventPriority.NORMAL)
        public void onPlayerQuit(PlayerQuitEvent e) {
            Player p = e.getPlayer();
            if (combatLogged.containsKey(p.getUniqueId())) {
                if (plugin.getConfig().getBoolean("broadcastcombatlog") == true) {
                    Bukkit.broadcastMessage(plugin.getConfig().getString("messages.broadcastcombatlog").replaceAll("&", "§").replaceAll("%player%", p.getDisplayName()));
                }
                for (ItemStack i : p.getInventory().getContents()) {
                    if (i != null) {
                        p.getWorld().dropItemNaturally(p.getLocation(), i);
                        p.getInventory().remove(i);
                    }
                }
            }
        }
    }
    EDIT

    I don't know how I shall change the thread.sleep. What is the best to change to?
     
  10. Offline

    mythbusterma

    @tizrain

    Why do you associate UUIDs with a List of Players? That really doesn't make sense....re-read my post and try again.
     
  11. Offline

    tizrain

    @mythbusterna Should the List be associated with a Long? I'm trying to do this but then the combatLogged.put(UUID, long); doesn't work since Long and long isn't the same according to Java?
     
  12. Offline

    mythbusterma

    @tizrain

    It will automatically perform "boxing" for you so that you can store the long in the Collection. It's the reason the "Long" type was added to the language.
     
  13. Offline

    tizrain

    @mythbusterna
    I have updated the HashMap and the put methods. (Note that I haven't cleaned up the code just yet)

    Code:
    package at.craftopia.theepicex.event.player;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.UUID;
    
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityDamageByEntityEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.inventory.ItemStack;
    
    import at.craftopia.theepicex.Main;
    
    public class CombatLog implements Listener {
      
        private Main plugin;
    
        public HashMap<UUID, ArrayList<Long>> combatLogged = new HashMap<UUID, ArrayList<Long>>();
      
        public CombatLog(Main instance) {
          
            plugin = instance;
        }
      
        @SuppressWarnings("deprecation")
        @EventHandler (priority = EventPriority.NORMAL)
        public void onPlayerDamage(EntityDamageByEntityEvent e) {
          
            if (((e.getDamager() instanceof Player) && (e.getEntity() instanceof Player))) {
                final Player p = (Player) e.getEntity();
                final Player t = (Player) e.getDamager();
              
                if ((!combatLogged.containsKey(p.getUniqueId())) && (!combatLogged.containsKey(t.getUniqueId()))) {
                    combatLogged.put(p.getUniqueId(), null);
                    combatLogged.put(t.getUniqueId(), null);
                    p.sendMessage(plugin.getConfig().getString("messages.combatlog").replaceAll("&", "§").replaceAll("%player%", t.getDisplayName()));
                    t.sendMessage(plugin.getConfig().getString("messages.combatlog").replaceAll("&", "§").replaceAll("%player%", p.getDisplayName()));
                  
                    Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin,
                    new Runnable() {
                        public void run() {
                            int combatLog = plugin.getConfig().getInt("combatlogged");
                            try {
                                Thread.sleep(combatLog * 1000);
                                if ((combatLogged.containsKey(p.getUniqueId())) && (combatLogged.containsKey(t.getUniqueId()))) {
                                    combatLogged.remove(p.getUniqueId());
                                    combatLogged.remove(t.getUniqueId());
                                    t.sendMessage(ChatColor.GREEN + "You can now log out safely.");
                                    p.sendMessage(ChatColor.GREEN + "You can now log out safely.");
                                }
                            } catch (Exception ignored) { }
                        }
                    });
                }
            }
        }
      
        @EventHandler (priority = EventPriority.NORMAL)
        public void onPlayerQuit(PlayerQuitEvent e) {
            Player p = e.getPlayer();
            if (combatLogged.containsKey(p.getUniqueId())) {
                if (plugin.getConfig().getBoolean("broadcastcombatlog") == true) {
                    Bukkit.broadcastMessage(plugin.getConfig().getString("messages.broadcastcombatlog").replaceAll("&", "§").replaceAll("%player%", p.getDisplayName()));
                }
                for (ItemStack i : p.getInventory().getContents()) {
                    if (i != null) {
                        p.getWorld().dropItemNaturally(p.getLocation(), i);
                        p.getInventory().remove(i);
                    }
                }
            }
        }
    }
    
     
  14. Offline

    mythbusterma

    @tizrain

    You haven't changed the type of your HashMap. And you're putting "null" into the HashMap (which will do nothing).
     
  15. Offline

    tizrain

    @mythbusterma The null was added intentionally for now until I get a hold of what I shall place there. The type of my HashMap. Should that be Player, as I intended to have it in the beginning, and then call directly to getUniqueId through that class?

    It would be easier if you would show me a simple example of the idea to help me finish this
     
  16. Offline

    mythbusterma

    @tizrain

    HashMap<UUID, Long>. You're storing the last time the player was hit. The time. Time is a Long.
     
  17. Offline

    tizrain

    @mythbusterma sorry for the lack of understanding. I've fixed the hashmap and it works like a charm. Now it's just the part where I make the long a timer

    You told me something about using scheduled tasks. When I did this and not the Async scheduled tasks I got strange results. The targeted player could not log out/be hit or anything else during the time I have set in the config?
     
  18. Offline

    Gamesareme

  19. Offline

    mythbusterma

    @tizrain

    Because you were freezing the server with the Thread.sleep. That's what that does.
     
  20. Offline

    tizrain

    @mythbusterma and @Gamesareme thanks for helping me with this. One last question though. Should I use runtasklater or runtasktimer? if it's runtasktimer, what do I add at the second long, since the first long probably is my timer?

    @mythbusterma @Gamesareme I found out how to do it. Thanks for helping me understand this. Have a good night :)

    <Edited by bwfcwalshy: Merged posts, please use the edit button rather than double posting.>
     
    Last edited by a moderator: Sep 12, 2015
  21. Offline

    DoggyCode™

    Thread sleep... very bad idea.
     
  22. Offline

    tizrain

    Yea I figured out how to do it in a better way. :)
     
  23. Offline

    DoggyCode™

    Well, if you read the above comments there are some very good suggestions. Like the storing in maps and stuff.

    Btw, thread.sleep makes your server like stop functioning for a amount of time. So NEVER use it. It's like every time a player would have a kit cool down before using it again the server would like kind of lag throughout that whole time, plus. Anyways, hash is a bad idea for kit cool down as well because as said above, will leak memory

    And btw, don't use String#replaceAll("&","..."), that's just stupid. Use:
    ChatColor.translateAlternateColorCodes('&', String#);

    And btw, EDIT by Timtower: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Sep 13, 2015
  24. Offline

    boomboompower

    Using sleep pauses the server.
     
Thread Status:
Not open for further replies.

Share This Page