Need help with hashmaps

Discussion in 'Plugin Development' started by PikaThieme, Feb 5, 2017.

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

    PikaThieme

    I'm trying to make that (for example) like every second the score of a player gets increased by 5.
    But I got an error...
    AND that if a score is higher than 100 they will get a message or something.

    Code:java
    1.  
    2. package com.pikathieme.dhd;
    3.  
    4. import java.util.HashMap;
    5.  
    6. import org.bukkit.Bukkit;
    7. import org.bukkit.entity.Player;
    8. import org.bukkit.event.player.AsyncPlayerChatEvent;
    9. import org.bukkit.plugin.java.JavaPlugin;
    10.  
    11. public class Main extends JavaPlugin {
    12. HashMap<String, Integer> time = new HashMap<>();
    13.  
    14. public void onPlayer(AsyncPlayerChatEvent e) {
    15. Player player = e.getPlayer();
    16. if (time.get(player.getName()) > 100 {
    17. Bukkit.broadcastMessage("hai");
    18. }
    19. }
    20.  
    21. public void onEnable() {
    22. Bukkit.getPluginManager().registerEvents(new Ranks(), this);
    23. int id = Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
    24. public void run() {
    25. for (Player all : Bukkit.getOnlinePlayers()) {
    26. if (all == null) {
    27. return;
    28. } else {
    29. time.put(all.getName(), time.get(all.getName()) + 10);
    30. }
    31. }
    32. }
    33. }, 0, 12);
    34. }
    35.  
    36. public void onDisable() {
    37.  
    38. }
    39. }
     
  2. Online

    timtower Administrator Administrator Moderator

    Moved to plugin development.
    @PikaThieme Please check if you are posting in "BukkitDev Information and Feedback" or "Plugin development"
    And your event doesn't has @EventHandler, nor is it registered.
     
  3. Offline

    Drkmaster83

    Code doesn't compile, missing parenthesis in the onPlayer method. Why not put whatever you're trying to do in the chat method in the scheduled repeating task?... (Also, using playernames to store data is discouraged, if you care, use UUIDs instead). Also, your onPlayer method isn't registered, isn't using EventHandler, and your main class isn't implementing the Listener interface regardless. Also, you got an "error" or it just wouldn't work or do anything?
     
  4. Offline

    JanTuck

    Excuse me where is your plugin instance?
     
  5. Offline

    Drkmaster83

    ...? It's PluginManager#registerEvents(Listener, Plugin)
     
  6. Offline

    JanTuck

    In my country it was morning and i read that line go into another line my bad. xD
     
    Rayzr522 likes this.
  7. Offline

    PikaThieme

    @JanTuck , @Drkmaster83 I recreated it but I still don't know how to test if the uuid score of a player is < than the variable. If the score of a player (the "time") is over hundred and under 200 they should get once a message like; "you're playing ... minutes on the server right now"

    Btw; thanks for all replies :)

    Code:java
    1.  
    2. package com.pikathieme.cheese;
    3.  
    4. import java.util.HashMap;
    5. import java.util.UUID;
    6.  
    7. import org.bukkit.Bukkit;
    8. import org.bukkit.entity.Player;
    9. import org.bukkit.event.EventHandler;
    10. import org.bukkit.event.Listener;
    11. import org.bukkit.event.player.AsyncPlayerChatEvent;
    12. import org.bukkit.event.player.PlayerJoinEvent;
    13. import org.bukkit.plugin.Plugin;
    14.  
    15. import net.md_5.bungee.api.ChatColor;
    16.  
    17. public class Ranks implements Listener {
    18.  
    19. HashMap<String, Integer> time = new HashMap<>();
    20.  
    21. @EventHandler
    22. public void onChat(AsyncPlayerChatEvent e) {
    23. Player p = e.getPlayer();
    24. for (Player all : Bukkit.getOnlinePlayers()) {
    25. e.setFormat("%s: %s");
    26. int id = Bukkit.getScheduler().scheduleSyncRepeatingTask((Plugin) this, new Runnable() {
    27. public void run() {
    28. for (Player all : Bukkit.getOnlinePlayers()) {
    29. if (all == null) {
    30. return;
    31. } else {
    32. time.put(all.getName(), time.get(all.getName()) + 10);
    33. }
    34. }
    35. }
    36. }, 0, 20);
    37. }
    38. }
    39.  
    40. @EventHandler
    41. public void onJoin(PlayerJoinEvent e) {
    42. Player p = e.getPlayer();
    43. if (!p.hasPlayedBefore()) {
    44. Bukkit.broadcastMessage(ChatColor.YELLOW + "Welcome" + p.getName());
    45. p.setDisplayName("ยง7[Default] " + ChatColor.WHITE + p.getName());
    46. }
    47. }
    48.  
    49. }
     
  8. Online

    timtower Administrator Administrator Moderator

    @PikaThieme Start that task in the onEnable or constructor please.
    Now you will spam your server with a new timer for every player every time somebody chats.
     
    Rayzr522 likes this.
  9. Offline

    Rayzr522

    • Your time variable is package-private. Please make it private.
    • Don't make a scheduler for every player, make a scheduler once when your plugin loads and inside the scheduler loop through every player.
    • Don't cast this to Plugin. It's entirely unnecessary.
    • Please please please don't use the old deprecated runnable syntax. It should be new BukkitRunnable() { ... }.runTaskTimer(this, 0, 20);
    • You're blindly assuming that time.get will return something. All you're going to get is an error because time never has an initial value for players.
    • Last but certainly not least, please do not use the Bungee import for ChatColor. Use the Bukkit one, otherwise the plugin will break on non-Spigot servers.
     
    Zombie_Striker and mehboss like this.
  10. Offline

    PikaThieme

    @Rayzr522 how do I get the timer from the main? I haven't use a scheduler 'till now.

    And how do I test if a score form a player > than 100
    What do you recommend instead of ChatEvent?

    My code now:
    Code:java
    1.  
    2. package com.pikathieme.cheese;
    3.  
    4. import java.util.HashMap;
    5.  
    6. import org.bukkit.Bukkit;
    7. import org.bukkit.entity.Player;
    8. import org.bukkit.plugin.java.JavaPlugin;
    9.  
    10. public class Main extends JavaPlugin {
    11.  
    12. private HashMap<String, Integer> time = new HashMap<>();
    13.  
    14. public void onEnable() {
    15. Bukkit.getPluginManager().registerEvents(new Ranks(), this);
    16. int id = Bukkit.getScheduler().scheduleSyncRepeatingTask(new Runnable() {
    17. public void run() {
    18. for (Player all : Bukkit.getOnlinePlayers()) {
    19. if (all == null) {
    20. return;
    21. } else {
    22. time.put(all.getName(), time.get(all.getName()) + 10);
    23. }
    24. }
    25. }
    26. }.runTaskTimer(this,0,20);
    27. }
    28.  
    29. public void onDisable() {
    30.  
    31. }
    32. }
    33.  
    34.  
    35. //the ranks.java:
    36.  
    37. package com.pikathieme.dhd;
    38.  
    39. import org.bukkit.Bukkit;
    40. import org.bukkit.ChatColor;
    41. import org.bukkit.entity.Player;
    42. import org.bukkit.event.EventHandler;
    43. import org.bukkit.event.Listener;
    44. import org.bukkit.event.player.AsyncPlayerChatEvent;
    45. import org.bukkit.event.player.PlayerJoinEvent;
    46.  
    47.  
    48. public class Ranks implements Listener {
    49.  
    50. @EventHandler
    51. public void onChat(AsyncPlayerChatEvent e) {
    52. Player p = e.getPlayer();
    53. for (Player all : Bukkit.getOnlinePlayers()) {
    54. e.setFormat("%s: %s");
    55. }
    56. }
    57.  
    58. @EventHandler
    59. public void onJoin(PlayerJoinEvent e) {
    60. Player p = e.getPlayer();
    61. if (!p.hasPlayedBefore()) {
    62. Bukkit.broadcastMessage(ChatColor.YELLOW + "welcome");
    63. p.setDisplayName("ยง7[Default] " + ChatColor.WHITE + p.getName());
    64. }
    65. }
    66.  
    67. }
     
    Last edited: Feb 6, 2017
  11. Offline

    Rayzr522

    @PikaThieme you've almost fixed it.

    1. Please don't use the deprecated BukkitScheduler scheduleSyncRepeatingTask syntax. It should be like this:
    Code:
    new BukkitRunnable() {
        public void run() {
            // Put your code here, just like the other runnable
        }
    }.runTaskTimer(this, 0, 20);
    2. The following code is bad:
    Code:
    } else {
        time.put(all.getName(), time.get(all.getName()) + 10);
    }
    Before time.put(...), you should add this:
    Code:
    if (!time.containsKey(all.getName()) {
        time.put(all.getName(), 0);
    }
    EDIT: Finally, please don't store by the player's name. Use the player's UUID, player.getUniqueId()
     
  12. Offline

    mehboss

    @PikaThieme
    1. get an instance of your main plugin by doing something like
    Code:
        private yourmainclass plugin;
    
        public thecurrentclass(yourmainclass plugin) {
            this.plugin = plugin;
        }
    
    then you do something like
    Code:
    //code
    if (plugin.time.get(all.getUniqueid()));

    2. get the integer in the hashmap and do something like
    Code:
    if (time.get(all.getUniqueid() > 100)) {
        //your code
    }
    
    3. Instead of doing
    do something like
    Code:
    int time = 0;
    time.put(all.getName(), time + 10);
    

     
    Last edited: Feb 6, 2017
    Rayzr522 likes this.
  13. Offline

    Rayzr522

    The time variable is private though, so you'll want to create a public method called getTime() in your main class that returns time.
    Code:
    public class YourMainClass extends JavaPlugin {
        private Map<String, Integer> time = new HashMap<String, Integer>();
    
        public map<String, Integer> getTime() {
            return time;
        }
    }
    
    Of course, the map is currently set up to use Strings. As I said, you should change it to use UUIDs by changing <String, Integer> to <UUID, Integer> and using player.getUniqueId() instead of player.getName()
     
    mehboss likes this.
  14. Offline

    PikaThieme

    @Rayzr522 and @mehboss it's seems hard, but I'll try it tomorrow.
    Thanks guys :)
    Btw: do you guys think it's smart to use ChatEvent because I don't know what to use else...
     
  15. Offline

    Rayzr522

    @PikaThieme
    What is your goal? What is time supposed to be tracking? Is it supposed to be the amount of time they've played?
     
  16. Offline

    mehboss

    @PikaThieme
    Change your hashmap variable :p

    It should look like this because you want to get the time hashmap from other classes, if you don't specify public it won't work.
    Code:
        public HashMap<String, Integer> time = new HashMap<String, Integer>();
    @Rayzr522
    eh, maybe. If it is then why would he do +20 every tick.. haha:p
     
  17. Offline

    Rayzr522

    @mehboss @PikaThieme
    Public variables aren't the best options. It's better to make the variable private, and to create a getter method for the variable ;)

    Java conventions and all that fun stuff :D
     
  18. Offline

    Drkmaster83

    @PikaThieme In summation, from your last set of code, you need to:
    1. Change
      Code:
      int id = Bukkit.getScheduler().scheduleSyncRepeatingTask(new Runnable() {
      to
      Code:
      new BukkitRunnable() {
      and change the end to
      Code:
      }.runTaskTimer(this, 0L, 20L);
    2. Make your "time" HashMap<String, Integer> a HashMap<UUID, Integer>, as it is discouraged to store playernames (even though realistically a player's name would be good enough if you never stored it in a file, but only in RAM)
    3. Create a getter method for your "time" HashMap... either public static or just public (I prefer public static)
      Code:
      public static HashMap<UUID, Integer> getTime() { return time; }
    4. In your onEnable(), change
      Code:
      time.put(all.getName(), time.get(all.getName()) + 10);
      to
      Code:
      time.put(all.getUniqueId(), (time.containsKey(all.getUniqueId()) ? time.get(all.getUniqueId()) : 0) + 10);
      . This allows for a quick one-line check that won't get you into trouble if the player doesn't have a time yet.
    @Rayzr522 Judging from the packaging name, I'd guess it's a screenshot plugin of some sort? "Cheese"?... Seems like he's adding his own formatting into the chat, too. It's a wild shot, just seemed like a time-based kinda thing. If that is a random package component, then I have no idea, apparently the time they've been online. And really, it's not so much the conventions of Java, but rather the fundamental ideas of OOP.
    But also, @PikaThieme, your "time" HashMap doesn't represent the amount of seconds they're playing, but rather their seconds * 10, so I guess their deciseconds played? (deci = base*10)
    @mehboss While I get that it is superfluous to do so, it's generally frowned upon to store a player's name as an identifier in a collection of any sorts, it's preferred to use a UUID. However, your proposed HashMap could be good for storing the UUID#toString(). If so, disregard this.
     
  19. Offline

    Rayzr522

    @Drkmaster83
    • Don't spoonfeed
    • Don't abuse static. Only make the method static if it is unbound from an instance or if you have to (like a getInstance() method in a plugin's main class)
    • He isn't even measuring time played, he's measuring number of messages sent * 10 :\
     
  20. Offline

    Drkmaster83

    @Rayzr522 I gave him no more code than you had initially, was just restating what he had missed. The only (maybe) additional thing was the HashMap declaration, but he knows how to do it, so I figured just show him what we want. Point #4 was just removing the need for the if statement you'd given

    The method might have to be static if you'd want to make sure that even if your main class had gotten duped, you'd still only have one global HashMap. I know there's a bit of an aversion to using it, and it should really be used in a method context for utilities, but if you think there could be a problem that arises from it, I'd be glad to hear, informs me more on the topic.

    In his most recent code, it was in the onEnable, and ticks every second, am I wrong?
     
  21. Offline

    Rayzr522

    @Drkmaster83
    The possibility of the class getting duped is the exact reason that you don't want static access. This data is related to the plugin instance, so it should be non-static.

    But I believe we've gotten a bit off topic. I simply wanted to clear this up so @PikaThieme had all the right facts.
     
    mehboss likes this.
  22. Offline

    PikaThieme

    @Rayzr522 @Drkmaster83 and @mehboss I wanted to make a total time on the server but I had no clue what event to use. I hope that you can help me with that so I can mark the thread as solved!
    Thanks for all replies!
     
  23. Offline

    mehboss

    @PikaThieme
    Perfect! One more thing to change is instead of adding +20 unless you're totaling it in ticks and then going to multiply the integer to change it to seconds or minutes

    I would recommend on move event because you can get the most accurate time on the server so it doesn't count if the person goes afk.


    Sent from my iPhone using Tapatalk
     
  24. Offline

    PikaThieme

    @mehboss , @Rayzr522 and @Drkmaster83 thank you for all your help guys! Unfortunately, I figured out this is way too hard for me. I do understand now what hashmaps and arraylists are but I just still don't get some other things work. Maybe I will ask someone if he/she can make a diff checker (that is with the whole code completed) so I can see what I did wrong. Or maybe one of you guys have time for that (you'd make me very happy :p).

    Again,
    thanks all
     
  25. Offline

    Rayzr522

  26. Offline

    PikaThieme

    @Rayzr522 I know some basics, I know what deprecated etc means, but I have never made a plugin like this. I know there are some guys in this forum that make diff checkers so I hope one of them can help me :)

    Maybe I'll figure it out later...
     
    Last edited: Feb 7, 2017
Thread Status:
Not open for further replies.

Share This Page