[Unsolved] Annoying HashMap Problems

Discussion in 'Plugin Development' started by krazytraynz, Jul 18, 2013.

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

    krazytraynz

    I'm trying to check if a Player is stored in a HashMap in one of my EventListeners, but it always returns as null, but only in the EventListener. If I check the HashMap in the command where the Player is stored, it says the Player is in the HashMap. I've spent hours on end googling fixes, and trying to come up with my own, but nothing has worked. How should I fix this?

    Code:
    Code:java
    1. package com.github.KrazyTraynz;
    2.  
    3. import java.io.BufferedReader;
    4. import java.io.BufferedWriter;
    5. import java.io.File;
    6. import java.io.FileNotFoundException;
    7. import java.io.FileReader;
    8. import java.io.FileWriter;
    9. import java.io.IOException;
    10. import java.util.HashMap;
    11. import java.util.Map;
    12.  
    13. import org.bukkit.ChatColor;
    14. import org.bukkit.Material;
    15. import org.bukkit.World;
    16. import org.bukkit.block.Block;
    17. import org.bukkit.block.Chest;
    18. import org.bukkit.command.Command;
    19. import org.bukkit.command.CommandExecutor;
    20. import org.bukkit.command.CommandSender;
    21. import org.bukkit.configuration.file.FileConfiguration;
    22. import org.bukkit.configuration.file.YamlConfiguration;
    23. import org.bukkit.entity.Player;
    24. import org.bukkit.event.EventHandler;
    25. import org.bukkit.event.Listener;
    26. import org.bukkit.event.block.Action;
    27. import org.bukkit.event.player.PlayerInteractEvent;
    28. import org.bukkit.inventory.Inventory;
    29. import org.bukkit.inventory.ItemStack;
    30.  
    31. public class ChestRestoreExecutor implements CommandExecutor, Listener{
    32.  
    33. @SuppressWarnings("unused")
    34. private PlayerRestore pr;
    35. public ChestRestoreExecutor(PlayerRestore pr){
    36. this.pr = pr;
    37. }
    38.  
    39. //Keep track of Players <PlayerName, ChestName>
    40. HashMap<String, String> players = new HashMap<String, String>();
    41.  
    42.  
    43. File dir = new File("plugins/Player Restore/Chest Inventories");
    44. File file = new File(dir + "/ChestPairs.yml");
    45. FileConfiguration yml = YamlConfiguration.loadConfiguration(file);
    46.  
    47. private String getPlayerKey(HashMap<String, String> hashmap, String value) {
    48. for (Map.Entry<String, String> entry : hashmap.entrySet()) {
    49. if (value.equals(entry.getValue())) {
    50. return entry.getKey();
    51. }
    52. }
    53. return null;
    54. }
    55.  
    56. public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
    57. if(cmd.getName().equalsIgnoreCase("restorechest")){
    58. if (args.length > 1) {
    59. sender.sendMessage(ChatColor.RED + "Too many arguments!");
    60. return false;
    61. }
    62. if (args.length < 1) {
    63. sender.sendMessage(ChatColor.RED + "Who's chest do you want to restore?");
    64. return false;
    65. }
    66.  
    67. String st = args[0];
    68. Player pl = (Player) sender;
    69.  
    70. String s = yml.getConfigurationSection(st.toLowerCase()).getKeys(false).toString();
    71. int x = yml.getInt(st.toLowerCase() + "." + s + ".X");
    72. int y = yml.getInt(st.toLowerCase() + "." + s + ".Y");
    73. int z = yml.getInt(st.toLowerCase() + "." + s + ".Z");
    74.  
    75. World w = pl.getLocation().getWorld();
    76. Block b = w.getBlockAt(x, y, z);
    77. Chest c = (Chest)b;
    78.  
    79. File dir = new File("plugins/Inv Restore/Chest Inventories");
    80. dir.mkdirs();
    81. File file = new File(dir + "/" + st.toLowerCase() + "ChestInventory.txt");
    82. @SuppressWarnings("unused")
    83. String str = "";
    84. try {
    85. FileReader fr = new FileReader(file);
    86. BufferedReader br = new BufferedReader(fr, 37268);
    87. str = br.readLine();
    88. br.close();
    89. fr.close();
    90. } catch (FileNotFoundException e) {
    91. e.printStackTrace();
    92. } catch (IOException e){
    93. e.printStackTrace();
    94. }
    95. Inventory i = PlayerRestoreSerializer.stringToInv(st);
    96. ItemStack[] it = i.getContents();
    97. if(it != null){
    98. c.getInventory().setContents(it);
    99. }
    100. return true;
    101. }
    102.  
    103. else if(cmd.getName().equalsIgnoreCase("claimchest")){
    104. if (args.length > 1) {
    105. sender.sendMessage(ChatColor.RED + "Too many arguments!");
    106. return false;
    107. }
    108. if (args.length < 1) {
    109. sender.sendMessage(ChatColor.RED + "What do you want to name your chest?");
    110. return false;
    111. }
    112.  
    113. Player p = (Player) sender;
    114. String pName = p.getName().toLowerCase();
    115.  
    116. String chestName = args[0];
    117.  
    118. players.put(pName, chestName);
    119. System.out.println(players.get(pName)); //not null
    120. p.sendMessage("Left click the chest you want to claim!");
    121. return true;
    122. }
    123. return false;
    124. }
    125.  
    126. @EventHandler
    127. public void onClick(PlayerInteractEvent e){
    128. if(e.getAction() == Action.LEFT_CLICK_BLOCK){
    129. if(e.getClickedBlock().getType() == Material.CHEST){
    130. String s = e.getPlayer().getName().toLowerCase();
    131. System.out.println(players.get(s)); //null
    132. if(players.containsKey(s)){
    133. System.out.println("4");
    134. yml.set(getPlayerKey(players, players.get(e.getPlayer().getName())).toLowerCase() + "." + players.get(e.getPlayer().getName()) + ".X", e.getClickedBlock().getLocation().getBlockX());
    135. yml.set(getPlayerKey(players, players.get(e.getPlayer().getName())).toLowerCase() + "." + players.get(e.getPlayer().getName()) + ".Y", e.getClickedBlock().getLocation().getBlockY());
    136. yml.set(getPlayerKey(players, players.get(e.getPlayer().getName())).toLowerCase() + "." + players.get(e.getPlayer().getName()) + ".Z", e.getClickedBlock().getLocation().getBlockZ());
    137.  
    138. File dir = new File("plugins/Inv Restore/Chest Inventories");
    139. dir.mkdirs();
    140. File file = new File(dir + "/" + e.getPlayer().getName() + "ChestInventory.txt");
    141. Block b = e.getClickedBlock();
    142. Chest c = (Chest)b;
    143. try {
    144. fw = new FileWriter(file);
    145. BufferedWriter bw = new BufferedWriter(fw, 32768);
    146. String st = PlayerRestoreSerializer.invToString(c.getBlockInventory());
    147. bw.write(st);
    148. bw.close();
    149. fw.close();
    150. } catch (IOException e1) {
    151. e1.printStackTrace();
    152. }
    153. players.remove(e.getPlayer().getName());
    154. e.getPlayer().sendMessage("Chest claimed!");
    155. }
    156. }
    157. }
    158. }
    159. }
     
  2. Offline

    sayaad

    You're checking if an entire entryset is equal to a single value that exists in the entryset, which would be fase. Iterate though the hashmap and check for each individual value.

    Code:java
    1. private String getPlayerKey(HashMap<String, String> hashmap, String value) {
    2. Iterator<Entry<String, String>> it = hashmap.entrySet().iterator();
    3. while(it.hasNext()){
    4. Map.Entry<String, String> pairs = (Map.Entry<String, String>)it.next();
    5. if(pairs.getValue().equals(pairs))
    6. return pairs.getKey();
    7. }
    8. return "";
    9. }
     
  3. Offline

    Chiller

    Just do this:
    Code:
    yml.set(e.getPlayer().getName().toLowerCase() + "." + players.get(e.getPlayer().getName().toLowerCase()) + ".X", e.getClickedBlock().getLocation().getBlockX());
     
  4. Offline

    krazytraynz

    sayaad
    Still no dice. Now the value instead of the key is returning null. Should I add an edited version of the getPlayerKey method?

    Chiller
    Added your fix too, thanks! I'm surprised I didn't think of that to begin with :p

    Bump

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  5. Offline

    krazytraynz

    Anyone?

    Bump

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  6. Offline

    CubieX

    Can you give us the current code please.
    And where is the hashmap returning null exactly?
     
  7. Offline

    1Rogue

    Just a thought, what happens when you print the value of "s", and then iterate/print the keys of your hashmap?

    Code:
    System.out.println(s);
    StringBuilder sb = new StringBuilder("Hashmap keys: ");
    for (String temp : players.keySet().toArray(new String[players.size()])) {
        sb.append(temp).append(", ");
    }
    System.out.println(sb.substring(0, sb.length() - 2));
    Edit: This being within your left-click event method.
     
  8. Offline

    krazytraynz

    CubieX
    It only returns null in the EventListener, I can get the values in the CommandExecutor just fine. Here's the updated code:
    Code:java
    1. package com.github.KrazyTraynz;
    2.  
    3. import java.io.BufferedReader;
    4. import java.io.BufferedWriter;
    5. import java.io.File;
    6. import java.io.FileNotFoundException;
    7. import java.io.FileReader;
    8. import java.io.FileWriter;
    9. import java.io.IOException;
    10. import java.util.HashMap;
    11. import java.util.Iterator;
    12. import java.util.Map;
    13. import java.util.Map.Entry;
    14.  
    15. import org.bukkit.ChatColor;
    16. import org.bukkit.Material;
    17. import org.bukkit.World;
    18. import org.bukkit.block.Block;
    19. import org.bukkit.block.Chest;
    20. import org.bukkit.command.Command;
    21. import org.bukkit.command.CommandExecutor;
    22. import org.bukkit.command.CommandSender;
    23. import org.bukkit.configuration.file.FileConfiguration;
    24. import org.bukkit.configuration.file.YamlConfiguration;
    25. import org.bukkit.entity.Player;
    26. import org.bukkit.event.EventHandler;
    27. import org.bukkit.event.Listener;
    28. import org.bukkit.event.block.Action;
    29. import org.bukkit.event.player.PlayerInteractEvent;
    30. import org.bukkit.inventory.Inventory;
    31. import org.bukkit.inventory.ItemStack;
    32.  
    33. public class ChestRestoreExecutor implements CommandExecutor, Listener{
    34.  
    35. @SuppressWarnings("unused")
    36. private PlayerRestore pr;
    37. public ChestRestoreExecutor(PlayerRestore pr){
    38. this.pr = pr;
    39. }
    40.  
    41. //Keep track of Players <PlayerName, ChestName>
    42. HashMap<String, String> players = new HashMap<String, String>();
    43.  
    44.  
    45. File dir = new File("plugins/Player Restore/Chest Inventories");
    46. File file = new File(dir + "/ChestPairs.yml");
    47. FileConfiguration yml = YamlConfiguration.loadConfiguration(file);
    48.  
    49. private String getPlayerKey(HashMap<String, String> hashmap, String value) {
    50. Iterator<Entry<String, String>> it = hashmap.entrySet().iterator();
    51. while(it.hasNext()){
    52. Map.Entry<String, String> pairs = (Map.Entry<String, String>)it.next();
    53. if(pairs.getValue().equals(pairs))
    54. return pairs.getKey();
    55. }
    56. return "";
    57. }
    58.  
    59. public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args){
    60. if(cmd.getName().equalsIgnoreCase("restorechest")){
    61. if (args.length > 1) {
    62. sender.sendMessage(ChatColor.RED + "Too many arguments!");
    63. return false;
    64. }
    65. if (args.length < 1) {
    66. sender.sendMessage(ChatColor.RED + "Who's chest do you want to restore?");
    67. return false;
    68. }
    69.  
    70. String st = args[0];
    71. Player pl = (Player) sender;
    72.  
    73. String s = yml.getConfigurationSection(st.toLowerCase()).getKeys(false).toString();
    74. int x = yml.getInt(st.toLowerCase() + "." + s + ".X");
    75. int y = yml.getInt(st.toLowerCase() + "." + s + ".Y");
    76. int z = yml.getInt(st.toLowerCase() + "." + s + ".Z");
    77.  
    78. World w = pl.getLocation().getWorld();
    79. Block b = w.getBlockAt(x, y, z);
    80. Chest c = (Chest)b;
    81.  
    82. File dir = new File("plugins/Inv Restore/Chest Inventories");
    83. dir.mkdirs();
    84. File file = new File(dir + "/" + st.toLowerCase() + "ChestInventory.txt");
    85. @SuppressWarnings("unused")
    86. String str = "";
    87. try {
    88. FileReader fr = new FileReader(file);
    89. BufferedReader br = new BufferedReader(fr, 37268);
    90. str = br.readLine();
    91. br.close();
    92. fr.close();
    93. } catch (FileNotFoundException e) {
    94. e.printStackTrace();
    95. } catch (IOException e){
    96. e.printStackTrace();
    97. }
    98. Inventory i = PlayerRestoreSerializer.stringToInv(st);
    99. ItemStack[] it = i.getContents();
    100. if(it != null){
    101. c.getInventory().setContents(it);
    102. }
    103. return true;
    104. }
    105.  
    106. else if(cmd.getName().equalsIgnoreCase("claimchest")){
    107. if (args.length > 1) {
    108. sender.sendMessage(ChatColor.RED + "Too many arguments!");
    109. return false;
    110. }
    111. if (args.length < 1) {
    112. sender.sendMessage(ChatColor.RED + "What do you want to name your chest?");
    113. return false;
    114. }
    115.  
    116. Player p = (Player) sender;
    117. String pName = p.getName().toLowerCase();
    118.  
    119. String chestName = args[0];
    120.  
    121. players.put(pName, chestName);
    122. StringBuilder sb = new StringBuilder("Hashmap keys: ");
    123. for (String temp : players.keySet().toArray(new String[players.size()])) {
    124. sb.append(temp).append(", ");
    125. }
    126. System.out.println(sb.substring(0, sb.length() - 2));
    127. p.sendMessage("Left click the chest you want to claim!");
    128. return true;
    129. }
    130. return false;
    131. }
    132.  
    133. @EventHandler
    134. public void onClick(PlayerInteractEvent e){
    135. System.out.println("1");
    136. if(e.getAction() == Action.LEFT_CLICK_BLOCK){
    137. System.out.println("2");
    138. if(e.getClickedBlock().getType() == Material.CHEST){
    139. System.out.println("3");
    140. StringBuilder sb = new StringBuilder("Hashmap keys: ");
    141. for (String temp : players.keySet().toArray(new String[players.size()])) {
    142. sb.append(temp).append(", ");
    143. }
    144. System.out.println(sb.substring(0, sb.length() - 2));
    145. if(players.containsKey(getPlayerKey(players, players.get(e.getPlayer().getName().toLowerCase())))){
    146. System.out.println("4");
    147. yml.set(e.getPlayer().getName().toLowerCase() + "." + players.get(e.getPlayer().getName().toLowerCase()) + ".X", e.getClickedBlock().getLocation().getBlockX());
    148. yml.set(e.getPlayer().getName().toLowerCase() + "." + players.get(e.getPlayer().getName().toLowerCase()) + ".Y", e.getClickedBlock().getLocation().getBlockY());
    149. yml.set(e.getPlayer().getName().toLowerCase() + "." + players.get(e.getPlayer().getName().toLowerCase()) + ".Z", e.getClickedBlock().getLocation().getBlockZ());
    150.  
    151. File dir = new File("plugins/Inv Restore/Chest Inventories");
    152. dir.mkdirs();
    153. File file = new File(dir + "/" + e.getPlayer().getName() + "ChestInventory.txt");
    154. Block b = e.getClickedBlock();
    155. Chest c = (Chest)b;
    156. try {
    157. fw = new FileWriter(file);
    158. BufferedWriter bw = new BufferedWriter(fw, 32768);
    159. String st = PlayerRestoreSerializer.invToString(c.getBlockInventory());
    160. bw.write(st);
    161. bw.close();
    162. fw.close();
    163. } catch (IOException e1) {
    164. e1.printStackTrace();
    165. }
    166. players.remove(e.getPlayer().getName());
    167. e.getPlayer().sendMessage("Chest claimed!");
    168. }
    169. }
    170. }
    171. }
    172. }


    1Rogue
    Here's the console output. The first time HashMap Keys is printed, it's within the CommandExecutor, the second time it's within the EventListener.
    Code:
    12:31:21 [INFO] KrazyTraynz issued server command: /claimchest alpha
    12:31:21 [INFO] Hashmap keys: krazytraynz
    12:31:26 [INFO] 1
    12:31:26 [INFO] 2
    12:31:26 [INFO] 3
    12:31:26 [INFO] Hashmap keys
    EDIT: I accidentally removed String s, but that shouldn't matter if the key returns null, right?

    Bump

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  9. Offline

    krazytraynz

  10. Offline

    krazytraynz

    There has to be a solution to this topic somewhere :confused:
     
  11. Offline

    CubieX

    I don't think that your hashmap is empty in the event listener.
    I think your "getPlayerKey()" method messes up somewhere.
    You could check that by inserting some debug messages.

    And could you explain a bit what this method does,....or sould do?
     
  12. Offline

    krazytraynz

    I can add the debugs, but the StringBuilder 1Rogue gave me earlier didn't return anything either.


    If a Player types the command /claimchest <name>, their name (in lowercase) is paired with the name they specified in the command in a HashMap. In PlayerInteractEvent, the Listener checks if the Player left-clicks a chest, and looks for their name (in lowercase) in the HashMap. If the Player is stored in the HashMap, it stores their name (again in lowercase) and the location of the chest in a custom yml file, and creates a .txt file of a serialized version of the chest's inventory.

    If a Player types /restorechest <name> it checks the yml file for the lowercase version of the name specified, and restores the chest at the location paired to the name using the serialized inventory.
     
  13. Offline

    1Rogue

    I think rather than storing all your information in a hashmap, it would be smarter to create a new player class (ChestPlayer?), and then store an arraylist of the different chests within those classes. You could then keep a hashmap of the player classes containing the list of chests.

    If you really don't want classes, then you could match a string with an arraylist:
    Map<String, ArrayList<String>> chests = new HashMap();

    Though, I'm not certain how you are pairing the string names with particular chests.
     
  14. Offline

    krazytraynz

    I'm not trying to pair Players with chests, the Players are paired with the name the specify in /claimchest. If they're found in the HashMap when they left-click a chest, something like this would generate in the yml file:
    Code:
    playername:
      chestname:
        X: 102
        Y: 65
        Z: -258
    /restorechest gets the block at those coordinates, and restores it using the serialized inventory.
     
  15. Offline

    1Rogue



    Right, but what if the player wants to protect 2 chests?
     
  16. Offline

    krazytraynz


    Code:
    playername:
      chestname:
        X: 102
        Y: 65
        Z: -258
      chestname1:
        X: 106
        Y: 65
        Z: -258
     
  17. Offline

    1Rogue


    Alright, but with a hashmap, you will only be able to store one of those values. Hashmaps have a "key" and a "value". If you have two values with the same key, only one will appear. Doing this without classes so far is going to end up with an object like

    HashMap<String, int>

    and using it for each individual coordinate.

    It might just be easier to create a chest class like so:

    Code:java
    1.  
    2. public class ChestClass {
    3.  
    4. private final String ownername;
    5. private final int xcord;
    6. private final int ycord;
    7. private final int zcord;
    8.  
    9. public ChestClass(String owner, int x, int y, int z) {
    10. ownername = owner;
    11. xcord = x;
    12. ycord = y;
    13. zcord = z;
    14. }
    15.  
    16. public String getOwner() {
    17. return ownername;
    18. }
    19.  
    20. public int getX() {
    21. return xcord;
    22. }
    23.  
    24. public int getY() {
    25. return ycord;
    26. }
    27.  
    28. public int getZ() {
    29. return zcord;
    30. }
    31. }


    And then store the chests like so:

    Map<String, ArrayList<ChestClass>> chests = new HashMap();

    and when setting the chest, you could create the chest object, and then decide where it goes.

    Code:java
    1.  
    2. ChestClass newChest = new ChestClass("Rogue", 37, 64, 199);
    3. ArrayList<ChestClass> ourchests = chests.get(newChest.getName());
    4. if (ourchests != null) {
    5. ourchests.add(newChest);
    6. } else {
    7. ourchests = new ArrayList();
    8. ourchests.add(newChest);
    9. }
    10. chests.put(outchests);
    11.  
     
  18. Offline

    krazytraynz

    Sorry, I forgot to mention that the key is removed after the Player claims the chest :oops: I'll test the code in a sec

    EDIT: 1Rogue Wait, maybe I didn't explain this well enough. The only things stored in the HashMap are the Player's name and the name they specify in the command /claimchest. The coordinates come from the block the Player clicks on, they aren't stored anywhere.
     
  19. Offline

    1Rogue


    Ah, I see, so then you're naming the chests, and then dynamically adding them to the config?

    At that rate, your map would look something like
    HashMap<String, ArrayList<String>> chests
    no?

    I'll bring it back to the original problem here, which is testing if a key exists. In which case, try using

    Map.containsKey(keyObject);
     
  20. Offline

    krazytraynz


    The command only allows one specified chest name at a time, so I don't think I would need to store an ArrayList in the HashMap, would I? Wouldn't HashMap<String, String> work? I'll test for the key and let you know how it goes.

    1Rogue so test it like this?
    Code:java
    1. if(players.containsKey(event.getPlayer().getName().toLowerCase())) System.out.println("Contains!")


    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  21. Offline

    1Rogue

    krazytraynz If you store the player names in lower case, then yes.
     
  22. Offline

    krazytraynz

    Nothing printed :(
     
  23. Offline

    1Rogue

    Iterate through players, and print the keys.
     
  24. Offline

    krazytraynz

    1Rogue
    Code:
    10:46:08 [INFO] Hashmap keys: krazytraynz
    10:46:09 [INFO] 1
    10:46:09 [INFO] 2
    10:46:09 [INFO] 3
    10:46:09 [INFO] Hashmap keys
    First time it was printed in the command executor, second time in the listener.
     
  25. Offline

    1Rogue

    That was the output of this code??:

    Code:
    System.out.println(s);
    StringBuilder sb = new StringBuilder("Hashmap keys: ");
    for (String temp : players.keySet().toArray(new String[players.size()])) {
        sb.append(temp).append(", ");
    }
    System.out.println(sb.substring(0, sb.length() - 2));
     
  26. Offline

    krazytraynz

    Yup.
     
  27. Offline

    krazytraynz

    Bump.

    Bump

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  28. Offline

    krazytraynz

    Somebody must have an answer to this...
     
  29. Offline

    krazytraynz

  30. Offline

    krazytraynz

    Comphenix
    Sorry for the random tag, but this is the only problem I have to fix before the plugin can be updated, and I haven't really made any progress with this topic so far.
     
Thread Status:
Not open for further replies.

Share This Page