Serialize Inventory to single string and vice versa

Discussion in 'Resources' started by Phil2812, Aug 9, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    Scizzr

    I can already see a problem with this. What if the item's name contains the characters that the serialization methods use for delimiters, such as where the item's data is split using colons :)), there would be a problem if the item's name contained a colon... We would need an intelligent way to prevent this from bugging out. :D
     
  2. Offline

    KeybordPiano459

    Maybe put the name in quotes or something :p
     
  3. Offline

    Scizzr

    Yeah, but what if someone uses a quote in the item name? It's a never-ending battle... I've been having this problem ever since the ability to name items came up. Currently, my database is using ASCII characters to split the text, hopefully a character that nobody accidentally stumbles upon. Haha! :D
     
  4. Offline

    KeybordPiano459

    We'll have to use some code to separate item names :p Or just disable users from naming items with a certain character in them lol
     
  5. Offline

    Scizzr

    Yeah, good idea. We could just check against certain characters and either deny them naming the item that or writing it into a page in a book OR we could just scrub it out when we serialize it into a string. The RegEx pattern [a-zA-Z0-9_- ] will match case insensitive alphanumeric and the standard spacer characters. Just a couple ways of doing it I guess. :3

    Edit: I guess you don't have to be that restrictive, maybe just deny them using a special character like the grave ` and then use that as the delimiter character. That would work as well.

    Edit 2: On second thought, using the grave as a delimiter character could cause some hiccups in MySQL... You'd definitely want to make an anti-MySQL injection scrubber as well if you used this in a database. A simple one would just replace the quotes (" and ') with escaped quotes. :cool:
     
  6. Offline

    ImTheFool

    I'm not too great at Java, but I made an itemstack-to-string-and-back version of Comphenix 's inventory-to-string-and-back function and updated it for 1.4.6. All credit goes to him, though.
    Code:java
    1. import java.io.ByteArrayInputStream;
    2. import java.io.ByteArrayOutputStream;
    3. import java.io.DataInputStream;
    4. import java.io.DataOutputStream;
    5. import java.math.BigInteger;
    6.  
    7. import net.minecraft.server.v1_4_6.NBTBase;
    8. import net.minecraft.server.v1_4_6.NBTTagCompound;
    9.  
    10. import org.bukkit.craftbukkit.v1_4_6.inventory.CraftItemStack;
    11. import org.bukkit.inventory.ItemStack;
    12.  
    13. public class ClassItemStacksAndStrings {
    14.  
    15. static public String itemstackToString(ItemStack is) {
    16. DataOutputStream dataOutput = new DataOutputStream(outputStream);
    17.  
    18. NBTTagCompound outputObject = new NBTTagCompound();
    19. CraftItemStack craft = getCraftVersion(is);
    20. if (craft != null)
    21. CraftItemStack.asNMSCopy(craft).save(outputObject);
    22. NBTBase.a(outputObject, dataOutput);
    23. return new BigInteger(1, outputStream.toByteArray()).toString(32);
    24. }
    25.  
    26. static public ItemStack stringToItemStack(String str) {
    27. ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(str, 32).toByteArray());
    28. NBTTagCompound item = (NBTTagCompound) NBTBase.b(new DataInputStream(inputStream));
    29. return CraftItemStack.asCraftMirror(net.minecraft.server.v1_4_6.ItemStack.a(item));
    30. }
    31.  
    32. private static CraftItemStack getCraftVersion(ItemStack stack) {
    33. if (stack instanceof CraftItemStack)
    34. return (CraftItemStack) stack;
    35. else if (stack != null)
    36. return CraftItemStack.asCraftCopy(stack);
    37. else
    38. return null;
    39. }
    40. }
    41.  


    I needed it for ItemStack->SQL, so I hope someone else can get some use out of it, too. ;P
     
  7. Offline

    FurmigaHumana

    This method saves enchantments data too? alright, I read now.

    My current method convert the item stack to a string just by taking its data and puting in a string in this form:

    Code:
    ID:DATA:DURABILITY:AMOUNT:[ENCHANTMENTS]
    , I just split everything after and create a new item stack. But it can result in a very big string to a full inventory :c
     
  8. Offline

    xXSniperzzXx_SD

    1.4.7 breaks the class...

    Code:
                // IsEmpty
                if (!inputObject.d()) {
                    inventory.setItem(i, CraftItemStack.asCraftMirror(
                          net.minecraft.server.v1_4_R1.ItemStack.a(inputObject)));
                }
            }
    Is the part that breaks

    @Comphenix
    Any chance you can update it again? :p
     
  9. Offline

    Comphenix

  10. Offline

    xXSniperzzXx_SD

    Comphenix likes this.
  11. Offline

    Eballer48

    How would I go about saving armor with enchants and what not.
     
  12. Offline

    Hellsing

    If anyone is interested in an 1.5.1 update, here is my version of it:
    Code:java
    1. package de.thehellscode.core.util;
    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_5_R2.NBTBase;
    10. import net.minecraft.server.v1_5_R2.NBTTagCompound;
    11. import net.minecraft.server.v1_5_R2.NBTTagList;
    12.  
    13. import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftInventoryCustom;
    14. import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftItemStack;
    15. import org.bukkit.inventory.Inventory;
    16. import org.bukkit.inventory.ItemStack;
    17. import org.bukkit.inventory.PlayerInventory;
    18.  
    19. public class InventoryUtil
    20. {
    21. public static Inventory getArmorInventory(PlayerInventory inventory)
    22. {
    23. ItemStack[] armor = inventory.getArmorContents();
    24. CraftInventoryCustom storage = new CraftInventoryCustom(null, armor.length);
    25.  
    26. for (int i = 0; i < armor.length; i++)
    27. storage.setItem(i, armor[i]);
    28.  
    29. return storage;
    30. }
    31.  
    32. public static Inventory getContentInventory(PlayerInventory inventory)
    33. {
    34. ItemStack[] content = inventory.getContents();
    35. CraftInventoryCustom storage = new CraftInventoryCustom(null, content.length);
    36.  
    37. for (int i = 0; i < content.length; i++)
    38. storage.setItem(i, content[i]);
    39.  
    40. return storage;
    41. }
    42.  
    43. public static String toBase64(Inventory inventory)
    44. {
    45. DataOutputStream dataOutput = new DataOutputStream(outputStream);
    46. NBTTagList itemList = new NBTTagList();
    47. // Save every element in the list
    48. for (int i = 0; i < inventory.getSize(); i++)
    49. {
    50. NBTTagCompound outputObject = new NBTTagCompound();
    51. net.minecraft.server.v1_5_R2.ItemStack craft = getCraftVersion(inventory.getItem(i));
    52. // Convert the item stack to a NBT compound
    53. if (craft != null)
    54. craft.save(outputObject);
    55. itemList.add(outputObject);
    56. }
    57.  
    58. // Now save the list
    59. NBTBase.a(itemList, dataOutput);
    60.  
    61. // Serialize that array
    62. return new BigInteger(1, outputStream.toByteArray()).toString(32);
    63. // return encodeBase64(outputStream.toByteArray());
    64. }
    65.  
    66. public static Inventory fromBase64(String data)
    67. {
    68. ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
    69. // ByteArrayInputStream inputStream = new
    70. // ByteArrayInputStream(decodeBase64(data));
    71. NBTTagList itemList = (NBTTagList) NBTBase.b(new DataInputStream(inputStream));
    72. Inventory inventory = new CraftInventoryCustom(null, itemList.size());
    73.  
    74. for (int i = 0; i < itemList.size(); i++)
    75. {
    76. NBTTagCompound inputObject = (NBTTagCompound) itemList.get(i);
    77. // IsEmpty
    78. if (!inputObject.isEmpty())
    79. {
    80. inventory.setItem(i, CraftItemStack.asBukkitCopy(net.minecraft.server.v1_5_R2.ItemStack.createStack(inputObject)));
    81. }
    82. }
    83. // Serialize that array
    84. return inventory;
    85. }
    86.  
    87. private static net.minecraft.server.v1_5_R2.ItemStack getCraftVersion(ItemStack stack)
    88. {
    89. if (stack != null)
    90. return CraftItemStack.asNMSCopy(stack);
    91.  
    92. return null;
    93. }
    94. }
    95. [/i][/i]
     
    woutwoot and chasechocolate like this.
  13. Offline

    woutwoot

    Thanks! I hope you keep updating this!
     
  14. Offline

    Burnett1

    Hellsing Does you above code support saving Enchanted books? Also written books?
     
  15. Offline

    Hellsing

  16. Offline

    lucasdidur

    @Hellsing I'm getting this error at line 69

    Code:
    Caused by: java.lang.NumberFormatException: Zero length BigInteger
    
     
  17. Offline

    Austy

    Isn't it easier to simply store a map from ItemStack.serialize() in a database as a BLOB type?
     
  18. Offline

    soulofw0lf

    Hellsing any chance of getting a 1.5.2 update?
     
  19. Offline

    Burnett1

    Think thats all that needs changed, might be wrong.


    Code:
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.math.BigInteger;
     
    import net.minecraft.server.v1_5_R3.NBTBase;
    import net.minecraft.server.v1_5_R3.NBTTagCompound;
    import net.minecraft.server.v1_5_R3.NBTTagList;
     
    import org.bukkit.craftbukkit.v1_5_R3.inventory.CraftInventoryCustom;
    import org.bukkit.craftbukkit.v1_5_R3.inventory.CraftItemStack;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.PlayerInventory;
     
    public class InventorySaver {
     
            public static Inventory getArmorInventory(PlayerInventory inventory)
            {
                ItemStack[] armor = inventory.getArmorContents();
                CraftInventoryCustom storage = new CraftInventoryCustom(null, armor.length);
       
                for (int i = 0; i < armor.length; i++)
                    storage.setItem(i, armor[i]);
       
                return storage;
            }
       
            public static Inventory getContentInventory(PlayerInventory inventory)
            {
                ItemStack[] content = inventory.getContents();
                CraftInventoryCustom storage = new CraftInventoryCustom(null, content.length);
       
                for (int i = 0; i < content.length; i++)
                    storage.setItem(i, content[i]);
       
                return storage;
            }
       
            public static String toBase64(Inventory inventory)
            {
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                DataOutputStream dataOutput = new DataOutputStream(outputStream);
                NBTTagList itemList = new NBTTagList();
                // Save every element in the list
                for (int i = 0; i < inventory.getSize(); i++)
                {
                    NBTTagCompound outputObject = new NBTTagCompound();
                    net.minecraft.server.v1_5_R3.ItemStack craft = getCraftVersion(inventory.getItem(i));
                    // Convert the item stack to a NBT compound
                    if (craft != null)
                        craft.save(outputObject);
                    itemList.add(outputObject);
                }
       
                // Now save the list
                NBTBase.a(itemList, dataOutput);
       
                // Serialize that array
                return new BigInteger(1, outputStream.toByteArray()).toString(32);
                // return encodeBase64(outputStream.toByteArray());
            }
       
            public static Inventory fromBase64(String data)
            {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
                // ByteArrayInputStream inputStream = new
                // ByteArrayInputStream(decodeBase64(data));
                NBTTagList itemList = (NBTTagList) NBTBase.b(new DataInputStream(inputStream));
                Inventory inventory = new CraftInventoryCustom(null, itemList.size());
       
                for (int i = 0; i < itemList.size(); i++)
                {
                    NBTTagCompound inputObject = (NBTTagCompound) itemList.get(i);
                    // IsEmpty
                    if (!inputObject.isEmpty())
                    {
                        inventory.setItem(i, CraftItemStack.asBukkitCopy(net.minecraft.server.v1_5_R3.ItemStack.createStack(inputObject)));
                    }
                }
                // Serialize that array
                return inventory;
            }
       
            private static net.minecraft.server.v1_5_R3.ItemStack getCraftVersion(ItemStack stack)
            {
                if (stack != null)
                    return CraftItemStack.asNMSCopy(stack);
       
                return null;
            }
       
    }
    
     
  20. Offline

    soulofw0lf

    Burnett1 to the rescue again :) I tried updating it but couldn't figure out what the craft itemstack was supposed to be changed to :)
     
  21. Offline

    Hellsing

    1.5.2
    Code:java
    1. package de.thehellscode.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_5_R3.NBTBase;
    10. import net.minecraft.server.v1_5_R3.NBTTagCompound;
    11. import net.minecraft.server.v1_5_R3.NBTTagList;
    12.  
    13. import org.bukkit.craftbukkit.v1_5_R3.inventory.CraftInventoryCustom;
    14. import org.bukkit.craftbukkit.v1_5_R3.inventory.CraftItemStack;
    15. import org.bukkit.inventory.Inventory;
    16. import org.bukkit.inventory.ItemStack;
    17. import org.bukkit.inventory.PlayerInventory;
    18.  
    19. public class InventoryUtil
    20. {
    21. public static Inventory getArmorInventory(PlayerInventory inventory)
    22. {
    23. ItemStack[] armor = inventory.getArmorContents();
    24. CraftInventoryCustom storage = new CraftInventoryCustom(null, armor.length);
    25.  
    26. for (int i = 0; i < armor.length; i++)
    27. storage.setItem(i, armor[i]);
    28.  
    29. return storage;
    30. }
    31.  
    32. public static Inventory getContentInventory(PlayerInventory inventory)
    33. {
    34. ItemStack[] content = inventory.getContents();
    35. CraftInventoryCustom storage = new CraftInventoryCustom(null, content.length);
    36.  
    37. for (int i = 0; i < content.length; i++)
    38. storage.setItem(i, content[i]);
    39.  
    40. return storage;
    41. }
    42.  
    43. public static String toBase64(Inventory inventory)
    44. {
    45. DataOutputStream dataOutput = new DataOutputStream(outputStream);
    46. NBTTagList itemList = new NBTTagList();
    47. // Save every element in the list
    48. for (int i = 0; i < inventory.getSize(); i++)
    49. {
    50. NBTTagCompound outputObject = new NBTTagCompound();
    51. net.minecraft.server.v1_5_R3.ItemStack craft = getCraftVersion(inventory.getItem(i));
    52. // Convert the item stack to a NBT compound
    53. if (craft != null)
    54. craft.save(outputObject);
    55. itemList.add(outputObject);
    56. }
    57.  
    58. // Now save the list
    59. NBTBase.a(itemList, dataOutput);
    60.  
    61. // Serialize that array
    62. return new BigInteger(1, outputStream.toByteArray()).toString(32);
    63. // return encodeBase64(outputStream.toByteArray());
    64. }
    65.  
    66. public static Inventory fromBase64(String data)
    67. {
    68. ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
    69. // ByteArrayInputStream inputStream = new
    70. // ByteArrayInputStream(decodeBase64(data));
    71. NBTTagList itemList = (NBTTagList) NBTBase.b(new DataInputStream(inputStream));
    72. Inventory inventory = new CraftInventoryCustom(null, itemList.size());
    73.  
    74. for (int i = 0; i < itemList.size(); i++)
    75. {
    76. NBTTagCompound inputObject = (NBTTagCompound) itemList.get(i);
    77. // IsEmpty
    78. if (!inputObject.isEmpty())
    79. {
    80. inventory.setItem(i, CraftItemStack.asBukkitCopy(net.minecraft.server.v1_5_R3.ItemStack.createStack(inputObject)));
    81. }
    82. }
    83. // Serialize that array
    84. return inventory;
    85. }
    86.  
    87. private static net.minecraft.server.v1_5_R3.ItemStack getCraftVersion(ItemStack stack)
    88. {
    89. if (stack != null)
    90. return CraftItemStack.asNMSCopy(stack);
    91.  
    92. return null;
    93. }
    94. }
    95. [/i][/i]
     
    boolean and Eballer48 like this.
  22. Offline

    Cryptite

    Hellsing Will your class work come 1.6? I have a means by which I'm using this class to store some player chests so that they can bring some of their items to a new world, but being that this uses specific 1.5 server stuff, should I be worried that there might be compatibility issues if I try this in a 1.6 build of bukkit?
     
  23. Offline

    Hellsing

    Cryptite If you know how to use reflection, you should be able to port this to a more version indipendent util. If the version of the package changes (like v1_5_R3 to v1_6_R1), you will need to change it by hand. If you don't do it, it will break.
     
  24. Offline

    ikkentim

    Might be a dumb question, but:
    net.minecraft.server.*

    is not included in the Bukkit package,
    where should I import it from?
     
  25. Offline

    Burnett1

    Craftbukkit not bukkit.
     
  26. Offline

    slayr288

    1.6.1 update for Hellsing 's method

    Code:
    package org.fatecrafters.plugins.versions;
     
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.math.BigInteger;
     
    import net.minecraft.server.v1_6_R1.NBTBase;
    import net.minecraft.server.v1_6_R1.NBTTagCompound;
    import net.minecraft.server.v1_6_R1.NBTTagList;
     
    import org.bukkit.ChatColor;
    import org.bukkit.craftbukkit.v1_6_R1.inventory.CraftInventoryCustom;
    import org.bukkit.craftbukkit.v1_6_R1.inventory.CraftItemStack;
    import org.bukkit.inventory.Inventory;
     
    public class v1_6_R1 {
     
        public static String inventoryToString(final Inventory inventory) {
            final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            final DataOutputStream dataOutput = new DataOutputStream(outputStream);
            final NBTTagList itemList = new NBTTagList();
            for (int i = 0; i < inventory.getSize(); i++) {
                final NBTTagCompound outputObject = new NBTTagCompound();
                net.minecraft.server.v1_6_R1.ItemStack craft = null;
                final org.bukkit.inventory.ItemStack is = inventory.getItem(i);
                if (is != null) {
                    craft = CraftItemStack.asNMSCopy(is);
                } else {
                    craft = null;
                }
                if (craft != null) {
                    craft.save(outputObject);
                }
                itemList.add(outputObject);
            }
            NBTBase.a(itemList, dataOutput);
            return new BigInteger(1, outputStream.toByteArray()).toString(32);
        }
     
        public static Inventory stringToInventory(final String data, final String name) {
            final ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
            final NBTTagList itemList = (NBTTagList) NBTBase.a(new DataInputStream(inputStream));
            final Inventory inventory = new CraftInventoryCustom(null, itemList.size(), ChatColor.translateAlternateColorCodes('&', name));
            for (int i = 0; i < itemList.size(); i++) {
                final NBTTagCompound inputObject = (NBTTagCompound) itemList.get(i);
                if (!inputObject.isEmpty()) {
                    inventory.setItem(i, CraftItemStack.asBukkitCopy(net.minecraft.server.v1_6_R1.ItemStack.createStack(inputObject)));
                }
            }
            return inventory;
        }
     
    }
    
     
    NathanWolf likes this.
  27. Offline

    s0undx

    1.6.1 update with the old structure (not tested)
    Code:
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.math.BigInteger;
     
    import net.minecraft.server.v1_6_R1.NBTBase;
    import net.minecraft.server.v1_6_R1.NBTTagCompound;
    import net.minecraft.server.v1_6_R1.NBTTagList;
     
    import org.bukkit.craftbukkit.v1_6_R1.inventory.CraftInventoryCustom;
    import org.bukkit.craftbukkit.v1_6_R1.inventory.CraftItemStack;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.PlayerInventory;
     
    public class InventorySerializer
    {
        public static Inventory getArmorInventory(PlayerInventory inventory)
        {
            ItemStack[] armor = inventory.getArmorContents();
            CraftInventoryCustom storage = new CraftInventoryCustom(null, armor.length);
     
            for (int i = 0; i < armor.length; i++)
                storage.setItem(i, armor[i]);
     
            return storage;
        }
     
        public static Inventory getContentInventory(PlayerInventory inventory)
        {
            ItemStack[] content = inventory.getContents();
            CraftInventoryCustom storage = new CraftInventoryCustom(null, content.length);
     
            for (int i = 0; i < content.length; i++)
                storage.setItem(i, content[i]);
     
            return storage;
        }
     
        public static String toBase64(Inventory inventory)
        {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dataOutput = new DataOutputStream(outputStream);
            NBTTagList itemList = new NBTTagList();
            // Save every element in the list
            for (int i = 0; i < inventory.getSize(); i++)
            {
                NBTTagCompound outputObject = new NBTTagCompound();
                net.minecraft.server.v1_6_R1.ItemStack craft = getCraftVersion(inventory.getItem(i));
     
                // Convert the item stack to a NBT compound
                if (craft != null)
                    craft.save(outputObject);
               
                itemList.add(outputObject);
            }
     
            // Now save the list
            NBTBase.a(itemList, dataOutput);
     
            // Serialize that array
            return new BigInteger(1, outputStream.toByteArray()).toString(32);
            // return encodeBase64(outputStream.toByteArray());
        }
     
        public static Inventory fromBase64(String data)
        {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
            // ByteArrayInputStream inputStream = new
            // ByteArrayInputStream(decodeBase64(data));
            //NBTTagList itemList = (NBTTagList) NBTBase.b(new DataInputStream(inputStream));
            NBTTagList itemList = (NBTTagList) NBTBase.a(new DataInputStream(inputStream));
            Inventory inventory = new CraftInventoryCustom(null, itemList.size());
     
            for (int i = 0; i < itemList.size(); i++)
            {
                NBTTagCompound inputObject = (NBTTagCompound) itemList.get(i);
                // IsEmpty
                if (!inputObject.isEmpty())
                {
                    inventory.setItem(i, CraftItemStack.asBukkitCopy(net.minecraft.server.v1_6_R1.ItemStack.createStack(inputObject)));
                }
            }
            // Serialize that array
            return inventory;
        }
     
        private static net.minecraft.server.v1_6_R1.ItemStack getCraftVersion(ItemStack stack)
        {
            if (stack != null)
                return CraftItemStack.asNMSCopy(stack);
     
            return null;
        }
    }
     
  28. Offline

    nitrousspark

    any way to serialize item meta with it?
     
  29. Offline

    NathanWolf

    EDIT: This won't work in 1.7.2 .. Sorry! I picked the wrong time to reflection-ify this code! See below, it looks like others are working on it.

    I realize this is kind of an old thread, but it still seems to be the most relevant for people looking to save inventories, so I thought I'd contribute. I took Hellsing 's advice and made a version that uses reflection so it will hopefully be safer and less prone to breakable between versions.
    It does still look up two obfuscated methods from the MC source, though, so no guarantees on the non-breakage. I've also only tested this in a limited fashion, so the use-at-your-own-risk stuff applies.
    https://raw.github.com/elBukkit/Mag...ers/mine/bukkit/utilities/InventoryUtils.java
    Code:java
    1. package com.elmakers.mine.bukkit.utilities;
    2.  
    3. import java.io.ByteArrayInputStream;
    4. import java.io.ByteArrayOutputStream;
    5. import java.io.DataInput;
    6. import java.io.DataInputStream;
    7. import java.io.DataOutput;
    8. import java.io.DataOutputStream;
    9. import java.lang.reflect.Constructor;
    10. import java.lang.reflect.Field;
    11. import java.lang.reflect.Method;
    12. import java.math.BigInteger;
    13.  
    14. import org.bukkit.Bukkit;
    15. import org.bukkit.ChatColor;
    16. import org.bukkit.inventory.Inventory;
    17. import org.bukkit.inventory.InventoryHolder;
    18. import org.bukkit.inventory.ItemStack;
    19.  
    20. public class InventoryUtils
    21. {
    22. private static String versionPrefix = "";
    23.  
    24. private static Class<?> class_ItemStack;
    25. private static Class<?> class_NBTBase;
    26. private static Class<?> class_NBTTagCompound;
    27. private static Class<?> class_NBTTagList;
    28. private static Class<?> class_CraftInventoryCustom;
    29. private static Class<?> class_CraftItemStack;
    30.  
    31. static
    32. {
    33. // Find classes Bukkit hides from us. :-D
    34. // Much thanks to @DPOHVAR for sharing the PowerNBT code that powers the reflection approach.
    35. try {
    36. String className = Bukkit.getServer().getClass().getName();
    37. String[] packages = className.split("\\.");
    38. if (packages.length == 5) {
    39. versionPrefix = packages[3] + ".";
    40. }
    41.  
    42. class_ItemStack = fixBukkitClass("net.minecraft.server.ItemStack");
    43. class_NBTBase = fixBukkitClass("net.minecraft.server.NBTBase");
    44. class_NBTTagCompound = fixBukkitClass("net.minecraft.server.NBTTagCompound");
    45. class_NBTTagList = fixBukkitClass("net.minecraft.server.NBTTagList");
    46. class_CraftInventoryCustom = fixBukkitClass("org.bukkit.craftbukkit.inventory.CraftInventoryCustom");
    47. class_CraftItemStack = fixBukkitClass("org.bukkit.craftbukkit.inventory.CraftItemStack");
    48. }
    49. catch (Throwable ex) {
    50. ex.printStackTrace();
    51. }
    52. }
    53.  
    54. private static Class<?> fixBukkitClass(String className) {
    55. className = className.replace("org.bukkit.craftbukkit.", "org.bukkit.craftbukkit." + versionPrefix);
    56. className = className.replace("net.minecraft.server.", "net.minecraft.server." + versionPrefix);
    57. try {
    58. return Class.forName(className);
    59. e.printStackTrace();
    60. return null;
    61. }
    62. }
    63.  
    64. protected static Object getNMSCopy(ItemStack stack) {
    65. Object nms = null;
    66. try {
    67. Method copyMethod = class_CraftItemStack.getMethod("asNMSCopy", ItemStack.class);
    68. nms = copyMethod.invoke(null, stack);
    69. } catch (Throwable ex) {
    70. ex.printStackTrace();
    71. }
    72. return nms;
    73. }
    74.  
    75. protected static Object getTag(Object mcItemStack) {
    76. Object tag = null;
    77. try {
    78. Field tagField = class_ItemStack.getField("tag");
    79. tag = tagField.get(mcItemStack);
    80. } catch (Throwable ex) {
    81. ex.printStackTrace();
    82. }
    83. return tag;
    84. }
    85.  
    86. public static String getMeta(ItemStack stack, String tag) {
    87. if (stack == null) return null;
    88. String meta = null;
    89. try {
    90. Object craft = getNMSCopy(stack);
    91. Object tagObject = getTag(craft);
    92. Method getStringMethod = class_NBTTagCompound.getMethod("getString", String.class);
    93. meta = (String)getStringMethod.invoke(tagObject, tag);
    94. } catch (Throwable ex) {
    95. ex.printStackTrace();
    96. }
    97. return meta;
    98. }
    99.  
    100. public static ItemStack setMeta(ItemStack stack, String tag, String value) {
    101. if (stack == null) return null;
    102. try {
    103. Object craft = getNMSCopy(stack);
    104. Object tagObject = getTag(craft);
    105. Method setStringMethod = class_NBTTagCompound.getMethod("setString", String.class, String.class);
    106. setStringMethod.invoke(tagObject, tag, value);
    107. Method mirrorMethod = class_CraftItemStack.getMethod("asCraftMirror", craft.getClass());
    108. stack = (ItemStack)mirrorMethod.invoke(null, craft);
    109. } catch (Throwable ex) {
    110. ex.printStackTrace();
    111. }
    112.  
    113. return stack;
    114. }
    115.  
    116. public static String inventoryToString(final Inventory inventory) {
    117. final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    118. final DataOutputStream dataOutput = new DataOutputStream(outputStream);
    119. try {
    120. final Object itemList = class_NBTTagList.newInstance();
    121. for (int i = 0; i < inventory.getSize(); i++) {
    122. final Object outputObject = class_NBTTagCompound.newInstance();
    123. Object craft = null;
    124. final ItemStack is = inventory.getItem(i);
    125. if (is != null) {
    126. craft = getNMSCopy(is);
    127. } else {
    128. craft = null;
    129. }
    130. if (craft != null && class_ItemStack.isInstance(craft)) {
    131. Method saveMethod = class_ItemStack.getMethod("save", outputObject.getClass());
    132. saveMethod.invoke(craft, outputObject);
    133. }
    134. Method addMethod = class_NBTTagList.getMethod("add", class_NBTBase);
    135. addMethod.invoke(itemList, outputObject);
    136. }
    137.  
    138. // This bit is kind of ugly and prone to break between versions
    139. // Well, moreso than the rest of this, even.
    140. Method saveMethod = class_NBTBase.getMethod("a", class_NBTBase, DataOutput.class);
    141. saveMethod.invoke(null, itemList, dataOutput);
    142. } catch (Throwable ex) {
    143. ex.printStackTrace();
    144. }
    145.  
    146. return new BigInteger(1, outputStream.toByteArray()).toString(32);
    147. }
    148.  
    149. public static Inventory stringToInventory(final String data, final String name) {
    150. Inventory inventory = null;
    151.  
    152. try {
    153. final ByteArrayInputStream inputStream = new ByteArrayInputStream(new BigInteger(data, 32).toByteArray());
    154.  
    155. // More MC internals :(
    156. Method loadMethod = class_NBTBase.getMethod("a", DataInput.class);
    157. final Object itemList = loadMethod.invoke(null, new DataInputStream(inputStream));
    158.  
    159. Method sizeMethod = class_NBTTagList.getMethod("size");
    160. Method getMethod = class_NBTTagList.getMethod("get", Integer.TYPE);
    161. final int listSize = (Integer)sizeMethod.invoke(itemList);
    162.  
    163. Method isEmptyMethod = class_NBTTagCompound.getMethod("isEmpty");
    164.  
    165. Constructor<?> inventoryConstructor = class_CraftInventoryCustom.getConstructor(InventoryHolder.class, Integer.TYPE, String.class);
    166. inventory = (Inventory)inventoryConstructor.newInstance(null, listSize, ChatColor.translateAlternateColorCodes('&', name));
    167.  
    168. Method setItemMethod = class_CraftInventoryCustom.getMethod("setItem", Integer.TYPE, ItemStack.class);
    169.  
    170. for (int i = 0; i < listSize; i++) {
    171. final Object inputObject = getMethod.invoke(itemList, i);
    172. if (!(Boolean)isEmptyMethod.invoke(inputObject)) {
    173. Method createMethod = class_ItemStack.getMethod("createStack", inputObject.getClass());
    174. Object newStack = createMethod.invoke(null, inputObject);
    175. Method bukkitCopyMethod = class_CraftItemStack.getMethod("asBukkitCopy", class_ItemStack);
    176. Object newCraftStack = bukkitCopyMethod.invoke(null, newStack);
    177. setItemMethod.invoke(inventory, i, newCraftStack);
    178. }
    179. }
    180. } catch (Throwable ex) {
    181. ex.printStackTrace();
    182. }
    183. return inventory;
    184. }
    185. }

    This (like the code above it's based on) saves all metadata for all (non-armor) items in the inventory.
    Also, as a freebie, there are two functions in there that let you get and set arbitrary NBT metadata on an ItemStack. Be careful with this, it's not supported and you could probably mess something up in a bad, client-crashing kind of way. But I wanted to create some special items with data attached (list of spells), so I'm experimenting with that.
    I wanted to do something similar for Entities, but as it turns out that's really complex and I'll just have to leave that to PowerNBT - which is unfortunate, I really wanted to save a little string attached to each player.
     
    ccrama and DPOH-VAR like this.
  30. Offline

    xXSniperzzXx_SD

    Thanks, this one the only thing making Infected need a specific CB NathanWolf
     
    NathanWolf likes this.
Thread Status:
Not open for further replies.

Share This Page