Reputation: 45
I have an abstract GUI parent class handling a click event.
public abstract class GUI implements Listener {
private final Inventory inventory;
public GUI(Player player) {
Bukkit.getPluginManager().registerEvents(this, NPCs.getPlugin());
ItemStack fillerItem = new ItemStack(getFiller());
ItemMeta fillerItemMeta = fillerItem.getItemMeta();
fillerItemMeta.setDisplayName("");
fillerItem.setItemMeta(fillerItemMeta);
int inventorySize = (getFunctionalItems().size()>=54) ? 54 : getFunctionalItems().size()+(9-getFunctionalItems().size()%9)*Math.min(1, getFunctionalItems().size()%9);
inventory = Bukkit.createInventory(player, inventorySize, getName());
for(int i = 0; i < inventory.getSize(); i++) {
inventory.setItem(i, fillerItem);
}
for(int i = 0; i < getFunctionalItems().size(); i++) {
inventory.setItem(i, getFunctionalItems().get(i));
}
}
@EventHandler
public void onClick(InventoryClickEvent event) {
handle(event);
}
public abstract ArrayList<ItemStack> getFunctionalItems();
public abstract String getName();
protected abstract void handle(InventoryClickEvent event);
public Material getFiller() {
return Material.GRAY_STAINED_GLASS_PANE;
}
public Inventory getInventory() {
return inventory;
}
protected final ItemStack createFunctionalItem(String name, Material material) {
ItemStack itemStack = new ItemStack(material);
ItemMeta itemMeta = itemStack.getItemMeta();
itemMeta.setDisplayName(name);
itemStack.setItemMeta(itemMeta);
return itemStack;
}
}
In my child class it gets handled like following
@Override
public void handle(InventoryClickEvent event) {
ItemStack clicked = event.getCurrentItem();
Player player = (Player) event.getWhoClicked();
MainGUI mainGUI = new MainGUI(player);
NameGUI nameGUI = new NameGUI(player);
SkinGUI skinGUI = new SkinGUI(player);
//Main GUI
if(Arrays.equals(event.getClickedInventory().getContents(), mainGUI.getInventory().getContents())) {
switch(clicked.getItemMeta().getDisplayName()) {
case "Set Name" -> player.openInventory(nameGUI.getInventory());
case "Set Skin" -> player.openInventory(skinGUI.getInventory());
}
event.setCancelled(true);
}
}
But if I test it gets called 2 times on the first click and on the following so many times it even forces my game to crash. I know I can just put in a delay but I really want to know why this is the case.
Thank you
Upvotes: 0
Views: 532
Reputation: 4908
It's running multiple times because you are adding each new GUI to listener.
For example, here:
MainGUI mainGUI = new MainGUI(player);
NameGUI nameGUI = new NameGUI(player);
SkinGUI skinGUI = new SkinGUI(player);
You are creating 3 GUIs, so 3 new inventory click event register in listener.
To fix this, I suggest you to :
InventoryClickEvent
event, and call GUI that you be called.For example, you have a list with all GUI:
public static List<GUI> ALL_GUIS = new ArrayList<>();
Then, you should have a way to determine in which inventory the player clicked, such as:
public class MainGUIHolder implements InventoryHolder {
@Override
public Inventory getInventory() {
return null;
}
}
Now use it like that:
Inventory mainInv = Bukkit.createInventory(new MainGUIHolder(), 9, "My inv");
You can check with inventory instanceof MainGUIHolder
, then get the holder instance with maybe some object that is currently edited by the player
MainGUI mainGUI = GuiManager.getMainGUID(); // here get the alone main GUI instance
// now use it
Upvotes: 2