How to detect if a player closes an inventory?

Discussion in 'Plugin Development' started by PineappleJuice, Mar 14, 2017.

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

    PineappleJuice

    So I just got into coding plugins, and still have a lot to learn.

    I am currently trying to make it so that when a player has a certain inventory open (that is caused by another command that made him open that inventory) he can't close it.

    It needs to make sure every time he closes the inventory it will just "pop" back...

    I need to detect if the player's inventory is no longer opened on that specific inventory, and if not, it should open it again.

    Any help would be greatly appreciated!
     
    Last edited: Mar 14, 2017
  2. Offline

    GRocksMc

    You could try:
    Code:java
    1.  
    2. public void invClose(InventoryCloseEvent event){
    3. Inventory inv = event.getInventory();
    4. event.getPlayer().openInventory(inv);
    5. }
    6.  

    NOTE: I just wrote this from the top of my head, so you might have to change some things.

    EDIT: You might have delay for 1 tick before running event.getPlayer().openInventory(inv);

    PineappleJuice
     
    Last edited: Mar 14, 2017
  3. Offline

    PineappleJuice

    I'm not exactly sure how to implement that into my code.

    This part of my code is suppose to "freeze" a player

    This is what I have:

    Code:
    package me.PineappleJuice.Freeze.commands;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    
    import net.md_5.bungee.api.ChatColor;
    
    public class Freeze implements CommandExecutor {
    
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
    
            Player player = (Player) sender;
    
            if (!(sender instanceof Player)) {
    
                sender.sendMessage("You must be a player to execute this command!");
                return false;
    
            }
    
            if (label.equalsIgnoreCase("freeze")) {
    
                Inventory inv = Bukkit.createInventory(null, 9, ChatColor.RED + "You have been frozen!");
    
                ItemStack paper = nameItem(Material.PAPER, ChatColor.RED + "You have been frozen!");
    
                inv.setItem(4, paper);
              
                player.openInventory(inv);
                  
                }
    
    
            return true;
        }
    
        private ItemStack nameItem(ItemStack item, String name) {
    
            ItemMeta meta = item.getItemMeta();
            meta.setDisplayName(name);
    
            item.setItemMeta(meta);
    
            return item;
        }
    
        private ItemStack nameItem(Material item, String name) {
    
            return nameItem(new ItemStack(item), name);
        }
    
    }
    
    NOTE: I don't know where else to paste the code
     
    Last edited by a moderator: Mar 14, 2017
  4. Offline

    Zombie_Striker

    @PineappleJuice
    First, don't use label. It is only there for backwards compatibility. Instead, replace that with command.getName()

    When a player is froze, add them to an array. Then, inside the event, check if they are in the array. If they are, re-open the inventory. Once the player is no longer froze, remove them from the array.
     
  5. Offline

    PineappleJuice

    That's a brilliant idea! I'll give it a try and let you know if I got it to work.

    Btw, what do you mean the label is only for backwards compatibility? Does that mean its compatible with older versions?

    NOTE: I changed up my code a little bit and used an ArrayList.

    I made an ArrayList "frozen" that adds the player into that list when the command has been executed, and removes them from the list if the command is executed once again.

    But now I have another problem that I can't figure out how to implement.


    I want to implement the following code:

    Code:
       @EventHandler
        public void onPlayerMove(PlayerMoveEvent playerMove) {
            Player player = playerMove.getPlayer();
    
            if (frozen.contains(player.getName())) {
                playerMove.setTo(playerMove.getFrom());
                player.sendMessage(ChatColor.RED + "You have been frozen!");
            }
        }
    in the rest of my code:

    Code:
    public class FreezeMeFreezeExecutor implements CommandExecutor {
    
        ArrayList<String> frozen = new ArrayList<String>();
    
        private FreezeMeControl plugin;
    
        public FreezeMeFreezeExecutor(FreezeMeControl plugin) {
            this.plugin = plugin;
        }
    
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            Player player = (Player) sender;
    
            if (command.getName().equalsIgnoreCase("freeze")) {
                if (args.length != 1) {
                    sender.sendMessage(ChatColor.RED + "Usage: /freeze <player_name>");
                    return true;
                }
    
                Player freeze = plugin.getServer().getPlayer(args[0]);
    
                if (freeze == null) {
                    sender.sendMessage(ChatColor.AQUA + args[0] + ChatColor.RED + " is not online!");
                    return true;
                }
    
                if (frozen.contains(freeze.getName())) {
                    frozen.remove(freeze.getName());
                    sender.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.GREEN + " is no longer frozen!");
    
                    return true;
                }
    
                frozen.add(freeze.getName());
                sender.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.RED + " has been frozen");
    
                Inventory inv = Bukkit.createInventory(null, 9, ChatColor.RED + "You have been frozen!");
                ItemStack paper = nameItem(Material.PAPER, ChatColor.RED + "ts.chaospvp.net");
    
                inv.setItem(4, paper);
    
                player.getWorld().playEffect(player.getLocation(), Effect.GHAST_SHRIEK, 1);
                player.openInventory(inv);
            }
    
            plugin.log.info(args[0] + " was frozen by " + player);
            return true;
        }
    
        private ItemStack nameItem(ItemStack item, String name) {
    
            ItemMeta meta = item.getItemMeta();
            meta.setDisplayName(name);
    
            item.setItemMeta(meta);
    
            return item;
        }
    
        private ItemStack nameItem(Material item, String name) {
    
            return nameItem(new ItemStack(item), name);
        }
    
    }
    Any help would be greatly appreciated!
     
    Last edited by a moderator: Mar 15, 2017
  6. Offline

    MrMinecraft15

    You MUST use a little delay (1 tick might be enough) before opening an inventory in InventoryCloseEvent, otherwise you'll get an error.
     
  7. Offline

    PineappleJuice

    How would I do that? Sorry, I am still new to the Java Language...
     
  8. Offline

    timtower Administrator Administrator Moderator

  9. Offline

    PineappleJuice

  10. Offline

    MrMinecraft15

    i would recommend using a synced scheduler like this:
    Code:
            Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                @Override
                public void run() {
                    //Your code here
                }
            }, 1); 
     
  11. Offline

    PineappleJuice

    Do I add all my code inside that scheduler? or just one part of it?
     
  12. Offline

    MrMinecraft15

    Just the opening of the inventory.


    Code:
        public void invClose(InventoryCloseEvent event) {
            Player p = (Player) event.getPlayer();
            Inventory inv = event.getInventory();
            Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
                @Override
                public void run() {
                    p.openInventory(inv);
                }
            }, 1);
        }
     
  13. Offline

    PineappleJuice

    Okay thank you, I'll try it and let you know if I got it to work.

    NOTE: So I tried what you said, and implemented that code as follow:

    Code:
        public void invClose(InventoryCloseEvent event) {
           
            Player player = (Player) event.getPlayer();
            Inventory inv = event.getInventory();
            Bukkit.getScheduler().scheduleSyncDelayedTask((Plugin) this, new Runnable() {
                @Override
                public void run() {
                    player.openInventory(inv);
                }
            }, 1);
        }
    but it doesn't seem to do a difference to my problem I am having. It doesn't seem to do anything.

    Remember, my problem is I want the certain inventory to stay open even if the player tries to close out of it.

    This is my entire code:

    Code:
    package me.PineappleJuice.FreezeMe.commands;
    
    import java.util.ArrayList;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Effect;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.inventory.InventoryCloseEvent;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    import org.bukkit.plugin.Plugin;
    
    import me.PineappleJuice.FreezeMe.FreezeMeControl;
    import net.md_5.bungee.api.ChatColor;
    
    public class FreezeMeFreezeExecutor implements CommandExecutor {
    
        ArrayList<String> frozen = new ArrayList<String>();
    
        // @EventHandler
        //public void onPlayerMove(PlayerMoveEvent playerMove) {
        //    Player player = playerMove.getPlayer();
    
        //    if (frozen.contains(player.getName())) {
        //        playerMove.setTo(playerMove.getFrom());
        //        player.sendMessage(ChatColor.RED + "You have been frozen!");
        //    }
        //}
    
        private FreezeMeControl plugin;
    
        public FreezeMeFreezeExecutor(FreezeMeControl plugin) {
            this.plugin = plugin;
        }
    
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            Player player = (Player) sender;
    
            if (command.getName().equalsIgnoreCase("freeze")) {
                if (args.length != 1) {
                    sender.sendMessage(ChatColor.RED + "Usage: /freeze <player_name>");
                    return true;
                }
    
                Player freeze = plugin.getServer().getPlayer(args[0]);
    
                if (freeze == null) {
                    sender.sendMessage(ChatColor.AQUA + args[0] + ChatColor.RED + " is not online!");
                    return true;
                }
    
                if (frozen.contains(freeze.getName())) {
                    frozen.remove(freeze.getName());
                    sender.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.GREEN + " is no longer frozen!");
    
                    return true;
                }
    
                frozen.add(freeze.getName());
                sender.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.RED + " has been frozen");
    
                Inventory inv = Bukkit.createInventory(null, 9, ChatColor.RED + "You have been frozen!");
                ItemStack paper = nameItem(Material.PAPER, ChatColor.RED + "ts.chaospvp.net");
    
                inv.setItem(4, paper);
    
                player.getWorld().playEffect(player.getLocation(), Effect.GHAST_SHRIEK, 1);
                player.openInventory(inv);
            }
    
            plugin.log.info(args[0] + " was frozen by " + player);
            return true;
        }
       
        public void invClose(InventoryCloseEvent event) {
           
            Player player = (Player) event.getPlayer();
            Inventory inv = event.getInventory();
            Bukkit.getScheduler().scheduleSyncDelayedTask((Plugin) this, new Runnable() {
                @Override
                public void run() {
                    player.openInventory(inv);
                }
            }, 1);
        }
    
        private ItemStack nameItem(ItemStack item, String name) {
    
            ItemMeta meta = item.getItemMeta();
            meta.setDisplayName(name);
    
            item.setItemMeta(meta);
    
            return item;
        }
    
        private ItemStack nameItem(Material item, String name) {
    
            return nameItem(new ItemStack(item), name);
        }
    
    }
    
    Any help would be greatly appreciated!
     
    Last edited: Mar 15, 2017
  14. Offline

    PineappleJuice

  15. Offline

    rj3824

    Have you checked that you have registered the event in your main class and that you have implemented Listener in your inventory close event class?


    Sent from my iPad using Tapatalk
     
  16. Offline

    timtower Administrator Administrator Moderator

  17. Offline

    PineappleJuice

    Yes, my events are correctly registered in my main class, and I have implemented Listener.

    I have now changed up my code a but, trying to correctly implement the scheduler to my code so that it will stop crashing my server.

    This is what I have done:

    Code:
    while (frozen.contains(freeze.getName())) {
                    Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                        public void run() {
                            freeze.openInventory(inv);
                        }
                    }, 1 * 20);
                    return true;
                }
    But now I have another problem, It seems to execute that once. It's almost as if the player just stops being in the array.

    Any solutions to this would be greatly appreciated.

    @timtower Where should I use the @EventHandler?

    This is my new code:

    Code:
    package me.PineappleJuice.FreezeMe.commands;
    
    import java.util.ArrayList;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Effect;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.Listener;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    
    import me.PineappleJuice.FreezeMe.FreezeMeControl;
    import net.md_5.bungee.api.ChatColor;
    
    public class FreezeMeFreezeExecutor implements CommandExecutor, Listener {
    
        ArrayList<String> frozen = new ArrayList<String>();
    
        private FreezeMeControl plugin;
    
        public FreezeMeFreezeExecutor(FreezeMeControl plugin) {
            this.plugin = plugin;
        }
    
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            Player player = (Player) sender;
    
            if (command.getName().equalsIgnoreCase("freeze")) {
                if (args.length != 1) {
                    player.sendMessage(ChatColor.RED + "Usage: /freeze <player_name>");
                    return true;
                }
    
                Player freeze = plugin.getServer().getPlayer(args[0]);
    
                if (freeze == null) {
                    player.sendMessage(ChatColor.AQUA + args[0] + ChatColor.RED + " is not online!");
                    return true;
                }
    
                if (frozen.contains(freeze.getName())) {
                    frozen.remove(freeze.getName());
                    sender.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.GREEN + " is no longer frozen!");
    
                    return true;
                }
    
                frozen.add(freeze.getName());
                player.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.RED + " has been frozen");
    
                Inventory inv = Bukkit.createInventory(null, 9, ChatColor.RED + "You have been frozen!");
                ItemStack paper = nameItem(Material.PAPER, ChatColor.RED + "ts.chaospvp.net");
    
                inv.setItem(4, paper);
    
                freeze.getWorld().playEffect(freeze.getLocation(), Effect.GHAST_SHRIEK, 1);
                freeze.openInventory(inv);
               
                while (frozen.contains(freeze.getName())) {
                    Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                        public void run() {
                            freeze.openInventory(inv);
                        }
                    }, 1 * 20);
                    return true;
                }
    
            }
    
            plugin.log.info(args[0] + " was frozen by " + player.getName());
            return true;
        }
    
        private ItemStack nameItem(ItemStack item, String name) {
    
            ItemMeta meta = item.getItemMeta();
            meta.setDisplayName(name);
    
            item.setItemMeta(meta);
    
            return item;
        }
    
        private ItemStack nameItem(Material item, String name) {
    
            return nameItem(new ItemStack(item), name);
        }
    
    }
    
     
  18. Offline

    timtower Administrator Administrator Moderator

    @PineappleJuice That inventorycloseevent that you had before.
    Don't use that while loop, it could freeze your server.
     
  19. Offline

    PineappleJuice

    k
    Okay, I added that InventoryCloseEvent back to my code, but it doesn't seem to do anything

    Code:
        @EventHandler
        public void invClose(InventoryCloseEvent event) {
              
            Player player = (Player) event.getPlayer();
            Inventory inv = event.getInventory();
            Bukkit.getScheduler().scheduleSyncDelayedTask((Plugin) this, new Runnable() {
                @Override
                public void run() {
                    player.openInventory(inv);
                }
            }, 1);
        }
    Also, if I don't use this InventoryCloseEvent, and want to continue with what I have right now (currently using that while statement) what should I use in that while loop's place?
     
  20. Offline

    timtower Administrator Administrator Moderator

  21. Offline

    PineappleJuice

    I'm not so sure about the InventoryCloseEvent, to me it seems like it will close the PLAYER's inventory and not the custom inventory (basically like when a player is inside a chest).

    That's not exactly what I want, I want it to make sure that if a command is executed, for e.g /freeze <playerName> , that the player who is being freezed will have a custom inventory being opened, like when he opens a chest. It must make sure that player can't close out of that inventory by "popping" it back when he close it.

    If the InventoryCloseEvent can do what I described above, then how would I implement that in my code?
     
  22. Offline

    Caderape2

    @PineappleJuice

    Add the frozen player to a list, and in the event, open the inventory if the player is in the list ?
     
  23. Offline

    timtower Administrator Administrator Moderator

    @PineappleJuice Events detect actions, they don't cause things to happen.
     
  24. Offline

    PineappleJuice

    If I understand what you are saying, then I already have it like so.

    I have an ArrayList called "frozen" and I have a variable called "freeze"

    They both look as follow:

    The ArrayList:
    Code:
    ArrayList<String> frozen = new ArrayList<String>();
    The freeze variable:
    Code:
    Player freeze = plugin.getServer().getPlayer(args[0]);
    the command usage is /freeze <player name>

    So "freeze" gets the player's name that is being frozen, and then I do the following command to add him to the Arraylist:

    Code:
    frozen.add(freeze.getName());
    So if that is correct I already have the list , the problem now is that I can't seem to figure out how to keep the the custom inventory opened. I tried doing :

    Code:
    while (frozen.contains(freeze.getName())) {
                    Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                        public void run() {
                            freeze.openInventory(inv);
                            frozen.add(freeze.getName());
                        }
                    }, 1 * 20);
                    return true;
                }
    but that seems to only have the player in the list once ... and if I only have the "freeze.openInventory(inv)" in the while loop, it crashes the server...

    BTW, just so that you know, I am new to the java language, so sorry if I understand wrong
     
  25. Offline

    Caderape2

    @PineappleJuice
    - Create an empty inventory (bukkit.createInventory(null, 9, "You are frozen");
    - Register the event InventoryCloseEvent
    - Check if the player is in the frozen list, then open the created inventory

    you don't need a boucle while or scheduler
     
  26. Offline

    PineappleJuice

    I don't think I understand you correctly, I did the following code:

    Code:
    @EventHandler
        public void onInventoryCloseEvent(InventoryCloseEvent event) {
            Player player = (Player) event.getPlayer();
    
            Inventory inv = Bukkit.createInventory(null, 9, ChatColor.RED + "You have been frozen!");
            ItemStack paper = nameItem(Material.PAPER, ChatColor.RED + "ts.chaospvp.net");
            inv.setItem(4, paper);
    
            if (frozen.contains(player.getName())) {
                player.openInventory(inv);
            }
        }
    and yet nothing happens...

    This is my entire code:

    Code:
    package me.PineappleJuice.FreezeMe.commands;
    
    import java.util.ArrayList;
    
    import org.bukkit.Bukkit;
    import org.bukkit.Effect;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandExecutor;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.inventory.InventoryCloseEvent;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    
    import me.PineappleJuice.FreezeMe.FreezeMeControl;
    import net.md_5.bungee.api.ChatColor;
    
    public class FreezeMeFreezeExecutor implements CommandExecutor, Listener {
    
        ArrayList<String> frozen = new ArrayList<String>();
    
        private FreezeMeControl plugin;
    
        public FreezeMeFreezeExecutor(FreezeMeControl plugin) {
            this.plugin = plugin;
        }
    
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            Player player = (Player) sender;
    
            if (command.getName().equalsIgnoreCase("freeze")) {
                if (args.length != 1) {
                    player.sendMessage(ChatColor.RED + "Usage: /freeze <player_name>");
                    return true;
                }
    
                Player freeze = plugin.getServer().getPlayer(args[0]);
    
                if (freeze == null) {
                    player.sendMessage(ChatColor.AQUA + args[0] + ChatColor.RED + " is not online!");
                    return true;
                }
    
                if (frozen.contains(freeze.getName())) {
                    frozen.remove(freeze.getName());
                    sender.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.GREEN + " is no longer frozen!");
                    return true;
                }
    
                frozen.add(freeze.getName());
                player.sendMessage(ChatColor.AQUA + freeze.getName() + ChatColor.RED + " has been frozen");
    
                freeze.getWorld().playEffect(freeze.getLocation(), Effect.GHAST_SHRIEK, 1);
    
            }
    
            plugin.log.info(args[0] + " was frozen by " + player.getName());
            return true;
        }
    
        @EventHandler
        public void onInventoryCloseEvent(InventoryCloseEvent event) {
            Player player = (Player) event.getPlayer();
    
            Inventory inv = Bukkit.createInventory(null, 9, ChatColor.RED + "You have been frozen!");
            ItemStack paper = nameItem(Material.PAPER, ChatColor.RED + "ts.chaospvp.net");
            inv.setItem(4, paper);
    
            if (frozen.contains(player.getName())) {
                player.openInventory(inv);
            }
        }
    
        private ItemStack nameItem(ItemStack item, String name) {
    
            ItemMeta meta = item.getItemMeta();
            meta.setDisplayName(name);
    
            item.setItemMeta(meta);
    
            return item;
        }
    
        private ItemStack nameItem(Material item, String name) {
    
            return nameItem(new ItemStack(item), name);
        }
    }
    
     
  27. Offline

    Caderape2

    @PineappleJuice
    I can guess your error. You create two instance of this class. One for the event, on for the command.

    You have two option.
    - Put the arraylist static.
    - on your onEnable, create a constructor of you class and pass the variable as parameters when you register the command and the event.

    I recommand the second option. Actually, there's two arraylist, onr for your command, one for the event.
     
Thread Status:
Not open for further replies.

Share This Page