MySQL - Store player inventory in database

Discussion in 'Plugin Development' started by sebasju1234, Oct 23, 2013.

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

    sebasju1234

    Hi guys,

    I want to store player inventories into a MySQL database, but I am lost. What is the best way to store the inventories?

    Greetings,
    Sebastiaan
     
  2. Offline

    Jalau

    Props to Hellsing:

    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]


    Update it to 1.6.4 cant to it now!
     
  3. Offline

    sebasju1234

    That wouldn't save the player inventory, so that I can acces it on other servers. Right?
     
  4. Offline

    1Rogue

  5. Offline

    sebasju1234

  6. Offline

    NathanWolf

    If you're interested, I made a version of Hellsing 's code that uses reflection to avoid issues across updates:

    See it here on github

    All this code does, though, is save/restore an inventory to a string.

    At that point, it's up to you to insert/select that string in and out of a database. From what I understand, Bukkit has a built-in DB API, so you should definitely start there. I think it's a bit tricky to set up but once you get it going it should be pretty easy to do what you want.

    Now please bear with me for a few notes, I think it's important to manage your expectations :)

    • If all you want to save is one string (inventory) per player, a flat file would probably be much easier (though I'm generally a big fan of storing data in databases rather than abusing a config file format....)
    • What database your data will actually go into is up to the server admin, who can configure Bukkit as she likes. I think by default is uses SQLLite. I mention this because you say "MySQL" in the title, though I'm thinking it shouldn't really matter where your data gets stored
    • Storing data in a database is just about persistence, so the data can be read later (e.g. after server reboot). This does not mean that data is somehow available to other servers.
    That last part is perhaps the most important, you haven't really shared your end goal with us, but I get the impression you might be trying to do something that doesn't really involve database at all (at least, not within Bukkit)
    Maybe let us know what you're trying to do, and we could help with general suggestions?
     
  7. Offline

    sebasju1234

    Well, I am developing a game like MineZ (just to give you an idea) and we are going to run multiple servers for that game. I want to store the player inventories in a database so that I can sync it between our servers. Anyways, thanks for your reaction!
     
  8. Offline

    lycano

    What you really should do is look into the code of InventorySQL. Even he is making heavy use of annotations you should be able to see how its done.

    Hint: https://github.com/ExoNetwork/Inven...datahandling/serializer/BukkitSerializer.java

    Technically an object has to be brought into a serialiseable form.

    Checkout the ItemStack serialise and deserialise method.

    A Map<String, Object> is created. Mostly the Data is converted to a string representation.

    When this is done recursively then you will have a Map that can be stored as binary large object (Blob) inside a database.

    So the main part is the following (Taken from stackoverflow for easy demonstration)
    Code:java
    1.  
    2. public static void main(String[] args) throws Exception {
    3. // Create raw data.
    4. Map<Integer, String> data = new HashMap<Integer, String>();
    5. data.put(1, "hello");
    6. data.put(2, "world");
    7. System.out.println(data.toString());
    8.  
    9. // Convert Map to byte array
    10. out.writeObject(data);
    11.  
    12. // Parse byte array to Map
    13. ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
    14. Map<Integer, String> data2 = (Map<Integer, String>) in.readObject();
    15. System.out.println(data2.toString());
    16. }
    17.  


    So as this is just demonstration code you would obviously have to do the "write to database part".

    What you have to do is get the bytes from the serialised byte array and store this in a blob to your database. Do not use a Text since it will produce too much overhead as text gets indexed plus is super ineffective not only because you can run into character encoding issues.

    A blob will save you from running into those problems. This data does not have to be in a human readable form. If you need those informations you should optimize your database structure and create a table/index for this purpose only linking the ref_id to the blob data if needed.

    Like if you need to fetch an item name many times from the database to lookup "items used" or whatever then you need a table for that. But going through all the object data in text form with the worst case "LIKE '%search%' ... good luck with that.

    Anyways, as im working on a item storage engine myself you can monitor xAuth branch experimental if you like.
     
  9. Offline

    NathanWolf

    Are all your servers going to be on the same local network? A MySQL connection across the internet is usually not a good idea (mainly for security reasons), though you can do it.

    So that said if you are the plugin author and the admin, then you have control I guess.

    So I'm hoping you've looked here?

    http://wiki.bukkit.org/Bukkit.yml#database

    As well as here, following the relevant links to the APIs you can use to store and load objects?

    http://wiki.bukkit.org/Plugin_Databases

    The first link shows you how to configure Bukkit's db (it has an example for MySQL)

    The second link points you towards how to use an ORM API to access that data from your plugin. It's not very hand-holdy, there may be some better resources out there, or even on this forum :)

    That, combines with a method to serialize/deserialize an inventory, should be all the pieces you need to get and store inventories for players across servers. (I assume your plugin would load on login/enable and save on logout/disable?)
     
Thread Status:
Not open for further replies.

Share This Page