Adding head to GUI

Discussion in 'Spigot Plugin Development' started by TheDiamondWorm, May 2, 2015.

  1. Hello, I am trying to use a repeating task to add an online player's head to an inventory if it's not already there, but, nothing seems to be happening :(

    Code (Java):
            final ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (byte) 3);
            final SkullMeta s = (SkullMeta) skull.getItemMeta();
            Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
                @Override
                public void run() {
                    for (Player all : Bukkit.getOnlinePlayers()) {
                        if (!inv.contains(skull) && s.getOwner() != all.getName()) {
                        s.setOwner(all.getName());
                        skull.setItemMeta(s);
                            inv.addItem(skull);

                        }
                    }
                }
            }, 0L, 20L);
    Thanks for any help!
     
  2. @TheDiamondWorm
    I think you need to do
    PHP:
    if (!inv.contains(skull.getType())
    instead. Otherwise bukkit will compare the itemmeta as well.
     
  3. gigosaurus

    Supporter

    Could we see the entire method, or at least more code? What is inv? Is it a player inventory or a custom inventory?

    Also i'm not entirely sure what you are trying to achieve with this:
    Code (Java):
    if(!inv.contains(skull)&& s.getOwner()!= all.getName()){
    For the first player this will always be true, because s.getOwner() will return null.
    For any players afterwards this will also always be true, as s.getOwner() will == the previous player's name. The inventory will also always contain skull because you just added it on the previous iteration.

    If there is at least 2 players online, the task you have will just keep adding a skull for each player online every time it is run, as s.getOwner() will never == all.getName(), because you keep changing it.
     
    #3 gigosaurus, May 2, 2015
    Last edited: May 2, 2015
    • Winner Winner x 1
  4. Inv is a custom inventory. I'm trying to add online player skulls to an inventory onCommand, which works fine. This repeating task is meant to update the inventory in the case of a new player join while the inventory is still open.
     
  5. gigosaurus

    Supporter

    So what exactly is and isn't happening when you run the command?

    It would probably be better to store a reference to this inventory somewhere, and then on the player join and quit events edit the inventory and add/remove the appropriate skull. This would get rid of the need for a repeating task. Then you just show this same inventory to anyone who types the command.

    Something like this:
    I only made this because i'm extremely bored, and I haven't tested it but it should work:
    Code (Java):

    import org.bukkit.Bukkit;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.SkullMeta;
    import org.bukkit.plugin.java.JavaPlugin;

    public class OnlineInv extends JavaPlugin implements Listener {

        private Inventory inv = Bukkit.createInventory(null, 54, "Online Players");

        @Override
        public void onEnable() {
            Bukkit.getPluginManager().registerEvents(this, this);
            getCommand("cmd").setExecutor(this);
        }

        @EventHandler
        public void onPlayerJoin(PlayerJoinEvent event) {
            if (inv.firstEmpty() == -1) {
                //inventory is full, might want to do something when this happens
            } else {
                //create the skull - might want to add a custom display name here as well
                ItemStack skull = new ItemStack(Material.SKULL_ITEM, 1, (byte) 3);
                SkullMeta meta = (SkullMeta) skull.getItemMeta();
                meta.setOwner(event.getPlayer().getName());
                skull.setItemMeta(meta);
                inv.addItem(skull);
            }
        }

        @EventHandler
        public void onPlayerQuit(PlayerQuitEvent event) {
            //remove this player's skull from the inventory
            //note: this will leave a gap if players have joined after.
            //You'll have to shuffle some heads around to get rid of the gap
            for (ItemStack item : inv.getContents()) {
                //not sure if the item.hasItemMeta() call is needed, but I added it anyway to avoid NPEs
                if ((item.getType() == Material.SKULL_ITEM) && item.hasItemMeta()) {
                    //check if this item belongs to the player who just left
                    if (((SkullMeta) item.getItemMeta()).getOwner().equals(event.getPlayer().getName())) {
                        inv.remove(item);
                        return;
                    }
                }
            }
        }

        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if (sender instanceof Player) {
                ((Player) sender).openInventory(inv);
            }
            return false;
        }

    }
     
     
    #5 gigosaurus, May 2, 2015
    Last edited: May 2, 2015
    • Useful Useful x 1
  6. Thanks, one last problem. So, here is how i'm trying to cancel clicking/moving in the inventory:

    Code (Java):
        @EventHandler
        public void onClick(InventoryClickEvent e) {
            if (e.getClickedInventory() != null) {
                if (e.getClickedInventory().equals(inv)) {
                    e.setCancelled(true);
                }
            }
        }

        @EventHandler
        public void onMove(InventoryMoveItemEvent e) {
            if (e.getSource().equals(inv) || e.getDestination().equals(inv)) {
                e.setCancelled(true);
            }
        }
    This cancels everything, except for one thing.. items can still be inserted INTO this inventory by doing shift + left click or shift + right click, but can't be taken out with that method.
     
  7. gigosaurus

    Supporter

    Use InventoryInteractEvent, then you'll only need one method.
     
  8. Using that event, checking if the inventory is equal to inv, and cancelling it doesn't prevent any form of item addition/removal/moving in that inventory.
     
  9. gigosaurus

    Supporter

    Ok I was wrong with my last post. That's an abstract event and so is never fired directly.

    InventoryClickEvent is all you need. The problems you were experiencing with it before is related to this:
    Code (Java):
    if(e.getClickedInventory().equals(inv)){
    This isn't going to be true if you click on your own inventory while viewing the custom inventory. Use this instead:
    Code (Java):
    if(e.getInventory().equals(inv)){
    or this if you end up wanting to get the item that was clicked in the custom inventory:
    Code (Java):
    if((e.getInventory() == e.getClickedInventory()) && (e.getClickedInventory().equals(inv)){