Saving and loading HashMap from file

Discussion in 'Spigot Plugin Development' started by Menfie, May 12, 2016.

  1. I'm trying to save my HashMap to a file but I can't find a solution. So far I got this. And I don't know how to load either. (Actually I can save everything as a string but can't load like that)

    Code (Text):
    public void onDisable() {
            for (Map.Entry<Player, Auctions> e : HashMap.auclist.entrySet()) {
                Player p = e.getKey();
                Auctions a = e.getValue();
                ItemStack i = a.item;
                int m = a.price;
            }
        }
     
  2. Make it a string, then save it, then turn it back from a string into the hashmap upon load.
     
    • Informative Informative x 1
    • Optimistic Optimistic x 1
  3. But the problem is there are 3 objects and I can't load ItemStack's than save it to an Auctions with price (Auctions auction = new Auctions(ItemStack, Integer)

    Ok now I got this:

    Code (Text):
    public void onDisable() {
            List<String> s = getConfig().getStringList("Auctions");
            for (Map.Entry<Player, Auctions> e : HashMap.auclist.entrySet()) {
                Player p = e.getKey();
                Auctions a = e.getValue();
                ItemStack i = a.item;
                int m = a.price;
                s.add(p.getName() + ":" + m + "|" + i);
            }
            getConfig().set("Auctions", s);
            saveConfig();
        }
     
    #3 Menfie, May 12, 2016
    Last edited: May 12, 2016
  4. Saving is done I think but I still can't load
    Code (Text):
    public void onDisable() {
            List<String> s = getConfig().getStringList("Auctions");
            for (Map.Entry<Player, Auctions> e : HashMap.auclist.entrySet()) {
                Player p = e.getKey();
                Auctions a = e.getValue();
                ItemStack i = a.item;
                int m = a.price;
                s.add(p.getName() + ":" + m + "|" + i);
            }
            getConfig().set("Auctions", s);
            saveConfig();
        }
    File looks like this:
    Code (Text):
    Auctions:
    - 'Menfie:15|ItemStack{STONE x 1, UNSPECIFIC_META:{meta-type=UNSPECIFIC, lore=[§cPrice:
      §715$ §cSeller: §7Menfie, §eClick to buy!]}}'
     
    If I use "String[] itemandprice = str.split("|");" it will split from | and get the Player name too. Also I still don't know how to convert string to ItemStack
    Code (Text):
    public void onEnable() {
            getServer().getPluginManager().registerEvents(new Events(), this);
            setupEconomy();
            getCommand("aa").setExecutor(new Commands());
            List<String> s = getConfig().getStringList("Auctions");

            for (String str : s) {
                String[] auctions = str.split(":");
                String[] itemandprice = str.split("|");
            }
        }
     
  5. Don't use Player as the key in a hashmap. Use their UUID or name. Also I think it is possible to store and retrieve HashMaps with the key being a String without doing what you are right now.
     
    • Informative Informative x 1
  6. I still have no clue about how to do this. And I will try your suggestion

    Edit: I converted every player to player name
     
    #6 Menfie, May 13, 2016
    Last edited: May 13, 2016
  7. I'm about to be crazy.

    Code (Text):
    public void onDisable() {
            List<String> players = getConfig().getStringList("players");
            List<ItemStack> items = new LinkedList<>();
            List<Integer> prices = getConfig().getIntegerList("prices");
            for (Map.Entry<Auctions, Player> e : HashMap.auclist.entrySet()) {
                String p = e.getValue().getName();
                Auctions a = e.getKey();
                ItemStack i = a.item;
                int m = a.price;
                players.add(p);
                items.add(i);
                prices.add(m);
            }
            for (int i = 0; i < players.size(); i++) {
                getConfig().set("players." + players.get(i) + "." + i + "." + prices.get(i), items.get(i));
            }
            saveConfig();
        }
    This is how I save my config and I can't load it I tried so much things but none of them worked

    Before player name (menfie) I added "players:" this file is before that.

    Code (Text):
    menfie:
      '0':
        '15':
          ==: org.bukkit.inventory.ItemStack
          type: STONE
          meta:
            ==: ItemMeta
            meta-type: UNSPECIFIC
            lore:
            - '§cPrice: §715$ §cSeller: §7menfie'
            - §eClick to buy!
            - §07040324690
      '1':
        '1':
          ==: org.bukkit.inventory.ItemStack
          type: EMERALD_ORE
          meta:
            ==: ItemMeta
            meta-type: UNSPECIFIC
            lore:
            - '§cPrice: §71$ §cSeller: §7menfie'
            - §eClick to buy!
            - §06372132011
     
     
  8. Serializator

    Supporter

    What you want to do is loop through every entry in the map that you're storing your information in and after every loop increment an integer that will act as an index. But before you increment the index you will want to save your first auction to the config so that the first index is 0 and not 1.

    After you read that you will probably want to ask me how to actually save the information to the config. What you want to do is the following:
    Code (Text):
    players.(uuid).(index).(item)
    players.(uuid).(index).(price)
    Those strings are the path that you will have to use for each auction to save and load them, the methods you want to use for both the item and price are:

    Save: YamlConfiguration#set()
    Load:
    ItemStack: YamlConfiguration#getItemStack()
    Price: YamlConfiguration#getInt()
     
    • Like Like x 1
    • Informative Informative x 1
  9. Ok. Now I got this and this is perfect but how can I get player's name when I'm loading file?

    Code (Text):
    public void onDisable() {
            int number = 0;
            File file = new File(getDataFolder().getAbsolutePath(), "auctions.yml");
            FileConfiguration c = YamlConfiguration.loadConfiguration(file);
            for (Map.Entry<Auctions, Player> e : HashMap.auclist.entrySet()) {
                String p = e.getValue().getName();
                Auctions a = e.getKey();
                ItemStack i = a.item;
                int price = a.price;
                c.set("players." + p + "." + number + ".item", i);
                c.set("players." + p + "." + number + ".price", price);
                number = number + 1;
            }
            try {
                c.save(file);
            } catch (Exception e) {
            }
        }
    No luck :(:

    Code (Text):
    for (String key : c.getStringList("players")) {
                String players = this.getConfig().getString("players." + key);
                getLogger().info(players);

            }
    And this gives me NPE (1st line):

    Code (Text):
    for (String playername : getConfig().getConfigurationSection("players").getKeys(false)) {
                String players = this.getConfig().getString("players." + playername);
                Player player = Bukkit.getPlayer(playername);
                getLogger().info(player.getDisplayName());

            }
     
    #9 Menfie, May 13, 2016
    Last edited: May 13, 2016
  10. Store it by UUID only. Names shouldn't be used as keys for data. @OP Gson is your friend, you can literally serialize and deserialize in a single line of code.
     
  11. I solve the problem by doing this :

    Code (Text):
    for (String playername : getConfig().getConfigurationSection("players").getKeys(false)) {
                Player player = Bukkit.getPlayer(playername);
                getLogger().info(player.getDisplayName());

            }
    and setting my file name to config.yml but is there a way to list players without getConfig ? (I really don't want to change it to config.yml)
     
  12. This is some kind of sick joke, right?

    Load your custom configuration in the onEnable using a FileConfiguration implementation. Would also highly advise you add null checks before attempting to invoke methods on the value of player.

    I'm assuming this is outside the onDisable method. Where is c defined?
     
    • Informative Informative x 1
  13. This is it and working I can see playernames flowing on console :) Thanks to @Serializator

    Code (Text):
    public void onEnable() {
            File file = new File(getDataFolder().getAbsolutePath(), "config.yml");
            FileConfiguration c = YamlConfiguration.loadConfiguration(file);

            getServer().getPluginManager().registerEvents(new Events(), this);
            setupEconomy();
            getCommand("aa").setExecutor(new Commands());

            for (String playername : getConfig().getConfigurationSection("players").getKeys(false)) {
                Player player = Bukkit.getPlayer(playername);
             
                getLogger().info(player.getDisplayName());
            }
        }

        public void onDisable() {
            int number = 0;
            File file = new File(getDataFolder().getAbsolutePath(), "config.yml");
            FileConfiguration c = YamlConfiguration.loadConfiguration(file);
            for (Map.Entry<Auctions, Player> e : HashMap.auclist.entrySet()) {
                String p = e.getValue().getName();
                Auctions a = e.getKey();
                ItemStack i = a.item;
                int price = a.price;
                c.set("players." + p + "." + number + ".item", i);
                c.set("players." + p + "." + number + ".price", price);
                number = number + 1;
            }
            try {
                c.save(file);
            } catch (Exception e) {
            }
        }
    But the thing is I can't change the file's name
     
  14. You can. Given the line number you gave us when you attempted to use a custom file one can assume c was undefined.
     
    • Informative Informative x 1
  15. Serializator

    Supporter

    "players" isn't a list of strings, it's a configuration section. Use YamlConfiguration#getConfigurationSection() and use getKeys(false) to get all the UUIDs.

    To get the names you can either directly query the Mojang API or you can set your configuration up differently and have a "players" section which maps UUID to name and you can have an "auctions" section which will map the UUID of the player to their auctions, this way you can get the name of the player through the "players" section and the auctions through "auctions". (Don't forget to update the name every time they connect to your server to keep the name as updated as possible)
     
    • Informative Informative x 1
  16. Right now this is working but when I try to change the name of file it just fails cause I'm using "
    getConfig().getConfigurationSection("players").getKeys(false)" and the UUID thing can not work on offline servers right? So I'm using playernames instead of UUID's
     
  17. Serializator

    Supporter

    In that case I won't provide any help anymore, I personally hate cracked servers.
    Goodluck with non-premium kids who haven't purchased the game they're playing.
     
  18. I have purchased the game 5 times what are you talkin' about offline server doesn't mean cracked. Since I'm hosting the server on my computer for lan this is not pirating.
     
  19. Serializator

    Supporter

    Servers in offline mode are used to disable authentication and make it able for players with a cracked version of the game to connect to your server.

    But may I ask why you have to put your server into offline mode if you have 5 accounts that can connect to it in online mode?
     
  20. It's because it's on my laptop which is not connected to internet mostly. (a lot of travel)
    And I'm just testing myself I'm not gonna use this plugin in any kind of server.