1.16.1 e.setCancelled(true) doesn't work after delaying it by 0 ticks

Discussion in 'Spigot Plugin Development' started by DiamondMiner88_, Jun 30, 2020.

  1. Code (Java):

    @EventHandler
    public void onInventoryClick(InventoryClickEvent e) {
        // delay is to get the inventory after the player has clicked, not before
        new BukkitRunnable() {
            @Override
            public void run() {
                if (e.getClickedInventory() == null) return;
                if (!e.getView().getTitle().equals("VanillaAddons Crafting")) return;
                if (e.getClickedInventory().getType() == InventoryType.PLAYER) return;

                Player p = (Player) e.getWhoClicked();
                Inventory inv = e.getClickedInventory();

                /**
                 * If player clicked on something that isn't interactive, cancel event and return
                 */

                if (!Arrays.asList(10, 11, 12, 19, 20, 21, 28, 29, 30, 25, 49).contains(e.getRawSlot())) {
                    e.setCancelled(true);
                    return;
                }
            }
        }.runTaskLater(plugin, 0);
    }
     
    The e.setCancelled(true); does not do anything, it allows the player to still pick up the item
     
  2. Is there an error in console?
     
  3. nothing
     
  4. You can try debugging it by sending a message to console after each if statement:
    Code (Text):
    System.out.println("Passed if statement 1");
    and the go from there.
     
  5. potentially try using e.getSlot rather than e.getrawslot
     
  6. You cannot cancel events after the server executes all the code in your event.
    The scheduling of a task is instant, even if the task has not been run yet.

    I'm not 100% sure on the inner-workings of the bukkit scheduler but when you create a task with a delay of zero ticks it most likely performs exactly the same as a delay of 1 tick. Even if the task does execute on the same tick it was created, you have no control over when the task is run during the tick ie. before or after the inventory has been updated.

    So in your case the following is happening (in this order):
    - Player clicks inventory
    - Bukkit creates inventory click event object
    - Bukkit passes this event to all the plugins running on the server
    - Plugins have the ability to now edit this event object
    - You create your task of "0" delay.
    - Bukkit checks if the event has been cancelled, and handles event accordingly
    - Some time later (most likely 1 tick later) your task is actually ran where you update the event object
    - Event object is never read past this point, so cancelling it does nothing.
     
    #6 Lammazz, Jun 30, 2020
    Last edited: Jun 30, 2020
    • Winner Winner x 2
  7. drives_a_ford

    Junior Mod

    This. A thousand times this.

    When you schedule a task, that task will be run at a different moment in time. By that time, changes to the event are irrelevant because the game has moved on.
    Even if this happens on the same tick, it'll be way after the result of the event handling has been dealt with by the server.

    If you want to run some code now, then just run your code.

    Did you also expect that if you set the delay to a negative value you'd be able to run some code in the past?
     
  8. This code worked on 1.8.8 so I was confused

    My problem is that i need the inventory AFTER the click, not before
    If you print out the inventory it gives you how it was before you clicked. I'm making a custom crafting gui so upon a click I need to check if certain slots matche a recipe, however what happens is it always doesn't match if its the final item placed because it tries to match it against a inventory before you placed the final item.
     
  9. TheViperShow

    TheViperShow Previously FendiTony777

    Wait???? I can't run tasks in the past... Ok uninstalling spigot rn
    very poor time traveling API
     
  10. If you want to see the changes that are made to the inventory after the event has finished, that can be fine. There is just no way to retroactively undo the event after that point.
    Given that information it's up to you to figure out how to do what you want.

    It seems like your options are either to predict what changes will happen to the inventory when the event is fired, or read from the inventory 1 tick after the event fires and manually figure out what updates you want to do to the inventory.
    In general I would recommend you don't schedule tasks in events as it introduces the chance that objects are not in the state you want them to be, for example it is possible the inventory can be updated unexpectedly in the tick between you scheduling your task and the task being executed.