1.15.2 How do I read inventory stack events?

Discussion in 'Spigot Plugin Development' started by NocturnalDev, Feb 5, 2020.

  1. Hello,

    My players currently have items with a screwed up lore. I have changed to implement NBT tags, so now I want to listen to whenever they try to stack two of them together so I can convert the whole thing into the new format.

    I'm also confused on how I'd be able to listen to what item they have on their cursor and what item they're clicking on.

    Thank you.
     
    #1 NocturnalDev, Feb 5, 2020
    Last edited: Feb 5, 2020
  2. Code (Text):
        @EventHandler
        public void onClick(InventoryClickEvent e) {
            if (!(e.getClick().equals(ClickType.LEFT) || e.getClick().equals(ClickType.CREATIVE)) || e.getClickedInventory() == null) return;

            /* Item held by mouse */
            ItemStack heldItem = e.getCursor();
         
            /* Item in Inventory */
            ItemStack clickItem = e.getClickedInventory().getItem(e.getSlot());

            if (heldItem == null || clickItem == null) return;

            //your code
        }
     
    #2 Heretere, Feb 5, 2020
    Last edited: Feb 5, 2020
  3. Ah, okay, I see. I've filled in my necessary checks, but how can I figure out the item slot of the clicked item so that I can set it back in their inventory?

    How would I also make the heldItem poof?
     
  4. 1) You can see it in the code from my first reply, e.getSlot()
    2) heldItem.setType(Material.AIR)
     
  5. But I'm getting the instance of that ItemStack right? Not the physical itemstack?
     
  6. What?
     
  7. Never mind, I got it. However, for setting the new item in the clicked slot, I can't seem to get it into an ItemStack the only set options I see are Material.
     
  8. Code (Java):
            e.getClickedInventory().setItem(e.getSlot(), /* Your Item stack */);
     
  9. remember to add before the code under InventoryClickEvent this
    if(!(e.getWhoClicked() instanceof Player))
    return;
    then cast the player entity
    Player p = (Player) e.getWhoClicked();
     
  10. Why would this be necessary? As far as I can see from the posts in this thread, he never has to use any Player specific methods.
     
  11. Doesn't matter, can still throw ClassCastException
     
  12. Exactly what robertlit said. And however the action has to be made from players as written so it's necessary
     
  13. Where exactly? I see no methods that are player specific being used here, at which point, you might as well use the HumanEntity provided instead of doing an unnecessary check and cast.
    Considering that the only subinterface of HumanEntity is Player, not doing this check doesn't matter. Not to mention that the javadocs for InventoryClickEvent explicitly states: "This event is called when a player clicks a slot in an inventory."
     
  14. I was always referring to this, that's the purpose of my answer. However with HumanEntity is right, but remember that in minecraft there are mobs than can interact with chests.

    When I refer to "player", i mean the fact that basically in game is the player to execute actions and clicks!
     
  15. Hmm, in this case you're correct, it can be safely casted to Player. However, it's better practice to do an instanceof check before casting because in most cases an exception can be thrown.
     
  16. Which mobs can actually interact with the contents of a chest? As far as I'm aware, the only entity that is able to do this is a Player. Regardless, when those mobs interact with a chest the InventoryClickEvent should not be called.
     
  17. Seeing how this was placed in the "Suggestions" category, I don't think this is actually implemented in the game, but rather someone just coming up with ideas they would like to see added.
     
  18. I've tried this:


    Code (Text):
    @EventHandler
    public void onClick(InventoryClickEvent event) {
        if (!(event.getClick().equals(ClickType.LEFT) || event.getClick().equals(ClickType.CREATIVE)) || event.getClickedInventory() == null)
            return;

        if (event.getRawSlot() >= 9 && event.getRawSlot() <= 44) {


            // Item held by mouse
            ItemStack heldItem = event.getCursor();
            ItemMeta heldMeta = heldItem.getItemMeta();
            if (heldMeta.getDisplayName().equalsIgnoreCase(“§bSword”)) {

                // Item in Inventory
                ItemStack clickItem = event.getClickedInventory().getItem(event.getSlot());
                ItemMeta clickMeta = clickItem.getItemMeta();

                if (heldItem == null || clickItem == null) return;

                if (clickMeta.getDisplayName().equalsIgnoreCase(“§bSword”)) {
                    int count = heldItem.getAmount() + clickItem.getAmount();
                    event.getCursor().setType(Material.AIR);
                    ItemStack sword = Utils.getSword();
                    sword.setAmount(count);

                    event.getClickedInventory().setItem(event.getSlot(), sword);
                    return;
                }

            }
     
    However, it doesn't seem to work as expected. For example, if you have the desired item it doesn't get removed from the cursor and the new sum of the items is not the sum of the two items being stacked.