UtilCooldown class

Discussion in 'Spigot Plugin Development' started by cocoraid, May 31, 2015.

?

Useful?

  1. Yeaaah

    30.0%
  2. Not really :(

    70.0%
  1. Hello everyone,

    I want to show you a different way to do cooldowns..
    I have seen many things not very professional and I want to show you something better:


    at first as this is the class util:


    Code (Text):

    private static HashMap<UUID, Long> cooldown = new HashMap<>();

       public static void setCooldown(Player p) {
         cooldown.put(p.getUniqueId(), System.currentTimeMillis());
       }

       public static boolean hasCooldown(Player p) {
         return cooldown.containsKey(p.getUniqueId());
       }

       public static void removeCooldown(Player p) {
         cooldown.remove(p.getUniqueId());
       }

    public static long getTime(Player p,  int time) {
            if(hasCooldown(p))
                return 0L;
            long x  = ((cooldown.get(p.getUniqueId()) /1000) + time) - (System.currentTimeMillis()/100);
            if(x == 0)
                cooldown.remove(p.getUniqueId());
            return x;
        }
     
    Now it must be used !

    Code (Text):
    public void playCooldown(Player p, int cooldownTime) {
            //To start without cooldown
            if(cooldownTime > 0) {
                //to remove the player if the cooldown is done
                if(UtilCooldown.hasCooldown(p)) {
                    if(UtilCooldown.getTime(p, cooldownTime) == 0) {
                        UtilCooldown.removeCooldown(p);
                    }
                }
                if(!UtilCooldown.hasCooldown(p)) {
                    UtilCooldown.setCooldown(p);
                    //Start here -->
                    p.playSound(p.getLocation(), Sound.LEVEL_UP,1, 1);
                } else {
                    //Display cooldown second or seconds ?
                    String s = (UtilCooldown.getTime(p, cooldownTime) == 1) ? "second" : "seconds";
                    if(UtilCooldown.getTime(p, cooldownTime) > 0) {
                        p.sendMessage(UtilCooldown.getTime(p cooldownTime) + s + "left");
                    }
                }
            } else {
                //Start here --> instant start
                p.playSound(p.getLocation(), Sound.LEVEL_UP,1, 1);
            }
        }
    Now the problem of this is that you can only save one cooldow per player, to correct this you can simply create a double hashmap :

    this is an example, you can save something other than a class

    Code (Text):
        private static HashMap<UUID, HashMap<Class<?>, Long>> cooldown = new HashMap<>();

        public static void setCooldown(Player p ,Class<?> gadget) {
            if(!cooldown.containsKey(p.getUniqueId())) {
                HashMap<Class<?>, Long> cooldown2 = new HashMap<>();
                cooldown2.put(gadget, System.currentTimeMillis());
                cooldown.put(p.getUniqueId(), cooldown2);
            } else {
                cooldown.get(p.getUniqueId()).put(gadget, System.currentTimeMillis());
            }
        }

        public static boolean hasCooldown(Player p,Class<?> gadget) {
            if(cooldown.containsKey(p.getUniqueId())) { return true; }
            else {
                return cooldown.get(p.getUniqueId()).containsKey(gadget));
                }
        }

        public static void removeCooldown(Player p, Class<?> gadget) {
            cooldown.get(p.getUniqueId()).remove(gadget);
        }

        public static long getTime(Player p, Class<?> gadget, int time) {
            long stat = 0;
            if(hasCooldown(p, gadget)) {
                stat = ((cooldown.get(p.getUniqueId()).get(gadget) /1000) + time) - (System.currentTimeMillis()/1000);
                if(stat < 0) {
                    cooldown.get(p.getUniqueId()).remove(gadget);
                }
            }
            return stat;
        }
    Happy coding !
     
    #1 cocoraid, May 31, 2015
    Last edited: May 31, 2015
  2. Advice: Don't write tutorials when you can't really code yourself.
    A more acceptable code snippet of what you're trying todo:
    Code (Text):

        public static void setCooldown(Player p) {
            cooldown.put(p.getUniqueId(), System.currentTimeMillis());
        }

        public static void removeCooldown(Player p) {
            cooldown.remove(p.getUniqueId());
        }

        @Deprecated
        public static boolean hasCooldown(Player p) {
            return cooldown.containsKey(p.getUniqueId());
        }

        public static long getTime(Player p,  int time) {
            if(hasCooldown(p))
                return 0L;
            long x  = ((cooldown.get(p.getUniqueId()) /1000) + time) - (System.currentTimeMillis()/100);
            if(x == 0)
                cooldown.remove(p.getUniqueId());
            return x;
        }
     
    Also, 5 intervals = 6 intervals according to your code.
     
    • Winner Winner x 1
  3. Thank you I am also here to improve myself
     
  4. It's an okay start...I guess...probably.
     
  5. ?
     
  6. The static abuse hurt my eyes. Don't use static for lazy access!
     
    • Funny Funny x 1
  7. It's going to be very useful for kitpvp plugins :D
     
    • Like Like x 1
  8. why have invented the static then?
    I can transform the class object but hey it's not great to use

    Code (Text):

    package yourpackage;

    import java.util.HashMap;
    import java.util.UUID;

    import org.bukkit.entity.Player;

    public class Cooldown {


       private HashMap<UUID, Long> cooldown = new HashMap<>();
       Player p;
       int time;

       public Cooldown(Player p, int time) {
         this.p = p;
         this.time = time;
         cooldown.put(p.getUniqueId(), System.currentTimeMillis());
       }

       public boolean hasCooldown() {
         return cooldown.containsKey(p.getUniqueId());
       }

       public void removeCooldown() {
         cooldown.remove(p.getUniqueId());
       }

       public long getTime() {
         if(hasCooldown())
           return 0L;
         long x  = ((cooldown.get(p.getUniqueId()) /1000) + time) - (System.currentTimeMillis()/100);
         if(x == 0)
           cooldown.remove(p.getUniqueId());
         return x;
       }

    }
     
    Cooldown c = new Cooldown(p, 10);
     
    #8 cocoraid, May 31, 2015
    Last edited: May 31, 2015
  9. To bind data to a type rather than an object. Without static you could create multiple cooldowns, and people could extend them and decorate them (decorator design pattern).
     
    • Agree Agree x 2
    • Winner Winner x 1
  10. Hey could you please send me a version that allows the anti-perm for OPS. So like ops can not have access to certain gadgets. This is for my Free-OP server. thanks!
    I also bought the plugin.
    skype --> mcluz1fer
     
  11. I have dealt with cooldowns a bit too, so here are my findings (just suggestions no hate):

    There is a potential memory leak here. Because you add players to the map, but you are not guaranteed they will be removed. Say you use this for an right-click ability, when they use it they are added to the map but never removed. (When they use it again while on cooldown they obviously stay in the map, and when they use it when the cooldown is over they are added again anyway. )

    For some plugins I use similar cooldowns quite a bit, and I have one async 'cleanup' task running every once in a while to remove old entries, shared for all cooldown instances. Maybe not the cleanest solution either but it handles the memory and its still far better than a separate task per entry.

    An other suggestion; currently you store the start time of the cooldown. If you store the end time instead, you can have different a duration per player in the same map. (based on level ect.)

    Would you like me to share my cooldown classes?
     
    • Useful Useful x 1
  12. You are right down the line !

    It would be great for the community if you will share your method, thank you Flamedek
     
  13. Store on quit & remove from Map, clean up on join.
     
  14. Then people can just relog to reset their cooldown.
     
  15. You are doing it wrong then.
     
  16. Or with store you mean save in a file? Then it works and it saves over restarts, but I mean.. then it's just more effort all around, and you ideally still need an async task to not do IO on the main thread.
    It all depends on use-case I suppose (as always really):
    For very long cooldowns that would be best, but for your average ability or other short cooldowns I don't think it will be any better