Icon Menu

Discussion in 'Resources' started by nisovin, Oct 30, 2012.

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

    Redzdaz

    After i updated to 1.5.1 i wont work. I keep getting "Chest must have a size that is a multiple of 9!" but it is 9 in my code...

    Main:
    PHP:
    package me.Patrick.Random;
    import java.util.logging.Logger;
     
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.DyeColor;
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.plugin.PluginDescriptionFile;
    import org.bukkit.plugin.java.JavaPlugin;
    public class 
    Main extends JavaPlugin{
            public final 
    Logger logger Logger.getLogger("Minecraft");
         
            public static 
    Main plugin;
             
         
            @
    Override
            
    public void onDisable() {
                
    PluginDescriptionFile pdfFile this.getDescription();     
                
    this.logger.info(pdfFile.getName() + " Er ikke til!");
            }
         
            @
    Override
            
    public void onEnable() {
                
    PluginDescriptionFile pdfFile this.getDescription();     
                
    this.logger.info(pdfFile.getName() + " Version " +  pdfFile.getVersion() +  " Er til!");
                
    getConfig().options().copyDefaults(true);
                
    saveConfig();
                
    Bukkit.getServer().getPluginManager();
            }
           
       
            public 
    boolean onCommand(CommandSender sCommand cmdString clString[] args) {
                final 
    Player p = (Players;
                if (
    cl.equalsIgnoreCase("mg")) {
           
                    
    IconMenu menu = new IconMenu("My Fancy Menu"9, new IconMenu.OptionClickEventHandler() {
                        @
    Override
                        
    public void onOptionClick(IconMenu.OptionClickEvent event) {
                            
    event.getPlayer().sendMessage("You have chosen " event.getName());
                            
    event.setWillClose(true);
                        }
                    }, 
    plugin)
                    .
    setOption(3, new ItemStack(Material.APPLE1), "Food""The food is delicious")
                    .
    setOption(4, new ItemStack(Material.IRON_SWORD1), "Weapon""Weapons are for awesome people")
                    .
    setOption(5, new ItemStack(Material.EMERALD1), "Money""Money brings happiness");
                }
                return 
    false;
            }
    }
    IconMenu:
    PHP:
    package me.Patrick.Random;
     
    import java.util.Arrays;
     
    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.HandlerList;
    import org.bukkit.event.Listener;
    import org.bukkit.event.inventory.InventoryClickEvent;
    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;
     
    public class 
    IconMenu implements Listener {
     
        private 
    String name;
        private 
    int size;
        private 
    OptionClickEventHandler handler;
        private 
    Plugin plugin;
    Player player null;
        private 
    String[] optionNames;
        private 
    ItemStack[] optionIcons;
     
        public 
    IconMenu(String nameint sizeOptionClickEventHandler handlerPlugin plugin) {
            
    this.name name;
            
    this.size size;
            
    this.handler handler;
            
    this.plugin plugin;
            
    this.optionNames = new String[size];
            
    this.optionIcons = new ItemStack[size];
            
    plugin.getServer().getPluginManager().registerEvents(thisplugin);
        }
        public 
    void onOptionClick(IconMenu.OptionClickEvent event) {
       
        }
     
        public 
    IconMenu setOption(int positionItemStack iconString nameString... info) {
            
    optionNames[position] = name;
            
    optionIcons[position] = setItemNameAndLore(iconnameinfo);
            return 
    this;
        }
     
        public 
    void open(Player player) {
            
    Inventory inventory Bukkit.createInventory(playersizename);
            for (
    int i 0optionIcons.lengthi++) {
                if (
    optionIcons != null) {
                    
    inventory.setItem(ioptionIcons[i]);
                }
            }
            
    player.openInventory(inventory);
        }
     
        public 
    void destroy() {
            
    HandlerList.unregisterAll(this);
            
    handler null;
            
    plugin null;
            
    optionNames null;
            
    optionIcons null;
        }
     
        @
    EventHandler(priority EventPriority.MONITOR)
        
    void onInventoryClose(InventoryCloseEvent event) {
            if (
    event.getInventory().getTitle().equals(name)) {
                
    destroy();
            }
        }
     
        @
    EventHandler(priority EventPriority.MONITOR)
        
    void onInventoryClick(InventoryClickEvent event) {
            if (
    event.getInventory().getTitle().equals(name)) {
                
    event.setCancelled(true);
                
    int slot event.getRawSlot();
                if (
    slot >= && slot size && optionNames[slot] != null) {
                    
    Plugin plugin this.plugin;
                    
    OptionClickEvent e = new OptionClickEvent((Playerevent.getWhoClicked(), slotoptionNames[slot]);
                    
    handler.onOptionClick(e);
                    if (
    e.willClose()) {
                        final 
    Player p = (Playerevent.getWhoClicked();
                        
    Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                            public 
    void run() {
                                
    p.closeInventory();
                            }
                        }, 
    1);
                    }
                    if (
    e.willDestroy()) {
                        
    destroy();
                    }
                }
            }
        }
     
        public interface 
    OptionClickEventHandler {
            public 
    void onOptionClick(OptionClickEvent event);
        }
     
        public class 
    OptionClickEvent {
            private 
    Player player;
            private 
    int position;
            private 
    String name;
            private 
    boolean close;
            private 
    boolean destroy;
     
            public 
    OptionClickEvent(Player playerint positionString name) {
                
    this.player player;
                
    this.position position;
                
    this.name name;
                
    this.close true;
                
    this.destroy false;
            }
     
            public 
    Player getPlayer() {
                return 
    player;
            }
     
            public 
    int getPosition() {
                return 
    position;
            }
     
            public 
    String getName() {
                return 
    name;
            }
     
            public 
    boolean willClose() {
                return 
    close;
            }
     
            public 
    boolean willDestroy() {
                return 
    destroy;
            }
     
            public 
    void setWillClose(boolean close) {
                
    this.close close;
            }
     
            public 
    void setWillDestroy(boolean destroy) {
                
    this.destroy destroy;
            }
        }
     
        private 
    ItemStack setItemNameAndLore(ItemStack itemString nameString[] lore) {
            
    ItemMeta im item.getItemMeta();
            
    im.setDisplayName(name);
            
    im.setLore(Arrays.asList(lore));
            
    item.setItemMeta(im);
            return 
    item;
        }
     
    }
     
  2. Offline

    creepers84

    I am Making an Inventory interface and this is my current state of code:
    Code:

    Code:
    IconMenu menu = new IconMenu("Choose a Head!", 9, new IconMenu.OptionClickEventHandler() {
        @Override
        public void onOptionClick(IconMenu.OptionClickEvent event) {
            event.getPlayer().sendMessage("You have chosen " + event.getName());
            event.setWillClose(true);
        }
    }, plugin)
    .setOption(3, new ItemStack (blockId == 397 && blockSubId == 1) , "Food", "The food is delicious")
    .setOption(4, new ItemStack(Material.IRON_SWORD, 1), "Weapon", "Weapons are for awesome people")
    .setOption(5, new ItemStack(Material.EMERALD, 1), "Money", "Money brings happiness");
    
    I need someone to edit the code above so that there are 4 slots with a:
    Creeper Skull With caption Click to add to inventory
    Skeleton Skull with caption Click to add to inventory
    WitherSkeleton Skull with caption Click to add to inventory
    Zombie skull with caption Click to add to inventory
    and when they are each clicked it puts that skull into their inventory and closes the interface. Leaving them with the message: [ProjectileHeads] Skull Has been added to your inventory!
     
  3. Offline

    nisovin

    CeramicTitan What exactly is your goal with adding that? What are you trying to accomplish?
     
  4. Offline

    CeramicTitan

    nisovin, I thought I would add it because I thought I would rather cancel the click event instead of closing the menu? But that doesnt work, it still closes the menu.
     
  5. Offline

    chasechocolate

  6. Offline

    CeramicTitan

    Don't know why i didn't think of this :/

    nisovin, Sorry for inconvience I may have caused
     
  7. Offline

    creepers84

    I have done this myself! This post was from late may.
     
  8. Offline

    chasechocolate

    Ok, so I am adding this as an option to choose a kit for a Ghost Squadron plugin I am making. However, I have come across a bug(?):
    [​IMG]
    As you can see, every time a player chooses a new kit, it will send them a message one more time than before. Here is my kit selection menu:
    Code:java
    1. public static IconMenu getKitSelectionMenu(){
    2. String title = ChatColor.RED + "" + ChatColor.BOLD + "Choose a Kit";
    3. int size = Utilities.round(KitType.values().length, 9);
    4.  
    5. ItemStack alchemistIcon = new ItemStack(Material.POTION);
    6. ItemStack archerIcon = new ItemStack(Material.BOW);
    7. ItemStack bruiserIcon = new ItemStack(Material.WOOD_SWORD);
    8. ItemStack pyroIcon = new ItemStack(Material.BLAZE_ROD);
    9. ItemStack scoutIcon = new ItemStack(Material.STICK);
    10. ItemStack spawnerIcon = new ItemStack(Material.MONSTER_EGG);
    11.  
    12. IconMenu menu = new IconMenu(title, size, new OptionClickEventHandler(){
    13. @Override
    14. public void onOptionClick(OptionClickEvent event){
    15. Player player = event.getPlayer();
    16. String name = event.getName();
    17.  
    18. if(name.contains("Alchemist")){
    19. KitUtils.setKit(player, new AlchemistKit());
    20. PlayerUtils.sendMessage(player, ChatColor.RED + "You are now an " + ChatColor.AQUA + "Alchemist" + ChatColor.RED + "!");
    21. } else if(name.contains("Archer")){
    22. KitUtils.setKit(player, new ArcherKit());
    23. PlayerUtils.sendMessage(player, ChatColor.RED + "You are now an " + ChatColor.AQUA + "Archer" + ChatColor.RED + "!");
    24. } else if(name.contains("Bruiser")){
    25. KitUtils.setKit(player, new BruiserKit());
    26. PlayerUtils.sendMessage(player, ChatColor.RED + "You are now a " + ChatColor.AQUA + "Bruiser" + ChatColor.RED + "!");
    27. } else if(name.contains("Pyro")){
    28. KitUtils.setKit(player, new PyroKit());
    29. PlayerUtils.sendMessage(player, ChatColor.RED + "You are now a " + ChatColor.AQUA + "Pyro" + ChatColor.RED + "!");
    30. } else if(name.contains("Scout")){
    31. KitUtils.setKit(player, new ScoutKit());
    32. PlayerUtils.sendMessage(player, ChatColor.RED + "You are now a " + ChatColor.AQUA + "Scout" + ChatColor.RED + "!");
    33. } else if(name.contains("Spawner")){
    34. KitUtils.setKit(player, new SpawnerKit());
    35. PlayerUtils.sendMessage(player, ChatColor.RED + "You are now a " + ChatColor.AQUA + "Spawner" + ChatColor.RED + "!");
    36. }
    37. }
    38. }, GhostSquadron.getInstance())
    39. .setOption(0, alchemistIcon, ChatColor.GOLD + "" + ChatColor.BOLD + "Alchemist Kit", ChatColor.DARK_PURPLE + "Lots and lots of potions.")
    40. .setOption(1, archerIcon, ChatColor.GOLD + "" + ChatColor.BOLD + "Archer Kit", ChatColor.DARK_PURPLE + "Start with a bow and", ChatColor.DARK_PURPLE + "128 arrows.")
    41. .setOption(2, bruiserIcon, ChatColor.GOLD + "" + ChatColor.BOLD + "Bruiser Kit", ChatColor.DARK_PURPLE + "Start with a stone sword.")
    42. .setOption(3, pyroIcon, ChatColor.GOLD + "" + ChatColor.BOLD + "Pyro Kit", ChatColor.DARK_PURPLE + "Blaze rod with fire aspect", ChatColor.DARK_PURPLE + "and a fire bow.")
    43. .setOption(4, scoutIcon, ChatColor.GOLD + "" + ChatColor.BOLD + "Scout Kit", ChatColor.DARK_PURPLE + "Start with a knockback stick", ChatColor.DARK_PURPLE + "and a speed II boost.")
    44. .setOption(5, spawnerIcon, ChatColor.GOLD + "" + ChatColor.BOLD + "Spawner Kit", ChatColor.DARK_PURPLE + "Lots and lots of", ChatColor.DARK_PURPLE + "spawn eggs.");
    45.  
    46. return menu;
    47. }
     
  9. Offline

    desht

    chasechocolate classic symptom of creating a new icon menu each time and not destroying (thus unregistering the event handler) the previous one. Each creation of a new icon menu is registering another event handler.

    Using event.setWillDestroy(true) should be helpful here.
     
    Malatak1 and chasechocolate like this.
  10. Offline

    ritipinheiro

    I make my own menu...
     
  11. Offline

    Ultimate_n00b

    So I noticed if you set setWillClose to false, and setWillDestroy to true, then it deletes the menu after the first click, and its still open for the player. How can I destroy it when the player exits the menu?
     
  12. Offline

    Rockon999

    Ultimate_n00b
    This may not work... but you could try listening for the InventoryCloseEvent, and deleting the inventory...
     
  13. Offline

    nicholas303

    I love the idea, but i have a problem. I have absolutly no knowledge of any coding, I would love to have it on my server. But that problem is stopping me
     
  14. Offline

    Artemis

    Hey,
    Is the first post's version of the class still working (with 1.5.2) ? I'm getting an NullPointerException for the onOptionClick event when I try to use it.
    Thanks!
     
  15. How do u open a hopper (5 Slots) like that?
     
  16. Offline

    Pizza371

    Main :
    Code:
    package me.pizza.menu;
     
    import org.bukkit.command.Command;
    import org.bukkit.command.CommandSender;
    import org.bukkit.entity.Player;
    import org.bukkit.event.Listener;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.plugin.Plugin;
    import org.bukkit.plugin.java.JavaPlugin;
    import org.bukkit.Bukkit;
    import org.bukkit.ChatColor;
    import org.bukkit.Material;
    public class Main extends JavaPlugin implements Listener {
     
        public Plugin plugin;
        public void plugin(Plugin instance) {
            this.plugin = instance;
        }
        public void onEnable() {
            getServer().getPluginManager().registerEvents(new IconMenu(), this);
        }
     
        public boolean onCommand(CommandSender sender, Command cmd, String cmdname, String[] args) {
            Player p = ((Player) sender).getPlayer();
            if(cmdname.equalsIgnoreCase("Menu")) {
                if(sender instanceof Player) {
                menu.open(p);
                }
            }
            return false;
        }
        IconMenu menu = new IconMenu("Help Menu", 9, new IconMenu.OptionClickEventHandler() {
            @Override
            public void onOptionClick(IconMenu.OptionClickEvent event) {
                String itemname = event.getName();
                Player player = event.getPlayer();
                if(itemname.equals("h")) {
                    event.setWillDestroy(true);
                    player.sendMessage("h");
                } else if(itemname.equals("test")) {
                    event.setWillDestroy(true);
                    player.sendMessage("test");
                    player.sendMessage("test");
                } else if(itemname.equals("LOOK, IT'S A CARROT!")) {
                    event.setWillDestroy(true);
                    player.sendMessage("not even.. does anytthing yet )@00");
                }
            }
        }, plugin)
        .setOption(3, new ItemStack(Material.BEDROCK, 1), "h", "h")
        .setOption(4, new ItemStack(Material.PAPER, 1), "test", "test")
        .setOption(5, new ItemStack(Material.CARROT, 1), "LOOK, IT'S A CARROT!", "nothing else here");
    }
    ItemMenu :
    Code:
    package me.pizza.menu;
     
    import java.util.Arrays;
     
    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.HandlerList;
    import org.bukkit.event.Listener;
    import org.bukkit.event.inventory.InventoryClickEvent;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    import org.bukkit.plugin.Plugin;
     
    public class IconMenu implements Listener {
        private String name;
        private int size;
        private OptionClickEventHandler handler;
        public Plugin plugin;
     
        private String[] optionNames;
        private ItemStack[] optionIcons;
     
        public IconMenu(String name, int size, OptionClickEventHandler handler, Plugin plugin) {
            this.name = name;
            this.size = size;
            this.handler = handler;
            this.plugin = plugin;
            this.optionNames = new String[size];
            this.optionIcons = new ItemStack[size];
        }
     
        public IconMenu() {
            // TODO Auto-generated constructor stub
        }
     
        public IconMenu setOption(int position, ItemStack icon, String name, String... info) {
            optionNames[position] = name;
            optionIcons[position] = setItemNameAndLore(icon, name, info);
            return this;
        }
     
        public void open(Player player) {
            Inventory inventory = Bukkit.createInventory(player, size, name);
            for (int i = 0; i < optionIcons.length; i++) {
                if (optionIcons[i] != null) {
                    inventory.setItem(i, optionIcons[i]);
                }
            }
            player.openInventory(inventory);
        }
     
        public void destroy() {
            HandlerList.unregisterAll(this);
            handler = null;
            plugin = null;
            optionNames = null;
            optionIcons = null;
        }
     
        @EventHandler(priority=EventPriority.MONITOR)
        void onInventoryClick(InventoryClickEvent event) {
            if (event.getInventory().getTitle().equals(name)) {
                event.setCancelled(true);
                int slot = event.getRawSlot();
                if (slot >= 0 && slot < size && optionNames[slot] != null) {
                    Plugin plugin = this.plugin;
                    OptionClickEvent e = new OptionClickEvent((Player)event.getWhoClicked(), slot, optionNames[slot]);
                    handler.onOptionClick(e);
                    if (e.willClose()) {
                        final Player p = (Player)event.getWhoClicked();
                        Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                            public void run() {
                                p.closeInventory();
                            }
                        }, 1);
                    }
                    if (e.willDestroy()) {
                        destroy();
                    }
                }
            }
        }
     
        public interface OptionClickEventHandler {
            public void onOptionClick(OptionClickEvent event);   
        }
     
        public class OptionClickEvent {
            private Player player;
            private int position;
            private String name;
            private boolean close;
            private boolean destroy;
       
            public OptionClickEvent(Player player, int position, String name) {
                this.player = player;
                this.position = position;
                this.name = name;
                this.close = true;
                this.destroy = false;
            }
       
            public Player getPlayer() {
                return player;
            }
       
            public int getPosition() {
                return position;
            }
       
            public String getName() {
                return name;
            }
       
            public boolean willClose() {
                return close;
            }
       
            public boolean willDestroy() {
                return destroy;
            }
       
            public void setWillClose(boolean close) {
                this.close = close;
            }
       
            public void setWillDestroy(boolean destroy) {
                this.destroy = destroy;
            }
        }
     
        private ItemStack setItemNameAndLore(ItemStack item, String name, String[] lore) {
            ItemMeta im = item.getItemMeta();
                im.setDisplayName(name);
                im.setLore(Arrays.asList(lore));
            item.setItemMeta(im);
            return item;
        }
     
    }
    Hey!
    I can freely move about the items in the inventory, and take them, and it doesn't execute anything.
    Anyone able to point out where I failed? Thanks! :)
     
  17. Offline

    CeramicTitan

    You destroy the menu before you send the message, try swapping them around.
     
  18. Offline

    Pizza371

  19. Offline

    CeramicTitan

    Of course it does? That is why you don't get the output.
     
  20. Offline

    Pizza371

    CeramicTitan
    It doesn't seem to be onOptionClick at all.. but it opens the menu.
    desht (sorry for tagging you, but I've been looking for ages, and you seem to know a lot :p)
     
  21. Offline

    desht

    Pizza371 you register your event handler with a new IconMenu instance in your onEnable(), ?
    but then you create and pop up a completely separate IconMenu instance, which has no event handler registered to cancel the clicks. And that's why you can pull items out of the menu.
     
    Malatak1 and Pizza371 like this.
  22. Offline

    Pizza371

    desht oh wow, thanks!! Helped so much :)
     
  23. Offline

    Malatak1

    I am semi-new to bukkit and am working on a magic spells sort of plugin for a server I own. I am using the icon menu for spell selection. I have been trying for the past few hours to work out the code, but something is wrong and I can't find the error myself.

    EDITED: As there were no replies within a day, I tried to work out the problems on my own by looking at some of the previous examples on this thread that worked. There are no errors on eclipse, but loading the plugin on server start-up continues to cause an error, and when I attempt to do what I want to open the menu, it doesn't do anything. The code is updated.

    Here is the code:

    MagicCraft.java (The main class of the plugin)
    Code:
    package com.Github.Malatak1.MagicCraft;
     
    import org.bukkit.Bukkit;
    import org.bukkit.Material;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.Action;
    import org.bukkit.event.player.PlayerInteractEvent;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    import org.bukkit.plugin.Plugin;
    import org.bukkit.plugin.PluginManager;
    import org.bukkit.plugin.java.JavaPlugin;
     
    public class MagicCraft extends JavaPlugin implements Listener{
     
    public static IconMenu im;
    private Plugin plugin;
     
        @Override
        public void onEnable(){
       getCommand("magic").setExecutor(new PluginCommandExecutor(this));
       PluginManager pm = Bukkit.getPluginManager();
       pm.registerEvents(im, this);
       getServer().getPluginManager().registerEvents(this, this);
        }
     
        @Override
        public void onDisable() {
       
        }
     
    IconMenu menu = new IconMenu("Known Spells", 9, new IconMenu.OptionClickEventHandler() {
            @Override
            public void onOptionClick(IconMenu.OptionClickEvent event) {
                event.getPlayer().sendMessage("You have chosen " + event.getName());
                event.setWillClose(true);
            }
        }, plugin)
        .setOption(1, new ItemStack(Material.FIREBALL, 1), "Fireball", "Fires a powerful fireball to decimate your enemies.")
        .setOption(2, new ItemStack(Material.DIAMOND, 1), "Thunderbolt", "Smites the target down with a bolt of deadly lightning.")
        .setOption(3, new ItemStack(Material.SNOW_BALL, 1), "Flash Freeze", "Conjures cold winds freeze nearby enemies in their tracks.");
        
        @EventHandler
        public void onPlayerInteract(PlayerInteractEvent event) { //PROBLEM
            if (event.getAction() == Action.RIGHT_CLICK_AIR) {
           ItemStack comparedTo = new ItemStack(Material.BOOK, 1);
           if(event.getPlayer().getItemInHand().equals(comparedTo)) {
           ItemStack book = event.getPlayer().getItemInHand();
           ItemMeta bookMeta = book.getItemMeta();
       if (bookMeta.getDisplayName().equals("Spell Book")) {    
       
       menu.open(event.getPlayer());
           }
           }
            }
            if (event.getAction() == Action.RIGHT_CLICK_BLOCK) {
           if(event.getPlayer().getItemInHand().equals(Material.BOOK)) {
           ItemStack book = event.getPlayer().getItemInHand();
           ItemMeta bookMeta = book.getItemMeta();
       if (bookMeta.getDisplayName().equals("Spell Book")) {
       
       menu.open(event.getPlayer());
           }
           }
            }
            
            
        }
    }
    

    IconMenu.java (The class used for the icon menu, which is completely copied from the op and unedited)
    Code:
    package com.Github.Malatak1.MagicCraft;
     
    import java.util.Arrays;
     
    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.HandlerList;
    import org.bukkit.event.Listener;
    import org.bukkit.event.inventory.InventoryClickEvent;
    import org.bukkit.inventory.Inventory;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    import org.bukkit.plugin.Plugin;
     
    public class IconMenu implements Listener {
     
        private String name;
        private int size;
        private OptionClickEventHandler handler;
        private Plugin plugin;
     
        private String[] optionNames;
        private ItemStack[] optionIcons;
     
        public IconMenu(String name, int size, OptionClickEventHandler handler, Plugin plugin) {
            this.name = name;
            this.size = size;
            this.handler = handler;
            this.plugin = plugin;
            this.optionNames = new String[size];
            this.optionIcons = new ItemStack[size];
            plugin.getServer().getPluginManager().registerEvents(this, plugin);
        }
     
        public IconMenu setOption(int position, ItemStack icon, String name, String... info) {
            optionNames[position] = name;
            optionIcons[position] = setItemNameAndLore(icon, name, info);
            return this;
        }
     
        public void open(Player player) {
            Inventory inventory = Bukkit.createInventory(player, size, name);
            for (int i = 0; i < optionIcons.length; i++) {
                if (optionIcons[i] != null) {
                    inventory.setItem(i, optionIcons[i]);
                }
            }
            player.openInventory(inventory);
        }
     
        public void destroy() {
            HandlerList.unregisterAll(this);
            handler = null;
            plugin = null;
            optionNames = null;
            optionIcons = null;
        }
     
        @EventHandler(priority=EventPriority.MONITOR)
        void onInventoryClick(InventoryClickEvent event) {
            if (event.getInventory().getTitle().equals(name)) {
                event.setCancelled(true);
                int slot = event.getRawSlot();
                if (slot >= 0 && slot < size && optionNames[slot] != null) {
                    Plugin plugin = this.plugin;
                    OptionClickEvent e = new OptionClickEvent((Player)event.getWhoClicked(), slot, optionNames[slot]);
                    handler.onOptionClick(e);
                    if (e.willClose()) {
                        final Player p = (Player)event.getWhoClicked();
                        Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
                            public void run() {
                                p.closeInventory();
                            }
                        }, 1);
                    }
                    if (e.willDestroy()) {
                        destroy();
                    }
                }
            }
        }
     
        public interface OptionClickEventHandler {
            public void onOptionClick(OptionClickEvent event);
        }
     
        public class OptionClickEvent {
            private Player player;
            private int position;
            private String name;
            private boolean close;
            private boolean destroy;
     
            public OptionClickEvent(Player player, int position, String name) {
                this.player = player;
                this.position = position;
                this.name = name;
                this.close = true;
                this.destroy = false;
            }
     
            public Player getPlayer() {
                return player;
            }
     
            public int getPosition() {
                return position;
            }
     
            public String getName() {
                return name;
            }
     
            public boolean willClose() {
                return close;
            }
     
            public boolean willDestroy() {
                return destroy;
            }
     
            public void setWillClose(boolean close) {
                this.close = close;
            }
     
            public void setWillDestroy(boolean destroy) {
                this.destroy = destroy;
            }
        }
     
        private ItemStack setItemNameAndLore(ItemStack item, String name, String[] lore) {
            ItemMeta im = item.getItemMeta();
                im.setDisplayName(name);
                im.setLore(Arrays.asList(lore));
            item.setItemMeta(im);
            return item;
        }
     
    }
    The error message when starting my test server using my plugin:
    Code:
    C:\Users\Matt\Desktop\TEST SERVER>java -Xms1024M -Xmx1024M -jar craftbukkit-1.6.
    2-R0.1-20130710.175709-4.jar -o true
    19:54:57 [INFO] Starting minecraft server version 1.6.2
    19:54:57 [INFO] Loading properties
    19:54:57 [INFO] Default game type: SURVIVAL
    19:54:57 [INFO] Generating keypair
    19:54:57 [INFO] Starting Minecraft server on *:25565
    19:54:58 [INFO] This server is running CraftBukkit version git-Bukkit-1.5.2-R1.0
    -22-gcea8f29-b2811jnks (MC: 1.6.2) (Implementing API version 1.6.2-R0.1-SNAPSHOT
    )
    19:54:58 [SEVERE] Could not load 'plugins\MagicCraft.jar' in folder 'plugins'
    org.bukkit.plugin.InvalidPluginException: java.lang.NullPointerException
            at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.j
    ava:182)
            at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.
    java:305)
            at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager
    .java:230)
            at org.bukkit.craftbukkit.v1_6_R2.CraftServer.loadPlugins(CraftServer.ja
    va:239)
            at org.bukkit.craftbukkit.v1_6_R2.CraftServer.<init>(CraftServer.java:21
    7)
            at net.minecraft.server.v1_6_R2.PlayerList.<init>(PlayerList.java:56)
            at net.minecraft.server.v1_6_R2.DedicatedPlayerList.<init>(SourceFile:11
    )
            at net.minecraft.server.v1_6_R2.DedicatedServer.init(DedicatedServer.jav
    a:106)
            at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java
    :391)
            at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:5
    82)
    Caused by: java.lang.NullPointerException
            at com.Github.Malatak1.MagicCraft.IconMenu.<init>(IconMenu.java:34)
            at com.Github.Malatak1.MagicCraft.MagicCraft.<init>(MagicCraft.java:39)
            at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
     
            at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
     
            at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Sou
    rce)
            at java.lang.reflect.Constructor.newInstance(Unknown Source)
            at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.j
    ava:178)
            ... 9 more
    
    A bit more information: The plugin is supposed to be able to do two things right now: 1. When the player does /magic spellbook, it gives them a book with the displayname of "Spell Book". 2. When a player right clicks with a book that has the displayname of "Spell Book", it is supposed to open up the icon menu, where later they will be able to select their spells.

    Honestly I am not sure how to fix the problem... I have been working at it for quite a few hours by now and I don't know where to look, but I figured that this would be a good place to start.
     
  24. Offline

    Malatak1

    Is anybody able to help? I have tried to fix it on my own but I don't understand why there is a nullPointerException. I am really stuck here, please help if you can see a way to fix the problem.
     
  25. Offline

    desht

    Malatak1 you have some cleanup to do on that code:
    • You declare a public static (why static?) IconMenu object - im - but never create the object. However you then pass it to registerEvents(). That won't work, although it's not the direct cause of your NPE.
    • You declare a private Plugin plugin field. Why? Use this - that's your plugin instance variable. Don't declare another one.
    • You're declaring (and this time creating) another IconMenu object outside the onEnable() method - don't do that. That code gets run when the plugin constructor is run (which is well before onEnable() is called), and you're passing the uninitialised and useless plugin to it. That's the cause of your NPE.
    Create one IconMenu object from inside your onEnable() method, and pass thisas the plugin instance to the IconMenu constructor. Don't explicitly register events for it in your onEnable() - if you look at the IconMenu code, you'll see that it registers itself as an event handler.
    Your logic in the PlayerInteractEvent handler looks odd too - two near-identical blocks of code for clicking air and blocks. Just combine them, and do if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) { ... }. You're also trying to compare an ItemStack with a Material in one of the code sections, which won't work.
     
    Malatak1 likes this.
  26. Offline

    Malatak1

    desht That helped A LOT, the plugin now loads fine, but now that IconMenu isn't local to the onPlayerInteract event, I get errors with "menu.open", where it says that "menu cannot be resolved". If you look at the IconMenu object, it says that the local variable menu has not been used.

    When right clicking with the "Spell Book" item ingame, it causes this error on the console, which I believe it says is because of the fact that menu is not resolved.

    I feel like there is an easy way to fix this aswell, but me being new at this I can't figure out how. All quick fixes just cause more errors and mess up the code more, so eclipse isn't much help and I can't really find anything on the internet that shows how to solve this sort of thing (believe, me I tried).

    If you don't mind can you show me what I am doing wrong exactly? I feel like there is a way to re-instantiate the IconMenu object before opening it, but everything that I tried to do in order to fix it didn't work.

    Here is my current main class, the other classes are unchanged:
    Code:
    package com.Github.Malatak1.MagicCraft;
     
    import org.bukkit.Material;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.Listener;
    import org.bukkit.event.block.Action;
    import org.bukkit.event.player.PlayerInteractEvent;
    import org.bukkit.inventory.ItemStack;
    import org.bukkit.inventory.meta.ItemMeta;
    import org.bukkit.plugin.java.JavaPlugin;
    import com.Github.Malatak1.MagicCraft.IconMenu;
     
    public class MagicCraft extends JavaPlugin implements Listener{
       
        public IconMenu im;
       
        @Override
        public void onEnable(){
            IconMenu menu = new IconMenu("Known Spells", 9, new IconMenu.OptionClickEventHandler() {
            //Error on line above: "The value of the local variable menu has not been used".
                @Override
                public void onOptionClick(IconMenu.OptionClickEvent event) {
                    event.getPlayer().sendMessage("You have chosen " + event.getName());
                    event.setWillClose(true);
                }
            }, this)
            .setOption(1, new ItemStack(Material.FIREBALL, 1), "Fireball", "Fires a destructive fireball to decimate your enemies.")
            .setOption(2, new ItemStack(Material.DIAMOND, 1), "Thunderbolt", "Smites the target down with a powerful bolt of lightning.")
            .setOption(3, new ItemStack(Material.SNOW_BALL, 1), "Flash Freeze", "Conjures cold winds to freeze nearby enemies in their tracks.");
           
           
            getCommand("magic").setExecutor(new PluginCommandExecutor(this));
            getServer().getPluginManager().registerEvents(this, this);
           
        }
     
        @Override
        public void onDisable() {
           
        }
       
        @EventHandler
        public void onPlayerInteract(PlayerInteractEvent event) {
            if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_AIR) {
                if(event.getPlayer().getItemInHand().equals(Material.BOOK)) {
                    ItemStack book = event.getPlayer().getItemInHand();
                    ItemMeta bookMeta = book.getItemMeta();
                    if (bookMeta.getDisplayName().equals("Spell Book")) {
                        menu.open(event.getPlayer()); //Error here: "menu cannot be resolved".
                    }
                }
            }
           
        }
    }
    
     
  27. Offline

    desht

    Malatak1 that's because your 'menu' variable is now a local variable in onEnable(), so it's completely invisible (not in scope) to the interact event handler. Make it a field of your plugin class, and get rid of the pointless 'im' field. The Eclipse error you included should have been a clue to that.

    And no offence (we all started somewhere) but you probably need to do a little more basic Java research. E.g. on the difference between local variables and object fields - http://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html
     
    Malatak1 likes this.
  28. Offline

    Malatak1

    desht Thank you so much, that fixed it. I understand that I'm not quite up to par on java, and I suppose I shouldn't be working with bukkit until I understand some of the basics of the java language better. Thank you for all your help though, I am glad you were able to help me.
     
    desht likes this.
  29. Offline

    Delocaz

    I'm trying to do a chest-based shop plugin using this, but for some reason the onOptionClick function never gets called.

    The menu opens fine, but nothing happens when I click anything.

    The debug output only goes up to 3.
    Code:java
    1.  
    2. /*
    3.  * To change this template, choose Tools | Templates
    4.  * and open the template in the editor.
    5.  */
    6. package net.delocaz.guishop;
    7.  
    8. import net.milkbowl.vault.economy.Economy;
    9. import org.bukkit.ChatColor;
    10. import org.bukkit.Location;
    11. import org.bukkit.Material;
    12. import org.bukkit.block.Chest;
    13. import org.bukkit.block.Sign;
    14. import org.bukkit.event.EventHandler;
    15. import org.bukkit.event.Listener;
    16. import org.bukkit.event.player.PlayerInteractEvent;
    17. import org.bukkit.inventory.Inventory;
    18. import org.bukkit.inventory.ItemStack;
    19. import org.bukkit.plugin.RegisteredServiceProvider;
    20. import org.bukkit.plugin.java.JavaPlugin;
    21. import utils.IconMenu;
    22.  
    23. /**
    24.  *
    25.  * @author Marvin
    26.  */
    27. public class GUIShop extends JavaPlugin implements Listener {
    28. @Override
    29. public void onEnable() {
    30. getServer().getPluginManager().registerEvents(this, this);
    31. }
    32. @EventHandler
    33. public void onPlayerInteract(final PlayerInteractEvent e) {
    34. if (e.getClickedBlock().getType() == Material.CHEST) {
    35. if (e.getPlayer().isSneaking() && e.getPlayer().isOp()) {
    36. return;
    37. }
    38. System.out.println(1);
    39. Location l = e.getClickedBlock().getLocation();
    40. l.setY(l.getY()-1);
    41. System.out.println(l.getBlock().getType());
    42. if ((l.getBlock().getType() == Material.SIGN_POST) || (l.getBlock().getType() == Material.WALL_SIGN)) {
    43. System.out.println(2);
    44. Sign s = (Sign) l.getBlock().getState();
    45. if (s.getLine(0).contains("[GUIShop]")) {
    46. System.out.println(3);
    47. IconMenu im = new IconMenu(s.getLine(1), 36, new IconMenu.OptionClickEventHandler() {
    48. @Override
    49. public void onOptionClick(IconMenu.OptionClickEvent event) {
    50. System.out.println(4);
    51. ItemStack is = ((Chest) e.getClickedBlock().getState()).getBlockInventory().getItem(event.getPosition());
    52. e.getPlayer().getInventory().addItem(is);
    53. double price = getConfig().getDouble(is.getType().toString())*is.getAmount();
    54. if (price == 0) {
    55. price = getConfig().getDouble("default")*is.getAmount();
    56. }
    57. RegisteredServiceProvider<Economy> economyProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
    58. Economy economy = null;
    59. if (economyProvider != null) {
    60. economy = economyProvider.getProvider();
    61. }
    62. economy.withdrawPlayer(event.getPlayer().getName(), price);
    63. event.getPlayer().sendMessage("You have bought "+is.getAmount()+" "+is.getType().toString()+" for "+price+"!");
    64. event.setWillClose(true);
    65. event.setWillDestroy(true);
    66. }
    67. }, this);
    68. Inventory i = ((Chest) e.getClickedBlock().getState()).getBlockInventory();
    69. for (int ii = 0;ii < i.getSize();ii++) {
    70. ItemStack is = i.getItem(ii);
    71. if (is == null) {
    72. continue;
    73. }
    74. double price = getConfig().getDouble(is.getType().toString())*is.getAmount();
    75. if (price == 0) {
    76. price = getConfig().getDouble("default")*is.getAmount();
    77. }
    78. im.setOption(ii, is, is.getItemMeta().getDisplayName(), "Price: "+ChatColor.GOLD+price);
    79. }
    80. im.open(e.getPlayer());
    81. e.setCancelled(true);
    82. }
    83. }
    84. }
    85. }
    86. }
    87.  
     
  30. You have to make the inventories in multiples of 9 right?
     
Thread Status:
Not open for further replies.

Share This Page