Cancelling InventoryClickEvent is inconsistent.

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

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

    BeMacized

    Hi there.

    I've been trying to make a stack of a certain item act as a single one. (it's an item displaying some value on the item using stacksize)
    That means that I should be able to pick it up from my inventory, place it down somewhere else in my inventory, but not right click it to only take half of the stack, or when I have it, right click to only put one down. I should also not be able to merge two stacks, so that 2, lets take papers, one of 10, one of 15, can't merge into a stack of 25. Same goes for dropping with Q, it should drop the whole stack, and when picking up such a stack, it should not merge with an already existing stack of the same item in your inventory, but take up a different slot.

    Now, I haven't got to picking up items from the ground, or throwing them on the ground yet, but I'm already stuck on the inventory management part.
    This is the code I've got:
    Code:java
    1. @EventHandler
    2. public void onGunFuckup(InventoryClickEvent evt) {
    3. if (evt.getCursor() != null && evt.getCurrentItem() != null) {
    4. if (evt.getCursor().getType().equals(evt.getCurrentItem().getType()) && Gun.getByMaterial(evt.getCursor().getType()) != null) {
    5. evt.setCancelled(true);
    6. }
    7. }
    8.  
    9. if (evt.getCursor() != null) {
    10. if (Gun.getByMaterial(evt.getCursor().getType()) != null && evt.getClick().isRightClick()) {
    11. evt.setCancelled(true);
    12. }
    13. }
    14.  
    15. if (evt.getCurrentItem() != null) {
    16. if (Gun.getByMaterial(evt.getCurrentItem().getType()) != null && evt.getClick().isRightClick()) {
    17. evt.setCancelled(true);
    18. }
    19. }
    20. }


    The good news is: it works. The bad news is: some times it doesn't. It's inconsistent.
    Sometimes it cancels the move just fine, and sometimes it just merges the stack when I try to because it feels like it, or drops 1 down when I right click on an empty slot while having a stack on my cursor, even though it's supposed to cancel it. This especially happens when i'm doing quick interactions with it inside my inventory, but not only when I do that.

    Is there any way I can make these "stacks" act & be treated like one item? I only use the stack size to display a certain variable about the item.

    Thanks a lot!
     
  2. Offline

    Technes

    CookieGamer100 What kind of help is that?

    I don't know if you've considered it yet, or what you're measuring, exactly, but using the item's durability could be a lot easier to visually display ammo, whathaveyou. I'm not much help either, but I will say that it'll be quite a challenging task to set it up to monitor every interaction possible with this itemstack of multiple items, making sure it preserves its contents..

    Though, I do sortof have an idea for the pickup event, so that it doesn't merge with anything else.

    When the event is fired to pick up an item, check to see if it's one of the items you don't want to merge with others, then iterate through your inventory. Within the iteration, when it returns null, get that slot and set the item to that slot.

    That way you'll only need to deal with interactions inside of the inventory... hopefully.
     
  3. Offline

    BeMacized


    Thanks. I still need to do the pickup stuff, but I'll make sure to use this idea of yours.
    I'd rather have used durability too, but I'm limited to the amount of items capable of displaying durability, and these are used for other items, so using those is no option. I was thinking about maybe adding (invisible) nbt data / lore which is randomly generated and therefore unique per stack, which should solve the merging, but then I still wouldn't have a solution for the splitting of the stack. Maybe auto merge stacks with the same random nbt data.
     
  4. Offline

    remremrem

    Try canceling all InventoryDrag events. This has helped me in the past with the same problems.
     
  5. Offline

    BeMacized


    Thanks man, I'll make sure to try that. I'll notify you guys if that worked :p

    Edit: Nope. Didn't really work.

    I tried the following:
    Code:java
    1. @EventHandler
    2. public void onGunFuckupPartTwo(InventoryDragEvent evt) {
    3. if (Gun.getByMaterial(evt.getOldCursor().getType()) != null || Gun.getByMaterial(evt.getCursor().getType()) != null) {
    4. evt.setCancelled(true);
    5. }
    6. }


    The gunGetByMaterial method is just to check if the item is of a certain type btw. nothing more.
    I use this together with the other method out of my first post, but still the methods allow me to split or merge the stack sometimes.

    I solved the merging and splitting issues.

    For the people who'd like to overcome a similar problem, here's an explanation:
    The examples work for paper. This way you can treat a stack as a single item:

    Listener events: (They prevent splitting)
    Code:java
    1. @EventHandler
    2. public void avoidItemSplitOne(InventoryClickEvent evt) {
    3. if (evt.getCursor() != null) {
    4. if (Gevt.getCursor().getType().equals(Material.PAPER) && evt.getClick().isRightClick()) {
    5. evt.setCancelled(true);
    6. }
    7. }
    8.  
    9. if (evt.getCurrentItem() != null) {
    10. if (evt.getCurrentItem().getType().equals(Material.PAPER) && evt.getClick().isRightClick()) {
    11. evt.setCancelled(true);
    12. }
    13. }
    14. try {
    15. if (evt.isCancelled()) {
    16. ((Player) evt.getWhoClicked()).updateInventory();
    17. }
    18. } catch (Exception e) {
    19. }
    20. }
    21.  
    22. @EventHandler
    23. public void avoidItemSplitTwo(InventoryDragEvent evt) {
    24. if (evt.getOldCursor().getType().equals(Material.PAPER) || evt.getNewCursor().getType().equals(Material.PAPER)) {
    25. evt.setCancelled(true);
    26. }
    27. }


    When getting the item, do this with it: (Note: uses nms imports) (Makes it unmergable)
    Code:java
    1.  
    2. ItemStack is = new ItemStack(Material.PAPER, 32) //Paper item displaying "32"
    3. //Do whatever ItemMeta stuff you want here
    4. net.minecraft.server.v1_6_R3.ItemStack ISNMS = CraftItemStack.asNMSCopy(is);
    5. NBTTagCompound c = (CraftItemStack.asNMSCopy(is)).getTag();
    6. SecureRandom random = new SecureRandom();
    7. c.setString("randomidentifier", new BigInteger(130, random).toString(32));
    8. ISNMS.setTag(c);
    9. is = CraftItemStack.asBukkitCopy(ISNMS);
    10. return is;


    I hope that's clear. Thanks to everyone helping me out here!

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

    NathanWolf


    Ha! Glad I'm not the only one that's used this particular sledgehammer :)

    That event seems really inconsistent (it doesn't always fire on drag or drop or... anything I can figure out). When it does fire, it generally replaces the dragged item with a Bukkit copy. Which leads me to...

    BeMacized - Was it adding an NBT tag to the itemstack that ultimately fixed the problem for you, to make it unstackable?

    I ask because I wonder if that's really working the way you want- have you tried stacking two guns? I'm expecting that might work ... in that they're not stacking due to one have metadata and the other not, not due to the random number.

    The reason I suspect this is because "CraftItemStack.asBukkitCopy" returns a copy of the item, with all non-standard NBT tag data stripped away. It will retain the fact that the item has metadata (which is why I think it's not stacking)- but not the random number you put in.

    If that is true, you could get the same effect cleaner this way:

    Code:java
    1. ItemStack is = new ItemStack(Material.PAPER, 32)
    2. ItemMeta meta = is.getItemMeta();
    3. meta.setDisplayName("Gun");
    4. is.setItemMeta(meta);
    5.  


    That would have the nice side-benefit of renaming your item to "Gun" :)
    You could still stack Guns.. but you may have to live with that unless you're willing to do more skirting around Bukkit functionality- any time it internally makes a copy of an itemstack, it's going to lose your custom data.

    I'm struggling with this right now- and canceling the drag event is definitely one prereq :) In your case, you could just cancel it for any stack of paper with metadata on it.

    Good luck!
     
  7. Offline

    BeMacized

    Thanks for your extensive reply :)
    I just debugged it a bit, and it indeed seemed that my custom nbt data had no influence on the item stacking or not.
    The naming option is no option, as both guns already have a custom name :p. Basically i'm having multiple guns, like a hunting rifle, and a laser pistol, and are all named accordingly. Now when someone finds a hunting rifle, and they already have a hunting rifle which contains the exact same amount of ammo, the lore & display name are the same, and therefore stack, which I off course want to prevent. I now prevented merging by checking if the cursor & current item are of the same material, and if that's the case, cancelling the event. I can prevent the merging from items picked up from the ground by only picking them up when there's an empty slot available, and then putting them in there, and if there's none, just cancelling the event. The only thing I need to figure out how to cancel, is stack merging by shift clicking the gun item. I still want people to be able to shift click their gun to move it to a chest, their inventory, or to their hotbar quickly, I just don't want it to merge.
     
Thread Status:
Not open for further replies.

Share This Page