Search code examples
javaminecraftbukkit

Infinite loop java / events in java for a plugin MC


I've a problem with a plugin for MC and I need an infinite loop which await the condition to be satisfiated. But it create an infinite loop but the variable have changed. Here is the code :

boolean bState;
public boolean GetState(){
    return bState;
}
public void SetState(boolean bState) {
    this.bState = bState;
}

@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) throws InterruptedException {
    Player player = event.getPlayer();
    if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && event.getClickedBlock().getType() == Material.CHEST && event.getItem().getType() == Material.DIAMOND_SWORD)  {
        Chest chest = (Chest) event.getClickedBlock().getState();
        event.setCancelled(true);
        Inventory inv = chest.getInventory();
        inv.getContents();
        Inventory sinv = Bukkit.createInventory(player, chest.getInventory().getSize());
        sinv.setContents(inv.getContents());
        SetState(false);
        player.openInventory(sinv);
        while(GetState() == false){
            getLogger().info("Ok");
        }
        //Some other things to do
    }
}

@EventHandler
public void onPlayerCloseInv(InventoryCloseEvent event) {
    Player player = (Player) event.getPlayer();
    SetState(true);
}

I'm sure at 100% that the event onPlayerCloseInv is triggered after onPlayerInteract. Can anyone help me ? Thank you :D

EDIT: With my new code onPlayerCloseInv doesn't start anyone have an idea ?


Solution

  • With bukkit, you have the principle of a single main thread only.

    Because this thread can only do 1 thing at a time, you cannot use spinlocks to wait for conditions, as a spinlock essentially keeps the thread busy.

    Moving the close code to the setState

    While this is the easiest method, using the will, you will lose track of your local variables.

    public void SetState(boolean bState) {
        if(this.bState == false && bState == true) {
            //Some other things to do
            getLogger().info('Inventory closed');
        }
        this.bState = bState;
    }
    

    Using a local runnable for the negative state

    While this method suffers of the penalty of a new lamba instance, and a slightly more obfuscated stack trace, it offers benefit in the fact that using this, you have access to all your local (implied) final variables.

    Runnable closeTask = null;
    public void SetState(boolean bState) {
        if(this.bState == false && bState == true ) {
            if(closeTask != null) {
                closeTask.run();
                closeTask = null;
            }
        }
        this.bState = bState;
    }
    
    @EventHandler
    public void onPlayerInteract(PlayerInteractEvent event) throws InterruptedException {
        Player player = event.getPlayer();
        if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK) && event.getClickedBlock().getType() == Material.CHEST && event.getItem().getType() == Material.DIAMOND_SWORD)  {
            ...
            player.openInventory(sinv);
            closeTask = () => {
                //Some other things to do
                 getLogger().info('Inventory closed');
            };
    
        }
    }