Solved InventoryClickEvent problem and canceling runnable if player moves or drops the item?

Discussion in 'Plugin Development' started by MrAndeos, Oct 23, 2017.

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

    MrAndeos

    Hello.

    I wrote this simple class, that checks if player moved blaze rod to one of it's hotbar slots, if so, its starting the runnable that applies INCREASE_DAMAGE effect to player:

    Code:
        private int taskId;
       
        @EventHandler
        public void onInteract(InventoryClickEvent event) {
            final Player player = (Player) event.getWhoClicked();
            for(int i = 0; i < 9; i++) {
                if(event.getSlot() == i) {
                    if(event.getCurrentItem().getType() == Material.BLAZE_ROD) {
                        this.taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.plugin, new Runnable() {
                            public void run() {
                                player.addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 40, 1));
                            }
                        }, 20, 20);
                    }
                }
            }
        }
    
    But, if I move the blaze rod to one of the hotbar slots, I need to insert it, remove it and reinsert it for the runnable to start, how to avoid this?

    The second thing, that i wanna do, is to cancel this runnable if the player moves blaze rod out of hotbar slots, or drops it, and then remove this blaze rod item. How to do this?

    Sorry for any mistakes, English is not my native language.
     
  2. Offline

    MightyOne

    Bukkit.getScheduler().cancelTask(taskId);
    Yeah just cancel the task like this xD
    Idk for what exactly do you need help?
    There is the InventoryClickEvent and the PlayerDropItemaevent you can use to detect when the rod gets removed from the hotbar and then cancel the task(-Id). Maybe put it anywhere where you can acces it more easily.

    What do you mean with that you have to reinsert the itemstack? what happens if you do not reinsert it?
     
    Last edited: Oct 23, 2017
    MrAndeos likes this.
  3. Offline

    Zombie_Striker

    @MrAndeos @MightyOne
    Don't use schedulers. Instead, use BukkitRunnables because it already has this feature built in with the cancel() method.
     
    MrAndeos likes this.
  4. Offline

    MrAndeos

    @MightyOne
    What happens? Nothing, I need to put it in slot, remove it and after removing it from slot, runnable starts...

    I don't think if I can remove the dropped item via PlayerDropItemEvent, I tried removing it when it gets spawned (ItemSpawnEvent), but doing this in that way, makes it impossible to check if player who spawned the item is in HashSet, here is what I got for now:

    Code:
        private int taskId;
        HashSet<String> enabled_users = new HashSet<String>();
    
        @EventHandler
        public void onInventoryClick(InventoryClickEvent event) {
            final Player player = (Player) event.getWhoClicked();
            for(int i = 0; i < 9; i++) {
                if(event.getSlot() == i) {
                    if(event.getCurrentItem().getType() == Material.BLAZE_ROD) {
                        enabled_users.add(player.getName());
                        player.sendMessage(ChatColor.DARK_GREEN + "debug0");
                        taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(Main.plugin, new Runnable() {
                            public void run() {
                                player.addPotionEffect(new PotionEffect(PotionEffectType.INCREASE_DAMAGE, 40, 1));
                            }
                        }, 20, 20);
                    }
                }
            }
        }
    
        @EventHandler
        public void onItemDrop(PlayerDropItemEvent event) {
            final Player player = (Player) event.getPlayer();
            if(event.getItemDrop().getItemStack().getType() == Material.BLAZE_ROD) {
                player.sendMessage(ChatColor.DARK_AQUA + "debug1");
                if (enabled_users.contains(player.getName())) {
                    player.sendMessage(ChatColor.DARK_RED + "debug2");
                    Bukkit.getScheduler().cancelTask(taskId);
                    enabled_users.remove(player.getName());
                }
            }
        }
      
        @EventHandler
        public void onItemSpawn(ItemSpawnEvent event) {
            boolean item = event.getEntity().getItemStack().getType() == Material.BLAZE_ROD;
            if(item == true) {
                event.getEntity().remove();
            }
        }
     
  5. Offline

    MightyOne

    @Zombie_Striker Bukkit says scheduleSyncTask whatever with a BukkitRunnable is deprecated. Or what do you mean with using BukkitRunnables?
     
  6. Offline

    Zombie_Striker

    @MightyOne
    Yeah, don't use schedulers. Just use BukkitRunnables by themselves by calling a new instance, and use its methods for running the task (i.e }.runTaskLater(...))
     
  7. Offline

    MightyOne

    @Zombie_Striker Till now I just used Bukkit.getScheduler.cancelTasks(plugin) to stop all tasks in onDisable(). I have no idea how good that is or if it is necessary but is there an equivalent for this with BukkitRunnabes?
     
  8. Offline

    Zombie_Striker

    @MightyOne
    Bukkit will handle canceling all tasks except if they are async tasks that are still running, so you don't need to cancel it (also, cancelTasks does not support those async tasks as well)

    The main reason to use BukkitRunnables over scheduling new tasks is because of the built in cancel method, and because after running bukkitrunnables, they return BukkitTasks which can be easily stored/modified without the need for id lookups.
     
  9. Offline

    MrAndeos

    So how to make runnable start when I put item in slot? As I described above, now I have to put the item into the slot and take it out to make something happen.
    Is there any way?
     
  10. Offline

    Unknown123

    NEVER USE Bukkit.getScheduler.scheduleSyncRepeatingTask.
    I would mark it as deprecated because it returns a task id.
    You can get The same result with runTaskX().getTaskId() or something like that.
    If you want to use Bukkit.getScheduler() please use runTaskX().
    But the best way is using BukkitRunnable.
    Just like that: new BukkitRunnable() {
    @Override
    public void run() {
    //You could use cancel() or do anything
    }
    }.runTaskTimer(PLUGIN, delay, period).
     
  11. Offline

    MrAndeos

    @Unknown123
    I know that I shoud use BukkitRunnable, but how to cancel the BukkitRunnale outside of it? And I still can't solve the problem with InventoryClickEvent I described in my previous post.
     
  12. Offline

    Zombie_Striker

    @MrAndeos
    To cancel it, call "BukkitTask#cancel()" where BukkitTask is the instance returned after calling one of the run methods.
     
    MrAndeos likes this.
  13. Offline

    MrAndeos

    @Zombie_Striker
    Thank you, this works now.

    I find out that InventoryClickEvent detects that I am inserting an item into the hotbar slot, but it looks like
    Code:
    if (event.getCurrentItem().getType() == Material.BLAZE_ROD)
    Returns true only when I remove the item from the slot after inserting it.

    How to solve this?
    Sorry for my bad explanation. I am not the best in English language.
     
  14. Offline

    MrAndeos

    I managed to solve the thread, I created BukkitRunnable that checks every second whether the player has the given itemstack in his hotbar.
     
Thread Status:
Not open for further replies.

Share This Page