Save inventory to Config file

Discussion in 'Plugin Development' started by Julian1Reinhardt, Aug 3, 2013.

Thread Status:
Not open for further replies.
  1. How can I save a whole Inventory to my config file, and when I need it i want to get this inventory back
     
  2. Offline

    deery50

    Julian1Reinhardt
    You can use base64 to serialize the inventory from the NBT data, create a new script and make this the contents:
    Code:java
    1. package com.runetooncraft.plugins.EasyMobArmory.core;
    2.  
    3. import java.io.ByteArrayInputStream;
    4. import java.io.ByteArrayOutputStream;
    5. import java.io.DataInputStream;
    6. import java.io.DataOutputStream;
    7. import java.math.BigInteger;
    8.  
    9. import net.minecraft.server.v1_6_R2.NBTBase;
    10. import net.minecraft.server.v1_6_R2.NBTTagCompound;
    11. import net.minecraft.server.v1_6_R2.NBTTagList;
    12.  
    13. import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftInventory;
    14. import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftInventoryCustom;
    15. import org.bukkit.craftbukkit.v1_6_R2.inventory.CraftItemStack;
    16. import org.bukkit.inventory.EntityEquipment;
    17. import org.bukkit.inventory.Inventory;
    18. import org.bukkit.inventory.ItemStack;
    19. import org.bukkit.inventory.PlayerInventory;
    20.  
    21. public class InventorySerializer {
    22. public static Inventory getArmorInventory(PlayerInventory inventory) {
    23. ItemStack[] a = inventory.getArmorContents();
    24. CraftInventoryCustom storage = new CraftInventoryCustom(null, a.length);
    25.  
    26. for (int i = 0; i < a.length; i++)
    27. storage.setItem(i, a[i]);
    28.  
    29. return storage;
    30. }
    31. public static String tobase64(Inventory inventory) {
    32. DataOutputStream dataOutput = new DataOutputStream(outputStream);
    33. NBTTagList itemList = new NBTTagList();
    34. for (int i = 0; i < inventory.getSize(); i++) {
    35. NBTTagCompound outputObject = new NBTTagCompound();
    36. net.minecraft.server.v1_6_R2.ItemStack craft = getCraftVersion(inventory.getItem(i));
    37.  
    38. if(craft != null) craft.save(outputObject);
    39.  
    40. itemList.add(outputObject);
    41. }
    42. NBTBase.a(itemList, dataOutput);
    43.  
    44. return new BigInteger(1, outputStream.toByteArray()).toString(32);
    45. }
    46.  
    47. public static Inventory frombase64(String data) {
    48. ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
    49. NBTTagList itemList = (NBTTagList) NBTBase.a(new DataInputStream(inputStream));
    50. Inventory inventory = new CraftInventoryCustom(null, itemList.size());
    51. for(int i = 0; i < itemList.size(); i++) {
    52. NBTTagCompound inputObject = (NBTTagCompound) itemList.get(i);
    53.  
    54. if(!inputObject.isEmpty()) {
    55. inventory.setItem(i, CraftItemStack.asBukkitCopy(net.minecraft.server.v1_6_R2.ItemStack.createStack(inputObject)));
    56. }
    57. }
    58. return inventory;
    59. }
    60.  
    61. private static net.minecraft.server.v1_6_R2.ItemStack getCraftVersion(ItemStack stack) {
    62. if(stack != null) return CraftItemStack.asNMSCopy(stack);
    63. return null;
    64. }
    65. }
    66. [/i]

    I did not create this code, I branched off from it but it was originally from here: https://forums.bukkit.org/threads/serialize-inventory-to-single-string-and-vice-versa.92094/page-2
    anyway you can not use this scripts tobase64 method to serialize the inventory to base64 and then the frombase64 method to de-serialize the created String back to an inventory. This then of course could be used to save the serialized inventory to a YamlConfiguration and then get that serialized data from the same file and de-serialize it.
    Hope this helped :).
     
  3. Offline

    gomeow

  4. deery50 I got a NullPointerException in this line:
    Code:
    net.minecraft.server.v1_6_R2.ItemStack craft = getCraftVersion(inventory.getItem(i));
    This Error:
    Code:
    [SEVERE] Could not pass event InventoryCloseEvent to AuroraCloudChest v
    1.0
    org.bukkit.event.EventException
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.ja
    va:427)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.jav
    a:62)
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.j
    ava:477)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.j
    ava:462)
            at org.bukkit.craftbukkit.v1_6_R2.event.CraftEventFactory.handleInventor
    yCloseEvent(CraftEventFactory.java:684)
            at net.minecraft.server.v1_6_R2.PlayerList.disconnect(PlayerList.java:25
    5)
            at net.minecraft.server.v1_6_R2.PlayerConnection.a(PlayerConnection.java
    :688)
            at net.minecraft.server.v1_6_R2.NetworkManager.b(NetworkManager.java:302
    )
            at net.minecraft.server.v1_6_R2.PlayerConnection.e(PlayerConnection.java
    :116)
            at net.minecraft.server.v1_6_R2.ServerConnection.b(SourceFile:37)
            at net.minecraft.server.v1_6_R2.DedicatedServerConnection.b(SourceFile:3
    0)
            at net.minecraft.server.v1_6_R2.MinecraftServer.t(MinecraftServer.java:5
    90)
            at net.minecraft.server.v1_6_R2.DedicatedServer.t(DedicatedServer.java:2
    26)
            at net.minecraft.server.v1_6_R2.MinecraftServer.s(MinecraftServer.java:4
    86)
            at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java
    :419)
            at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:5
    82)
    Caused by: java.lang.NullPointerException
            at me.virhonestum.auroracloudchest.listener.tobase64(listener.java:73)
            at me.virhonestum.auroracloudchest.listener.inventoryClose(listener.java
    :40)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.ja
    va:425)
            ... 15 more
     
  5. Offline

    deery50

    gomeow
    You could, but that doesn't save all of the NBT data and can miss enchantments, item names, etc.

    Julian1Reinhardt
    is the inventory null? You will have to do some more debugging.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  6. deery50
    It is:
    Code:
    Inventory cloudInventory = Bukkit.createInventory(null, 54, "CloudChest");
    I just want the same inventory for everyone. Is there a better way to do that?
     
  7. Offline

    deery50

    Julian1Reinhardt
    You will need to set the Player the inventory is attached to, otherwise the Inventory will be null. Other players will still be able to open the inventory though through Player.openInventory(inventory), but it has to be attached to a player.
     
  8. deery50
    can i create a dummy player somehow, or can i switch the person who owns this inventory?
     
  9. Offline

    AmShaegar

    This is how I do it:
    Code:java
    1. public void save(Player p) throws IOException {
    2. YamlConfiguration c = new YamlConfiguration();
    3. c.set("inventory.armor", p.getInventory().getArmorContents());
    4. c.set("inventory.content", p.getInventory().getContents());
    5. c.save(new File(path, p.getName()+".yml"));
    6. }

    It looks something like this:
    Code:
    inventory:
      armor:
      - ==: org.bukkit.inventory.ItemStack
        type: AIR
        damage: -1
        amount: 0
      - ==: org.bukkit.inventory.ItemStack
        type: AIR
        damage: -1
        amount: 0
      - ==: org.bukkit.inventory.ItemStack
        type: AIR
        damage: -1
        amount: 0
      - ==: org.bukkit.inventory.ItemStack
        type: AIR
        damage: -1
        amount: 0
      content:
      - ==: org.bukkit.inventory.ItemStack
        type: SIGN
      - ==: org.bukkit.inventory.ItemStack
        type: DIAMOND_SWORD
        meta:
          ==: ItemMeta
          meta-type: UNSPECIFIC
          enchants:
            KNOCKBACK: 1
      - null
      - null
      - null
      - ...
    To get it back use:
    Code:java
    1. @SuppressWarnings("unchecked")
    2. public void restore(Player p) throws IOException {
    3. YamlConfiguration c = YamlConfiguration.loadConfiguration(new File(path, p.getName()+".yml"));
    4. ItemStack[] content = ((List<ItemStack>) c.get("inventory.armor")).toArray(new ItemStack[0]);
    5. p.getInventory().setArmorContents(content);
    6. content = ((List<ItemStack>) c.get("inventory.content")).toArray(new ItemStack[0]);
    7. p.getInventory().setContents(content);
    8. }
     
  10. deery50
    It won't work with this either:
    Code:
    Inventory cloudInventory = Bukkit.createInventory((InventoryHolder)sender, 54, "CloudChest");
    AmShaegar
    That doesn't save custom names, does it?
     
  11. Offline

    AmShaegar

    Code:
      - ==: org.bukkit.inventory.ItemStack
        type: PAPER
        meta:
          ==: ItemMeta
          meta-type: UNSPECIFIC
          display-name: §1Cottage
          lore:
          - Use this deed to rent a spot.
          - 'Rent for this type: $100.00'
    Works!
     
  12. Offline

    gomeow

    erm... It does save everything? It uses the ItemStack's .serialize() method which returns everything and deserializes the same way. This being the case, if Mojang ever adds new data to the ItemStack, this won't break.

    Sample yaml file: http://pastebin.com/Ak0MshrS

    I'm also curious, why do you think it doesn't save everything?
     
  13. Offline

    AmShaegar

    This looks much cleaner than my version... I am thinking of switching to this method. This also seems to avoid the "unchecked" warning.
     
  14. Offline

    deery50

    gomeow
    Because I didn't see the Serialization class, I just used a different method by using base64 serialization, your way works fine though :). Base64 ends up looking like a random bunch of characters but generally also doesn't take up as much space, depending on the size of the inventory...but at the end of the day both of them look fine. If your intention is to edit some inventory contents via the yml file then you would need to use your method.

    Julian1Reinhardt
    Make sure your player isn't null either. What is the error returned from that?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 3, 2016
  15. deery50
    the exact same error

    deery50
    Alright, I can not figure out what the problem might be, so I'm going to post my whole code here:
    The main.java file: http://pastebin.com/dxcw2FmR
    The listener.java: http://pastebin.com/srQzNgD6
    I guess you don't need my permissions.java :3

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

    deery50

    Julian1Reinhardt
    Try something like this:
    Code:
    Player p = (Player) sender;
    Inventory inv = Bukkit.createInventory(p, 9, "pigzombieinv");
    
    Sorry for the late reply.
     
  17. deery50
    Doesn't work...
    Code:
    03:14:06 [SEVERE] Could not pass event InventoryCloseEvent to AuroraCloudChest v
    1.0
    org.bukkit.event.EventException
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.ja
    va:427)
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.jav
    a:62)
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.j
    ava:477)
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.j
    ava:462)
            at org.bukkit.craftbukkit.v1_6_R2.event.CraftEventFactory.handleInventor
    yCloseEvent(CraftEventFactory.java:684)
            at net.minecraft.server.v1_6_R2.PlayerConnection.handleContainerClose(Pl
    ayerConnection.java:1166)
            at net.minecraft.server.v1_6_R2.Packet101CloseWindow.handle(SourceFile:1
    7)
            at net.minecraft.server.v1_6_R2.NetworkManager.b(NetworkManager.java:296
    )
            at net.minecraft.server.v1_6_R2.PlayerConnection.e(PlayerConnection.java
    :116)
            at net.minecraft.server.v1_6_R2.ServerConnection.b(SourceFile:37)
            at net.minecraft.server.v1_6_R2.DedicatedServerConnection.b(SourceFile:3
    0)
            at net.minecraft.server.v1_6_R2.MinecraftServer.t(MinecraftServer.java:5
    90)
            at net.minecraft.server.v1_6_R2.DedicatedServer.t(DedicatedServer.java:2
    26)
            at net.minecraft.server.v1_6_R2.MinecraftServer.s(MinecraftServer.java:4
    86)
            at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java
    :419)
            at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:5
    82)
    Caused by: java.lang.NullPointerException
            at me.virhonestum.auroracloudchest.listener.tobase64(listener.java:72)
            at me.virhonestum.auroracloudchest.listener.inventoryClose(listener.java
    :40)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
            at java.lang.reflect.Method.invoke(Unknown Source)
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.ja
    va:425)
            ... 15 more
     
  18. Offline

    deery50

    Julian1Reinhardt
    Can you paste the line that the NPE is happening on from the InventorySerializer class please? From the error that looks like like 72.
     
  19. deery50
    I've alredy posted it, it was the same line as before. :) But here it is:
    Code:
    net.minecraft.server.v1_6_R2.ItemStack craft = getCraftVersion(inventory.getItem(i));
     
  20. Offline

    deery50

    Julian1Reinhardt
    I'm not entirely sure why you are getting that problem, the code for the InventorySerializer class has been tested quiet a lot, the NPE you are having is occuring because the contents of the inventory is null, in your listener class it seems like you are calling this line:
    Code:
    tobase64(plugin.cloudInventory);
    
    before actually setting the contents of the inventory, thus keeping the contents of the inventory as null.
     
  21. deery50
    Oh i forgot to implement the frombase64 in my code. But what string do i need to call this function? And even if i put somehting in the inventory, it still got this error.
     
  22. Offline

    deery50

    Julian1Reinhardt
    In your listener script, you don't actually set the contents of the inventory, you have to get the inventory from the event like so:
    Code:
    Inventory i = event.getInventory();
    plugin.cloudInventory.setContents(i.getContents());
    
     
  23. deery50
    Now the error is in this line:
    Code:
    plugin.cloudInventory.setContents(i.getContents());
    Again, a NPE
     
  24. Offline

    deery50

    Julian1Reinhardt
    Does the listener script have access to it? I personally think the best thing to do would be this:
    Code:
    tobase64(i.getContents());
    
    Also are you actually doing anything to the base64? Like saving it to a config file or such? Because from that script it seems you just have tobase64.
     
  25. deery50
    tobase64 needs an inventory not an itemstack.
    And nom i don't do anything with it yet. To be honest, I'm not even sure hot ...
     
  26. Offline

    deery50

    Julian1Reinhardt
    Yeah sorry I meant to create a new inventory within the method and set the contents as i.getContents() and then base64 that.
     
  27. I'm way to stupid for this but i want to make this plugin :3

    deery50
    So you don't know what the problem is right now, either?
     
  28. Offline

    deery50

    Julian1Reinhardt
    Did you try what I said before?
     
  29. Offline

    virhonestum

Thread Status:
Not open for further replies.

Share This Page