Save inventory inside HashMap to config then load it?

Discussion in 'Spigot Plugin Development' started by VivianMusic, Jul 15, 2018.

  1. Title explains it. Right now I am trying to do...


    Code (Text):
        public void saveInventoryToConfig(Player player) {
            File playerFile = new File(getDataFolder() + File.separator + player.getUniqueId().toString() + ".yml");
            FileConfiguration playerConfig = YamlConfiguration.loadConfiguration(playerFile);
           
            if(inventory.containsKey(player.getUniqueId())) {
                playerConfig.set("inventory", inventory.get(player.getUniqueId()));
                try {
                    playerConfig.save(playerFile);
                } catch (IOException e) {
                    e.printStackTrace();
                }
               
                inventory.remove(player.getUniqueId());
            }
        }
    inventory is the HashMap

    Code (Text):
    static HashMap<UUID, Inventory> inventory = new HashMap<UUID, Inventory> ();
    and its saving to the config like...
    Code (Text):
    inventory: !!org.bukkit.craftbukkit.v1_12_R1.inventory.CraftInventoryCustom
      contents:
      - ==: org.bukkit.inventory.ItemStack
        type: WOOL
        damage: 2
      - ==: org.bukkit.inventory.ItemStack
        type: DIAMOND_LEGGINGS
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      maxStackSize: 64
      storageContents:
      - ==: org.bukkit.inventory.ItemStack
        type: WOOL
        damage: 2
      - ==: org.bukkit.inventory.ItemStack
        type: DIAMOND_LEGGINGS
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
      - null
     
    and giving me this error:

    Code (Text):
    15.07 14:11:48 [Server] ERROR Cannot load plugins/IndigoInventories/89cb5649-3494-4d7d-949d-94a114d2ae91.yml
    15.07 14:11:48 [Server] INFO org.bukkit.configuration.InvalidConfigurationException: could not determine a constructor for the tag tag:yaml.org,2002:org.bukkit.craftbukkit.v1_12_R1.inventory.CraftInventoryCustom
    15.07 14:11:48 [Server] INFO in 'string', line 2, column 10:
    15.07 14:11:48 [Server] INFO items: !!org.bukkit.craftbukkit.v1_12_R ...
    15.07 14:11:48 [Server] INFO ^
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:55) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:162) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.FileConfiguration.load(FileConfiguration.java:130) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(YamlConfiguration.java:178) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at com.squallz.indigoinventories.MainClass.saveInventoryToConfig(MainClass.java:127) [IndigoInventories.jar:?]
    15.07 14:11:48 [Server] INFO at com.squallz.indigoinventories.MainClass.onLeave(MainClass.java:165) [IndigoInventories.jar:?]
    15.07 14:11:48 [Server] INFO at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_152]
    15.07 14:11:48 [Server] INFO at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_152]
    15.07 14:11:48 [Server] INFO at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_152]
    15.07 14:11:48 [Server] INFO at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_152]
    15.07 14:11:48 [Server] INFO at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:302) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:500) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:485) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.PlayerList.disconnect(PlayerList.java:405) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.PlayerConnection.a(PlayerConnection.java:1102) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.NetworkManager.handleDisconnection(NetworkManager.java:321) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.ServerConnection.c(ServerConnection.java:174) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.MinecraftServer.D(MinecraftServer.java:845) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.DedicatedServer.D(DedicatedServer.java:406) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.MinecraftServer.C(MinecraftServer.java:679) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at net.minecraft.server.v1_12_R1.MinecraftServer.run(MinecraftServer.java:577) [spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at java.lang.Thread.run(Thread.java:748) [?:1.8.0_152]
    15.07 14:11:48 [Server] INFO Caused by: org.yaml.snakeyaml.constructor.ConstructorException: could not determine a constructor for the tag tag:yaml.org,2002:org.bukkit.craftbukkit.v1_12_R1.inventory.CraftInventoryCustom
    15.07 14:11:48 [Server] INFO in 'string', line 2, column 10:
    15.07 14:11:48 [Server] INFO items: !!org.bukkit.craftbukkit.v1_12_R ...
    15.07 14:11:48 [Server] INFO ^
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructUndefined.construct(SafeConstructor.java:539) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:207) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:196) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:462) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:183) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:443) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:519) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:26) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:207) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:196) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:462) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:183) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:443) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:519) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.YamlConstructor$ConstructCustomObject.construct(YamlConstructor.java:26) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:207) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:196) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:161) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.constructor.BaseConstructor.getSingleData(BaseConstructor.java:147) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.Yaml.loadFromReader(Yaml.java:524) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.yaml.snakeyaml.Yaml.load(Yaml.java:437) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO at org.bukkit.configuration.file.YamlConfiguration.loadFromString(YamlConfiguration.java:53) ~[spigot.jar:git-Spigot-642f6d2-57ab4cf]
    15.07 14:11:48 [Server] INFO ... 22 more
     
  2. Hey, you can not save a inventory object in the file, because the inventory class don't implement the "ConfigurationSerializable" interface.
    Save the content from the inventory as list in the file. Not the inventory object.

    EDIT: And filter out the null objects
     
  3. You need the filter the empty slots. If there's nothing in them, the ItemStack returns as null.
     
  4. Save the contents, not the actual inventory object. The "!!" means it can't really parse what it's reading. (CraftInventoryCustom isn't serializable)
    ItemStacks, the contents, are though. Then retrieve it as an object list with just .get() and cast it, as you're already aware of what it is.
     
  5. I ended up having to do this


    Code (Text):

        public static void restoreInventory(Player player){
           
            player.getInventory().clear();
           
            for(ItemStack i : inventory.get(player.getUniqueId()).getContents()) {
                if(i == null) continue;
                player.getInventory().addItem(i);
            }
           
           
            inventory.remove(player.getUniqueId());
        }
    because it wasn't working by just setting contents. Right now I am doing this to add them to an Inventory....

    Code (Text):
        public static void saveInventory(Player player){
            Inventory inv = Bukkit.getServer().createInventory(player, 36, "Inv");
           
            for(ItemStack i : player.getInventory().getContents()) {
                if(i == null) continue;
                inv.addItem(i);
            }
           
            inventory.put(player.getUniqueId(), inv);
        }
    which is really ugly, dirty and messy but it's the only thing that works...

    How would I convert that inventory to lists in the config and also save NBT data, lore, display names, enchants....then fetch it?
     
  6. Code (Text):
    name: Squallz
    inventory:
    - ==: org.bukkit.inventory.ItemStack
      type: WOOL
      damage: 2
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - null
    - ==: org.bukkit.inventory.ItemStack
      type: DIAMOND_LEGGINGS
    - null
    - null
    - null
     
    Now its saving like this so how do I restore it
     
  7. you just get the Configuration section where its saved and loop trough the elements and get the Itemstack with YamlConfiguration#getItemStack(String path);
     
  8. So how exactly would I loop through that then
     
  9. Do Inventory.getContents(), which returns a ItemStack[] of the Inventory's items. This includes NBT data, enchants, etc...
    Looping through the inventory contents I would suggest making a ConfigurationSection with the UUID (Cause they can change their name) and setting the items in it.
    Example:
    Code (Text):
    (UUID):
        1: (item)
        7: (item)
        9: (item)
    Then add them to the player's inventory. In case you don't know, use ConfigurationSection.getKeys(false) to get all the keys (item slots) and use ConfigurationSection.getItemStack(key) to get the ItemStack.
     
  10. Thanks I'm trying this..


    Code (Text):
        public void restoreConfigInventory(Player player){
           
            player.getInventory().clear();
           
            File playerFile = new File(getDataFolder() + File.separator + player.getUniqueId().toString() + ".yml");
            FileConfiguration playerConfig = YamlConfiguration.loadConfiguration(playerFile);
           
            for(String i : playerConfig.getConfigurationSection("inventory").getKeys(false)){
                ItemStack is = playerConfig.getItemStack(i);
               
                player.getInventory().addItem(is);
            }
           
            inventory.remove(player.getUniqueId());
        }
    and getting an NPE and empty inventory
     
  11. I got it all sorted out. All works good now.
     
  12. You should use an instance of your main class and use .getConfig() to get your ConfigurationFile.
    Also loadConfiguration() replaces the old configuration file, which is unnecessary.
    Use setItem(playerConfig.getConfigurationSection("inventory").getInt(is), is);
    I suggest setting the ConfigurationSection to a variable.
    Here's what my code looks like, where instance is an instance of your main class:
    Code (Text):
    config.set("backpacks", null);
            ConfigurationSection section = config.createSection("inventori");
            ConfigurationSection inv = section.createSection(""
                + id);
            for (int i = 0; i < inventory.getSize(); i++) {
                ItemStack item = inventory.getItem(i);
                if (item != null)
                    inv.set("" + i, item);
            }
            instance.saveConfig();
    To load the inventory:
    Code (Text):
    ConfigurationSection inventory = config
                    .getConfigurationSection("inventory");
            Inventory inv = null;
            if (inventory != null) {
                Inventory inv = Bukkit.createInventory(null,
                    backpack.getInt(key), key);
                for (String itemNo : invSection.getKeys(false)) {
                    inv.setItem(Integer.parseInt(itemNo),
                        invSection.getItemStack(itemNo));
                }
            }
            return inv;
    You have to modify it to work with a player's inventory though.

    Also, the reason why you should just save the ItemStack and not use some other method:
    Each ItemStack has an internal variable. Heres what it looks like in a config file:
    Code (Text):
    ==: org.bukkit.inventory.ItemStack
          type: MONSTER_EGG
          meta:
            ==: ItemMeta
            meta-type: SPAWN_EGG
            internal: H4sIAAAAAAAAAONiYOBi4HTNK8ksqQxJTOdgYMpMYRDIzcxLTS5KTCuxqsrPTcpMZWAAADz7vV8oAAAA
            id: zombie
    That's a zombie egg. Odds are other methods will lose certain data, plus its simpler to use a yml instead of a flat file.
     
  13. Every player has their own config.