Solved Deserialize a string to an itemstack

Discussion in 'Plugin Development' started by Dark_Narcosis, Feb 10, 2020.

  1. Offline

    Dark_Narcosis

    In currently trying to save a players inventory as a single string using the following code. I'm able to save the players inventory, however, after looking into this for a while i haven't quite figured out how to deserialize the string back into an ItemStack.

    I'm using this to save a players inventory to a mySQL database so that their inventory can be shared across servers.

    Code:
    public void saveInv(Player player){
            String items = "";
            // get all items in players inventory
            for(int slot = 0 ; slot < player.getInventory().getSize() ; slot++){
                // check if item is null
                if(player.getInventory().getItem(slot) != null){
                    // get the ItemStack
                    ItemStack item = player.getInventory().getItem(slot);
                
                    Map<String, Object> serializedMap = item.serialize();
                    String itemStackString = String.valueOf(serializedMap);
    
                    if(slot == player.getInventory().getSize()-1){
                        item.deserialize(args)
                        items = items+itemStackString;
                    }else{
                        items = items+itemStackString+"##";
                    }
                }else{
                    if(slot == player.getInventory().getSize()-1){
                        items = items+"null";
                    }else{
                        items = items+"null"+"##";
                    }
                }        
            }
            Bukkit.broadcastMessage(ChatColor.stripColor(items));
            // save string in mySQL database
            setValueString(player.getUniqueId().toString(), "INVENTORY", items);
        }
    String Outputted (open)

    {v=1976, type=LEATHER_LEGGINGS, meta=LEATHER_ARMOR_META:{meta-type=LEATHER_ARMOR, display-name=423 THORNSWEPT PANTS (Exotic), lore=[, +10 Health, +8 Defence, +8 Strength, +8% Recovery, +3% Mobility, +7 Energy, , (drop to dismantle), , (Right-Click to equip)], attribute-modifiers={GENERIC_ARMOR_TOUGHNESS=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armorToughness, operation=ADD_NUMBER, amount=0.0, slot=}], GENERIC_ARMOR=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armor, operation=ADD_NUMBER, amount=0.0, slot=}]}, ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=BOW, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=499 ROBUST BOW (Legendary), lore=[, +86 Damage, +4.0 Attack Speed, +7% Crit Chance, +18% Crit Damage, +11 Energy, , (drop to dismantle), , (Right-Click to equip)], enchants={ARROW_INFINITE=1}, ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=STONE_SWORD, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=500 ROBUST SWORD (Legendary), lore=[, +68 Damage, +4.0 Attack Speed, +8% Crit Chance, +2% Crit Damage, +9 Energy, , (drop to dismantle), , (Right-Click to equip)], ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=STONE_SWORD, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=500 ROBUST SWORD (Legendary), lore=[, +43 Damage, +3.0 Attack Speed, +15% Crit Chance, +6% Crit Damage, +11 Energy, , (drop to dismantle), , (Right-Click to equip)], ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=STONE_SWORD, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=499 FLORAL SWORD (Exotic), lore=[, +79 Damage, +3.0 Attack Speed, +14% Crit Chance, +15% Crit Damage, +20 Energy, , (drop to dismantle), ], enchants={DAMAGE_ALL=3, FIRE_ASPECT=2}, ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=BOW, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=500 ROBUST BOW (Legendary), lore=[, +20 Damage, +4.0 Attack Speed, +17% Crit Chance, +14% Crit Damage, +4 Energy, , (drop to dismantle), ], enchants={ARROW_INFINITE=1}, ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=STONE_SWORD, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name=488 ROBUST SWORD (Legendary), lore=[, +96 Damage, +2.0 Attack Speed, +15% Crit Chance, +14% Crit Damage, +14 Energy, , (drop to dismantle), , (Right-Click to equip)], ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##{v=1976, type=GRAY_STAINED_GLASS_PANE, meta=UNSPECIFIC_META:{meta-type=UNSPECIFIC, display-name= }}##{v=1976, type=LEATHER_CHESTPLATE, meta=LEATHER_ARMOR_META:{meta-type=LEATHER_ARMOR, display-name=500 LPLATE CHESTPIECE (Legendary), lore=[, +8 Health, +9 Defence, +3 Strength, +2% Recovery, +1% Mobility, +10 Energy, , (drop to dismantle), , (Right-Click to equip)], attribute-modifiers={GENERIC_ARMOR_TOUGHNESS=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armorToughness, operation=ADD_NUMBER, amount=0.0, slot=}], GENERIC_ARMOR=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armor, operation=ADD_NUMBER, amount=0.0, slot=}]}, ItemFlags=[HIDE_ENCHANTS, HIDE_ATTRIBUTES, HIDE_UNBREAKABLE, HIDE_DESTROYS, HIDE_PLACED_ON, HIDE_POTION_EFFECTS], Unbreakable=true}}##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##{v=1976, type=LEATHER_LEGGINGS, meta=LEATHER_ARMOR_META:{meta-type=LEATHER_ARMOR, display-name=500 LPLATE PANTS (Legendary), lore=[, +7 Health, +8 Defence, +10 Strength, +8% Recovery, +4% Mobility, +2 Energy, , (drop to dismantle), ], attribute-modifiers={GENERIC_ARMOR_TOUGHNESS=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armorToughness, operation=ADD_NUMBER, amount=0.0, slot=}], GENERIC_ARMOR=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armor, operation=ADD_NUMBER, amount=0.0, slot=}]}, ItemFlags=[HIDE_ATTRIBUTES, HIDE_UNBREAKABLE], Unbreakable=true, color=Color:[rgb0x0CC0]}}##{v=1976, type=LEATHER_CHESTPLATE, meta=LEATHER_ARMOR_META:{meta-type=LEATHER_ARMOR, display-name=500 THORNSWEPT CHESTPIECE (Exotic), lore=[, +3 Health, +6 Defence, +9 Strength, +2% Recovery, +5% Mobility, +8 Energy, , (drop to dismantle), ], attribute-modifiers={GENERIC_ARMOR_TOUGHNESS=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armorToughness, operation=ADD_NUMBER, amount=0.0, slot=}], GENERIC_ARMOR=[AttributeModifier{uuid=00000000-0000-0b38-0000-0000000da6be, name=generic.armor, operation=ADD_NUMBER, amount=0.0, slot=}]}, ItemFlags=[HIDE_ATTRIBUTES, HIDE_UNBREAKABLE], Unbreakable=true, color=Color:[rgb0xCC00]}}##null##null


    This is the method i'm using to load the inventory:
    Code:
    public void loadInv(Player player){
            // load string from mySQL database
            if(getValueString(player.getUniqueId().toString(), "INVENTORY") != null){
                String input = getValueString(player.getUniqueId().toString(), "INVENTORY");
    
                for(int slot = 0 ; slot < player.getInventory().getSize() ; slot++){
    
                    String[] parts = input.split("##");
    
                    if(parts[slot].equalsIgnoreCase("null")){
                        player.getInventory().setItem(slot, null);
                    }else{
                        //get ItemStack from string and add to players inventory in slot 'slot'
                    }
                }
            }
        }
    The documentation for the deserialize states "Required method for configuration serialization", I've soo far been unable to figure it out and spent a fair while googling alternatives all with no success

    I have found this method online, yet i'm still struggling to work out how to convert the string i have into a hashmap.
    Code:
     Map<String, Object> itemStackMap = new HashMap<String, Object>();
                    ItemStack item = ItemStack.deserialize(itemStackMap);
    Any help on how to convert the string im getting back into an ItemStack would be appreciated :)
     
    Last edited: Feb 10, 2020
  2. Offline

    Strahan

    Dark_Narcosis likes this.
  3. Offline

    Dark_Narcosis

    I've managed to get a method working using that link, Thanks a lot for that! :)

    If anyone is interested here is the methods i'm using:

    Saving the Inventory:
    Code:
    public void saveInv(Player player){
            String items = "";
            //get all items in players inventory
            for(int slot = 0 ; slot < player.getInventory().getSize() ; slot++){
                //check if slot is empty
                if(player.getInventory().getItem(slot) != null){
                    //get item in slot
                    ItemStack item = player.getInventory().getItem(slot);
                    String itemStackString = "";
                   
                    //encode the item into a string
                    try {
                        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                        BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
                        dataOutput.writeObject(item);
                        dataOutput.close();
                        itemStackString = Base64Coder.encodeLines(outputStream.toByteArray());
                    } catch (IOException e) {
                        throw new IllegalStateException("Unable to save item stacks.", e);
                    }
    
                    if(slot == player.getInventory().getSize()-1){
                        items = items+itemStackString;
                    }else{
                        items = items+itemStackString+"##";
                    }
                }else{
                    if(slot == player.getInventory().getSize()-1){
                        items = items+"null";
                    }else{
                        items = items+"null"+"##";
                    }
                }          
            }
            setValueString(player.getUniqueId().toString(), "INVENTORY", items);
        }
    Loading the inventory:
    Code:
    public void loadInv(Player player) throws IOException {
            //get inventory from mySQL
            if(getValueString(player.getUniqueId().toString(), "INVENTORY") != null){
                //get stored string
                String input = getValueString(player.getUniqueId().toString(), "INVENTORY");
    
                //loop through players inv slots
                for(int slot = 0 ; slot < player.getInventory().getSize() ; slot++){
    
                    String[] parts = input.split("##");
    
                    String itemString = parts[slot];
    
                    //check if slot from saved inventory was empty
                    if(parts[slot].equalsIgnoreCase("null")){
                        player.getInventory().setItem(slot, null);
                    }else{
                      
                        ItemStack itemtoreturn = new ItemStack(Material.AIR);
                      
                        //decode the string back to an itemstack
                        try {
                            ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(itemString));
                            BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
                            itemtoreturn = (ItemStack) dataInput.readObject();
                            dataInput.close();
                        } catch (ClassNotFoundException e) {
                            throw new IOException("Unable to decode class type.", e);
                        }
    
                        player.getInventory().setItem(slot, itemtoreturn);
                    }
                }
            }
        }
    The only downside to this is that it creates a very long string (about 50000 characters long) and may cause a lot of lag saving and reading this. The method i used before was much shorter (Around 5000 characters). If there was a way of using that the i would prefer it, however, this works for now.
     
    Last edited: Feb 11, 2020
  4. Offline

    Strahan

    It's not that big a deal. Even if you were using a clunky old 5400 RPM hard drive, getting 100 MBps, you'd read the data in 500 microseconds. That's micro seconds, not milliseconds. It'd be 0.5 milliseconds, and that's on a crappy drive.

    On my Samsung 970 Pro SSD, it'd be about 0.016 ms. I really don't think that's gonna be a problem lol
     

Share This Page