Solved HashMap ItemStack[] to and from config.

Discussion in 'Plugin Development' started by soulofw0lf, Apr 30, 2013.

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

    soulofw0lf

    The intent: to save a players entire inventory, clear it from their inventory when teleporting them, and then later restoring their inventory when teleporting them back to the same spot.

    The Problem: I can get the full inventory to save to config, but any attempt to retrieve it ends with utter disaster. Been at this for a very very long time now and i am admitting defeat. Right now I don't have it saving to config at all, just in a hash map that someone else wrote, which will work as long as i never reset the server. I've searched all over the forums for a way to do this and none of the "solutions" that i have found actually work at all. I would greatly appreciate any help / guidance with this.

    I've got everything shoved in the command handler right now so it's not the neatest code but here it is.
    Code:
    package com.vartala.soulofw0lf.rpglobby;
     
     
     
     
    import java.util.HashMap;
    import java.util.Map;
     
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.PlayerInventory;
     
    public class LobbyHandler implements CommandExecutor {
     
        RpgLobby Rpgl;
     
        Map<Player, ItemStack[]> pArmor = new HashMap<Player, ItemStack[]>();
     
        Map<Player, ItemStack[]> pItems = new HashMap<Player, ItemStack[]>();
        public LobbyHandler(RpgLobby rpgl){
            this.Rpgl = rpgl;
        }
     
        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label,
                String[] args) {
     
     
            Player player = (Player) sender;
            String currentWorld = player.getLocation().getWorld().getName();
     
            if ((args.length != 1) || ((!(args[0].equalsIgnoreCase("enter")) && (!(args[0].equalsIgnoreCase("leave")))))){
                player.sendMessage("Please use {/lobby enter} or {/lobby leave} ");
                return true;
            }
            if ((args[0].equalsIgnoreCase("enter"))&& (!(currentWorld.equalsIgnoreCase("spawn")))){
                pArmor.put(player, player.getInventory().getArmorContents());
                pItems.put(player, player.getInventory().getContents());
                this.Rpgl.getConfig().set(player.getName() + ".X", player.getLocation().getX());
                this.Rpgl.getConfig().set(player.getName() + ".Y", player.getLocation().getY());
                this.Rpgl.getConfig().set(player.getName() + ".Z", player.getLocation().getZ());
                this.Rpgl.getConfig().set(player.getName() + ".Pitch", player.getLocation().getPitch());
                this.Rpgl.getConfig().set(player.getName() + ".Yaw", player.getLocation().getYaw());
                this.Rpgl.getConfig().set(player.getName() + ".World", player.getLocation().getWorld().getName());
                pArmor.put(player, player.getInventory().getArmorContents());
                pItems.put(player, player.getInventory().getContents());
                player.getInventory().clear();
                player.getInventory().setHelmet(null);
                player.getInventory().setChestplate(null);
                player.getInventory().setLeggings(null);
                player.getInventory().setBoots(null);
                this.Rpgl.saveConfig();
                World Lobby = Bukkit.getServer().getWorld("spawn");
                Location Spawn = new Location(Lobby, 2, 27, -96, -2, 8);
                player.teleport(Spawn);
                return true;
            }
            if ((args[0].equalsIgnoreCase("enter")) && (currentWorld.equalsIgnoreCase("spawn"))){
                player.sendMessage("You cannot use this command from the Lobby");
                return true;
            }
            if ((args[0].equalsIgnoreCase("leave")) && (!(currentWorld.equalsIgnoreCase("spawn")))){
                player.sendMessage("You can only use this command from the Lobby");
                return true;
            }
            if ((args[0].equalsIgnoreCase("leave")) && (currentWorld.equalsIgnoreCase("spawn"))){
                if (!(this.Rpgl.getConfig().contains(player.getName()))){
                    World Viking = Bukkit.getServer().getWorld("Cretin's_Chasm");
                    Location newloc = new Location(Viking,30,41,216,-174,-24);
                    player.teleport(newloc);
                    return true;
                }
                String pitch = this.Rpgl.getConfig().getString(player.getName() + ".Pitch");
                String yaw = this.Rpgl.getConfig().getString(player.getName() + ".Yaw");
                World thisworld = Bukkit.getWorld(this.Rpgl.getConfig().getString(player.getName() + ".World"));
                Float newpitch = Float.parseFloat(pitch);
                Float newyaw = Float.parseFloat(yaw);
                Location newloc = new Location(thisworld,this.Rpgl.getConfig().getDouble(player.getName() + ".X"),this.Rpgl.getConfig().getDouble(player.getName() + ".Y"),this.Rpgl.getConfig().getDouble(player.getName() + ".Z"),newyaw,newpitch);
                player.teleport(newloc);
                PlayerInventory pi = player.getInventory();
     
               
                if (pArmor.containsKey(player)) {
                    pi.setArmorContents(pArmor.get(player));
                }
     
                if (pItems.containsKey(player)) {
                    pi.setContents(pItems.get(player));
                }
                this.Rpgl.getConfig().set(player.getName(), null);
                this.Rpgl.saveConfig();
     
                return true;
            }
            return false;
        }
     
    }
    
     
  2. Offline

    Nitnelave

    If you want to write an inventory to the config, you should look around Serializable (ItemStack implements it, I believe), so you should be able to save/read ItemStacks from the config.
     
  3. Offline

    soulofw0lf

    I've spent about the past 11 hours trying to use the configSerializable and cannot for the life of me get it to work, i also tried using the itemStack implementing Serializable but couldn't get it to iterate through all the items to save em to config, it kept error'ing out with all the nulls that are put in from empty inventory slots.
     
  4. Offline

    Burnett1

  5. Offline

    soulofw0lf

    Burnett you are a life saver :)
     
  6. Offline

    Burnett1

    No problem :)
     
  7. Offline

    soulofw0lf

    ok apparently i need to go back to the basics, i can't figure out how i'm supposed to pass a player to this to get the players inventories, how to save it to config, or how to call on it to get the players inventory back. This one's a bit over my head i think. Could i possibly get a bit of guidance from you Burnett1 ?
     
  8. Offline

    Burnett1

    Sure give me a second

    Code:
        public static void loadInv(){
           
            if(Config.getString("Inventory-Do-Not-Edit") == null) return;
           
            Inventory i = InventoryUtil.fromBase64(Config.getString("Inventory-Do-Not-Edit"));
            if(i != null){
                GlobalInv.setContents(i.getContents());
            }
        }
       
        public static void saveInv(){
                   
            Config.set("Inventory-Do-Not-Edit", InventoryUtil.toBase64(GlobalInv));
           
        }
    If you still don't understand then say.

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

    soulofw0lf

    ok so i got it 99% working, it's clearing inventory on entering the lobby, saving it to config, teleporting back to last location on leaving the lobby, giving back regular inventory, clearing the config, only thing it's not doing is restoring the players armor, and I have no idea how to get it to, this plugin really is outside my grasp, if it wasn't for your help Burnett1 i'm sure i wouldn't have gotten this far with it :) feel like helping with one last little piece? here's all three classes. I'm at a loss for now.

    RpgLobby main class
    Code:
    package com.vartala.soulofw0lf.rpglobby;
     
     
    import org.bukkit.entity.Player;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.plugin.java.JavaPlugin;
     
     
     
    public class RpgLobby extends JavaPlugin {
     
     
     
     
     
        public void loadInv(Inventory GlobalInv, Player player){
           
            if(getConfig().getString(player.getName() + ".Inventory-Do-Not-Edit") == null) return;
     
            Inventory i = InventoryUtil.fromBase64(getConfig().getString(player.getName() + ".Inventory-Do-Not-Edit"));
            if(i != null){
         
         
                GlobalInv.setContents(i.getContents());
            }
        }
     
        public void saveInv(Inventory GlobalInv, Player player){
           
            getConfig().set(player.getName() + ".Inventory-Do-Not-Edit", InventoryUtil.toBase64(GlobalInv));
     
        }
     
        @Override
        public void onEnable(){
            getCommand("lobby").setExecutor(new LobbyHandler(this));
            saveDefaultConfig();
            getLogger().info("RPG Lobby onEnable has been invoked!");
        }
        @Override
        public void onDisable(){
            getLogger().info("RPG Lobby onDisable has been invoked!");
        }
    }
    
    command handler
    Code:
    package com.vartala.soulofw0lf.rpglobby;
     
     
     
     
    import org.bukkit.Bukkit;
    import org.bukkit.Location;
    import org.bukkit.World;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
     
    import org.bukkit.inventory.PlayerInventory;
     
     
    public class LobbyHandler implements CommandExecutor {
     
     
        RpgLobby Rpgl;
     
        public LobbyHandler(RpgLobby rpgl){
            this.Rpgl = rpgl;
     
        }
     
     
        @Override
        public boolean onCommand(CommandSender sender, Command cmd, String label,
                String[] args) {
     
     
            Player player = (Player) sender;
            String currentWorld = player.getLocation().getWorld().getName();
     
            if ((args.length != 1) || ((!(args[0].equalsIgnoreCase("enter")) && (!(args[0].equalsIgnoreCase("leave")))))){
                player.sendMessage("Please use {/lobby enter} or {/lobby leave} ");
                return true;
            }
            if ((args[0].equalsIgnoreCase("enter"))&& (!(currentWorld.equalsIgnoreCase("spawn")))){
                this.Rpgl.getConfig().set(player.getName() + ".X", player.getLocation().getX());
                this.Rpgl.getConfig().set(player.getName() + ".Y", player.getLocation().getY());
                this.Rpgl.getConfig().set(player.getName() + ".Z", player.getLocation().getZ());
                this.Rpgl.getConfig().set(player.getName() + ".Pitch", player.getLocation().getPitch());
                this.Rpgl.getConfig().set(player.getName() + ".Yaw", player.getLocation().getYaw());
                this.Rpgl.getConfig().set(player.getName() + ".World", player.getLocation().getWorld().getName());
                PlayerInventory inventory = player.getInventory();
                PlayerInventory armorinv = player.getInventory();
                InventoryUtil.getContentInventory(inventory);
                InventoryUtil.getArmorInventory(armorinv);
                this.Rpgl.saveInv(inventory, player);
                player.getInventory().clear();
                player.getInventory().setHelmet(null);
                player.getInventory().setChestplate(null);
                player.getInventory().setLeggings(null);
                player.getInventory().setBoots(null);
                this.Rpgl.saveConfig();
                World Lobby = Bukkit.getServer().getWorld("spawn");
                Location Spawn = new Location(Lobby, 2, 27, -96, -2, 8);
                player.teleport(Spawn);
                return true;
            }
            if ((args[0].equalsIgnoreCase("enter")) && (currentWorld.equalsIgnoreCase("spawn"))){
                player.sendMessage("You cannot use this command from the Lobby");
                return true;
            }
            if ((args[0].equalsIgnoreCase("leave")) && (!(currentWorld.equalsIgnoreCase("spawn")))){
                player.sendMessage("You can only use this command from the Lobby");
                return true;
            }
            if ((args[0].equalsIgnoreCase("leave")) && (currentWorld.equalsIgnoreCase("spawn"))){
                if (!(this.Rpgl.getConfig().contains(player.getName()))){
                    World Viking = Bukkit.getServer().getWorld("Cretin's_Chasm");
                    Location newloc = new Location(Viking,30,41,216,-174,-24);
                    player.teleport(newloc);
                    return true;
                }
                String pitch = this.Rpgl.getConfig().getString(player.getName() + ".Pitch");
                String yaw = this.Rpgl.getConfig().getString(player.getName() + ".Yaw");
                World thisworld = Bukkit.getWorld(this.Rpgl.getConfig().getString(player.getName() + ".World"));
                Float newpitch = Float.parseFloat(pitch);
                Float newyaw = Float.parseFloat(yaw);
                Location newloc = new Location(thisworld,this.Rpgl.getConfig().getDouble(player.getName() + ".X"),this.Rpgl.getConfig().getDouble(player.getName() + ".Y"),this.Rpgl.getConfig().getDouble(player.getName() + ".Z"),newyaw,newpitch);
                player.teleport(newloc);
                this.Rpgl.loadInv(player.getInventory(), player);
         
                this.Rpgl.getConfig().set(player.getName(), null);
                this.Rpgl.saveConfig();
     
                return true;
            }
            return false;
        }
     
     
    }
    
    and finaly InventoryUtil

    Code:
    package com.vartala.soulofw0lf.rpglobby;
     
    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_R2.NBTBase;
    import net.minecraft.server.v1_5_R2.NBTTagCompound;
    import net.minecraft.server.v1_5_R2.NBTTagList;
     
     
     
    import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftInventoryCustom;
    import org.bukkit.craftbukkit.v1_5_R2.inventory.CraftItemStack;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.PlayerInventory;
     
    public class InventoryUtil
    {
     
        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_R2.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_R2.ItemStack.createStack(inputObject)));
                }
            }
            // Serialize that array
            return inventory;
        }
     
        private static net.minecraft.server.v1_5_R2.ItemStack getCraftVersion(ItemStack stack)
        {
            if (stack != null)
                return CraftItemStack.asNMSCopy(stack);
     
            return null;
        }
    }
    
    Hellsing if you might know why it's not pulling armor your codes a bit much for me to interpret, i'm getting a migraine trying to puzzle through it :)
     
  10. Offline

    devilquak

    soulofw0lf

    If you're making any type of minigame, there's no need to give yourself a brain tumor by trying to save a serialized inventory to a flat file. Save the players' inventory in a HashMap and restore it from the same map when you want to return the inventory.
     
  11. Offline

    soulofw0lf

    I wish it was just for a minigame, but it's actually for an mmo rpg i'm making, the lobby will be an area where people can switch to their "alts" so the inventory / postion of current char needs to be saved to a flat file.

    well the rest of the plugin is done, being able to hold multiple lobbies, list all lobbies, delete lobbies, have a first spawn lobby, add unlimited lobbies, save your position from where you were, send you back to position with the items that you had when you enterted the lobby in the first place, except for armor.. if anyo0ne has any clue how to get armor to work please please help me! i'm at a complete lost! it dissapears fine, but when all inventory items are added back armor doesn't come with it at all :(

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

    devilquak

    soulofw0lf

    Ah, that makes more sense. If you really do need to save inventories to a flat file, you can try what I did and use ProtocolLib to convert an inventory to a string and vice-versa.
     
  13. Offline

    soulofw0lf

    it's saving them just fine now, and loading back in everything but the armor, i just can't figure out where the problem with the armor is.
     
  14. Offline

    Burnett1

    Is the armor getting put into the inventory or is it not there?
     
  15. Offline

    soulofw0lf

    it's just not there at all.
     
  16. Offline

    Burnett1

    Hmm i'm not sure whats wrong ill test it when i can.
     
  17. Offline

    soulofw0lf

    Allright i appreciate that alot man. Once i'm done figuring out the sync event for the plugin if you haven't figured it out i'm gonna try to delve into it and see if i can't figure out what's wrong.

    Still not able to get the armor to load back in when the player leaves the lobby, anyone have any suggestions?

    allright i got it sorted out after i actually too the time to really look into it. if you want the fixed functions Burnett1 here they are
    Code:
    public void loadInv(Player player){
     
            if(getConfig().getString(player.getName() + ".Inventory-Do-Not-Edit") == null) return;
            Inventory a = InventoryUtil.fromBase64(getConfig().getString(player.getName() + ".Armor-Inventory-Do-Not-Edit"));
            if(a != null){
     
               
                player.getInventory().setArmorContents(a.getContents());
               
            }
            Inventory i = InventoryUtil.fromBase64(getConfig().getString(player.getName() + ".Inventory-Do-Not-Edit"));
            if(i != null){
     
               
                player.getInventory().setContents(i.getContents());
               
            }
        }
     
        public void saveInv(Player player){
           
            Inventory storage = InventoryUtil.getArmorInventory(player.getInventory());
            Inventory GlobalInv = InventoryUtil.getContentInventory(player.getInventory());
            getConfig().set(player.getName() + ".Inventory-Do-Not-Edit", InventoryUtil.toBase64(GlobalInv));
            getConfig().set(player.getName() + ".Armor-Inventory-Do-Not-Edit", InventoryUtil.toBase64(storage));
     
        }
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 1, 2016
  18. Offline

    skore87

    You could just make this really simple and save the whole ItemStack array to a binary file since it is serializable. And if by some chance you use more than one inventory per player you could either prefix the file name with an identifier, add an identifier in the file, or generate a file name and place the location in a yml file.
     
  19. Offline

    soulofw0lf

    I started off trying to serialize the inventory and was failing horribly at getting it to work. this way of converting it to a string and saving it on the other hand works amazingly well now. I'll toss the full plugin up on bukkitdev after i'm finished bug testing tonight for anyone that's interested in it.
     
  20. Offline

    Compressions

    soulofw0lf I'd love to see the source code (assuming it's open source)
     
  21. Offline

    soulofw0lf

    yeah it is, but fair warning i have very little to no commenting in the source for this one :) I'll put it up on a bitbukkit in a bit here, testing permissions on it right now.
     
  22. Offline

    devilquak

    soulofw0lf

    That's no issue, most people don't expect commenting on code they see. Most developers here can usually instantly tell whatever is going on in the source just by looking at it.
     
  23. Offline

    soulofw0lf

Thread Status:
Not open for further replies.

Share This Page