Solved HashMaps to config and back

Discussion in 'Plugin Development' started by kyoceri, May 13, 2017.

Thread Status:
Not open for further replies.
  1. Hi,
    I'm relatively new to coding bukkit (started 2 days ago) so I apologise if this is a nooby question, but for the method I have to save/load the HashMap is imperfect; it generates duplicates if any value is changed: let me give an example
    Code:
    playerData:
    - eb3a0a89-7b30-4d77-a560-8d6706966cfa:0:0.0:false
    - eb3a0a89-7b30-4d77-a560-8d6706966cfa:5:0.0:false
    As you can see, one value is changed but the UUID and everything else is the same, and it generates duplicates.
    My code:
    Code:
    @Override
        public void onEnable() {
            getServer().getPluginManager().registerEvents(new PlayerListener(), this);
            getServer().getConsoleSender().sendMessage(ChatColor.AQUA + "\n\n[naro] has been enabled\n");
            registerListeners();
            registerCommands();
            loadConfig();
           
            saveDefaultConfig();
           
            List<String> pd = getConfig().getStringList("playerData");
    
            for (String str : pd) {
    
                String[] words = str.split(":");
                UUID uuid = UUID.fromString(words[0]);
                playermanager.put(uuid, new PlayerManager(uuid, 0, 0, false));
                playermanager.get(uuid).setRank(Integer.parseInt(words[1]));
                playermanager.get(uuid).setMoney(Double.parseDouble(words[2]));
                playermanager.get(uuid).setDead(Boolean.parseBoolean(words[3]));
               
            }
       
        }
    
    @Override
        public void onDisable() {
            getServer().getConsoleSender().sendMessage(ChatColor.RED + "\n\n[naro] has been disabled\n");
            List<String> pd = getConfig().getStringList("playerData");
    
            for (UUID uuid : playermanager.keySet()) {
    
                pd.add(uuid + ":" + playermanager.get(uuid).getRank() + ":" + playermanager.get(uuid).getMoney() + ":"
                        + playermanager.get(uuid).isDead());
            }
            getConfig().set("playerData", pd);
    
            saveConfig();
    
        }
     
  2. You're currently using a List of strings to store your information. Since you use the uuid as a key (= an uuid is only allowed to appear once), it's much easier to use a (Hash)Map with uuid as the key and the remaining data as the value.

    You can take a look at the config api reference (search for 'HashMap' - there is one paragraph for setting and one for getting HashMaps from the config).
     
  3. Thanks for replying! anyway since I'm a noob at this, when creating the HashMap, other than UUID what value should I use for the 2nd argument in the creation of the HashMap?
     
  4. Currently one entry in your string list is
    Code:
    eb3a0a89-7b30-4d77-a560-8d6706966cfa:5:0.0:false
    And contains the player's uuid, his rank, his money and whether he is dead or not.
    When you use the uuid as your key, you have
    Code:
    5:0.0:false
    left as your value.

    You could save this information as a string and, when reading from the config, parse the string to get the components from it.
    Alternatively you could create a more complex structure e.g.:
    Code:
    playerData:
      eb3a0a89-7b30-4d77-a560-8d6706966cfa:
        rank: 5
        money: 0.0
        dead: false
    This would allow you to directy access all values, when you for example want to change the player's rank: playerData.<player'sUuid>.money
     
  5. Thanks yet again. I've managed to iterate over the pd HashSet but I've run into troubles...
    When the plugin first runs and there are no entries in the HashSet, it works fine:
    Code:
    playerData: {}
    However (I made a /rank command to test this, it just sets the player's rank to 5), when any entries are made the cmd prompt throws a YML error and the playerData: {} configuration section is deleted:
    Code:
    Caused by: org.yaml.snakeyaml.constructor.ConstructorException: could not determine a constructor for the tag tag:yaml.org,2002:java.util.UUID
    in 'string', line 16, column 3:
          !!java.util.UUID 'eb3a0a89-7b30- ...
          ^
    
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructUndefined.construct(SafeConstructor.java:505) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:182) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:363) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:147) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:354) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:489) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:26) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:182) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:373) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:147) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:354) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:489) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:26) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:182) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:141) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:127) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:450) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.yaml.snakeyaml.Yaml.load(Yaml.java:369) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:54) ~[craftbukkit-1.11.2.jar:git-Bukkit-2b6c9f4]
            ... 30 more
    My code is as follows:
    Code:
        // onEnable
        @Override
        public void onEnable() {
            getServer().getPluginManager().registerEvents(new PlayerListener(), this);
            getServer().getConsoleSender().sendMessage(ChatColor.AQUA + "\n\n[naro] has been enabled\n");
            registerListeners();
            registerCommands();
            loadConfig();
          
            saveDefaultConfig();
          
            HashMap<UUID, String> pd = new HashMap<UUID, String>();
    
            for (UUID uuid : pd.keySet()) {
    
                Set<UUID> set = pd.keySet();
                String[] words = set.toArray(new String[set.size()]);
              
                playermanager.put(uuid, new PlayerManager(uuid, 0, 0, false));
                playermanager.get(uuid).setRank(Integer.parseInt(words[1]));
                playermanager.get(uuid).setMoney(Double.parseDouble(words[2]));
                playermanager.get(uuid).setDead(Boolean.parseBoolean(words[3]));
              
            }
      
        }
    
        // onDisable
        @Override
        public void onDisable() {
            getServer().getConsoleSender().sendMessage(ChatColor.RED + "\n\n[naro] has been disabled\n");
            HashMap<UUID, String> pd = new HashMap<UUID, String>();
    
            for (UUID uuid : playermanager.keySet()) {
              
                String data = uuid.toString() + ":" + playermanager.get(uuid).getRank() + ":" + playermanager.get(uuid).getMoney() + ":" + playermanager.get(uuid).isDead();
              
                pd.put(uuid, data);
              
            }
            getConfig().set("playerData", pd);
    
            saveConfig();
    
        }
     
    Last edited: May 13, 2017
  6. Well, YAML doesn't know how to (de-)serialize an UUID object - you can probably add this functionality...
    An easier way however would be store the UUID in its string representation and use UUID.toString and UUID.fromString instead of the uuid object itself: https://docs.oracle.com/javase/8/docs/api/java/util/UUID.html
     
  7. Thanks Coww for responding again. I've been trying to get this to work for hours and I appreciate you're trying to make me learn instead of spoonfeeding me. I really don't know how to do this.. There are no IDE errors, just the YAML one. Same as before.
    Can you please give me some tips & advice? You don't have to do it for me.
    thanks!

    Code:
    // onEnable
        @Override
        public void onEnable() {
            getServer().getPluginManager().registerEvents(new PlayerListener(), this);
            getServer().getConsoleSender().sendMessage(ChatColor.AQUA + "\n\n[naro] has been enabled\n");
            registerListeners();
            registerCommands();
            loadConfig();
           
            saveDefaultConfig();
           
            HashMap<String, String> pd = new HashMap<String, String>();
    
            for (String uuid : pd.keySet()) {
    
                UUID uuidFromString = UUID.fromString(uuid);
                       
                Set<String> set = pd.keySet();
                String[] words = set.toArray(new String[set.size()]);
               
                playermanager.put(uuidFromString, new PlayerManager(uuidFromString, 0, 0, false));
                playermanager.get(uuidFromString).setRank(Integer.parseInt(words[1]));
                playermanager.get(uuidFromString).setMoney(Double.parseDouble(words[2]));
                playermanager.get(uuidFromString).setDead(Boolean.parseBoolean(words[3]));
               
            }
       
        }
    
        // onDisable
        @Override
        public void onDisable() {
            getServer().getConsoleSender().sendMessage(ChatColor.RED + "\n\n[naro] has been disabled\n");
            HashMap<UUID, String> pd = new HashMap<UUID, String>();
    
            for (UUID uuid : playermanager.keySet()) {
               
               
               
                String data = playermanager.get(uuid).getRank() + ":" + playermanager.get(uuid).getMoney() + ":" + playermanager.get(uuid).isDead();
               
                log(data);
               
                pd.put(uuid, data);
                log(pd.toString());
                getConfig().set("playerData", uuid);
                getConfig().set(uuid.toString(), pd);
               
            }
            //getConfig().set("playerData", uuid);
    
            saveConfig();
    
        }
     
  8. I'll split this post into 3 sections.

    1) You're still using UUIDs as a key in your yaml file! In your onDisable:
    Code:
    getConfig().set(uuid.toString(), pd);
    And 'pd' is also a HashMap<UUID, String>

    So you're basically saving: <uuidAsString, Map<UUID, String>>
    Instead of just <uuidAsString, String>. This creates (more or less) this data structure:
    Code:
    playerData:
      eb3a0a89-7b30-4d77-a560-8d6706966cfa:
        UUID(eb3a0a89-7b30-4d77-a560-8d6706966cfa): "5:42.0:false"

    2) Is this your full code? I'm not really sure what you're trying to do in your onEnable:
    Code:
      HashMap<String, String> pd = new HashMap<String, String>();
      for (String uuid : pd.keySet()) { ...
    You create an empty Map and iterate over it?!
    You probably want to iterate over all players. To get all keys from your config file (= all uuids as String) you can use
    Code:
    Map<String, Object> allPlayersData = getConfig().getConfigurationSection("playerData").getValues(false);
    Set<String> allUuids = allPlayersData.keySet();
    You can then use a for loop to iterate over the set of uuids and use the code following in 3) to get the player's rank, balance and isDead status.


    3) It's probably easier to use the dot notation to access config values. That way you don't have to split your data String into its 3 components (rank, money & isDead). To get your rank you can use:
    Code:
    int rank = getConfig().getInt("playerData." + uuid.toString() ".rank");
    And to update a player's rank:
    Code:
    int newRank = 1337;
    getConfig().set("playerData." + uuid.toString() + ".rank", newRank);
    This would create an entry similar to:
    Code:
    playerData:
      eb3a0a89-7b30-4d77-a560-8d6706966cfa:
        rank: 1337

    I hope this helps you to get on the right track ;)
     
  9. Finally! After reading your submission I could finally get it to work... thanks so much!
     
Thread Status:
Not open for further replies.

Share This Page