diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 400e109..4b6eb6b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,7 +4,7 @@ stages: variables: name: "UltimateKits" path: "/builds/$CI_PROJECT_PATH" - version: "2.3.19" + version: "2.3.20" build: stage: build diff --git a/pom.xml b/pom.xml index 35a43f7..45fa8d5 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ com.songoda:songodaupdater + com.zaxxer:HikariCP @@ -221,5 +222,20 @@ 0.1.3.0 provided + + com.zrips + CMI + 8.0.8.1 + + + com.zaxxer + HikariCP + 3.2.0 + + + org.xerial + sqlite-jdbc + 3.23.1 + diff --git a/src/main/java/com/songoda/ultimatekits/UltimateKits.java b/src/main/java/com/songoda/ultimatekits/UltimateKits.java index 32aca50..4c8bdb7 100644 --- a/src/main/java/com/songoda/ultimatekits/UltimateKits.java +++ b/src/main/java/com/songoda/ultimatekits/UltimateKits.java @@ -2,6 +2,11 @@ package com.songoda.ultimatekits; import com.songoda.ultimatekits.command.CommandManager; import com.songoda.ultimatekits.conversion.Convert; +import com.songoda.ultimatekits.database.DataManager; +import com.songoda.ultimatekits.database.DataMigrationManager; +import com.songoda.ultimatekits.database.DatabaseConnector; +import com.songoda.ultimatekits.database.MySQLConnector; +import com.songoda.ultimatekits.database.SQLiteConnector; import com.songoda.ultimatekits.economy.Economy; import com.songoda.ultimatekits.economy.PlayerPointsEconomy; import com.songoda.ultimatekits.economy.ReserveEconomy; @@ -59,6 +64,10 @@ public class UltimateKits extends JavaPlugin { private ItemSerializer itemSerializer; + private DatabaseConnector databaseConnector; + private DataMigrationManager dataMigrationManager; + private DataManager dataManager; + /** * Grab instance of UltimateKits * @@ -136,8 +145,38 @@ public class UltimateKits extends JavaPlugin { // Starting Metrics new Metrics(this); - console.sendMessage(Methods.formatText("&a=============================")); + try { + if (Setting.MYSQL_ENABLED.getBoolean()) { + String hostname = Setting.MYSQL_HOSTNAME.getString(); + int port = Setting.MYSQL_PORT.getInt(); + String database = Setting.MYSQL_DATABASE.getString(); + String username = Setting.MYSQL_USERNAME.getString(); + String password = Setting.MYSQL_PASSWORD.getString(); + boolean useSSL = Setting.MYSQL_USE_SSL.getBoolean(); + this.databaseConnector = new MySQLConnector(this, hostname, port, database, username, password, useSSL); + this.getLogger().info("Data handler connected using MySQL."); + } else { + this.databaseConnector = new SQLiteConnector(this); + this.getLogger().info("Data handler connected using SQLite."); + } + } catch (Exception ex) { + this.getLogger().severe("Fatal error trying to connect to database. " + + "Please make sure all your connection settings are correct and try again. Plugin has been disabled."); + Bukkit.getPluginManager().disablePlugin(this); + } + + this.dataManager = new DataManager(this.databaseConnector, this); + this.dataMigrationManager = new DataMigrationManager(this.databaseConnector, this.dataManager); + this.dataMigrationManager.runMigrations(); + + Bukkit.getScheduler().runTaskLater(this, () -> { + this.dataManager.getBlockData((blockData) -> { + this.kitManager.setKitLocations(blockData); + }); + }, 20L); + + console.sendMessage(Methods.formatText("&a=============================")); } /* @@ -146,6 +185,7 @@ public class UltimateKits extends JavaPlugin { public void onDisable() { saveToFile(); kitManager.clearKits(); + this.dataManager.bulkUpdateBlockData(this.getKitManager().getKitLocations()); console.sendMessage(Methods.formatText("&a=============================")); console.sendMessage(Methods.formatText("&7UltimateKits " + this.getDescription().getVersion() + " by &5Songoda <3!")); console.sendMessage(Methods.formatText("&7Action: &cDisabling&7...")); @@ -273,26 +313,8 @@ public class UltimateKits extends JavaPlugin { kitFile.getConfig().set("Kits." + kit.getName() + ".items", strContents); } - // Wipe old block information. - dataFile.getConfig().set("BlockData", null); - - /* - * Save kit locations from KitManager to Configuration. - */ - for (KitBlockData kitBlockData : kitManager.getKitLocations().values()) { - String locationStr = Methods.serializeLocation(kitBlockData.getLocation()); - if (locationStr == null) continue; - dataFile.getConfig().set("BlockData." + locationStr + ".type", kitBlockData.getType().name()); - dataFile.getConfig().set("BlockData." + locationStr + ".kit", kitBlockData.getKit().getName()); - dataFile.getConfig().set("BlockData." + locationStr + ".holograms", kitBlockData.showHologram()); - dataFile.getConfig().set("BlockData." + locationStr + ".displayItems", kitBlockData.isDisplayingItems()); - dataFile.getConfig().set("BlockData." + locationStr + ".particles", kitBlockData.hasParticles()); - dataFile.getConfig().set("BlockData." + locationStr + ".itemOverride", kitBlockData.isItemOverride()); - } - // Save to file kitFile.saveConfig(); - dataFile.saveConfig(); } /* @@ -391,4 +413,12 @@ public class UltimateKits extends JavaPlugin { public DisplayItemHandler getDisplayItemHandler() { return displayItemHandler; } + + public DatabaseConnector getDatabaseConnector() { + return databaseConnector; + } + + public DataManager getDataManager() { + return dataManager; + } } diff --git a/src/main/java/com/songoda/ultimatekits/command/AbstractCommand.java b/src/main/java/com/songoda/ultimatekits/command/AbstractCommand.java index cd6c4a5..e197b50 100644 --- a/src/main/java/com/songoda/ultimatekits/command/AbstractCommand.java +++ b/src/main/java/com/songoda/ultimatekits/command/AbstractCommand.java @@ -3,18 +3,34 @@ package com.songoda.ultimatekits.command; import com.songoda.ultimatekits.UltimateKits; import org.bukkit.command.CommandSender; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public abstract class AbstractCommand { - private final AbstractCommand parent; - private final String command; private final boolean noConsole; - private final boolean subCommands; + private AbstractCommand parent = null; + private boolean hasArgs = false; + private String command; - protected AbstractCommand(String command, AbstractCommand parent, boolean noConsole, boolean subCommands) { - this.command = command; + private List subCommand = new ArrayList<>(); + + protected AbstractCommand(AbstractCommand parent, boolean noConsole, String... command) { + if (parent != null) { + this.subCommand = Arrays.asList(command); + } else { + this.command = Arrays.asList(command).get(0); + } this.parent = parent; this.noConsole = noConsole; - this.subCommands = subCommands; + } + + protected AbstractCommand(boolean noConsole, boolean hasArgs, String... command) { + this.command = Arrays.asList(command).get(0); + + this.hasArgs = hasArgs; + this.noConsole = noConsole; } public AbstractCommand getParent() { @@ -25,21 +41,32 @@ public abstract class AbstractCommand { return command; } - public boolean isNoConsole() { - return noConsole; + public List getSubCommand() { + return subCommand; } - public boolean isSubCommands() { - return subCommands; + public void addSubCommand(String command) { + subCommand.add(command); } protected abstract ReturnType runCommand(UltimateKits instance, CommandSender sender, String... args); + protected abstract List onTab(UltimateKits instance, CommandSender sender, String... args); + public abstract String getPermissionNode(); public abstract String getSyntax(); public abstract String getDescription(); + public boolean hasArgs() { + return hasArgs; + } + + public boolean isNoConsole() { + return noConsole; + } + public enum ReturnType {SUCCESS, FAILURE, SYNTAX_ERROR} } + diff --git a/src/main/java/com/songoda/ultimatekits/command/CommandManager.java b/src/main/java/com/songoda/ultimatekits/command/CommandManager.java index 8a7070b..f22c575 100644 --- a/src/main/java/com/songoda/ultimatekits/command/CommandManager.java +++ b/src/main/java/com/songoda/ultimatekits/command/CommandManager.java @@ -15,11 +15,13 @@ import java.util.List; public class CommandManager implements CommandExecutor { private UltimateKits plugin; + private TabManager tabManager; private List commands = new ArrayList<>(); public CommandManager(UltimateKits plugin) { this.plugin = plugin; + this.tabManager = new TabManager(this); plugin.getCommand("kitadmin").setExecutor(this); plugin.getCommand("kit").setExecutor(this); @@ -36,6 +38,11 @@ public class CommandManager implements CommandExecutor { addCommand(new CommandKey(commandUltimateKits)); addCommand(new CommandSet(commandUltimateKits)); addCommand(new CommandRemove(commandUltimateKits)); + + for (AbstractCommand abstractCommand : commands) { + if (abstractCommand.getParent() != null) continue; + plugin.getCommand(abstractCommand.getCommand()).setTabCompleter(tabManager); + } } private AbstractCommand addCommand(AbstractCommand abstractCommand) { @@ -46,16 +53,19 @@ public class CommandManager implements CommandExecutor { @Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) { for (AbstractCommand abstractCommand : commands) { - if (abstractCommand.getCommand().equalsIgnoreCase(command.getName())) { - if (strings.length == 0 || !abstractCommand.isSubCommands()) { + if (abstractCommand.getCommand() != null && abstractCommand.getCommand().equalsIgnoreCase(command.getName().toLowerCase())) { + if (strings.length == 0 || abstractCommand.hasArgs()) { processRequirements(abstractCommand, commandSender, strings); return true; } } else if (strings.length != 0 && abstractCommand.getParent() != null && abstractCommand.getParent().getCommand().equalsIgnoreCase(command.getName())) { String cmd = strings[0]; - if (cmd.equalsIgnoreCase(abstractCommand.getCommand())) { - processRequirements(abstractCommand, commandSender, strings); - return true; + String cmd2 = strings.length >= 2 ? String.join(" ", strings[0], strings[1]) : null; + for (String cmds : abstractCommand.getSubCommand()) { + if (cmd.equalsIgnoreCase(cmds) || (cmd2 != null && cmd2.equalsIgnoreCase(cmds))) { + processRequirements(abstractCommand, commandSender, strings); + return true; + } } } } @@ -76,7 +86,7 @@ public class CommandManager implements CommandExecutor { } return; } - plugin.getLocale().newMessage("event.general.nopermission").sendPrefixedMessage(sender); + plugin.getLocale().getMessage("event.general.nopermission").sendPrefixedMessage(sender); } public List getCommands() { diff --git a/src/main/java/com/songoda/ultimatekits/command/TabManager.java b/src/main/java/com/songoda/ultimatekits/command/TabManager.java new file mode 100644 index 0000000..8f1203c --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/command/TabManager.java @@ -0,0 +1,52 @@ +package com.songoda.ultimatekits.command; + +import com.songoda.ultimatekits.UltimateKits; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.List; + +public class TabManager implements TabCompleter { + + private final CommandManager commandManager; + + TabManager(CommandManager commandManager) { + this.commandManager = commandManager; + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] strings) { + for (AbstractCommand abstractCommand : commandManager.getCommands()) { + if (abstractCommand.getCommand() != null && abstractCommand.getCommand().equalsIgnoreCase(command.getName().toLowerCase())) { + if (strings.length == 1) { + List subs = new ArrayList<>(); + for (AbstractCommand ac : commandManager.getCommands()) { + if (ac.getSubCommand() == null) continue; + subs.addAll(ac.getSubCommand()); + } + subs.removeIf(s -> !s.toLowerCase().startsWith(strings[0].toLowerCase())); + return subs; + } + } else if (strings.length != 0 && abstractCommand.getParent() != null && abstractCommand.getParent().getCommand().equalsIgnoreCase(command.getName().toLowerCase())) { + String cmd = strings[0]; + String cmd2 = strings.length >= 2 ? String.join(" ", strings[0], strings[1]) : null; + for (String cmds : abstractCommand.getSubCommand()) { + if (cmd.equalsIgnoreCase(cmds) || (cmd2 != null && cmd2.equalsIgnoreCase(cmds))) { + List list = abstractCommand.onTab(UltimateKits.getInstance(), sender, strings); + String str = strings[strings.length - 1]; + if (list != null && str != null && str.length() >= 1) { + try { + list.removeIf(s -> !s.toLowerCase().startsWith(str.toLowerCase())); + } catch (UnsupportedOperationException ignored) { + } + } + return list; + } + } + } + } + return new ArrayList<>(); + } +} diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandCreatekit.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandCreatekit.java index 4c68289..cea93ca 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandCreatekit.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandCreatekit.java @@ -8,10 +8,14 @@ import com.songoda.ultimatekits.utils.Methods; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class CommandCreatekit extends AbstractCommand { public CommandCreatekit(AbstractCommand parent) { - super("createkit", parent, true, false); + super(parent, true, "createkit"); } @Override @@ -31,6 +35,11 @@ public class CommandCreatekit extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + return Arrays.asList("name"); + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandEdit.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandEdit.java index 4bdeff2..e7b381f 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandEdit.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandEdit.java @@ -1,19 +1,25 @@ package com.songoda.ultimatekits.command.commands; +import bammerbom.ultimatecore.bukkit.UltimateMetrics; import com.songoda.ultimatekits.UltimateKits; import com.songoda.ultimatekits.command.AbstractCommand; import com.songoda.ultimatekits.gui.GUIBlockEditor; import com.songoda.ultimatekits.gui.GUIKitEditor; +import com.songoda.ultimatekits.kit.Kit; import com.songoda.ultimatekits.kit.KitBlockData; +import com.songoda.ultimatekits.kit.KitManager; import com.songoda.ultimatekits.utils.Methods; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class CommandEdit extends AbstractCommand { public CommandEdit(AbstractCommand parent) { - super("edit", parent, true, false); + super(parent, true, "edit"); } @Override @@ -41,6 +47,19 @@ public class CommandEdit extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + if (!(sender instanceof Player)) return null; + + List tab = new ArrayList<>(); + if (args.length == 2) { + for (Kit kit : UltimateKits.getInstance().getKitManager().getKits()) + tab.add(kit.getName()); + return tab; + } + return tab; + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandKey.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandKey.java index 42740f7..e6d2913 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandKey.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandKey.java @@ -9,10 +9,14 @@ import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public class CommandKey extends AbstractCommand { public CommandKey(AbstractCommand parent) { - super("key", parent, false, false); + super(parent, false, "key"); } @Override @@ -66,6 +70,36 @@ public class CommandKey extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + if (!(sender instanceof Player)) return null; + + List tab = new ArrayList<>(); + + if (args.length == 2) { + tab.add("all"); + for (Kit kit : UltimateKits.getInstance().getKitManager().getKits()) + tab.add(kit.getName()); + return tab; + } + + if (args.length == 3) { + for (Key key : UltimateKits.getInstance().getKeyManager().getKeys()) + tab.add(key.getName()); + return tab; + } + + if (args.length == 4) { + tab.add("all"); + for (Player player : Bukkit.getOnlinePlayers()) + tab.add(player.getName()); + return tab; + } + + if (args.length == 5) return Arrays.asList("amount"); + return tab; + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandKit.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandKit.java index d627250..fda389b 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandKit.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandKit.java @@ -9,10 +9,13 @@ import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class CommandKit extends AbstractCommand { public CommandKit() { - super("Kit", null, false, false); + super(null, false, "kit"); } @Override @@ -72,6 +75,11 @@ public class CommandKit extends AbstractCommand { return ReturnType.SYNTAX_ERROR; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return null; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandPreviewKit.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandPreviewKit.java index 62559fd..98e0d5f 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandPreviewKit.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandPreviewKit.java @@ -6,10 +6,13 @@ import com.songoda.ultimatekits.kit.Kit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class CommandPreviewKit extends AbstractCommand { public CommandPreviewKit() { - super("PreviewKit", null, true, false); + super(null, true, "PreviewKit"); } @Override @@ -28,6 +31,19 @@ public class CommandPreviewKit extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + if (!(sender instanceof Player)) return null; + + if (args.length == 2) { + List tab = new ArrayList<>(); + for (Kit kit : UltimateKits.getInstance().getKitManager().getKits()) + tab.add(kit.getName()); + return tab; + } + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return null; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandReload.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandReload.java index 256ba5e..dcb8218 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandReload.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandReload.java @@ -5,10 +5,13 @@ import com.songoda.ultimatekits.command.AbstractCommand; import com.songoda.ultimatekits.utils.Methods; import org.bukkit.command.CommandSender; +import java.util.ArrayList; +import java.util.List; + public class CommandReload extends AbstractCommand { public CommandReload(AbstractCommand parent) { - super("reload", parent, false, false); + super(parent, false, "reload"); } @Override @@ -18,6 +21,11 @@ public class CommandReload extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandRemove.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandRemove.java index 4f2c328..9b01c68 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandRemove.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandRemove.java @@ -7,10 +7,13 @@ import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class CommandRemove extends AbstractCommand { public CommandRemove(AbstractCommand parent) { - super("remove", parent, true, false); + super(parent, true, "remove"); } @Override @@ -30,6 +33,11 @@ public class CommandRemove extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandSet.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandSet.java index f0fef57..eba55d4 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandSet.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandSet.java @@ -2,15 +2,19 @@ package com.songoda.ultimatekits.command.commands; import com.songoda.ultimatekits.UltimateKits; import com.songoda.ultimatekits.command.AbstractCommand; +import com.songoda.ultimatekits.kit.Kit; import com.songoda.ultimatekits.utils.Methods; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class CommandSet extends AbstractCommand { public CommandSet(AbstractCommand parent) { - super("set", parent, true, false); + super(parent, true, "set"); } @Override @@ -32,6 +36,19 @@ public class CommandSet extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + if (!(sender instanceof Player)) return null; + + if (args.length == 2) { + List tab = new ArrayList<>(); + for (Kit kit : UltimateKits.getInstance().getKitManager().getKits()) + tab.add(kit.getName()); + return tab; + } + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandSettings.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandSettings.java index 7aec25a..ec1e952 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandSettings.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandSettings.java @@ -5,10 +5,13 @@ import com.songoda.ultimatekits.command.AbstractCommand; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.ArrayList; +import java.util.List; + public class CommandSettings extends AbstractCommand { public CommandSettings(AbstractCommand parent) { - super("settings", parent, true, false); + super(parent, true, "settings"); } @Override @@ -17,6 +20,11 @@ public class CommandSettings extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return "ultimatekits.admin"; diff --git a/src/main/java/com/songoda/ultimatekits/command/commands/CommandUltimateKits.java b/src/main/java/com/songoda/ultimatekits/command/commands/CommandUltimateKits.java index 81cd8c2..4c86b7b 100644 --- a/src/main/java/com/songoda/ultimatekits/command/commands/CommandUltimateKits.java +++ b/src/main/java/com/songoda/ultimatekits/command/commands/CommandUltimateKits.java @@ -5,10 +5,13 @@ import com.songoda.ultimatekits.command.AbstractCommand; import com.songoda.ultimatekits.utils.Methods; import org.bukkit.command.CommandSender; +import java.util.ArrayList; +import java.util.List; + public class CommandUltimateKits extends AbstractCommand { public CommandUltimateKits() { - super("KitAdmin", null, false, true); + super(null, false, "KitAdmin"); } @Override @@ -27,6 +30,11 @@ public class CommandUltimateKits extends AbstractCommand { return ReturnType.SUCCESS; } + @Override + protected List onTab(UltimateKits instance, CommandSender sender, String... args) { + return new ArrayList<>(); + } + @Override public String getPermissionNode() { return null; diff --git a/src/main/java/com/songoda/ultimatekits/conversion/Convert.java b/src/main/java/com/songoda/ultimatekits/conversion/Convert.java index 1174481..ba947dd 100644 --- a/src/main/java/com/songoda/ultimatekits/conversion/Convert.java +++ b/src/main/java/com/songoda/ultimatekits/conversion/Convert.java @@ -1,6 +1,7 @@ package com.songoda.ultimatekits.conversion; import com.songoda.ultimatekits.UltimateKits; +import com.songoda.ultimatekits.conversion.hooks.CMIHook; import com.songoda.ultimatekits.conversion.hooks.DefaultHook; import com.songoda.ultimatekits.conversion.hooks.EssentialsHook; import com.songoda.ultimatekits.conversion.hooks.UltimateCoreHook; @@ -27,6 +28,9 @@ public class Convert { } } else if (instance.getServer().getPluginManager().getPlugin("UltimateCore") != null) { hook = new UltimateCoreHook(); + + } else if (instance.getServer().getPluginManager().getPlugin("CMI") != null) { + hook = new CMIHook(); } else { hook = new DefaultHook(); } diff --git a/src/main/java/com/songoda/ultimatekits/conversion/hooks/CMIHook.java b/src/main/java/com/songoda/ultimatekits/conversion/hooks/CMIHook.java new file mode 100644 index 0000000..2b86924 --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/conversion/hooks/CMIHook.java @@ -0,0 +1,43 @@ +package com.songoda.ultimatekits.conversion.hooks; + +import com.Zrips.CMI.CMI; +import com.Zrips.CMI.Modules.Kits.Kit; +import com.songoda.ultimatekits.UltimateKits; +import com.songoda.ultimatekits.conversion.Hook; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.inventory.ItemStack; + +import java.util.HashSet; +import java.util.Set; + +public class CMIHook implements Hook { + + private CMI cmi; + + public CMIHook() { + cmi = (CMI) UltimateKits.getInstance().getServer().getPluginManager().getPlugin("CMI"); + } + + public Set getItems(String kitName) { + Set stacks = new HashSet<>(); + try { + Kit kit = cmi.getKitsManager().getKit(kitName, true); + + for (ItemStack item : kit.getItems()) { + if (item != null) stacks.add(item); + } + } catch (Exception e) { + e.printStackTrace(); + } + return stacks; + } + + public Set getKits() { + return cmi.getKitsManager().getKitMap().keySet(); + } + + public long getDelay(String kitName) { + return cmi.getKitsManager().getKit(kitName, true).getDelay(); + } +} diff --git a/src/main/java/com/songoda/ultimatekits/database/DataManager.java b/src/main/java/com/songoda/ultimatekits/database/DataManager.java new file mode 100644 index 0000000..2140aa5 --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/DataManager.java @@ -0,0 +1,166 @@ +package com.songoda.ultimatekits.database; + +import com.songoda.ultimatekits.UltimateKits; +import com.songoda.ultimatekits.kit.KitBlockData; +import com.songoda.ultimatekits.kit.KitType; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.plugin.Plugin; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +public class DataManager { + + private final DatabaseConnector databaseConnector; + private final Plugin plugin; + + public DataManager(DatabaseConnector databaseConnector, Plugin plugin) { + this.databaseConnector = databaseConnector; + this.plugin = plugin; + } + + public String getTablePrefix() { + return this.plugin.getDescription().getName().toLowerCase() + '_'; + } + + public void bulkUpdateBlockData(Map blockData) { + this.databaseConnector.connect(connection -> { + String updateData = "UPDATE " + this.getTablePrefix() + "blockdata SET kit = ? WHERE " + + "world = ? AND x = ? AND y = ? AND z = ?"; + try (PreparedStatement statement = connection.prepareStatement(updateData)) { + for (int i = 0; i < blockData.size(); i++) { + KitBlockData data = blockData.get(i); + statement.setString(2, data.getKit().getName()); + statement.setString(7, data.getWorld().getName()); + statement.setInt(8, data.getX()); + statement.setInt(9, data.getY()); + statement.setInt(10, data.getZ()); + statement.executeUpdate(); + statement.addBatch(); + } + + statement.executeBatch(); + } + }); + } + + public void updateBlockData(KitBlockData blockData) { + this.async(() -> this.databaseConnector.connect(connection -> { + String updateData = "UPDATE " + this.getTablePrefix() + "blockdata SET kit = ? WHERE " + + "world = ? AND x = ? AND y = ? AND z = ?"; + try (PreparedStatement statement = connection.prepareStatement(updateData)) { + statement.setString(2, blockData.getKit().getName()); + statement.setString(7, blockData.getWorld().getName()); + statement.setInt(8, blockData.getX()); + statement.setInt(9, blockData.getY()); + statement.setInt(10, blockData.getZ()); + statement.executeUpdate(); + } + })); + } + + public void createBlockData(KitBlockData blockData) { + this.async(() -> this.databaseConnector.connect(connection -> { + String createData ="INSERT INTO " + this.getTablePrefix() + "blockdata (" + + "type, kit, holograms, displayItems, particles, itemOverride, world, x, y, z)" + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + try (PreparedStatement statement = connection.prepareStatement(createData)) { + statement.setString(1, blockData.getType().toString()); + statement.setString(2, blockData.getKit().getName()); + statement.setBoolean(3, blockData.showHologram()); + statement.setBoolean(4, blockData.isDisplayingItems()); + statement.setBoolean(5, blockData.hasParticles()); + statement.setBoolean(6, blockData.isItemOverride()); + statement.setString(7, blockData.getWorld().getName()); + statement.setInt(8, blockData.getX()); + statement.setInt(9, blockData.getY()); + statement.setInt(10, blockData.getZ()); + statement.executeUpdate(); + } + })); + } + + public void deleteBlockData(KitBlockData blockData) { + this.async(() -> this.databaseConnector.connect(connection -> { + String deleteData = "DELETE FROM " + this.getTablePrefix() + "blockdata WHERE world = ? " + + "AND x = ? AND y = ? AND z = ?"; + try (PreparedStatement statement = connection.prepareStatement(deleteData)) { + statement.setString(1, blockData.getType().toString()); + statement.setString(2, blockData.getKit().getName()); + statement.setBoolean(3, blockData.showHologram()); + statement.setBoolean(4, blockData.isDisplayingItems()); + statement.setBoolean(5, blockData.hasParticles()); + statement.setBoolean(6, blockData.isItemOverride()); + statement.setString(7, blockData.getWorld().getName()); + statement.setInt(8, blockData.getX()); + statement.setInt(9, blockData.getY()); + statement.setInt(10, blockData.getZ()); + statement.executeUpdate(); + } + })); + } + + public void getBlockData(Consumer> callback) { + this.async(() -> this.databaseConnector.connect(connection -> { + String selectData = "SELECT * FROM " + this.getTablePrefix() + "blockdata"; + Map blockData = new HashMap<>(); + try (Statement statement = connection.createStatement()) { + ResultSet result = statement.executeQuery(selectData); + while (result.next()) { + KitType type = KitType.valueOf(result.getString("type")); + String kit = result.getString("kit"); + boolean holograms = result.getBoolean("holograms"); + boolean displayItems = result.getBoolean("displayItems"); + boolean particles = result.getBoolean("particles"); + boolean itemOverride = result.getBoolean("itemOverride"); + World world = Bukkit.getWorld(result.getString("world")); + int x = result.getInt("x"); + int y = result.getInt("y"); + int z = result.getInt("z"); + Location location = new Location(world, x, y, z); + + KitBlockData kitBlockData = + new KitBlockData(UltimateKits.getInstance().getKitManager().getKit(kit), + location, type, holograms, particles, displayItems, itemOverride); + blockData.put(location, kitBlockData); + } + } + + this.sync(() -> callback.accept(blockData)); + })); + } + + private int lastInsertedId(Connection connection) { + String query; + if (this.databaseConnector instanceof SQLiteConnector) { + query = "SELECT last_insert_rowid()"; + } else { + query = "SELECT LAST_INSERT_ID()"; + } + + try (Statement statement = connection.createStatement()) { + ResultSet result = statement.executeQuery(query); + result.next(); + return result.getInt(1); + } catch (SQLException e) { + e.printStackTrace(); + return -1; + } + } + + public void async(Runnable runnable) { + Bukkit.getScheduler().runTaskAsynchronously(this.plugin, runnable); + } + + public void sync(Runnable runnable) { + Bukkit.getScheduler().runTask(this.plugin, runnable); + } +} diff --git a/src/main/java/com/songoda/ultimatekits/database/DataMigration.java b/src/main/java/com/songoda/ultimatekits/database/DataMigration.java new file mode 100644 index 0000000..f0a9307 --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/DataMigration.java @@ -0,0 +1,19 @@ +package com.songoda.ultimatekits.database; + +import java.sql.Connection; +import java.sql.SQLException; + +public abstract class DataMigration { + + private final int revision; + + public DataMigration(int revision) { + this.revision = revision; + } + + public abstract void migrate(Connection connection, String tablePrefix) throws SQLException; + + public int getRevision() { + return this.revision; + } +} diff --git a/src/main/java/com/songoda/ultimatekits/database/DataMigrationManager.java b/src/main/java/com/songoda/ultimatekits/database/DataMigrationManager.java new file mode 100644 index 0000000..aa80b4b --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/DataMigrationManager.java @@ -0,0 +1,108 @@ +package com.songoda.ultimatekits.database; + +import com.songoda.ultimatekits.database.migrations._1_InitialMigration; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +public class DataMigrationManager { + + private List migrations; + private DatabaseConnector databaseConnector; + private DataManager dataManager; + + public DataMigrationManager(DatabaseConnector databaseConnector, DataManager dataManager) { + this.databaseConnector = databaseConnector; + this.dataManager = dataManager; + + this.migrations = Arrays.asList( + new _1_InitialMigration() + ); + } + + /** + * Runs any needed data migrations + */ + public void runMigrations() { + this.databaseConnector.connect((connection -> { + int currentMigration = -1; + boolean migrationsExist; + + String query; + if (this.databaseConnector instanceof SQLiteConnector) { + query = "SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?"; + } else { + query = "SHOW TABLES LIKE ?"; + } + + try (PreparedStatement statement = connection.prepareStatement(query)) { + statement.setString(1, this.getMigrationsTableName()); + migrationsExist = statement.executeQuery().next(); + } + + if (!migrationsExist) { + // No migration table exists, create one + String createTable = "CREATE TABLE " + this.getMigrationsTableName() + " (migration_version INT NOT NULL)"; + try (PreparedStatement statement = connection.prepareStatement(createTable)) { + statement.execute(); + } + + // Insert primary row into migration table + String insertRow = "INSERT INTO " + this.getMigrationsTableName() + " VALUES (?)"; + try (PreparedStatement statement = connection.prepareStatement(insertRow)) { + statement.setInt(1, -1); + statement.execute(); + } + } else { + // Grab the current migration version + String selectVersion = "SELECT migration_version FROM " + this.getMigrationsTableName(); + try (PreparedStatement statement = connection.prepareStatement(selectVersion)) { + ResultSet result = statement.executeQuery(); + result.next(); + currentMigration = result.getInt("migration_version"); + } + } + + // Grab required migrations + int finalCurrentMigration = currentMigration; + List requiredMigrations = this.migrations + .stream() + .filter(x -> x.getRevision() > finalCurrentMigration) + .sorted(Comparator.comparingInt(DataMigration::getRevision)) + .collect(Collectors.toList()); + + // Nothing to migrate, abort + if (requiredMigrations.isEmpty()) + return; + + // Migrate the data + for (DataMigration dataMigration : requiredMigrations) + dataMigration.migrate(connection, this.dataManager.getTablePrefix()); + + // Set the new current migration to be the highest migrated to + currentMigration = requiredMigrations + .stream() + .map(DataMigration::getRevision) + .max(Integer::compareTo) + .orElse(-1); + + String updateVersion = "UPDATE " + this.getMigrationsTableName() + " SET migration_version = ?"; + try (PreparedStatement statement = connection.prepareStatement(updateVersion)) { + statement.setInt(1, currentMigration); + statement.execute(); + } + })); + } + + /** + * @return the name of the migrations table + */ + private String getMigrationsTableName() { + return this.dataManager.getTablePrefix() + "migrations"; + } + +} diff --git a/src/main/java/com/songoda/ultimatekits/database/DatabaseConnector.java b/src/main/java/com/songoda/ultimatekits/database/DatabaseConnector.java new file mode 100644 index 0000000..5e50966 --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/DatabaseConnector.java @@ -0,0 +1,34 @@ +package com.songoda.ultimatekits.database; + +import java.sql.Connection; +import java.sql.SQLException; + +public interface DatabaseConnector { + + /** + * Checks if the connection to the database has been created + * + * @return true if the connection is created, otherwise false + */ + boolean isInitialized(); + + /** + * Closes all open connections to the database + */ + void closeConnection(); + + /** + * Executes a callback with a Connection passed and automatically closes it when finished + * + * @param callback The callback to execute once the connection is retrieved + */ + void connect(ConnectionCallback callback); + + /** + * Wraps a connection in a callback which will automagically handle catching sql errors + */ + interface ConnectionCallback { + void accept(Connection connection) throws SQLException; + } + +} diff --git a/src/main/java/com/songoda/ultimatekits/database/MySQLConnector.java b/src/main/java/com/songoda/ultimatekits/database/MySQLConnector.java new file mode 100644 index 0000000..cc46d5a --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/MySQLConnector.java @@ -0,0 +1,49 @@ +package com.songoda.ultimatekits.database; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.bukkit.plugin.Plugin; + +import java.sql.Connection; +import java.sql.SQLException; + +public class MySQLConnector implements DatabaseConnector { + + private final Plugin plugin; + private HikariDataSource hikari; + private boolean initializedSuccessfully; + + public MySQLConnector(Plugin plugin, String hostname, int port, String database, String username, String password, boolean useSSL) { + this.plugin = plugin; + HikariConfig config = new HikariConfig(); + + config.setJdbcUrl("jdbc:mysql://" + hostname + ":" + port + "/" + database + "?useSSL=" + useSSL); + config.setUsername(username); + config.setPassword(password); + config.setMaximumPoolSize(3); + + try { + this.hikari = new HikariDataSource(config); + this.initializedSuccessfully = true; + } catch (Exception ex) { + this.initializedSuccessfully = false; + } + } + + public boolean isInitialized() { + return this.initializedSuccessfully; + } + + public void closeConnection() { + this.hikari.close(); + } + + public void connect(ConnectionCallback callback) { + try (Connection connection = this.hikari.getConnection()) { + callback.accept(connection); + } catch (SQLException ex) { + this.plugin.getLogger().severe("An error occurred executing a MySQL query: " + ex.getMessage()); + ex.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/songoda/ultimatekits/database/SQLiteConnector.java b/src/main/java/com/songoda/ultimatekits/database/SQLiteConnector.java new file mode 100644 index 0000000..b9053f6 --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/SQLiteConnector.java @@ -0,0 +1,58 @@ +package com.songoda.ultimatekits.database; + +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class SQLiteConnector implements DatabaseConnector { + + private final Plugin plugin; + private final String connectionString; + private Connection connection; + + public SQLiteConnector(Plugin plugin) { + this.plugin = plugin; + this.connectionString = "jdbc:sqlite:" + plugin.getDataFolder() + File.separator + plugin.getDescription().getName().toLowerCase() + ".db"; + + try { + Class.forName("org.sqlite.JDBC"); // This is required to put here for Spigot 1.10 and below for some reason + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + public boolean isInitialized() { + return true; // Always available + } + + public void closeConnection() { + try { + if (this.connection != null) { + this.connection.close(); + } + } catch (SQLException ex) { + this.plugin.getLogger().severe("An error occurred closing the SQLite database connection: " + ex.getMessage()); + } + } + + public void connect(ConnectionCallback callback) { + if (this.connection == null) { + try { + this.connection = DriverManager.getConnection(this.connectionString); + } catch (SQLException ex) { + this.plugin.getLogger().severe("An error occurred retrieving the SQLite database connection: " + ex.getMessage()); + } + } + + try { + callback.accept(this.connection); + } catch (Exception ex) { + this.plugin.getLogger().severe("An error occurred executing an SQLite query: " + ex.getMessage()); + ex.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/songoda/ultimatekits/database/migrations/_1_InitialMigration.java b/src/main/java/com/songoda/ultimatekits/database/migrations/_1_InitialMigration.java new file mode 100644 index 0000000..2982a8e --- /dev/null +++ b/src/main/java/com/songoda/ultimatekits/database/migrations/_1_InitialMigration.java @@ -0,0 +1,38 @@ +package com.songoda.ultimatekits.database.migrations; + +import com.songoda.ultimatekits.UltimateKits; +import com.songoda.ultimatekits.database.DataMigration; +import com.songoda.ultimatekits.database.MySQLConnector; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +public class _1_InitialMigration extends DataMigration { + + public _1_InitialMigration() { + super(1); + } + + @Override + public void migrate(Connection connection, String tablePrefix) throws SQLException { + String autoIncrement = UltimateKits.getInstance().getDatabaseConnector() instanceof + MySQLConnector ? " AUTO_INCREMENT" : ""; + + // Create plugin settings table + try (Statement statement = connection.createStatement()) { + statement.execute("CREATE TABLE " + tablePrefix + "blockdata (" + + "type TEXT NOT NULL," + + "kit TEXT NOT NULL," + + "holograms BOOLEAN NOT NULL," + + "displayItems BOOLEAN NOT NULL," + + "particles BOOLEAN NOT NULL," + + "itemOverride BOOLEAN NOT NULL," + + "world TEXT NOT NULL," + + "x INTEGER NOT NULL," + + "y INTEGER NOT NULL," + + "z INTEGER NOT NULL " + + ")"); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/songoda/ultimatekits/kit/KitManager.java b/src/main/java/com/songoda/ultimatekits/kit/KitManager.java index 25dbb59..bad1c63 100644 --- a/src/main/java/com/songoda/ultimatekits/kit/KitManager.java +++ b/src/main/java/com/songoda/ultimatekits/kit/KitManager.java @@ -7,7 +7,7 @@ import java.util.*; public final class KitManager { - private final Map kitsAtLocations = new HashMap<>(); + private Map kitsAtLocations = new HashMap<>(); private List registeredKits = new LinkedList<>(); public boolean addKit(Kit kit) { @@ -30,13 +30,16 @@ public final class KitManager { } public void addKitToLocation(Kit kit, Location location) { - kitsAtLocations.put(roundLocation(location), new KitBlockData(kit, location)); + KitBlockData data = new KitBlockData(kit, location); + kitsAtLocations.put(roundLocation(location), data); + UltimateKits.getInstance().getDataManager().createBlockData(data); } public void addKitToLocation(Kit kit, Location location, KitType type, boolean hologram, boolean particles, boolean items, boolean itemOverride) { KitBlockData kitBlockData = kitsAtLocations.put(roundLocation(location), new KitBlockData(kit, location, type, hologram, particles, items, itemOverride)); if (UltimateKits.getInstance().getHologram() != null) UltimateKits.getInstance().getHologram().update(kitBlockData); + UltimateKits.getInstance().getDataManager().createBlockData(kitBlockData); } public Kit removeKitFromLocation(Location location) { @@ -47,6 +50,7 @@ public final class KitManager { kit.reset(); KitBlockData removed = kitsAtLocations.remove(roundLocation(location)); + UltimateKits.getInstance().getDataManager().deleteBlockData(removed); return (removed != null ? removed.getKit() : null); } @@ -68,6 +72,10 @@ public final class KitManager { return Collections.unmodifiableMap(kitsAtLocations); } + public void setKitLocations(Map kits) { + kitsAtLocations = kits; + } + public void clearKits() { this.registeredKits.clear(); this.kitsAtLocations.clear(); diff --git a/src/main/java/com/songoda/ultimatekits/utils/settings/Setting.java b/src/main/java/com/songoda/ultimatekits/utils/settings/Setting.java index bdb0d26..5dbcdbf 100644 --- a/src/main/java/com/songoda/ultimatekits/utils/settings/Setting.java +++ b/src/main/java/com/songoda/ultimatekits/utils/settings/Setting.java @@ -39,7 +39,15 @@ public enum Setting { LANGUGE_MODE("System.Language Mode", "en_US", "The enabled language file.", - "More language files (if available) can be found in the plugins data folder."); + "More language files (if available) can be found in the plugins data folder."), + + MYSQL_ENABLED("MySQL.Enabled", false, "Set to 'true' to use MySQL for data storage."), + MYSQL_HOSTNAME("MySQL.Hostname", "localhost"), + MYSQL_PORT("MySQL.Port", 3306), + MYSQL_DATABASE("MySQL.Database", "your-database"), + MYSQL_USERNAME("MySQL.Username", "user"), + MYSQL_PASSWORD("MySQL.Password", "pass"), + MYSQL_USE_SSL("MySQL.Use SSL", false); private String setting; private Object option; diff --git a/src/main/java/com/songoda/ultimatekits/utils/settings/SettingsManager.java b/src/main/java/com/songoda/ultimatekits/utils/settings/SettingsManager.java index 1df605b..c9529c2 100644 --- a/src/main/java/com/songoda/ultimatekits/utils/settings/SettingsManager.java +++ b/src/main/java/com/songoda/ultimatekits/utils/settings/SettingsManager.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -35,6 +36,7 @@ public class SettingsManager implements Listener { @EventHandler public void onInventoryClick(InventoryClickEvent event) { + if (event.getView().getType() != InventoryType.CHEST) return; ItemStack clickedItem = event.getCurrentItem(); if (event.getInventory() != event.getWhoClicked().getOpenInventory().getTopInventory()