Random player from hashmap

Discussion in 'Plugin Development' started by DonkeyTeeth2013, Sep 21, 2013.

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

    DonkeyTeeth2013

    Hello, I'm making a MarcoPolo minigame. I want to randomly select a player to be Marco from a hashmap I have named "join" that players are added to when they join the game (I also have a problem with people joining also, but I feel this is more important).
    This is my hashmap declaration:
    Code:java
    1. public HashMap<Player, ArrayList<Block>> join = new HashMap<Player, ArrayList<Block>>();
    2. public HashMap<Player, ArrayList<Block>> marcoPlayers = new HashMap<Player, ArrayList<Block>>();
    3. public HashMap<Player, ArrayList<Block>> poloPlayers = new HashMap<Player, ArrayList<Block>>();


    This is my current randomization code:
    Code:java
    1. int random = new Random().nextInt(join.keySet().size());
    2. Player marco = Bukkit.getOnlinePlayers()[random];

    The problem with this code, is that it takes the size of my "join" hashmap and chooses an online player that has the same number (as an object).. Can anybody help, please?
     
  2. Offline

    Iroh

    Moved to plugin development.
     
  3. Offline

    Deleted user

  4. Offline

    DonkeyTeeth2013

    JHG0 There isn't one. It takes the player with the corresponding object ID on the server as the amount of people who joined, and they get put into the "marcoPlayers" hashmap instead of a random player who actually joined the match
     
  5. Offline

    Mitsugaru

    Well, one improvement that would help is if you make things less tightly coupled.

    1) Use the player name as the key instead of the Player object.
    2) Use the List interface within the Map instead of specifying ArrayList.
    Code:
    public Map<String, List<Block>> join = new HashMap<String, List<Block>>();
    Also, I don't really get what the original issue is. Is it that you can't get a random player from the entire server? I mean, it may be linked to the other issue that you mention about a problem with people joining. If your join map isn't getting populated with entries, then your randomizer isn't going to get the full range.

    Is there a reason you can't just pick from all players on the server?
    Code:
    Player[] allPlayers = Bukkit.getOnlinePlayers();
    int random = new Random().nextInt(allPlayers.length);
    Player marco = allPlayers[random];
    Note, above code completely untested.
     
  6. Offline

    DonkeyTeeth2013

    Mitsugaru Thanks for the tip about using player names instead of player objects. Also, I dont want to get a random player from the entire server, but rather only the players who joined the match (found in the "join" hashmap)
     
  7. Offline

    Mitsugaru

    Alright, then, why don't you check the contents of your join map and make sure its getting populated with entries.

    If your join map is working, then this should help out: http://stackoverflow.com/a/9919827
    Also, you should be grabbing the "marco" object from the hashmap and not from all online players if you're trying to restrict it to a specific group. And if you need the Player object, you should be able to get it from the server since you have their name.
     
    DonkeyTeeth2013 likes this.
  8. Offline

    DonkeyTeeth2013

    Awesome, but how would I get the player object from the string it gives me?
     
  9. Offline

    Mitsugaru

    DonkeyTeeth2013 likes this.
  10. Offline

    DonkeyTeeth2013

    Mitsugaru Weird.. I got this error:
    Code:
    20:22:42 [SEVERE] java.lang.NullPointerException
    20:22:42 [SEVERE]      at me.donkeyteeth2013.marcopolo.marcopolo.onCommand(marcopolo.java:272)
    20:22:42 [SEVERE]      at org.bukkit.command.PluginCommand.execute(PluginCommand.java:44)
    20:22:42 [SEVERE]      at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:189)
    20:22:42 [SEVERE]      at org.bukkit.craftbukkit.v1_6_R2.CraftServer.dispatchCommand(CraftServer.ja
    va:523)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.PlayerConnection.handleCommand(PlayerConnect
    ion.java:964)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.PlayerConnection.chat(PlayerConnection.java:
    882)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.PlayerConnection.a(PlayerConnection.java:839
    )
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.Packet3Chat.handle(SourceFile:49)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.NetworkManager.b(NetworkManager.java:296)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.PlayerConnection.e(PlayerConnection.java:118
    )
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.ServerConnection.b(SourceFile:37)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.DedicatedServerConnection.b(SourceFile:30)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.MinecraftServer.t(MinecraftServer.java:590)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.DedicatedServer.t(DedicatedServer.java:226)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.MinecraftServer.s(MinecraftServer.java:486)
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java:419
    )
    20:22:42 [SEVERE]      at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:582)
    This is line 272:
    Code:java
    1. marco.teleport(new Location(w, x, y, z));

    These are w, x, y, and z delarations:
    Code:java
    1. double x = getConfig().getDouble("marco.x");
    2. double y = getConfig().getDouble("marco.y");
    3. double z = getConfig().getDouble("marco.z");

    My current config:
    Code:
    join:
      world: flat
      x: 59.54185855028068
      y: 4.0
      z: 1043.6648413862351
    marco:
      world: flat
      x: 62.173690556442054
      y: 4.0
      z: 1044.7292621334918
    polo:
      world: flat
      x: 54.70418531349299
      y: 4.0
      z: 1045.1751529007288
    
     
  11. Offline

    Mitsugaru

    Did you check to see if the marco object is null? Only thing I can think of as to why you'd get an NPE at that line.
     
  12. Offline

    DonkeyTeeth2013

    Mitsugaru It isn't null because when the player does the join command, the player is added to the join/joinNames hashmaps and marco gets the random player from joinNames and gets the player of it, as we talked about earlier. This is the code for when the player is added to the hashmap and surrounding it:
    Code:java
    1. if(join.containsKey(player)){
    2. player.sendMessage(ChatColor.GOLD + "[" + ChatColor.AQUA + "MarcoPolo" + ChatColor.GOLD + "] " + ChatColor.YELLOW + "You are already in the match! (" + join.size() + "/14)");
    3. }else{
    4. if(join.size() < 14){
    5. if (getConfig().getConfigurationSection("join") == null) {
    6. player.sendMessage(ChatColor.RED + "The join spawn has not yet been set!");
    7. getLogger().warning("The join spawn for MarcoPolo has not been set! Use /mp spawn join to set the join spawn!");
    8. }else{
    9. World w = Bukkit.getServer().getWorld(getConfig().getString("join.world"));
    10. double x = getConfig().getDouble("join.x");
    11. double y = getConfig().getDouble("join.y");
    12. double z = getConfig().getDouble("join.z");
    13. player.teleport(new Location(w, x, y, z));
    14. }
    15. join.put(player, null);
    16. joinNames.put(player.getName(), player + "");
    17. for(Player all :join.keySet()) {
    18. player.sendMessage(ChatColor.YELLOW + "You have joined the match! (" + join.size() + "/14)");
    19. all.sendMessage(ChatColor.YELLOW + player.getName() + " has entered the match! (" + join.size() + "/14)");
    20. }


    Edit: And sorry for the late reply, Bukkit wanted to keep sending me errors every time I make a post lol

    Another edit: Fixed it!! :D at
    Code:java
    1. joinNames.put(player.getName(), player + "");

    I put the player object as the value, where I now replaced it with
    Code:java
    1. joinNames.put(player.getName(), player.getName());


    Yay! That works now! Now the other problem I had (stated in the OP) was a countdown. I dont know why but I can't get a countdown to work. Thread.sleep(long); blocks out all commands, and scheduleSyncRepeatingTask works well, but gets less reliable because the timer gets faster each time it's run.. Is there a way to fix this or a better way?
     
  13. Offline

    Mitsugaru

    When does this countdown start? What happens after the countdown is finished?

    Using the scheduler is the way to go. I don't really understand why you would say it gets less reliable nor how the time length changes per repeat...
     
  14. Offline

    DonkeyTeeth2013

    The countdown starts when there's at least 2 people in the match (but players can still join), and when its done it sets up the match giving potion effects, adding people to hashmaps, etc. I'm saying it gets less reliable because the first time its used, it works perfectly. Second time, intervals in between lower a slight bit. Another time, there's a noticeable change in the intervals between each broadcast, and each time after that the change gets more obvious and faster until its literally taking less than a second to do the entire process. I was testing with this code:
    Code:java
    1. //count was specified earlier, of course
    2. count = 5;
    3. this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){
    4. public void run(){
    5. if(count != -1){
    6. if(count != 0){
    7. Bukkit.broadcastMessage(count + "");
    8. count--;
    9. }else{
    10. Bukkit.broadcastMessage("test");
    11. count--;
    12. }
    13. }
    14. }
    15. }, 0L, 20L);
     
  15. Offline

    Mitsugaru

    DonkeyTeeth2013 Are you cancelling the previous task? It looks like you might be running multiple repeating tasks editing the count variable.

    I don't see why this should be a repeating task... Should it not be just a single one-off task that runs for the length of the match? And only one task should be managing a single match. You don't want any conflict with having multiple tasks changing values for the same match.

    EDIT: I suppose you're doing a repeating task to keep time and report the current countdown to all players in the match. Still, part of the above still stands where you might be running into a situation where you're creating another repeating task without stopping the previously created task which is also repeating.
     
  16. Offline

    DonkeyTeeth2013

    So I would have to cancel the currently running task where it broadcasts "test" to fix this? I thought maybe the check for count != -1 would technically cancel it but I guess it still runs..? lol so what would be the code for cancelling the running task? Sorry for my newbiness ;P

    EDIT: Yayyy!! Fixed it through some Googling and a little testing. I set a variable for the countdown (countdown = this.getServer()...etc.) and then cancelled the countdown with:
    Code:java
    1. Bukkit.getServer().getScheduler().cancelTask(countdown);

    It works perfectly now :D Thanks for all your help!!
     
Thread Status:
Not open for further replies.

Share This Page