Get all items in a chest

Discussion in 'Spigot Plugin Development' started by TheWackyTV, May 31, 2016.

  1. Hello, I am trying to make a plugin that will sell all the items in a chest, if the item is in a hashmap it will get the price of it, and sell it for that (give the player who is trying to sell it)

    The problem is, that it only works if there is 1 of the specific item, so lets say you put 2 bread and one diamond sword, it will only sell the diamond sword.

    My code
    Code (Text):
        public HashMap<ItemStack, Integer> items = new HashMap<>();

        public void onEnable() {
            items.put(new ItemStack(Material.DIAMOND_HELMET), 300);
            items.put(new ItemStack(Material.DIAMOND_CHESTPLATE), 400);
            items.put(new ItemStack(Material.DIAMOND_LEGGINGS), 300);
            items.put(new ItemStack(Material.DIAMOND_BOOTS), 300);

            items.put(new ItemStack(Material.IRON_HELMET), 150);
            items.put(new ItemStack(Material.IRON_CHESTPLATE), 200);
            items.put(new ItemStack(Material.IRON_LEGGINGS), 150);
            items.put(new ItemStack(Material.IRON_BOOTS), 150);

            items.put(new ItemStack(Material.GOLD_HELMET), 100);
            items.put(new ItemStack(Material.GOLD_CHESTPLATE), 150);
            items.put(new ItemStack(Material.GOLD_LEGGINGS), 100);
            items.put(new ItemStack(Material.GOLD_BOOTS), 100);

            items.put(new ItemStack(Material.LEATHER_HELMET), 100);
            items.put(new ItemStack(Material.LEATHER_CHESTPLATE), 125);
            items.put(new ItemStack(Material.LEATHER_LEGGINGS), 100);
            items.put(new ItemStack(Material.LEATHER_BOOTS), 100);

            items.put(new ItemStack(Material.DIAMOND_SWORD), 200);
            items.put(new ItemStack(Material.IRON_SWORD), 100);
            items.put(new ItemStack(Material.STONE_SWORD), 50);
            items.put(new ItemStack(Material.WOOD_SWORD), 20);
            items.put(new ItemStack(Material.WHEAT), 80);
            items.put(new ItemStack(Material.SEEDS), 80);
            items.put(new ItemStack(Material.BREAD), 240);
            Bukkit.getPluginManager().registerEvents(this, this);
        }



        @EventHandler
        public void openMenu(PlayerInteractEvent e) {
            Player p = e.getPlayer();
            Block b = e.getClickedBlock();
            if(b.getType() != null && b.getType().equals(Material.EMERALD_BLOCK)) {
                Inventory inv = Bukkit.createInventory(null, 54, "Sell your items");
                p.openInventory(inv);
            }
        }

        @EventHandler
        public void close(InventoryCloseEvent e) {
            Player p = (Player) e.getPlayer();
            Inventory inv = e.getInventory();
            if(inv.getTitle().contains("Sælg dine items")) {
                for(ItemStack itemStack : e.getInventory().getContents()) {
                    if(items.containsKey(itemStack)) {
                        for(int x=0;x<itemStack.getAmount();x++) {
                            p.sendMessage("Test");
                        }
                    }
                }
            }
        }
     
  2. The ItemStacks object hold an int value that keeps track of how many items are in the stack. So an ItemStack of five apples does not equal an ItemStack of one apple. Your HashMap only stores the ItemStacks as if there was only one item in the stack. To account for this there is a method called isSimilar(); this will compare the ItemStacks normally, except it will ignore the stack size. Use that in your loop and it should work.

    You will have to change your loop structure to apply it, but that is one method you could use.
     
  3. Which loop should I put it in?

    EDIT: Can you give an example as I am pretty lost.
     
  4. You'd have to create a double for-loop. One that loops through the inventory contents, and then another that loops through the items in your HashMap. If it finds a match using #isSimilar() between the inventory item and the HashMap item, then you can do whatever you need to do.
     
  5. Choco

    Moderator

    You could do that, or your other option would be to create a duplicate of every item in the chest as you loop through them with only an amount of 1, and check the HashMap keys for that object instead

    OR the suggested way, change your Map to use <Material, Integer>. Reference the material rather than the item stack itself. That would also remove the need for you to create tons of ItemStacks in your HashMap upon loading
     
  6. This is what I have, is it correct?

    Code (Text):
    for(ItemStack item : inv.getContents()) {
                    for(ItemStack listItem : items.keySet()) {
                        if(item.isSimilar(listItem)) {
                            p.sendMessage("Test");
                        }
                    }
                }
     
  7. I was going to recommend using Material, but then if he decided to add armour with extra data like enchantments, then using material wouldn't work.


    That should work. If the inventory sizes and the list starting getting large there are some performance tweaks you could do using booleans and continue. Other than that, it should work now.
     
  8. Well it did not work :(
     
  9. Can you show code which the loop is in? I just want to see how you are adding the items and checking them?
     
  10. Here you go :)


    Code (Text):
        public HashMap<ItemStack, Integer> items = new HashMap<>();

        public void onEnable() {
            items.put(new ItemStack(Material.DIAMOND_HELMET), 300);
            items.put(new ItemStack(Material.DIAMOND_CHESTPLATE), 400);
            items.put(new ItemStack(Material.DIAMOND_LEGGINGS), 300);
            items.put(new ItemStack(Material.DIAMOND_BOOTS), 300);

            items.put(new ItemStack(Material.IRON_HELMET), 150);
            items.put(new ItemStack(Material.IRON_CHESTPLATE), 200);
            items.put(new ItemStack(Material.IRON_LEGGINGS), 150);
            items.put(new ItemStack(Material.IRON_BOOTS), 150);

            items.put(new ItemStack(Material.GOLD_HELMET), 100);
            items.put(new ItemStack(Material.GOLD_CHESTPLATE), 150);
            items.put(new ItemStack(Material.GOLD_LEGGINGS), 100);
            items.put(new ItemStack(Material.GOLD_BOOTS), 100);

            items.put(new ItemStack(Material.LEATHER_HELMET), 100);
            items.put(new ItemStack(Material.LEATHER_CHESTPLATE), 125);
            items.put(new ItemStack(Material.LEATHER_LEGGINGS), 100);
            items.put(new ItemStack(Material.LEATHER_BOOTS), 100);

            items.put(new ItemStack(Material.DIAMOND_SWORD), 200);
            items.put(new ItemStack(Material.IRON_SWORD), 100);
            items.put(new ItemStack(Material.STONE_SWORD), 50);
            items.put(new ItemStack(Material.WOOD_SWORD), 20);
            items.put(new ItemStack(Material.WHEAT), 80);
            items.put(new ItemStack(Material.SEEDS), 80);
            items.put(new ItemStack(Material.BREAD), 240);
            Bukkit.getPluginManager().registerEvents(this, this);
        }



        @EventHandler
        public void openMenu(PlayerInteractEvent e) {
            Player p = e.getPlayer();
            Block b = e.getClickedBlock();
            if(b.getType() != null && b.getType().equals(Material.EMERALD_BLOCK)) {
                Inventory inv = Bukkit.createInventory(null, 54, "Sell your items");
                p.openInventory(inv);
            }
        }

        @EventHandler
        public void close(InventoryCloseEvent e) {
            Player p = (Player) e.getPlayer();
            Inventory inv = e.getInventory();
            if(inv.getTitle().contains("Sælg dine items")) {
                for(ItemStack item : inv.getContents()) {
                    for(ItemStack listItem : items.keySet()) {
                        if(item.isSimilar(listItem)) {
                            p.sendMessage("Test");
                        }
                    }
                }
            }
        }
     
  11. When you check the inventory name, it doesn't appear to be the same as the name that you set the inventory to. Also you should set inv to e#getView#getTopInventory, that way you won't loop through the player's inventory as well.
     
  12. Okay, so it works sometimes, but I tried to put 4 bread in and it said nothing but came up with this error:

    Code (Text):
    [20:43:37 ERROR]: Could not pass event InventoryCloseEvent to VagtChest v1.0
    org.bukkit.event.EventException
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:310) ~[spigot-1.8.8.jar:git-Spigot-db
    6de12-18fbb24]
            at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:62) ~[spigot-1.8.8.jar:git-Spigot-db6d
    e12-18fbb24]
            at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:502) [spigot-1.8.8.jar:git-Spigot-db
    6de12-18fbb24]
            at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:487) [spigot-1.8.8.jar:git-Spigot-db
    6de12-18fbb24]
            at org.bukkit.craftbukkit.v1_8_R3.event.CraftEventFactory.handleInventoryCloseEvent(CraftEventFactory.java:852)
    [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24]
            at net.minecraft.server.v1_8_R3.PlayerConnection.a(PlayerConnection.java:1411) [spigot-1.8.8.jar:git-Spigot-db6d
    e12-18fbb24]
            at net.minecraft.server.v1_8_R3.PacketPlayInCloseWindow.a(PacketPlayInCloseWindow.java:18) [spigot-1.8.8.jar:git
    -Spigot-db6de12-18fbb24]
            at net.minecraft.server.v1_8_R3.PacketPlayInCloseWindow.a(PacketPlayInCloseWindow.java:1) [spigot-1.8.8.jar:git-
    Spigot-db6de12-18fbb24]
            at net.minecraft.server.v1_8_R3.PlayerConnectionUtils$1.run(SourceFile:13) [spigot-1.8.8.jar:git-Spigot-db6de12-
    18fbb24]
            at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:1.8.0_72]
            at java.util.concurrent.FutureTask.run(Unknown Source) [?:1.8.0_72]
            at net.minecraft.server.v1_8_R3.SystemUtils.a(SourceFile:44) [spigot-1.8.8.jar:git-Spigot-db6de12-18fbb24]
            at net.minecraft.server.v1_8_R3.MinecraftServer.B(MinecraftServer.java:715) [spigot-1.8.8.jar:git-Spigot-db6de12
    -18fbb24]
            at net.minecraft.server.v1_8_R3.DedicatedServer.B(DedicatedServer.java:374) [spigot-1.8.8.jar:git-Spigot-db6de12
    -18fbb24]
            at net.minecraft.server.v1_8_R3.MinecraftServer.A(MinecraftServer.java:654) [spigot-1.8.8.jar:git-Spigot-db6de12
    -18fbb24]
            at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:557) [spigot-1.8.8.jar:git-Spigot-db6de
    12-18fbb24]
            at java.lang.Thread.run(Unknown Source) [?:1.8.0_72]
    Caused by: java.lang.NullPointerException
            at com.darkstarpvp.chest.Core.close(Core.java:95) ~[?:?]
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_72]
            at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_72]
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_72]
            at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_72]
            at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:306) ~[spigot-1.8.8.jar:git-Spigot-db
    6de12-18fbb24]
            ... 16 more
    >
    >
     
  13. What line is line 95?
     
  14. Code (Text):
    p.sendMessage("§aDu har solgt §b" + item.getAmount() + "x " + item.getType().name() + " for " + items.get(item) * item.getAmount());
    Code (Text):
        public HashMap<ItemStack, Integer> items = new HashMap<>();

        public void onEnable() {
            items.put(new ItemStack(Material.DIAMOND_HELMET), 300);
            items.put(new ItemStack(Material.DIAMOND_CHESTPLATE), 400);
            items.put(new ItemStack(Material.DIAMOND_LEGGINGS), 300);
            items.put(new ItemStack(Material.DIAMOND_BOOTS), 300);

            items.put(new ItemStack(Material.IRON_HELMET), 150);
            items.put(new ItemStack(Material.IRON_CHESTPLATE), 200);
            items.put(new ItemStack(Material.IRON_LEGGINGS), 150);
            items.put(new ItemStack(Material.IRON_BOOTS), 150);

            items.put(new ItemStack(Material.GOLD_HELMET), 100);
            items.put(new ItemStack(Material.GOLD_CHESTPLATE), 150);
            items.put(new ItemStack(Material.GOLD_LEGGINGS), 100);
            items.put(new ItemStack(Material.GOLD_BOOTS), 100);

            items.put(new ItemStack(Material.LEATHER_HELMET), 100);
            items.put(new ItemStack(Material.LEATHER_CHESTPLATE), 125);
            items.put(new ItemStack(Material.LEATHER_LEGGINGS), 100);
            items.put(new ItemStack(Material.LEATHER_BOOTS), 100);

            items.put(new ItemStack(Material.DIAMOND_SWORD), 200);
            items.put(new ItemStack(Material.IRON_SWORD), 100);
            items.put(new ItemStack(Material.STONE_SWORD), 50);
            items.put(new ItemStack(Material.WOOD_SWORD), 20);
            items.put(new ItemStack(Material.WHEAT), 80);
            items.put(new ItemStack(Material.SEEDS), 80);
            items.put(new ItemStack(Material.BREAD), 240);
            Bukkit.getPluginManager().registerEvents(this, this);
        }



        @EventHandler
        public void openMenu(PlayerInteractEvent e) {
            Player p = e.getPlayer();
            Block b = e.getClickedBlock();
            if(b.getType() != null && b.getType().equals(Material.EMERALD_BLOCK)) {
                Inventory inv = Bukkit.createInventory(null, 54, "Sell your items");
                p.openInventory(inv);
            }
        }

        @EventHandler
        public void close(InventoryCloseEvent e) {
            Player p = (Player) e.getPlayer();
            Inventory inv = e.getView().getTopInventory();
            if(inv.getTitle().contains("Sell your items")) {
                for (ItemStack item : inv.getContents()) {
                    for (ItemStack listItem : items.keySet()) {
                        if (item.isSimilar(listItem)) {
                            p.sendMessage("§aDu har solgt §b" + item.getAmount() + "x " + item.getType().name() + " for " + items.get(item) * item.getAmount());
                        }
                    }
                }
            }
        }
     
  15. Instead of doing item#getType#name, do item#getType#toString. The error is happening because something in that line is null.
    It is one of the following:
    item.getAmount()
    item.getType.name
    items.get(item)
     
  16. I used item.getType().name
     
  17. It won't really make a difference except, name gets the string value of the ENUM data, whereas toString gets the Material name associated with it. For most materials is won't make a difference, but toString is the proper way if you're trying to send a message to a player.
     
  18. Okay, so I found out the bug. The bug is if you place 1 bread in the inv, it will tell you the message and everything works, but if you place 2 in a stack so it's 2x bread then it wont tell you the message and fail the code. And if you lay 2 times 1x bread in it, it will only sell 1 of them.
     
  19. There is no difference.

    Don't go spreading false information.

    Yes, it's good to use, but no, not the 'proper' way.

    Code (Text):
       /**
       * Returns the name of this enum constant, exactly as declared in its
       * enum declaration.
       *
       * @return the name of this enum constant
       */
        public final String name() {
            return name;
        }

        /**
         * Returns the name of this enum constant, as contained in the
         * declaration.  This method may be overridden, though it typically
         * isn't necessary or desirable.  An enum type should override this
         * method when a more "programmer-friendly" string form exists.
         *
         * @return the name of this enum constant
         */
        public String toString() {
            return name;
        }
     
     
  20. I did say it doesn't really make a difference, but there is a difference, however minute the difference may be. Yes, at moment, in the code you showed, they both return the same value, but in a scenario where the objective is to send a message to player, I'd assume you'd want it in as "user-friendly' form as possible; in the future, toString might be changed to do exactly that. Using name is if you want to get the exact ENUM constant for compatibly because that constant will never change. It doesn't hurt to do it in the recommended way, even if it doesn't make a difference at the moment.