Resource Inventory System Tutorial (GUI)

Discussion in 'Spigot Plugin Development' started by MaTaMoR_, Jul 20, 2017.

  1. I have seen lately many people asking for help with stuff related to inventories, and honestly most of the replies aren't exactly good, so i decided to make my own tutorial to help all the people out there wanting to make a proper inventory system, i do have a public API for inventories (open source) if any one wants to check it here is the link.

    What most people making an Inventory don't know is that you can use an InventoryHolder when creating an Inventory:
    Code (Java):

    Inventory inventory = Bukkit.createInventory(null, 36, "Title");
     
    As you can see the first parameter is left null when you create a custom inventory, the thing is you can actually make a good use of that first paramenter, the InventoryHolder, you can create a class a implement that interface so you can store information there:
    Code (Java):

    public class CustomHolder implements InventoryHolder {

        @Override
        public Inventory getInventory() {
            return Bukkit.createInventory(this, 9);
        }
    }
     
    Now we have our custom InventoryHolder, now we need to create another class to store the data for each Icon, we will store an ItemStack and ClickActions, but before that lets create our "ClickActions".
    Code (Java):

    public interface ClickAction {

     void execute(Player player);

    }
     
    Now our Icon class:
    Code (Java):

    public class Icon {

        public final ItemStack itemStack;

        public final List<ClickAction> clickActions = new ArrayList<>();

        public Icon(ItemStack itemStack) {
            this.itemStack = itemStack;
        }

        public Icon addClickAction(ClickAction clickAction) {
            this.clickActions.add(clickAction);
            return this;
        }

        public List<ClickAction> getClickActions() {
            return this.clickActions;
        }
    }
     
    Now we have our Icon class, here is a simple example of how we can use it:
    Code (Java):

    ItemStack diamond = new ItemStack(Material.DIAMOND);
    Icon icon = new Icon(diamond).addClickAction(new ClickAction() {
        @Override
        public void execute(Player player) {
            //This will be executed when the player clicks on the Icon (in the inventory)
        }
    };
     
    Of course we can add more stuff here like for example Permissions or a ClickType, so it only works when clicked with certain click, and more stuf... Now we need to expand our CustomHolder:
    Code (Java):

    public class CustomHolder implements InventoryHolder {
     
        private final Map<Integer, Icon> icons = new  HashMap<>();

        private final int size;
        private final String title;

        public CustomHolder(int size, String title) {
            this.size = size;
            this.title = title;
        }

        public void setIcon(int position, Icon icon) {
            this.icons.put(position, icon);
        }
     
        public Icon getIcon(int position) {
            return this.icons.get(position);
        }

        @Override
        public Inventory getInventory() {
            Inventory inventory = Bukkti.createInventory(this, this.size, this.title);

            //You should check for inventory size so you don't get errors
            for (Entry<Integer, Icon> entry : this.icons.entrySet()) {
                inventory.setItem(entry.getKey(), entry.getValue());
            }
       
            return inventory;
        }
    }
     
    Okay now we have our CustomHolder so we can use it like this:
    Code (Java):

    CustomHolder customHolder = new CustomHolder(9, "Title");
    customHolder.setIcon(0, icon);

    Inventory inventory = customHolder.getInventory();
     
    Okay now we need to create our events so our inventory can work:
    Code (Java):

    @EventHandler
    public void onClick(InventoryClickEvent event) {
        //Check if the inventory is custom
        if (event.getView().getTopInventory().getHolder() instanceof CustomHolder) {
            //Cancel the event
            event.setCancelled(true);

            //Check if who clicked is a Player
            if (event.getWhoClicked() instanceof Player) {
                Player player = (Player) event.getWhoClicked();

                //Check if the item the player clicked on is valid
                ItemStack itemStack = event.getCurrentItem();
                if (itemStack == null || itemStack.getType() == Material.AIR) return;

                //Get our CustomHolder
                CustomHolder customHolder = (CustomHolder) event.getView().getTopInventory().getHolder();

                //Check if the clicked slot is any icon
                Icon icon = customHolder.getIcon(event.getRawSlot());
                if (icon == null) return;

                //Execute all the actions
                for (ClickAction clickAction : icon.getClickActions()) {
                    clickAction.execute(player);
                }
            }
        }
    }
     
    So that would be it... Just register the listener and your Inventory system should be working. I hope this tutorial has helped you, if you have any question don't doubt asking.
     
    #1 MaTaMoR_, Jul 20, 2017
    Last edited: Sep 26, 2017
    • Like Like x 7
    • Useful Useful x 5
    • Agree Agree x 1
  2. Neat tutorial, but I would create a class implementing that ClickAction interface that handles all the different ClickActions easier instead of having to define new ClickActions each time you want to create a new Icon.
     
  3. You can also do that, i just made the base system, if you want to expand it then it's up to you, my API does have something like you what said.
     
    • Useful Useful x 1
  4. This is a good tutorial for thoes people who want to create GUI's for lobbys, yet have no idea where to start. Nice job!
     
  5. I love the simplicity of most tutorials like these. Very easy to follow and understand but for the people that have no knowledge when it comes to Spigot, let alone simple Java they just copy and paste which is sad because tutorials like these should be a LESSON.

    Good tutorial!
     
  6. Then those people will figure out their mistakes the hard way for being lazy.
     
  7. where you expand the getInventory (7th codeblock) with the stuff to add the icon to the actual inventory you forgot something: you try to set an Icon where it only accepts an ItemStack so you have to get first the itemstack from the icon before you set it

    Edit: Also i would cache the inventory there because of better performance
     
    #7 essem, Jul 21, 2017
    Last edited: Jul 21, 2017
  8. I know i made that mistake, but didn't really fix it, if someone copied it would notice that error and fix it, if you don't know how to fix then you shouldn't be copying and pasting the code. I don't cache the Inventory simply because if you want to expand the system to something better, like to have personal stuff, etc... You can't cache it, anyways it's something that doesn't really lag, i have tested my API a lot and it doesn't lag with way more stuff.
     
  9. This is actually the first time I've seen someone use custom InventoryHolders... Interesting
     
    • Agree Agree x 1
  10. did made huge changes anyway for better performance and usability. and it was my second thought that you let this bug so that people doesn't copy and paste