public class ShopCommand {

    private static boolean commandCreated = false;

    private final ShopChest plugin;
    private final String name;
    private final String fallbackPrefix;
    private final PluginCommand pluginCommand;
    private final ShopCommandExecutor executor;

    private final List<ShopSubCommand> subCommands = new ArrayList<>();

    public ShopCommand(final ShopChest plugin) {
        if (commandCreated) {
            IllegalStateException e = new IllegalStateException("Command has already been registered");
            plugin.debug(e);
            throw e;
        }

        this.plugin = plugin;
        this.name = Config.mainCommandName.toLowerCase(Locale.ENGLISH).trim();
        this.fallbackPrefix = plugin.getName().toLowerCase(Locale.ENGLISH).trim();
        this.pluginCommand = createPluginCommand();
        this.executor = new ShopCommandExecutor(plugin);

        ShopTabCompleter tabCompleter = new ShopTabCompleter(plugin);

        final Replacement cmdReplacement = new Replacement(Placeholder.COMMAND, name);

        addSubCommand(new ShopSubCommand("create", true, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                boolean receiveCreateMessage = sender.hasPermission(Permissions.CREATE);
                if (!receiveCreateMessage) {
                    for (PermissionAttachmentInfo permInfo : sender.getEffectivePermissions()) {
                        String perm = permInfo.getPermission();
                        if (perm.startsWith(Permissions.CREATE) && sender.hasPermission(perm)) {
                            receiveCreateMessage = true;
                            break;
                        }
                    }
                }

                if (sender.hasPermission(Permissions.CREATE_ADMIN)) {
                    return LanguageUtils.getMessage(Message.COMMAND_DESC_CREATE_ADMIN, cmdReplacement);
                } else if (receiveCreateMessage) {
                    return LanguageUtils.getMessage(Message.COMMAND_DESC_CREATE, cmdReplacement);
                }

                return "";
            }
        });

        addSubCommand(new ShopSubCommand("remove", true, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                return LanguageUtils.getMessage(Message.COMMAND_DESC_REMOVE, cmdReplacement);
            }
        });

        addSubCommand(new ShopSubCommand("info", true, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                return LanguageUtils.getMessage(Message.COMMAND_DESC_INFO, cmdReplacement);
            }
        });

        addSubCommand(new ShopSubCommand("limits", true, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                return LanguageUtils.getMessage(Message.COMMAND_DESC_LIMITS, cmdReplacement);
            }
        });

        addSubCommand(new ShopSubCommand("open", true, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                return LanguageUtils.getMessage(Message.COMMAND_DESC_OPEN, cmdReplacement);
            }
        });

        addSubCommand(new ShopSubCommand("removeall", false, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                if (sender.hasPermission(Permissions.REMOVE_OTHER)) {
                    return LanguageUtils.getMessage(Message.COMMAND_DESC_REMOVEALL, cmdReplacement);
                } else {
                    return "";
                }
            }
        });

        addSubCommand(new ShopSubCommand("reload", false, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                if (sender.hasPermission(Permissions.RELOAD)) {
                    return LanguageUtils.getMessage(Message.COMMAND_DESC_RELOAD, cmdReplacement);
                } else {
                    return "";
                }
            }
        });

        addSubCommand(new ShopSubCommand("update", false, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                if (sender.hasPermission(Permissions.UPDATE)) {
                    return LanguageUtils.getMessage(Message.COMMAND_DESC_UPDATE, cmdReplacement);
                } else {
                    return "";
                }
            }
        });

        addSubCommand(new ShopSubCommand("config", false, executor, tabCompleter) {
            @Override
            public String getHelpMessage(CommandSender sender) {
                if (sender.hasPermission(Permissions.CONFIG)) {
                    return LanguageUtils.getMessage(Message.COMMAND_DESC_CONFIG, cmdReplacement);
                } else {
                    return "";
                }
            }
        });

        register();
        commandCreated = true;
    }

    public PluginCommand getCommand() {
        return pluginCommand;
    }

    /**
     * Call the second part of the create method after the player
     * has selected an item from the creative inventory.
     */
    public void createShopAfterSelected(Player player, SelectClickType clickType) {
        executor.create2(player, clickType);
    }

    private PluginCommand createPluginCommand() {
        plugin.debug("Creating plugin command");
        try {
            Constructor<PluginCommand> c = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
            c.setAccessible(true);

            PluginCommand cmd = c.newInstance(name, plugin);
            cmd.setDescription("Manage players' shops or this plugin.");
            cmd.setUsage("/" + name);
            cmd.setExecutor(new ShopBaseCommandExecutor());
            cmd.setTabCompleter(new ShopBaseTabCompleter());

            return cmd;
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
            plugin.getLogger().severe("Failed to create command");
            plugin.debug("Failed to create plugin command");
            plugin.debug(e);
        }

        return null;
    }

    public void addSubCommand(ShopSubCommand subCommand) {
        plugin.debug("Adding sub command \"" + subCommand.getName() + "\"");
        this.subCommands.add(subCommand);
    }

    public List<ShopSubCommand> getSubCommands() {
        return new ArrayList<>(subCommands);
    }

    private void register() {
        if (pluginCommand == null) return;

        plugin.debug("Registering command " + name);

        try {
            Field fCommandMap = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
            fCommandMap.setAccessible(true);

            Object commandMapObject = fCommandMap.get(Bukkit.getPluginManager());
            if (commandMapObject instanceof CommandMap) {
                CommandMap commandMap = (CommandMap) commandMapObject;
                commandMap.register(fallbackPrefix, pluginCommand);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            plugin.getLogger().severe("Failed to register command");
            plugin.debug("Failed to register plugin command");
            plugin.debug(e);
        }
    }

    public void unregister() {
        if (pluginCommand == null) return;

        plugin.debug("Unregistering command " + name);

        try {
            Field fCommandMap = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
            fCommandMap.setAccessible(true);

            Object commandMapObject = fCommandMap.get(Bukkit.getPluginManager());
            if (commandMapObject instanceof CommandMap) {
                CommandMap commandMap = (CommandMap) commandMapObject;
                pluginCommand.unregister(commandMap);

                Field fKnownCommands = SimpleCommandMap.class.getDeclaredField("knownCommands");
                fKnownCommands.setAccessible(true);

                Object knownCommandsObject = fKnownCommands.get(commandMap);
                if (knownCommandsObject instanceof Map) {
                    Map<?, ?> knownCommands = (Map<?, ?>) knownCommandsObject;
                    knownCommands.remove(fallbackPrefix + ":" + name);
                    if (pluginCommand.equals(knownCommands.get(name))) {
                        knownCommands.remove(name);
                    }
                }
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            plugin.getLogger().severe("Failed to unregister command");
            plugin.debug("Failed to unregister plugin command");
            plugin.debug(e);
        }
    }

    /**
     * Sends the basic help message
     *
     * @param sender {@link CommandSender} who will receive the message
     */
    private void sendBasicHelpMessage(CommandSender sender) {
        plugin.debug("Sending basic help message to " + sender.getName());

        sender.sendMessage(" ");
        String header = LanguageUtils.getMessage(Message.COMMAND_DESC_HEADER,
                new Replacement(Placeholder.COMMAND, Config.mainCommandName));

        if (!header.trim().isEmpty()) sender.sendMessage(header);

        for (ShopSubCommand subCommand : subCommands) {
            String msg = subCommand.getHelpMessage(sender);
            if (msg == null || msg.isEmpty()) {
                continue;
            }

            sender.sendMessage(msg);
        }

        String footer = LanguageUtils.getMessage(Message.COMMAND_DESC_FOOTER,
                new Replacement(Placeholder.COMMAND,Config.mainCommandName));

        if (!footer.trim().isEmpty()) sender.sendMessage(footer);
        sender.sendMessage(" ");
    }

    private class ShopBaseCommandExecutor implements CommandExecutor {

        @Override
        public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
            if (args.length > 0) {
                for (ShopSubCommand subCommand : subCommands) {
                    if (subCommand.getName().equalsIgnoreCase(args[0])) {
                        if (!(sender instanceof Player) && subCommand.isPlayerCommand()) {
                            sender.sendMessage(ChatColor.RED + "Only players can use this command.");
                            return true;
                        }

                        if (!subCommand.execute(sender, command, label, args)) {
                            sendBasicHelpMessage(sender);
                        }

                        return true;
                    }
                }

                sendBasicHelpMessage(sender);
            } else {
                sendBasicHelpMessage(sender);
            }

            return true;
        }
    }

    private class ShopBaseTabCompleter implements TabCompleter {

        @Override
        public List<String> onTabComplete(CommandSender sender, Command command, String label, String[] args) {
            List<String> subCommandNames = new ArrayList<>();

            List<String> tabCompletions = new ArrayList<>();

            for (ShopSubCommand subCommand : subCommands) {
                subCommandNames.add(subCommand.getName());
            }

            if (args.length == 1) {
                if (!args[0].isEmpty()) {
                    for (String s : subCommandNames) {
                        if (s.startsWith(args[0])) {
                            tabCompletions.add(s);
                        }
                    }
                    return tabCompletions;
                } else {
                    return subCommandNames;
                }
            } else if (args.length > 1) {
                for (ShopSubCommand subCmd : subCommands) {
                    if (subCmd.getName().equalsIgnoreCase(args[0])) {
                        return subCmd.getTabCompletions(sender, command, label, args);
                    }
                }
            }

            return new ArrayList<>();
        }

    }

} public class Config {

    /**
     * The item with which a player can click a shop to retrieve information
     **/
    public static ItemStack shopInfoItem;

    /**
     * The default value for the custom WorldGuard flag 'create-shop'
     **/
    public static boolean wgAllowCreateShopDefault;

    /**
     * The default value for the custom WorldGuard flag 'use-admin-shop'
     **/
    public static boolean wgAllowUseAdminShopDefault;

    /**
     * The default value for the custom WorldGuard flag 'use-shop'
     **/
    public static boolean wgAllowUseShopDefault;

    /**
     * The types of town plots residents are allowed to create shops in
     **/
    public static List<String> townyShopPlotsResidents;

    /**
     * The types of town plots the mayor is allowed to create shops in
     **/
    public static List<String> townyShopPlotsMayor;

    /**
     * The types of town plots the king is allowed to create shops in
     **/
    public static List<String> townyShopPlotsKing;

    /**
     * The events of AreaShop when shops in that region should be removed
     **/
    public static List<String> areashopRemoveShopEvents;

    /**
     * The hostname used in ShopChest's MySQL database
     **/
    public static String databaseMySqlHost;

    /**
     * The port used for ShopChest's MySQL database
     **/
    public static int databaseMySqlPort;

    /**
     * The database used for ShopChest's MySQL database
     **/
    public static String databaseMySqlDatabase;

    /**
     * The username used in ShopChest's MySQL database
     **/
    public static String databaseMySqlUsername;

    /**
     * The password used in ShopChest's MySQL database
     **/
    public static String databaseMySqlPassword;

    /**
     * The prefix to be used for database tables
     */
    public static String databaseTablePrefix;

    /**
     * The database type used for ShopChest
     **/
    public static Database.DatabaseType databaseType;

    /**
     * The interval in seconds, a ping is sent to the MySQL server
     **/
    public static int databaseMySqlPingInterval;

    /**
     * <p>The minimum prices for certain items</p>
     * This returns a key set, which contains e.g "STONE", "STONE:1", of the <i>minimum-prices</i> section in ShopChest's config.
     * To actually retrieve the minimum price for an item, you have to get the double {@code minimum-prices.<key>}.
     **/
    public static Set<String> minimumPrices;

    /**
     * <p>The maximum prices for certain items</p>
     * This returns a key set, which contains e.g "STONE", "STONE:1", of the {@code maximum-prices} section in ShopChest's config.
     * To actually retrieve the maximum price for an item, you have to get the double {@code maximum-prices.<key>}.
     **/
    public static Set<String> maximumPrices;

    /**
     * <p>List containing items, of which players can't create a shop</p>
     * If this list contains an item (e.g "STONE", "STONE:1"), it's in the blacklist.
     **/
    public static List<String> blacklist;

    /**
     * Whether prices may contain decimals
     **/
    public static boolean allowDecimalsInPrice;

    /**
     * Whether the buy price of a shop must be greater than or equal the sell price
     **/
    public static boolean buyGreaterOrEqualSell;

    /**
     * Whether buys and sells must be confirmed
     **/
    public static boolean confirmShopping;

    /**
     * Whether the shop creation price should be refunded at removal.
     */
    public static boolean refundShopCreation;

    /**
     * <p>Whether the update checker should run on start and notify players on join.</p>
     * The command is not affected by this setting and will continue to check for updates.
     **/
    public static boolean enableUpdateChecker;

    /**
     * Whether the debug log file should be created
     **/
    public static boolean enableDebugLog;

    /**
     * Whether buys and sells should be logged in the database
     **/
    public static boolean enableEconomyLog;

    /**
     * Whether WorldGuard integration should be enabled
     **/
    public static boolean enableWorldGuardIntegration;

    /**
     * <p>Sets the time limit for cleaning up the economy log in days</p>
     * 
     * If this equals to {@code 0}, the economy log will not be cleaned.
     **/
    public static int cleanupEconomyLogDays;

    /**
     * Whether Towny integration should be enabled
     **/
    public static boolean enableTownyIntegration;

    /**
     * Whether AuthMe integration should be enabled
     **/
    public static boolean enableAuthMeIntegration;

    /**
     * Whether PlotSquared integration should be enabled
     **/
    public static boolean enablePlotsquaredIntegration;

    /**
     * Whether uSkyBlock integration should be enabled
     **/
    public static boolean enableUSkyblockIntegration;

    /**
     * Whether ASkyBlock integration should be enabled
     **/
    public static boolean enableASkyblockIntegration;

    /**
     * Whether BentoBox integration should be enabled
     **/
    public static boolean enableBentoBoxIntegration;

    /**
     * Whether IslandWorld integration should be enabled
     **/
    public static boolean enableIslandWorldIntegration;

    /**
     * Whether GriefPrevention integration should be enabled
     **/
    public static boolean enableGriefPreventionIntegration;

    /**
     * Whether AreaShop integration should be enabled
     **/
    public static boolean enableAreaShopIntegration;

    /**
     * Whether the vendor of the shop should get messages about buys and sells
     **/
    public static boolean enableVendorMessages;

    /**
     * Whether the vendor of the shop should get messages on all servers about buys and sells
     **/
    public static boolean enableVendorBungeeMessages;

    /**
     * Whether the extension of a potion or tipped arrow (if available) should be appended to the item name.
     **/
    public static boolean appendPotionLevelToItemName;

    /**
     * Whether players are allowed to sell/buy broken items
     **/
    public static boolean allowBrokenItems;

    /**
     * Whether only the shop a player is pointing at should be shown
     **/
    public static boolean onlyShowShopsInSight;

    /**
     * <p>Whether shops should automatically be removed from the database if an error occurred while loading</p>
     * (e.g. when no chest is found at a shop's location)
     */
    public static boolean removeShopOnError;

    /**
     * Whether the item amount should be calculated to fit the available money or inventory space
     **/
    public static boolean autoCalculateItemAmount;

    /**
     * Whether players should be able to select an item from the creative inventory
     */
    public static boolean creativeSelectItem;

    /**
     * <p>Whether the mouse buttons are inverted</p>
     * <b>Default:</b><br>
     * Right-Click: Buy<br>
     * Left-Click: Sell
     **/
    public static boolean invertMouseButtons;

    /**
     * Whether the hologram's location should be fixed at the bottom
     **/
    public static boolean hologramFixedBottom;

    /**
     * Amount every hologram should be lifted
     **/
    public static double hologramLift;

    /**
     * The maximum distance between a player and a shop to see the hologram
     **/
    public static double maximalDistance;

    /**
     * The maximum distance between a player and a shop to see the shop item
     **/
    public static double maximalItemDistance;

    /**
     * The price a player has to pay in order to create a normal shop
     **/
    public static double shopCreationPriceNormal;

    /**
     * The price a player has to pay in order to create an admin shop
     **/
    public static double shopCreationPriceAdmin;

    /**
     * The default shop limit for players whose limit is not set via a permission
     **/
    public static int defaultLimit;

    /**
     * The main command of ShopChest <i>(default: shop)</i>
     **/
    public static String mainCommandName;

    /**
     * The language file to use (e.g <i>en_US</i>, <i>de_DE</i>)
     **/
    public static String languageFile;

    /**
     * The language configuration of the currently selected language file
     */
    public static LanguageConfiguration langConfig;

    private ShopChest plugin;

    public Config(ShopChest plugin) {
        this.plugin = plugin;

        plugin.saveDefaultConfig();

        reload(true, true, true);
    }

    /**
     * <p>Set a configuration value</p>
     * <i>Config is automatically reloaded</i>
     *
     * @param property Property to change
     * @param value    Value to set
     */
    public void set(String property, String value) {
        boolean langChange = (property.equalsIgnoreCase("language-file"));
        try {
            int intValue = Integer.parseInt(value);
            plugin.getConfig().set(property, intValue);

            plugin.saveConfig();
            reload(false, langChange, false);

            return;
        } catch (NumberFormatException e) { /* Value not an integer */ }

        try {
            double doubleValue = Double.parseDouble(value);
            plugin.getConfig().set(property, doubleValue);

            plugin.saveConfig();
            reload(false, langChange, false);

            return;
        } catch (NumberFormatException e) { /* Value not a double */ }

        if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
            boolean boolValue = Boolean.parseBoolean(value);
            plugin.getConfig().set(property, boolValue);
        } else {
            plugin.getConfig().set(property, value);
        }

        plugin.saveConfig();

        reload(false, langChange, false);
    }

    /**
     * Add a value to a list in the config.yml.
     * If the list does not exist, a new list with the given value will be created
     *
     * @param property Location of the list
     * @param value    Value to add
     */
    public void add(String property, String value) {
        List list = (plugin.getConfig().getList(property) == null) ? new ArrayList<>() : plugin.getConfig().getList(property);

        try {
            int intValue = Integer.parseInt(value);
            list.add(intValue);

            plugin.saveConfig();
            reload(false, false, false);

            return;
        } catch (NumberFormatException e) { /* Value not an integer */ }

        try {
            double doubleValue = Double.parseDouble(value);
            list.add(doubleValue);

            plugin.saveConfig();
            reload(false, false, false);

            return;
        } catch (NumberFormatException e) { /* Value not a double */ }

        if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
            boolean boolValue = Boolean.parseBoolean(value);
            list.add(boolValue);
        } else {
            list.add(value);
        }

        plugin.saveConfig();

        reload(false, false, false);
    }

    public void remove(String property, String value) {
        List list = (plugin.getConfig().getList(property) == null) ? new ArrayList<>() : plugin.getConfig().getList(property);

        try {
            int intValue = Integer.parseInt(value);
            list.remove(intValue);

            plugin.saveConfig();
            reload(false, false, false);

            return;
        } catch (NumberFormatException e) { /* Value not an integer */ }

        try {
            double doubleValue = Double.parseDouble(value);
            list.remove(doubleValue);

            plugin.saveConfig();
            reload(false, false, false);

            return;
        } catch (NumberFormatException e) { /* Value not a double */ }

        if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) {
            boolean boolValue = Boolean.parseBoolean(value);
            list.remove(boolValue);
        } else {
            list.remove(value);
        }

        plugin.saveConfig();

        reload(false, false, false);
    }

    /**
     * Reload the configuration values from config.yml
     * @param firstLoad Whether the config values have not been loaded before
     * @param langReload Whether the language configuration should be reloaded
     * @param showMessages Whether console (error) messages should be shown
     */
    public void reload(boolean firstLoad, boolean langReload, boolean showMessages) {
        plugin.reloadConfig();

        shopInfoItem = ItemUtils.getItemStack(plugin.getConfig().getString("shop-info-item"));
        wgAllowCreateShopDefault = plugin.getConfig().getBoolean("worldguard-default-flag-values.create-shop");
        wgAllowUseAdminShopDefault = plugin.getConfig().getBoolean("worldguard-default-flag-values.use-admin-shop");
        wgAllowUseShopDefault = plugin.getConfig().getBoolean("worldguard-default-flag-values.use-shop");
        townyShopPlotsResidents = plugin.getConfig().getStringList("towny-shop-plots.residents");
        townyShopPlotsMayor = plugin.getConfig().getStringList("towny-shop-plots.mayor");
        townyShopPlotsKing = plugin.getConfig().getStringList("towny-shop-plots.king");
        areashopRemoveShopEvents = plugin.getConfig().getStringList("areashop-remove-shops");
        databaseMySqlPingInterval = plugin.getConfig().getInt("database.mysql.ping-interval");
        databaseMySqlHost = plugin.getConfig().getString("database.mysql.hostname");
        databaseMySqlPort = plugin.getConfig().getInt("database.mysql.port");
        databaseMySqlDatabase = plugin.getConfig().getString("database.mysql.database");
        databaseMySqlUsername = plugin.getConfig().getString("database.mysql.username");
        databaseMySqlPassword = plugin.getConfig().getString("database.mysql.password");
        databaseTablePrefix = plugin.getConfig().getString("database.table-prefix");
        databaseType = Database.DatabaseType.valueOf(plugin.getConfig().getString("database.type"));
        minimumPrices = (plugin.getConfig().getConfigurationSection("minimum-prices") == null) ? new HashSet<String>() : plugin.getConfig().getConfigurationSection("minimum-prices").getKeys(true);
        maximumPrices = (plugin.getConfig().getConfigurationSection("maximum-prices") == null) ? new HashSet<String>() : plugin.getConfig().getConfigurationSection("maximum-prices").getKeys(true);
        allowDecimalsInPrice = plugin.getConfig().getBoolean("allow-decimals-in-price");
        allowBrokenItems = plugin.getConfig().getBoolean("allow-broken-items");
        autoCalculateItemAmount = (allowDecimalsInPrice && plugin.getConfig().getBoolean("auto-calculate-item-amount"));
        creativeSelectItem = plugin.getConfig().getBoolean("creative-select-item");
        blacklist = (plugin.getConfig().getStringList("blacklist") == null) ? new ArrayList<String>() : plugin.getConfig().getStringList("blacklist");
        buyGreaterOrEqualSell = plugin.getConfig().getBoolean("buy-greater-or-equal-sell");
        confirmShopping = plugin.getConfig().getBoolean("confirm-shopping");
        refundShopCreation = plugin.getConfig().getBoolean("refund-shop-creation");
        enableUpdateChecker = plugin.getConfig().getBoolean("enable-update-checker");
        enableDebugLog = plugin.getConfig().getBoolean("enable-debug-log");
        enableEconomyLog = plugin.getConfig().getBoolean("enable-economy-log");
        cleanupEconomyLogDays = plugin.getConfig().getInt("cleanup-economy-log-days");
        enableWorldGuardIntegration = plugin.getConfig().getBoolean("enable-worldguard-integration");
        enableTownyIntegration = plugin.getConfig().getBoolean("enable-towny-integration");
        enableAuthMeIntegration = plugin.getConfig().getBoolean("enable-authme-integration");
        enablePlotsquaredIntegration = plugin.getConfig().getBoolean("enable-plotsquared-integration");
        enableUSkyblockIntegration = plugin.getConfig().getBoolean("enable-uskyblock-integration");
        enableASkyblockIntegration = plugin.getConfig().getBoolean("enable-askyblock-integration");
        enableBentoBoxIntegration = plugin.getConfig().getBoolean("enable-bentobox-integration");
        enableIslandWorldIntegration = plugin.getConfig().getBoolean("enable-islandworld-integration");
        enableGriefPreventionIntegration = plugin.getConfig().getBoolean("enable-griefprevention-integration");
        enableAreaShopIntegration = plugin.getConfig().getBoolean("enable-areashop-integration");
        enableVendorMessages = plugin.getConfig().getBoolean("enable-vendor-messages");
        enableVendorBungeeMessages = plugin.getConfig().getBoolean("enable-vendor-bungee-messages");
        onlyShowShopsInSight = plugin.getConfig().getBoolean("only-show-shops-in-sight");
        appendPotionLevelToItemName = plugin.getConfig().getBoolean("append-potion-level-to-item-name");
        removeShopOnError = plugin.getConfig().getBoolean("remove-shop-on-error");
        invertMouseButtons = plugin.getConfig().getBoolean("invert-mouse-buttons");
        hologramFixedBottom = plugin.getConfig().getBoolean("hologram-fixed-bottom");
        hologramLift = plugin.getConfig().getDouble("hologram-lift");
        maximalDistance = plugin.getConfig().getDouble("maximal-distance");
        maximalItemDistance = plugin.getConfig().getDouble("maximal-item-distance");
        shopCreationPriceNormal = plugin.getConfig().getDouble("shop-creation-price.normal");
        shopCreationPriceAdmin = plugin.getConfig().getDouble("shop-creation-price.admin");
        defaultLimit = plugin.getConfig().getInt("shop-limits.default");
        mainCommandName = plugin.getConfig().getString("main-command-name");
        languageFile = plugin.getConfig().getString("language-file");

        if (firstLoad || langReload) loadLanguageConfig(showMessages);
        if (!firstLoad && langReload) LanguageUtils.load();
    }

    /**
     * @return ShopChest's {@link LanguageConfiguration}
     */
    public LanguageConfiguration getLanguageConfig() {
        return langConfig;
    }

    private Reader getTextResource(String file, boolean showMessages) {
        try {
            return (Reader) plugin.getClass().getDeclaredMethod("getTextResource", String.class).invoke(plugin, file);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            if (showMessages) plugin.getLogger().severe("Failed to get file from jar: " + file);
            plugin.debug("Failed to get file from jar: " + file);
            plugin.debug(e);
        }

        return null;
    }

    private void loadLanguageConfig(boolean showMessages) {
        langConfig = new LanguageConfiguration(plugin, showMessages);
        File langFolder = new File(plugin.getDataFolder(), "lang");

        String legacy = Utils.getMajorVersion() < 13 ? "-legacy" : "";

        if (!(new File(langFolder, "en_US" + legacy + ".lang")).exists())
            plugin.saveResource("lang/en_US" + legacy + ".lang", false);
    
        if (!(new File(langFolder, "de_DE" + legacy + ".lang")).exists())
            plugin.saveResource("lang/de_DE" + legacy + ".lang", false);

        File langConfigFile = new File(langFolder, languageFile + legacy + ".lang");
        File langDefaultFile = new File(langFolder, "en_US" + legacy + ".lang");

        if (!langConfigFile.exists()) {
            if (!langDefaultFile.exists()) {
                try {
                    Reader r = getTextResource("lang/" + langConfigFile.getName(), showMessages);

                    if (r == null) {
                        r = getTextResource("lang/en_US" + legacy + ".lang", showMessages);
                        if (showMessages) plugin.getLogger().info("Using locale \"en_US" + legacy + "\" (Streamed from jar file)");
                    } else {
                        if (showMessages)
                            plugin.getLogger().info("Using locale \"" + langConfigFile.getName().substring(0, langConfigFile.getName().length() - 5) + "\" (Streamed from jar file)");
                    }

                    if (r == null) {
                        if (showMessages) plugin.getLogger().warning("Using default language values");
                        plugin.debug("Using default language values (#1)");
                    }

                    BufferedReader br = new BufferedReader(r);

                    StringBuilder sb = new StringBuilder();
                    String line = br.readLine();

                    while (line != null) {
                        sb.append(line);
                        sb.append("\n");
                        line = br.readLine();
                    }

                    langConfig.loadFromString(sb.toString());
                } catch (IOException | InvalidConfigurationException e) {
                    if (showMessages) {
                        plugin.getLogger().warning("Using default language values");
                    }

                    plugin.debug("Using default language values (#2)");
                    plugin.debug(e);
                }
            } else {
                try {
                    langConfig.load(langDefaultFile);
                    if (showMessages) plugin.getLogger().info("Using locale \"en_US" + legacy + "\"");
                } catch (IOException | InvalidConfigurationException e) {
                    if (showMessages) {
                        plugin.getLogger().warning("Using default language values");
                    }

                    plugin.debug("Using default language values (#3)");
                    plugin.debug(e);
                }
            }
        } else {
            try {
                if (showMessages)
                    plugin.getLogger().info("Using locale \"" + langConfigFile.getName().substring(0, langConfigFile.getName().length() - 5) + "\"");
                langConfig.load(langConfigFile);
            } catch (IOException | InvalidConfigurationException e) {
                if (showMessages) {
                    plugin.getLogger().warning("Using default language values");
                }

                plugin.debug("Using default language values (#4)");
                plugin.debug(e);
            }
        }
    }

} public class HologramFormat {

    public enum Requirement {
        VENDOR, AMOUNT, ITEM_TYPE, ITEM_NAME, HAS_ENCHANTMENT, BUY_PRICE,
        SELL_PRICE, HAS_POTION_EFFECT, IS_MUSIC_DISC, IS_POTION_EXTENDED, IS_BANNER_PATTERN,
        IS_WRITTEN_BOOK, ADMIN_SHOP, NORMAL_SHOP, IN_STOCK, MAX_STACK, CHEST_SPACE, DURABILITY
    }

    // no "-" sign since no variable can be negative
    // e.g.: 100.0 >= 50.0
    private static final Pattern SIMPLE_NUMERIC_CONDITION = Pattern.compile("^(\\d+(?:\\.\\d+)?) ([<>][=]?|[=!]=) (\\d+(?:\\.\\d+)?)$");

    // e.g.: "STONE" == "DIAMOND_SWORD"
    private static final Pattern SIMPLE_STRING_CONDITION = Pattern.compile("^\"([^\"]*)\" ([=!]=) \"([^\"]*)\"$");

    private ScriptEngineManager manager = new ScriptEngineManager();
    private ScriptEngine engine = manager.getEngineByName("JavaScript");

    private ShopChest plugin;
    private File configFile;
    private YamlConfiguration config;

    public HologramFormat(ShopChest plugin) {
        this.configFile = new File(plugin.getDataFolder(), "hologram-format.yml");
        this.config = YamlConfiguration.loadConfiguration(configFile);
        this.plugin = plugin;
    }

    /**
     * Get the format for the given line of the hologram
     * @param line Line of the hologram
     * @param reqMap Values of the requirements that might be needed by the format (contains {@code null} if not comparable)
     * @param plaMap Values of the placeholders that might be needed by the format
     * @return  The format of the first working option, or an empty String if no option is working
     *          because of not fulfilled requirements
     */
    public String getFormat(int line, Map<Requirement, Object> reqMap, Map<Placeholder, Object> plaMap) {
        ConfigurationSection options = config.getConfigurationSection("lines." + line + ".options");

        optionLoop:
        for (String key : options.getKeys(false)) {
            ConfigurationSection option = options.getConfigurationSection(key);
            List<String> requirements = option.getStringList("requirements");

            String format = option.getString("format");

            for (String sReq : requirements) {
                for (Requirement req : reqMap.keySet()) {
                    if (sReq.contains(req.toString())) {
                        if (!evalRequirement(sReq, reqMap)) {
                            continue optionLoop;
                        }
                    }
                }
            }

            return evalPlaceholder(format, plaMap);
        }

        return "";
    }

    public void reload() {
        config = YamlConfiguration.loadConfiguration(configFile);
    }

    /**
     * @return Whether the hologram text has to change dynamically without reloading
     */
    public boolean isDynamic() {
        int count = getLineCount();
        for (int i = 0; i < count; i++) {
            ConfigurationSection options = config.getConfigurationSection("lines." + i + ".options");

            for (String key : options.getKeys(false)) {
                ConfigurationSection option = options.getConfigurationSection(key);

                String format = option.getString("format");
                if (format.contains(Placeholder.STOCK.toString()) || format.contains(Placeholder.CHEST_SPACE.toString())) {
                    return true;
                }

                for (String req : option.getStringList("requirements")) {
                    if (req.contains(Requirement.IN_STOCK.toString()) || req.contains(Requirement.CHEST_SPACE.toString())) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * @return Amount of lines in a hologram
     */
    public int getLineCount() {
        return config.getConfigurationSection("lines").getKeys(false).size();
    }

    /** 
     * @return Configuration of the "hologram-format.yml" file
     */
    public YamlConfiguration getConfig() {
        return config;
    }

    /**
     * Parse and evaluate a condition
     * @param condition Condition to evaluate
     * @param values Values of the requirements
     * @return Result of the condition
     */
    public boolean evalRequirement(String condition, Map<Requirement, Object> values) {
        String cond = condition;

        for (HologramFormat.Requirement req : HologramFormat.Requirement.values()) {
            if (cond.contains(req.toString()) && values.containsKey(req)) {
                Object val = values.get(req);
                String sVal = String.valueOf(val);

                if (val instanceof String && !(sVal.startsWith("\"") && sVal.endsWith("\""))) {
                    sVal = String.format("\"%s\"", sVal);
                }

                cond = cond.replace(req.toString(), sVal);
            }
        }

        if (cond.equals("true")) {
            // e.g.: ADMIN_SHOP
            return true;
        } else if (cond.equals("false")) {
            return false;
        } else {
            char firstChar = cond.charAt(0);

            // numeric cond: first char must be a digit (no variable can be negative)
            if (firstChar >= '0' && firstChar <= '9') {
                Matcher matcher = SIMPLE_NUMERIC_CONDITION.matcher(cond);

                if (matcher.find()) {
                    Double a, b;
                    Operator operator;
                    try {
                        a = Double.valueOf(matcher.group(1));
                        operator = Operator.from(matcher.group(2));
                        b = Double.valueOf(matcher.group(3));

                        return operator.compare(a, b);
                    } catch (IllegalArgumentException ignored) {
                        // should not happen, since regex checked that there is valid number and valid operator
                    }
                }
            }

            // string cond: first char must be a: "
            if (firstChar == '"') {
                Matcher matcher = SIMPLE_STRING_CONDITION.matcher(cond);

                if (matcher.find()) {
                    String a, b;
                    Operator operator;
                    try {
                        a = matcher.group(1);
                        operator = Operator.from(matcher.group(2));
                        b = matcher.group(3);

                        return operator.compare(a, b);
                    } catch (IllegalArgumentException | UnsupportedOperationException ignored) {
                        // should not happen, since regex checked that there is valid operator
                    }
                }
            }

            // complex comparison
            try {
                return (boolean) engine.eval(cond);
            } catch (ScriptException e) {
                plugin.debug("Failed to eval condition: " + condition);
                plugin.debug(e);
                return false;
            }
        }
    }

    /**
     * Parse and evaluate a condition
     * @param string Message or hologram format whose containing scripts to execute
     * @param values Values of the placeholders
     * @return Result of the condition
     */
    public String evalPlaceholder(String string, Map<Placeholder, Object> values) {
        try {
            Matcher matcher = Pattern.compile("\\{([^}]+)}").matcher(string);
            String newString = string;

            while (matcher.find()) {
                String withBrackets = matcher.group();
                String script = withBrackets.substring(1, withBrackets.length() - 1);

                for (Placeholder placeholder : values.keySet()) {
                    if (script.contains(placeholder.toString())) {
                        Object val = values.get(placeholder);
                        String sVal = String.valueOf(val);

                        if (val instanceof String && !(sVal.startsWith("\"") && sVal.endsWith("\""))) {
                            sVal = String.format("\"%s\"", sVal);
                        }

                        script = script.replace(placeholder.toString(), sVal);
                    }
                }

                String result = String.valueOf(engine.eval(script));
                newString = newString.replace(withBrackets, result);
            }

            return newString;
        } catch (ScriptException e) {
            plugin.debug("Failed to eval placeholder script in string: " + string);
            plugin.debug(e);
        }

        return string;
    }
} @Deprecated
public class ShopInitializedEvent extends Event {

    private static final HandlerList handlers = new HandlerList();
    private int amount;

    public ShopInitializedEvent(int amount) {
        this.amount = amount;
    }

    public int getAmount() {
        return amount;
    }

    public static HandlerList getHandlerList() {
        return handlers;
    }

    @Override
    public HandlerList getHandlers() {
        return handlers;
    }
} public class BentoBoxShopFlag {
    public static final Flag SHOP_FLAG = new Flag.Builder("CREATE_SHOPS", Material.CHEST)
            .type(Flag.Type.PROTECTION)
            .mode(Flag.Mode.BASIC)
            .defaultRank(RanksManager.TRUSTED_RANK)
            .build();

    public static void register(ShopChest plugin) {
        if (BentoBox.getInstance().getFlagsManager().registerFlag(SHOP_FLAG)) {
            plugin.debug("Registered BentoBox shop flag");
        } else {
            plugin.getLogger().warning("Failed to register BentoBox shop flag");
            plugin.debug("Failed to register BentoBox shop flag");
        }
    }
} public class PlotSquaredOldShopFlag {
    public enum Group {
        OWNERS, MEMBERS, TRUSTED, EVERYONE, NONE
    }

    public static final GroupFlag CREATE_SHOP = new GroupFlag("create-shop");
    public static final GroupFlag USE_SHOP = new GroupFlag("use-shop");
    public static final GroupFlag USE_ADMIN_SHOP = new GroupFlag("use-admin-shop");

    private static boolean registered = false;

    public static void register(ShopChest plugin) {
        if (registered) return;

        Flags.registerFlag(CREATE_SHOP);
        Flags.registerFlag(USE_SHOP);
        Flags.registerFlag(USE_ADMIN_SHOP);
        registered = true;

        plugin.debug("Registered custom PlotSquared flags");
    }

    /**
     * Check if a flag is allowed for a player on a plot from PlotSquared
     * @param plot Plot from PlotSquared
     * @param flag Flag to check
     * @param p Player to check
     * @return Whether the flag is allowed for the player
     */
    public static boolean isFlagAllowedOnPlot(Plot plot, GroupFlag flag, Player p) {
        if (plot != null && flag != null) {
            Group group = plot.getFlag(flag, Group.NONE);
            ShopChest.getInstance().debug("Flag " + flag.getName() + " is set to " + group);

            switch (group) {
                case OWNERS:
                    return plot.getOwners().contains(p.getUniqueId());
                case TRUSTED:
                    return plot.getOwners().contains(p.getUniqueId()) || plot.getTrusted().contains(p.getUniqueId());
                case MEMBERS:
                    return plot.getOwners().contains(p.getUniqueId()) || plot.getTrusted().contains(p.getUniqueId()) || plot.getMembers().contains(p.getUniqueId());
                case EVERYONE:
                    return true;
                case NONE:
                    return false;
            }
        }

        ShopChest.getInstance().debug("Flag or plot is null, or value of flag is not a group");

        return true;
    }

    public static class GroupFlag extends Flag<Group> {
        public GroupFlag(String name) {
            super(name);
        }

        @Override
        public String valueToString(Object value) {
            return String.valueOf(value);
        }

        @Override
        public Group parseValue(String s) {
            String val = s.toLowerCase(Locale.ENGLISH);

            switch (val) {
                case "owners":
                case "owner":
                    return Group.OWNERS;
                case "members":
                case "member":
                case "helpers":
                case "helper":
                    return Group.MEMBERS;
                case "trusted":
                    return Group.TRUSTED;
                case "everyone":
                case "all":
                    return Group.EVERYONE;
                case "deny":
                case "disallow":
                case "false":
                case "no":
                case "0":
                case "none":
                case "noone":
                    return Group.NONE;
            }

            return null;
        }

        @Override
        public String getValueDescription() {
            return "Flag value must be a group: 'owner' , 'members', 'trusted', 'everyone' or 'none'";
        }
    }
} public class PlotSquaredShopFlag {
    public enum Group {
        OWNERS, MEMBERS, TRUSTED, EVERYONE, NONE
    }

    private static final String[] lowercaseValues = Arrays.asList(Group.values()).stream()
            .map(value -> String.valueOf(value).toLowerCase(Locale.ENGLISH))
            .toArray(String[]::new);

    public static final GroupFlag<?> CREATE_SHOP = new CreateShopFlag(Group.MEMBERS);
    public static final GroupFlag<?> USE_SHOP = new UseShopFlag(Group.EVERYONE);

    private static boolean registered = false;

    public static void register(ShopChest plugin) {
        if (registered) return;

        GlobalFlagContainer.getInstance().addFlag(CREATE_SHOP);
        GlobalFlagContainer.getInstance().addFlag(USE_SHOP);
        registered = true;

        plugin.debug("Registered custom PlotSquared flags");
    }

    /**
     * Check if a flag is allowed for a player on a plot from PlotSquared
     * 
     * @param plot Plot from PlotSquared
     * @param flag Flag to check
     * @param p Player to check
     * @return Whether the flag is allowed for the player
     */
    public static boolean isFlagAllowedOnPlot(Plot plot, GroupFlag<?> flag, Player p) {
        if (plot != null && flag != null) {
            Group group = plot.getFlag(flag);
            ShopChest.getInstance().debug("Flag " + flag.getName() + " is set to " + group);

            switch (group) {
                case OWNERS:
                    return plot.getOwners().contains(p.getUniqueId());
                case TRUSTED:
                    return plot.getOwners().contains(p.getUniqueId()) || plot.getTrusted().contains(p.getUniqueId());
                case MEMBERS:
                    return plot.getOwners().contains(p.getUniqueId()) || plot.getTrusted().contains(p.getUniqueId()) || plot.getMembers().contains(p.getUniqueId());
                case EVERYONE:
                    return true;
                case NONE:
                    return false;
            }
        }

        ShopChest.getInstance().debug("Flag or plot is null, or value of flag is not a group");

        return true;
    }

    public static class CreateShopFlag extends GroupFlag<CreateShopFlag> {
        public CreateShopFlag(Group value) {
            super(value, StaticCaption.of("Set to the group that is allowed to create shops."));
        }

        @Override
        protected CreateShopFlag flagOf(@NotNull Group value) {
            return new CreateShopFlag(value);
        }
    }

    public static class UseShopFlag extends GroupFlag<UseShopFlag> {
        public UseShopFlag(Group value) {
            super(value, StaticCaption.of("Set to the group that is allowed to use shops."));
        }

        @Override
        protected UseShopFlag flagOf(@NotNull Group value) {
            return new UseShopFlag(value);
        }
    }

    public abstract static class GroupFlag<F extends PlotFlag<Group, F>> extends PlotFlag<Group, F> {
        protected GroupFlag(Group value, Caption description) {
            super(value, TranslatableCaption.of("flags.flag_category_enum"), description);
        }

        @Override
        public String toString() {
            return String.valueOf(getValue()).toLowerCase(Locale.ENGLISH);
        }

        @Override
        public String getExample() {
            return "members";
        }

        @Override
        public F merge(@NotNull Group newValue) {
            return flagOf(newValue);
        }

        @Override
        public F parse(@NotNull String input) throws FlagParseException {
            switch (input.toLowerCase(Locale.ENGLISH)) {
                case "owners":
                case "owner":
                    return this.flagOf(Group.OWNERS);
                case "members":
                case "member":
                case "helpers":
                case "helper":
                    return this.flagOf(Group.MEMBERS);
                case "trusted":
                    return this.flagOf(Group.TRUSTED);
                case "everyone":
                case "all":
                    return this.flagOf(Group.EVERYONE);
                case "deny":
                case "disallow":
                case "false":
                case "no":
                case "0":
                case "none":
                case "noone":
                    return this.flagOf(Group.NONE);
            }

            throw new FlagParseException(this, input, TranslatableCaption.of("flags.flag_error_enum"),
                    Template.of("list", String.join(", ", lowercaseValues)));
        }

        @Override
        public Collection<String> getTabCompletions() {
            return Arrays.asList(lowercaseValues);
        }
    }
} public class WorldGuardShopFlag {

    public static void register(final ShopChest plugin) {
        WorldGuardWrapper wrapper = WorldGuardWrapper.getInstance();

        Optional<IWrappedFlag<WrappedState>> createFlag = wrapper.registerFlag("create-shop",
                WrappedState.class, Config.wgAllowCreateShopDefault ? WrappedState.ALLOW : WrappedState.DENY);
                
        Optional<IWrappedFlag<WrappedState>> useFlag = wrapper.registerFlag("use-shop",
                WrappedState.class, Config.wgAllowUseShopDefault ? WrappedState.ALLOW : WrappedState.DENY);
                
        Optional<IWrappedFlag<WrappedState>> useAdminFlag = wrapper.registerFlag("use-admin-shop",
                WrappedState.class, Config.wgAllowUseAdminShopDefault ? WrappedState.ALLOW : WrappedState.DENY);

        plugin.debug("Flag create-shop: " + String.valueOf(createFlag.isPresent()));
        plugin.debug("Flag use-shop: " + String.valueOf(useFlag.isPresent()));
        plugin.debug("Flag use-admin-shop: " + String.valueOf(useAdminFlag.isPresent()));
    }

} public class ASkyBlockListener implements Listener {
    private final ShopChest plugin;

    public ASkyBlockListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onCreateShop(ShopCreateEvent e) {
        if (!Config.enableASkyblockIntegration)
            return;

        Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
        for (Location loc : chestLocations) {
            if (handleForLocation(e.getPlayer(), loc, e))
                return;
        }
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onExtendShop(ShopExtendEvent e) {
        if (!Config.enableASkyblockIntegration)
            return;

        handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
    }

    private boolean handleForLocation(Player player, Location loc, Cancellable e) {
        Island island = ASkyBlockAPI.getInstance().getIslandAt(loc);
        if (island == null) 
            return false;

        if (!player.getUniqueId().equals(island.getOwner()) && !island.getMembers().contains(player.getUniqueId())) {
            e.setCancelled(true);
            plugin.debug("Cancel Reason: ASkyBlock");
            return true;
        }

        return false;
    }
    
} public class GriefPreventionListener implements Listener {
    private final ShopChest plugin;
    private final GriefPrevention griefPrevention;

    public GriefPreventionListener(ShopChest plugin) {
        this.plugin = plugin;
        this.griefPrevention = plugin.getGriefPrevention();
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onCreateShop(ShopCreateEvent e) {
        if (!Config.enableGriefPreventionIntegration)
            return;

        Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
        for (Location loc : chestLocations) {
            if (handleForLocation(e.getPlayer(), loc, e))
                return;
        }
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onExtendShop(ShopExtendEvent e) {
        if (!Config.enableASkyblockIntegration)
            return;

        handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
    }

    private boolean handleForLocation(Player player, Location loc, Cancellable e) {
        Claim claim = griefPrevention.dataStore.getClaimAt(loc, false, null);
        if (claim == null) 
            return false;

        if (claim.allowContainers(player) != null) {
            e.setCancelled(true);
            plugin.debug("Cancel Reason: GriefPrevention");
            return true;
        }

        return false;
    }
} public class IslandWorldListener implements Listener {
    private final ShopChest plugin;

    public IslandWorldListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onCreateShop(ShopCreateEvent e) {
        if (!Config.enableIslandWorldIntegration || !IslandWorldApi.isInitialized())
            return;

        Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
        for (Location loc : chestLocations) {
            if (handleForLocation(e.getPlayer(), loc, e))
                return;
        }
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onExtendShop(ShopExtendEvent e) {
        if (!Config.enableIslandWorldIntegration || !IslandWorldApi.isInitialized())
            return;

        handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
    }

    private boolean handleForLocation(Player player, Location loc, Cancellable e) {
        if (!loc.getWorld().getName().equals(IslandWorldApi.getIslandWorld().getName())) 
            return false;

        if (!IslandWorldApi.canBuildOnLocation(player, loc, true)) {
            e.setCancelled(true);
            plugin.debug("Cancel Reason: IslandWorld");
            return true;
        }

        return false;
    }
    
} public class PlotSquaredListener implements Listener {
    private final ShopChest plugin;

    public PlotSquaredListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onCreateShop(ShopCreateEvent e) {
        if (!Config.enablePlotsquaredIntegration)
            return;

        Set<org.bukkit.Location> chestLocations = Utils.getChestLocations(e.getShop());
        for (org.bukkit.Location loc : chestLocations) {
            if (handleForLocation(e.getPlayer(), loc, e))
                return;
        }
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onExtendShop(ShopExtendEvent e) {
        if (!Config.enablePlotsquaredIntegration)
            return;

        handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
    }

    // TODO: Outsource shop use external permission

    // @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    // public void onBuySell(ShopBuySellEvent e) {
    //     if (!Config.enablePlotsquaredIntegration)
    //         return;

    //     Set<org.bukkit.Location> chestLocations = Utils.getChestLocations(e.getShop());
    //     for (org.bukkit.Location loc : chestLocations) {
    //         Location plotLocation = new Location(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
    //         Plot plot = plotLocation.getOwnedPlot();
    //         if (!isFlagAllowed(plot, PlotSquaredShopFlag.USE_SHOP, e.getPlayer())) {
    //             e.setCancelled(true);
    //             plugin.debug("Cancel Reason: PlotSquared");
    //             return;
    //         }
    //     }
    // }

    private boolean handleForLocation(Player player, org.bukkit.Location loc, Cancellable e) {
        boolean isAllowed = false;

        try {
            Class.forName("com.plotsquared.core.PlotSquared");
            Location plotLocation = Location.at(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
            Plot plot = plotLocation.getOwnedPlot();
            isAllowed = PlotSquaredShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredShopFlag.CREATE_SHOP, player);
        } catch (ClassNotFoundException ex) {
            com.github.intellectualsites.plotsquared.plot.object.Location plotLocation = new com.github.intellectualsites.plotsquared.plot.object.Location(
                    loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
            com.github.intellectualsites.plotsquared.plot.object.Plot plot = plotLocation.getOwnedPlot();
            isAllowed = PlotSquaredOldShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredOldShopFlag.CREATE_SHOP, player);
        }

        if (!isAllowed) {
            e.setCancelled(true);
            plugin.debug("Cancel Reason: PlotSquared");
            return true;
        }
        return false;
    }
} public class TownyListener implements Listener {
    private final ShopChest plugin;

    public TownyListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onCreateShop(ShopCreateEvent e) {
        if (!Config.enableTownyIntegration)
            return;

        Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
        for (Location loc : chestLocations) {
            if (handleForLocation(e.getPlayer(), loc, e))
                return;
        }
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onExtendShop(ShopExtendEvent e) {
        if (!Config.enablePlotsquaredIntegration)
            return;

        handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
    }

    private boolean handleForLocation(Player player, Location loc, Cancellable e) {
        try {
            TownBlock townBlock = TownyUniverse.getInstance().getTownBlock(WorldCoord.parseWorldCoord(loc));
            if (townBlock == null)
                return false;
                
            Town town = townBlock.getTown();
            Optional<Resident> playerResident = town.getResidents().stream()
                    .filter(r -> r.getName().equals(player.getName()))
                    .findFirst();
                    
            if (!playerResident.isPresent()) {
                e.setCancelled(true);
                plugin.debug("Cancel Reason: Towny (no resident)");
                return true;
            }

            Resident resident = playerResident.get();
            String plotType = townBlock.getType().name();
            boolean cancel = (resident.isMayor() && !Config.townyShopPlotsMayor.contains(plotType))
                    || (resident.isKing() && !Config.townyShopPlotsKing.contains(plotType))
                    || (!resident.isKing() && !resident.isMayor() && !Config.townyShopPlotsResidents.contains(plotType));
            
            if (cancel) {
                e.setCancelled(true);
                plugin.debug("Cancel Reason: Towny (no permission)");
                return true;
            }
        } catch (NotRegisteredException ignored) {
        }
        return false;
    }
} public class USkyBlockListener implements Listener {
    private final ShopChest plugin;
    private final uSkyBlockAPI uSkyBlockAPI;

    public USkyBlockListener(ShopChest plugin) {
        this.plugin = plugin;
        this.uSkyBlockAPI = plugin.getUSkyBlock();
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onCreateShop(ShopCreateEvent e) {
        if (!Config.enableUSkyblockIntegration)
            return;

        Set<Location> chestLocations = Utils.getChestLocations(e.getShop());
        for (Location loc : chestLocations) {
            if (handleForLocation(e.getPlayer(), loc, e))
                return;
        }
    }

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onExtendShop(ShopExtendEvent e) {
        if (!Config.enablePlotsquaredIntegration)
            return;

        handleForLocation(e.getPlayer(), e.getNewChestLocation(), e);
    }

    private boolean handleForLocation(Player player, Location loc, Cancellable e) {
        IslandInfo islandInfo = uSkyBlockAPI.getIslandInfo(loc);
        if (islandInfo == null) 
            return false;

        if (!player.getName().equals(islandInfo.getLeader()) && !islandInfo.getMembers().contains(player.getName())) {
            e.setCancelled(true);
            plugin.debug("Cancel Reason: uSkyBlock");
            return true;
        }
        return false;
    }
} public class LanguageUtils {

    private static ShopChest plugin = ShopChest.getInstance();
    private static LanguageConfiguration langConfig;

    private static ArrayList<ItemName> itemNames = new ArrayList<>();
    private static ArrayList<EnchantmentName> enchantmentNames = new ArrayList<>();
    private static ArrayList<EnchantmentName.EnchantmentLevelName> enchantmentLevelNames = new ArrayList<>();
    private static ArrayList<PotionEffectName> potionEffectNames = new ArrayList<>();
    private static ArrayList<EntityName> entityNames = new ArrayList<>();
    private static ArrayList<PotionName> potionNames = new ArrayList<>();
    private static ArrayList<MusicDiscName> musicDiscNames = new ArrayList<>();
    private static ArrayList<BannerPatternName> bannerPatternNames = new ArrayList<>();
    private static ArrayList<BookGenerationName> generationNames = new ArrayList<>();
    private static ArrayList<LocalizedMessage> messages = new ArrayList<>();


    private static void loadLegacy() {
        // Add Block Names
        itemNames.add(new ItemName(Material.valueOf("STONE"), langConfig.getString("tile.stone.stone.name", "Stone")));
        itemNames.add(new ItemName(Material.valueOf("STONE"), 1, langConfig.getString("tile.stone.granite.name", "Granite")));
        itemNames.add(new ItemName(Material.valueOf("STONE"), 2, langConfig.getString("tile.stone.graniteSmooth.name", "Polished Granite")));
        itemNames.add(new ItemName(Material.valueOf("STONE"), 3, langConfig.getString("tile.stone.diorite.name", "Diorite")));
        itemNames.add(new ItemName(Material.valueOf("STONE"), 4, langConfig.getString("tile.stone.dioriteSmooth.name", "Polished Diorite")));
        itemNames.add(new ItemName(Material.valueOf("STONE"), 5, langConfig.getString("tile.stone.andesite.name", "Andesite")));
        itemNames.add(new ItemName(Material.valueOf("STONE"), 6, langConfig.getString("tile.stone.andesiteSmooth.name", "Polished Andesite")));
        itemNames.add(new ItemName(Material.valueOf("GRASS"), langConfig.getString("tile.grass.name", "Grass Block")));
        itemNames.add(new ItemName(Material.valueOf("DIRT"), langConfig.getString("tile.dirt.default.name", "Dirt")));
        itemNames.add(new ItemName(Material.valueOf("DIRT"), 1, langConfig.getString("tile.dirt.coarse.name", "Coarse Dirt")));
        itemNames.add(new ItemName(Material.valueOf("DIRT"), 2, langConfig.getString("tile.dirt.podzol.name", "Podzol")));
        itemNames.add(new ItemName(Material.valueOf("COBBLESTONE"), langConfig.getString("tile.stonebrick.name", "Cobblestone")));
        itemNames.add(new ItemName(Material.valueOf("WOOD"), langConfig.getString("tile.wood.oak.name", "Oak Wood Planks")));
        itemNames.add(new ItemName(Material.valueOf("WOOD"), 1, langConfig.getString("tile.wood.spruce.name", "Spruce Wood Planks")));
        itemNames.add(new ItemName(Material.valueOf("WOOD"), 2, langConfig.getString("tile.wood.birch.name", "Birch Wood Planks")));
        itemNames.add(new ItemName(Material.valueOf("WOOD"), 3, langConfig.getString("tile.wood.jungle.name", "Jungle Wood Planks")));
        itemNames.add(new ItemName(Material.valueOf("WOOD"), 4, langConfig.getString("tile.wood.acacia.name", "Acacia Wood Planks")));
        itemNames.add(new ItemName(Material.valueOf("WOOD"), 5, langConfig.getString("tile.wood.big_oak.name", "Dark Oak Wood Planks")));
        itemNames.add(new ItemName(Material.valueOf("SAPLING"), langConfig.getString("tile.sapling.oak.name", "Oak Sapling")));
        itemNames.add(new ItemName(Material.valueOf("SAPLING"), 1, langConfig.getString("tile.sapling.spruce.name", "Spruce Sapling")));
        itemNames.add(new ItemName(Material.valueOf("SAPLING"), 2, langConfig.getString("tile.sapling.birch.name", "Birch Sapling")));
        itemNames.add(new ItemName(Material.valueOf("SAPLING"), 3, langConfig.getString("tile.sapling.jungle.name", "Jungle Sapling")));
        itemNames.add(new ItemName(Material.valueOf("SAPLING"), 4, langConfig.getString("tile.sapling.acacia.name", "Acacia Sapling")));
        itemNames.add(new ItemName(Material.valueOf("SAPLING"), 5, langConfig.getString("tile.sapling.big_oak.name", "Dark Oak Sapling")));
        itemNames.add(new ItemName(Material.valueOf("BEDROCK"), langConfig.getString("tile.bedrock.name", "Bedrock")));
        itemNames.add(new ItemName(Material.valueOf("WATER"), langConfig.getString("tile.water.name", "Water")));
        itemNames.add(new ItemName(Material.valueOf("LAVA"), langConfig.getString("tile.lava.name", "Lava")));
        itemNames.add(new ItemName(Material.valueOf("SAND"), langConfig.getString("tile.sand.default.name", "Sand")));
        itemNames.add(new ItemName(Material.valueOf("SAND"), 1, langConfig.getString("tile.sand.red.name", "Red Sand")));
        itemNames.add(new ItemName(Material.valueOf("GRAVEL"), langConfig.getString("tile.gravel.name", "Gravel")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_ORE"), langConfig.getString("tile.oreGold.name", "Gold Ore")));
        itemNames.add(new ItemName(Material.valueOf("IRON_ORE"), langConfig.getString("tile.oreIron.name", "Iron Ore")));
        itemNames.add(new ItemName(Material.valueOf("COAL_ORE"), langConfig.getString("tile.oreCoal.name", "Coal Ore")));
        itemNames.add(new ItemName(Material.valueOf("LOG"), langConfig.getString("tile.log.oak.name", "Oak Wood")));
        itemNames.add(new ItemName(Material.valueOf("LOG"), 1, langConfig.getString("tile.log.spruce.name", "Spruce Wood")));
        itemNames.add(new ItemName(Material.valueOf("LOG"), 2, langConfig.getString("tile.log.birch.name", "Birch Wood")));
        itemNames.add(new ItemName(Material.valueOf("LOG"), 3, langConfig.getString("tile.log.jungle.name", "Jungle Wood")));
        itemNames.add(new ItemName(Material.valueOf("LEAVES"), langConfig.getString("tile.leaves.oak.name", "Oak Leaves")));
        itemNames.add(new ItemName(Material.valueOf("LEAVES"), 1, langConfig.getString("tile.leaves.spruce.name", "Spruce Leaves")));
        itemNames.add(new ItemName(Material.valueOf("LEAVES"), 2, langConfig.getString("tile.leaves.birch.name", "Birch Leaves")));
        itemNames.add(new ItemName(Material.valueOf("LEAVES"), 3, langConfig.getString("tile.leaves.jungle.name", "Jungle Leaves")));
        itemNames.add(new ItemName(Material.valueOf("SPONGE"), langConfig.getString("tile.sponge.dry.name", "Sponge")));
        itemNames.add(new ItemName(Material.valueOf("SPONGE"), 1, langConfig.getString("tile.sponge.wet.name", "Wet Sponge")));
        itemNames.add(new ItemName(Material.valueOf("GLASS"), langConfig.getString("tile.glass.name", "Glass")));
        itemNames.add(new ItemName(Material.valueOf("LAPIS_ORE"), langConfig.getString("tile.oreLapis.name", "Lapis Lazuli Ore")));
        itemNames.add(new ItemName(Material.valueOf("LAPIS_BLOCK"), langConfig.getString("tile.blockLapis.name", "Lapis Lazuli Block")));
        itemNames.add(new ItemName(Material.valueOf("DISPENSER"), langConfig.getString("tile.dispenser.name", "Dispenser")));
        itemNames.add(new ItemName(Material.valueOf("SANDSTONE"), langConfig.getString("tile.sandStone.default.name", "Sandstone")));
        itemNames.add(new ItemName(Material.valueOf("SANDSTONE"), 1, langConfig.getString("tile.sandStone.chiseled.name", "Chiseled Sandstone")));
        itemNames.add(new ItemName(Material.valueOf("SANDSTONE"), 2, langConfig.getString("tile.sandStone.smooth.name", "Smooth Sandstone")));
        itemNames.add(new ItemName(Material.valueOf("NOTE_BLOCK"), langConfig.getString("tile.musicBlock.name", "Note Block")));
        itemNames.add(new ItemName(Material.valueOf("POWERED_RAIL"), langConfig.getString("tile.goldenRail.name", "Powered Rail")));
        itemNames.add(new ItemName(Material.valueOf("DETECTOR_RAIL"), langConfig.getString("tile.detectorRail.name", "Detector Rail")));
        itemNames.add(new ItemName(Material.valueOf("PISTON_STICKY_BASE"), langConfig.getString("tile.pistonStickyBase.name", "Sticky Piston")));
        itemNames.add(new ItemName(Material.valueOf("WEB"), langConfig.getString("tile.web.name", "Web")));
        itemNames.add(new ItemName(Material.valueOf("LONG_GRASS"), langConfig.getString("tile.tallgrass.shrub.name", "Shrub")));
        itemNames.add(new ItemName(Material.valueOf("LONG_GRASS"), 1, langConfig.getString("tile.tallgrass.grass.name", "Grass")));
        itemNames.add(new ItemName(Material.valueOf("LONG_GRASS"), 2, langConfig.getString("tile.tallgrass.fern.name", "Fern")));
        itemNames.add(new ItemName(Material.valueOf("DEAD_BUSH"), langConfig.getString("tile.deadbush.name", "Dead Bush")));
        itemNames.add(new ItemName(Material.valueOf("PISTON_BASE"), langConfig.getString("tile.pistonBase.name", "Piston")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), langConfig.getString("tile.cloth.white.name", "White Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 1, langConfig.getString("tile.cloth.orange.name", "Orange Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 2, langConfig.getString("tile.cloth.magenta.name", "Magenta Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 3, langConfig.getString("tile.cloth.lightBlue.name", "Light Blue Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 4, langConfig.getString("tile.cloth.yellow.name", "Yellow Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 5, langConfig.getString("tile.cloth.lime.name", "Lime Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 6, langConfig.getString("tile.cloth.pink.name", "Pink Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 7, langConfig.getString("tile.cloth.gray.name", "Gray Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 8, langConfig.getString("tile.cloth.silver.name", "Light Gray Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 9, langConfig.getString("tile.cloth.cyan.name", "Cyan Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 10, langConfig.getString("tile.cloth.purple.name", "Purple Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 11, langConfig.getString("tile.cloth.blue.name", "Blue Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 12, langConfig.getString("tile.cloth.brown.name", "Brown Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 13, langConfig.getString("tile.cloth.green.name", "Green Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 14, langConfig.getString("tile.cloth.red.name", "Red Wool")));
        itemNames.add(new ItemName(Material.valueOf("WOOL"), 15, langConfig.getString("tile.cloth.black.name", "Black Wool")));
        itemNames.add(new ItemName(Material.valueOf("YELLOW_FLOWER"), langConfig.getString("tile.flower1.dandelion.name", "Dandelion")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), langConfig.getString("tile.flower2.poppy.name", "Poppy")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 1, langConfig.getString("tile.flower2.blueOrchid.name", "Blue Orchid")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 2, langConfig.getString("tile.flower2.allium.name", "Allium")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 3, langConfig.getString("tile.flower2.houstonia.name", "Azure Bluet")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 4, langConfig.getString("tile.flower2.tulipRed.name", "Red Tulip")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 5, langConfig.getString("tile.flower2.tulipOrange.name", "Orange Tulip")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 6, langConfig.getString("tile.flower2.tulipWhite.name", "White Tulip")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 7, langConfig.getString("tile.flower2.tulipPink.name", "Pink Tulip")));
        itemNames.add(new ItemName(Material.valueOf("RED_ROSE"), 8, langConfig.getString("tile.flower2.oxeyeDaisy.name", "Oxeye Daisy")));
        itemNames.add(new ItemName(Material.valueOf("BROWN_MUSHROOM"), langConfig.getString("tile.mushroom.name", "Mushroom")));
        itemNames.add(new ItemName(Material.valueOf("RED_MUSHROOM"), langConfig.getString("tile.mushroom.name", "Mushroom")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_BLOCK"), langConfig.getString("tile.blockGold.name", "Block of Gold")));
        itemNames.add(new ItemName(Material.valueOf("IRON_BLOCK"), langConfig.getString("tile.blockIron.name", "Block of Iron")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), langConfig.getString("tile.stoneSlab.stone.name", "Stone Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 1, langConfig.getString("tile.stoneSlab.sand.name", "Sandstone Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 2, langConfig.getString("tile.stoneSlab.wood.name", "Wooden Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 3, langConfig.getString("tile.stoneSlab.cobble.name", "Cobblestone Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 4, langConfig.getString("tile.stoneSlab.brick.name", "Brick Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 5, langConfig.getString("tile.stoneSlab.smoothStoneBrick.name", "Stone Brick Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 6, langConfig.getString("tile.stoneSlab.netherBrick.name", "Nether Brick Slab")));
        itemNames.add(new ItemName(Material.valueOf("STEP"), 7, langConfig.getString("tile.stoneSlab.quartz.name", "Quartz Slab")));
        itemNames.add(new ItemName(Material.valueOf("BRICK"), langConfig.getString("tile.brick.name", "Brick")));
        itemNames.add(new ItemName(Material.valueOf("TNT"), langConfig.getString("tile.tnt.name", "TNT")));
        itemNames.add(new ItemName(Material.valueOf("BOOKSHELF"), langConfig.getString("tile.bookshelf.name", "Bookshelf")));
        itemNames.add(new ItemName(Material.valueOf("MOSSY_COBBLESTONE"), langConfig.getString("tile.stoneMoss.name", "Moss Stone")));
        itemNames.add(new ItemName(Material.valueOf("OBSIDIAN"), langConfig.getString("tile.obsidian.name", "Obsidian")));
        itemNames.add(new ItemName(Material.valueOf("TORCH"), langConfig.getString("tile.torch.name", "Torch")));
        itemNames.add(new ItemName(Material.valueOf("FIRE"), langConfig.getString("tile.fire.name", "Fire")));
        itemNames.add(new ItemName(Material.valueOf("MOB_SPAWNER"), langConfig.getString("tile.mobSpawner.name", "Mob Spawner")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STAIRS"), langConfig.getString("tile.stairsWood.name", "Oak Wood Stairs")));
        itemNames.add(new ItemName(Material.valueOf("CHEST"), langConfig.getString("tile.chest.name", "Chest")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_ORE"), langConfig.getString("tile.oreDiamond.name", "Diamond Ore")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_BLOCK"), langConfig.getString("tile.blockDiamond.name", "Block of Diamond")));
        itemNames.add(new ItemName(Material.valueOf("WORKBENCH"), langConfig.getString("tile.workbench.name", "Crafting Table")));
        itemNames.add(new ItemName(Material.valueOf("SOIL"), langConfig.getString("tile.farmland.name", "Farmland")));
        itemNames.add(new ItemName(Material.valueOf("FURNACE"), langConfig.getString("tile.furnace.name", "Furnace")));
        itemNames.add(new ItemName(Material.valueOf("LADDER"), langConfig.getString("tile.ladder.name", "Ladder")));
        itemNames.add(new ItemName(Material.valueOf("RAILS"), langConfig.getString("tile.rail.name", "Rail")));
        itemNames.add(new ItemName(Material.valueOf("COBBLESTONE_STAIRS"), langConfig.getString("tile.stairsStone.name", "Stone Stairs")));
        itemNames.add(new ItemName(Material.valueOf("LEVER"), langConfig.getString("tile.lever.name", "Lever")));
        itemNames.add(new ItemName(Material.valueOf("STONE_PLATE"), langConfig.getString("tile.pressurePlateStone.name", "Stone Pressure Plate")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_PLATE"), langConfig.getString("tile.pressurePlateWood.name", "Wooden Pressure Plate")));
        itemNames.add(new ItemName(Material.valueOf("REDSTONE_ORE"), langConfig.getString("tile.oreRedstone.name", "Redstone Ore")));
        itemNames.add(new ItemName(Material.valueOf("REDSTONE_TORCH_ON"), langConfig.getString("tile.notGate.name", "Redstone Torch")));
        itemNames.add(new ItemName(Material.valueOf("SNOW"), langConfig.getString("tile.snow.name", "Snow")));
        itemNames.add(new ItemName(Material.valueOf("ICE"), langConfig.getString("tile.ice.name", "Ice")));
        itemNames.add(new ItemName(Material.valueOf("SNOW_BLOCK"), langConfig.getString("tile.snow.name", "Snow")));
        itemNames.add(new ItemName(Material.valueOf("CACTUS"), langConfig.getString("tile.cactus.name", "Cactus")));
        itemNames.add(new ItemName(Material.valueOf("CLAY"), langConfig.getString("tile.clay.name", "Clay")));
        itemNames.add(new ItemName(Material.valueOf("JUKEBOX"), langConfig.getString("tile.jukebox.name", "Jukebox")));
        itemNames.add(new ItemName(Material.valueOf("FENCE"), langConfig.getString("tile.fence.name", "Oak Fence")));
        itemNames.add(new ItemName(Material.valueOf("PUMPKIN"), langConfig.getString("tile.pumpkin.name", "Pumpkin")));
        itemNames.add(new ItemName(Material.valueOf("NETHERRACK"), langConfig.getString("tile.hellrock.name", "Netherrack")));
        itemNames.add(new ItemName(Material.valueOf("SOUL_SAND"), langConfig.getString("tile.hellsand.name", "Soul Sand")));
        itemNames.add(new ItemName(Material.valueOf("GLOWSTONE"), langConfig.getString("tile.lightgem.name", "Glowstone")));
        itemNames.add(new ItemName(Material.valueOf("PORTAL"), langConfig.getString("tile.portal.name", "Portal")));
        itemNames.add(new ItemName(Material.valueOf("JACK_O_LANTERN"), langConfig.getString("tile.litpumpkin.name", "Jack o'Lantern")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), langConfig.getString("tile.stainedGlass.white.name", "White Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 1, langConfig.getString("tile.stainedGlass.orange.name", "Orange Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 2, langConfig.getString("tile.stainedGlass.magenta.name", "Magenta Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 3, langConfig.getString("tile.stainedGlass.lightBlue.name", "Light Blue Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 4, langConfig.getString("tile.stainedGlass.yellow.name", "Yellow Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 5, langConfig.getString("tile.stainedGlass.lime.name", "Lime Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 6, langConfig.getString("tile.stainedGlass.pink.name", "Pink Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 7, langConfig.getString("tile.stainedGlass.gray.name", "Gray Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 8, langConfig.getString("tile.stainedGlass.silver.name", "Light Gray Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 9, langConfig.getString("tile.stainedGlass.cyan.name", "Cyan Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 10, langConfig.getString("tile.stainedGlass.purple.name", "Purple Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 11, langConfig.getString("tile.stainedGlass.blue.name", "Blue Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 12, langConfig.getString("tile.stainedGlass.brown.name", "Brown Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 13, langConfig.getString("tile.stainedGlass.green.name", "Green Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 14, langConfig.getString("tile.stainedGlass.red.name", "Red Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS"), 15, langConfig.getString("tile.stainedGlass.black.name", "Black Stained Glass")));
        itemNames.add(new ItemName(Material.valueOf("TRAP_DOOR"), langConfig.getString("tile.trapdoor.name", "Wooden Trapdoor")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGGS"), langConfig.getString("tile.monsterStoneEgg.stone.name", "Stone Monster Egg")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGGS"), 1, langConfig.getString("tile.monsterStoneEgg.cobble.name", "Cobblestone Monster Egg")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGGS"), 2, langConfig.getString("tile.monsterStoneEgg.brick.name", "Stone Brick Monster Egg")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGGS"), 3, langConfig.getString("tile.monsterStoneEgg.mossybrick.name", "Mossy Stone Brick Monster Egg")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGGS"), 4, langConfig.getString("tile.monsterStoneEgg.crackedbrick.name", "Cracked Stone Brick Monster Egg")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGGS"), 5, langConfig.getString("tile.monsterStoneEgg.chiseledbrick.name", "Chiseled Stone Brick Monster Egg")));
        itemNames.add(new ItemName(Material.valueOf("SMOOTH_BRICK"), langConfig.getString("tile.stonebricksmooth.default.name", "Stone Bricks")));
        itemNames.add(new ItemName(Material.valueOf("SMOOTH_BRICK"), 1, langConfig.getString("tile.stonebricksmooth.mossy.name", "Mossy Stone Bricks")));
        itemNames.add(new ItemName(Material.valueOf("SMOOTH_BRICK"), 2, langConfig.getString("tile.stonebricksmooth.cracked.name", "Cracked Stone Bricks")));
        itemNames.add(new ItemName(Material.valueOf("SMOOTH_BRICK"), 3, langConfig.getString("tile.stonebricksmooth.chiseled.name", "Chiseled Stone Bricks")));
        itemNames.add(new ItemName(Material.valueOf("HUGE_MUSHROOM_1"), langConfig.getString("tile.mushroom.name", "Mushroom")));
        itemNames.add(new ItemName(Material.valueOf("HUGE_MUSHROOM_2"), langConfig.getString("tile.mushroom.name", "Mushroom")));
        itemNames.add(new ItemName(Material.valueOf("IRON_FENCE"), langConfig.getString("tile.fenceIron.name", "Iron Bars")));
        itemNames.add(new ItemName(Material.valueOf("THIN_GLASS"), langConfig.getString("tile.thinGlass.name", "Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("MELON_BLOCK"), langConfig.getString("tile.melon.name", "Melon")));
        itemNames.add(new ItemName(Material.valueOf("VINE"), langConfig.getString("tile.vine.name", "Vines")));
        itemNames.add(new ItemName(Material.valueOf("FENCE_GATE"), langConfig.getString("tile.fenceGate.name", "Oak Fence Gate")));
        itemNames.add(new ItemName(Material.valueOf("BRICK_STAIRS"), langConfig.getString("tile.stairsBrick.name", "Brick Stairs")));
        itemNames.add(new ItemName(Material.valueOf("SMOOTH_STAIRS"), langConfig.getString("tile.stairsStoneBrickSmooth.name", "Stone Brick Stairs")));
        itemNames.add(new ItemName(Material.valueOf("MYCEL"), langConfig.getString("tile.mycel.name", "Mycelium")));
        itemNames.add(new ItemName(Material.valueOf("WATER_LILY"), langConfig.getString("tile.waterlily.name", "Lily Pad")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_BRICK"), langConfig.getString("tile.netherBrick.name", "Nether Brick")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_FENCE"), langConfig.getString("tile.netherFence.name", "Nether Brick Fence")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_BRICK_STAIRS"), langConfig.getString("tile.stairsNetherBrick.name", "Nether Brick Stairs")));
        itemNames.add(new ItemName(Material.valueOf("ENCHANTMENT_TABLE"), langConfig.getString("tile.enchantmentTable.name", "Enchantment Table")));
        itemNames.add(new ItemName(Material.valueOf("ENDER_PORTAL_FRAME"), langConfig.getString("tile.endPortalFrame.name", "End Portal Frame")));
        itemNames.add(new ItemName(Material.valueOf("ENDER_STONE"), langConfig.getString("tile.whiteStone.name", "End Stone")));
        itemNames.add(new ItemName(Material.valueOf("DRAGON_EGG"), langConfig.getString("tile.dragonEgg.name", "Dragon Egg")));
        itemNames.add(new ItemName(Material.valueOf("REDSTONE_LAMP_OFF"), langConfig.getString("tile.redstoneLight.name", "Redstone Lamp")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STEP"), langConfig.getString("tile.woodSlab.oak.name", "Oak Wood Slab")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STEP"), 1, langConfig.getString("tile.woodSlab.spruce.name", "Spruce Wood Slab")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STEP"), 2, langConfig.getString("tile.woodSlab.birch.name", "Birch Wood Slab")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STEP"), 3, langConfig.getString("tile.woodSlab.jungle.name", "Jungle Wood Slab")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STEP"), 4, langConfig.getString("tile.woodSlab.acacia.name", "Acacia Wood Slab")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_STEP"), 5, langConfig.getString("tile.woodSlab.big_oak.name", "Dark Oak Wood Slab")));
        itemNames.add(new ItemName(Material.valueOf("SANDSTONE_STAIRS"), langConfig.getString("tile.stairsSandStone.name", "Mycelium")));
        itemNames.add(new ItemName(Material.valueOf("EMERALD_ORE"), langConfig.getString("tile.oreEmerald.name", "Emerald Ore")));
        itemNames.add(new ItemName(Material.valueOf("ENDER_CHEST"), langConfig.getString("tile.enderChest.name", "Ender Chest")));
        itemNames.add(new ItemName(Material.valueOf("TRIPWIRE_HOOK"), langConfig.getString("tile.tripWireSource.name", "Tripwire Hook")));
        itemNames.add(new ItemName(Material.valueOf("EMERALD_BLOCK"), langConfig.getString("tile.blockEmerald.name", "Block of Emerald")));
        itemNames.add(new ItemName(Material.valueOf("SPRUCE_WOOD_STAIRS"), langConfig.getString("tile.stairsWoodSpruce.name", "Spruce Wood Stairs")));
        itemNames.add(new ItemName(Material.valueOf("BIRCH_WOOD_STAIRS"), langConfig.getString("tile.stairsWoodBirch.name", "Birch Wood Stairs")));
        itemNames.add(new ItemName(Material.valueOf("JUNGLE_WOOD_STAIRS"), langConfig.getString("tile.stairsWoodJungle.name", "Jungle Wood Stairs")));
        itemNames.add(new ItemName(Material.valueOf("COMMAND"), langConfig.getString("tile.commandBlock.name", "Command Block")));
        itemNames.add(new ItemName(Material.valueOf("BEACON"), langConfig.getString("tile.beacon.name", "Beacon")));
        itemNames.add(new ItemName(Material.valueOf("COBBLE_WALL"), langConfig.getString("tile.cobbleWall.normal.name", "Cobblestone Wall")));
        itemNames.add(new ItemName(Material.valueOf("COBBLE_WALL"), 1, langConfig.getString("tile.cobbleWall.mossy.name", "Mossy Cobblestone Wall")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_BUTTON"), langConfig.getString("tile.button.name", "Button")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_STALK"), langConfig.getString("tile.netherStalk.name", "Nether Wart")));
        itemNames.add(new ItemName(Material.valueOf("ANVIL"), langConfig.getString("tile.anvil.intact.name", "Anvil")));
        itemNames.add(new ItemName(Material.valueOf("ANVIL"), 1, langConfig.getString("tile.anvil.slightlyDamaged.name", "Slightly Damaged Anvil")));
        itemNames.add(new ItemName(Material.valueOf("ANVIL"), 2, langConfig.getString("tile.anvil.veryDamaged.name", "Very Damaged Anvil")));
        itemNames.add(new ItemName(Material.valueOf("TRAPPED_CHEST"), langConfig.getString("tile.chestTrap.name", "Trapped Chest")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_PLATE"), langConfig.getString("tile.weightedPlate_light.name", "Weighted Pressure Plate (Light)")));
        itemNames.add(new ItemName(Material.valueOf("IRON_PLATE"), langConfig.getString("tile.weightedPlate_heavy.name", "Weighted Pressure Plate (Heavy)")));
        itemNames.add(new ItemName(Material.valueOf("DAYLIGHT_DETECTOR"), langConfig.getString("tile.daylightDetector.name", "Daylight Sensor")));
        itemNames.add(new ItemName(Material.valueOf("REDSTONE_BLOCK"), langConfig.getString("tile.blockRedstone.name", "Block of Redstone")));
        itemNames.add(new ItemName(Material.valueOf("QUARTZ_ORE"), langConfig.getString("tile.netherquartz.name", "Nether Quartz Ore")));
        itemNames.add(new ItemName(Material.valueOf("HOPPER"), langConfig.getString("tile.hopper.name", "Hopper")));
        itemNames.add(new ItemName(Material.valueOf("QUARTZ_BLOCK"), langConfig.getString("tile.quartzBlock.default.name", "Block of Quartz")));
        itemNames.add(new ItemName(Material.valueOf("QUARTZ_BLOCK"), langConfig.getString("tile.quartzBlock.chiseled.name", "Chiseled Quartz Block")));
        itemNames.add(new ItemName(Material.valueOf("QUARTZ_BLOCK"), langConfig.getString("tile.quartzBlock.lines.name", "Pillar Quartz Block")));
        itemNames.add(new ItemName(Material.valueOf("QUARTZ_STAIRS"), langConfig.getString("tile.stairsQuartz.name", "Quartz Stairs")));
        itemNames.add(new ItemName(Material.valueOf("ACTIVATOR_RAIL"), langConfig.getString("tile.activatorRail.name", "Activator Rail")));
        itemNames.add(new ItemName(Material.valueOf("DROPPER"), langConfig.getString("tile.dropper.name", "Dropper")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), langConfig.getString("tile.clayHardenedStained.white.name", "White Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 1, langConfig.getString("tile.clayHardenedStained.orange.name", "Orange Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 2, langConfig.getString("tile.clayHardenedStained.magenta.name", "Magenta Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 3, langConfig.getString("tile.clayHardenedStained.lightBlue.name", "Light Blue Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 4, langConfig.getString("tile.clayHardenedStained.yellow.name", "Yellow Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 5, langConfig.getString("tile.clayHardenedStained.lime.name", "Lime Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 6, langConfig.getString("tile.clayHardenedStained.pink.name", "Pink Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 7, langConfig.getString("tile.clayHardenedStained.gray.name", "Gray Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 8, langConfig.getString("tile.clayHardenedStained.silver.name", "Light Gray Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 9, langConfig.getString("tile.clayHardenedStained.cyan.name", "Cyan Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 10, langConfig.getString("tile.clayHardenedStained.purple.name", "Purple Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 11, langConfig.getString("tile.clayHardenedStained.blue.name", "Blue Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 12, langConfig.getString("tile.clayHardenedStained.brown.name", "Brown Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 13, langConfig.getString("tile.clayHardenedStained.green.name", "Green Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 14, langConfig.getString("tile.clayHardenedStained.red.name", "Red Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_CLAY"), 15, langConfig.getString("tile.clayHardenedStained.black.name", "Black Terracotta")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), langConfig.getString("tile.thinStainedGlass.white.name", "White Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 1, langConfig.getString("tile.thinStainedGlass.orange.name", "Orange Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 2, langConfig.getString("tile.thinStainedGlass.magenta.name", "Magenta Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 3, langConfig.getString("tile.thinStainedGlass.lightBlue.name", "Light Blue Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 4, langConfig.getString("tile.thinStainedGlass.yellow.name", "Yellow Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 5, langConfig.getString("tile.thinStainedGlass.lime.name", "Lime Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 6, langConfig.getString("tile.thinStainedGlass.pink.name", "Pink Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 7, langConfig.getString("tile.thinStainedGlass.gray.name", "Gray Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 8, langConfig.getString("tile.thinStainedGlass.silver.name", "Light Gray Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 9, langConfig.getString("tile.thinStainedGlass.cyan.name", "Cyan Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 10, langConfig.getString("tile.thinStainedGlass.purple.name", "Purple Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 11, langConfig.getString("tile.thinStainedGlass.blue.name", "Blue Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 12, langConfig.getString("tile.thinStainedGlass.brown.name", "Brown Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 13, langConfig.getString("tile.thinStainedGlass.green.name", "Green Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 14, langConfig.getString("tile.thinStainedGlass.red.name", "Red Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("STAINED_GLASS_PANE"), 15, langConfig.getString("tile.thinStainedGlass.black.name", "Black Stained Glass Pane")));
        itemNames.add(new ItemName(Material.valueOf("LEAVES_2"), langConfig.getString("tile.leaves.acacia.name", "Acacia Leaves")));
        itemNames.add(new ItemName(Material.valueOf("LEAVES_2"), 1, langConfig.getString("tile.leaves.big_oak.name", "Dark Oak Leaves")));
        itemNames.add(new ItemName(Material.valueOf("LOG_2"), langConfig.getString("tile.log.acacia.name", "Acacia Wood")));
        itemNames.add(new ItemName(Material.valueOf("LOG_2"), 1, langConfig.getString("tile.log.big_oak.name", "Dark Oak Wood")));
        itemNames.add(new ItemName(Material.valueOf("ACACIA_STAIRS"), langConfig.getString("tile.stairsWoodAcacia.name", "Acacia Wood Stairs")));
        itemNames.add(new ItemName(Material.valueOf("DARK_OAK_STAIRS"), langConfig.getString("tile.stairsWoodDarkOak.name", "Dark Oak Wood Stairs")));
        itemNames.add(new ItemName(Material.valueOf("SLIME_BLOCK"), langConfig.getString("tile.slime.name", "Slime Block")));
        itemNames.add(new ItemName(Material.valueOf("BARRIER"), langConfig.getString("tile.barrier.name", "Barrier")));
        itemNames.add(new ItemName(Material.valueOf("IRON_TRAPDOOR"), langConfig.getString("tile.ironTrapdoor.name", "Iron Trapdoor")));
        itemNames.add(new ItemName(Material.valueOf("PRISMARINE"), langConfig.getString("tile.prismarine.rough.name", "Prismarine")));
        itemNames.add(new ItemName(Material.valueOf("PRISMARINE"), 1, langConfig.getString("tile.prismarine.bricks.name", "Prismarine Bricks")));
        itemNames.add(new ItemName(Material.valueOf("PRISMARINE"), 2, langConfig.getString("tile.prismarine.dark.name", "Dark Prismarine")));
        itemNames.add(new ItemName(Material.valueOf("SEA_LANTERN"), langConfig.getString("tile.seaLantern.name", "Sea Lantern")));
        itemNames.add(new ItemName(Material.valueOf("HAY_BLOCK"), langConfig.getString("tile.hayBlock.name", "Hay Bale")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), langConfig.getString("tile.woolCarpet.white.name", "White Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 1, langConfig.getString("tile.woolCarpet.orange.name", "Orange Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 2, langConfig.getString("tile.woolCarpet.magenta.name", "Magenta Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 3, langConfig.getString("tile.woolCarpet.lightBlue.name", "Light Blue Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 4, langConfig.getString("tile.woolCarpet.yellow.name", "Yellow Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 5, langConfig.getString("tile.woolCarpet.lime.name", "Lime Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 6, langConfig.getString("tile.woolCarpet.pink.name", "Pink Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 7, langConfig.getString("tile.woolCarpet.gray.name", "Gray Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 8, langConfig.getString("tile.woolCarpet.silver.name", "Light Gray Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 9, langConfig.getString("tile.woolCarpet.cyan.name", "Cyan Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 10, langConfig.getString("tile.woolCarpet.purple.name", "Purple Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 11, langConfig.getString("tile.woolCarpet.blue.name", "Blue Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 12, langConfig.getString("tile.woolCarpet.brown.name", "Brown Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 13, langConfig.getString("tile.woolCarpet.green.name", "Green Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 14, langConfig.getString("tile.woolCarpet.red.name", "Red Carpet")));
        itemNames.add(new ItemName(Material.valueOf("CARPET"), 15, langConfig.getString("tile.woolCarpet.black.name", "Black Carpet")));
        itemNames.add(new ItemName(Material.valueOf("HARD_CLAY"), langConfig.getString("tile.clayHardened.name", "Hardened Clay")));
        itemNames.add(new ItemName(Material.valueOf("COAL_BLOCK"), langConfig.getString("tile.blockCoal.name", "Block of Coal")));
        itemNames.add(new ItemName(Material.valueOf("PACKED_ICE"), langConfig.getString("tile.icePacked.name", "Packed Ice")));
        itemNames.add(new ItemName(Material.valueOf("DOUBLE_PLANT"), langConfig.getString("tile.doublePlant.sunflower.name", "Sunflower")));
        itemNames.add(new ItemName(Material.valueOf("DOUBLE_PLANT"), 1, langConfig.getString("tile.doublePlant.syringa.name", "Lilac")));
        itemNames.add(new ItemName(Material.valueOf("DOUBLE_PLANT"), 2, langConfig.getString("tile.doublePlant.grass.name", "Double Tallgrass")));
        itemNames.add(new ItemName(Material.valueOf("DOUBLE_PLANT"), 3, langConfig.getString("tile.doublePlant.fern.name", "Large Fern")));
        itemNames.add(new ItemName(Material.valueOf("DOUBLE_PLANT"), 4, langConfig.getString("tile.doublePlant.rose.name", "Rose Bush")));
        itemNames.add(new ItemName(Material.valueOf("DOUBLE_PLANT"), 5, langConfig.getString("tile.doublePlant.paeonia.name", "Peony")));
        itemNames.add(new ItemName(Material.valueOf("RED_SANDSTONE"), langConfig.getString("tile.redSandStone.default.name", "Red Sandstone")));
        itemNames.add(new ItemName(Material.valueOf("RED_SANDSTONE"), 1, langConfig.getString("tile.redSandStone.chiseled.name", "Chiseled Red Sandstone")));
        itemNames.add(new ItemName(Material.valueOf("RED_SANDSTONE"), 2, langConfig.getString("tile.redSandStone.smooth.name", "Smooth Red Sandstone")));
        itemNames.add(new ItemName(Material.valueOf("RED_SANDSTONE_STAIRS"), langConfig.getString("tile.stairsRedSandStone.name", "Red Sandstone Stairs")));
        itemNames.add(new ItemName(Material.valueOf("STONE_SLAB2"), langConfig.getString("tile.stoneSlab2.red_sandstone.name", "Red Sandstone Slab")));
        itemNames.add(new ItemName(Material.valueOf("SPRUCE_FENCE_GATE"), langConfig.getString("tile.spruceFenceGate.name", "Spruce Fence Gate")));
        itemNames.add(new ItemName(Material.valueOf("BIRCH_FENCE_GATE"), langConfig.getString("tile.birchFenceGate.name", "Birch Fence Gate")));
        itemNames.add(new ItemName(Material.valueOf("JUNGLE_FENCE_GATE"), langConfig.getString("tile.jungleFenceGate.name", "Jungle Fence Gate")));
        itemNames.add(new ItemName(Material.valueOf("DARK_OAK_FENCE_GATE"), langConfig.getString("tile.darkOakFenceGate.name", "Dark Oak Fence Gate")));
        itemNames.add(new ItemName(Material.valueOf("ACACIA_FENCE_GATE"), langConfig.getString("tile.acaciaFenceGate.name", "Acacia Fence Gate")));
        itemNames.add(new ItemName(Material.valueOf("SPRUCE_FENCE"), langConfig.getString("tile.spruceFence.name", "Spruce Fence")));
        itemNames.add(new ItemName(Material.valueOf("BIRCH_FENCE"), langConfig.getString("tile.birchFence.name", "Birch Fence")));
        itemNames.add(new ItemName(Material.valueOf("JUNGLE_FENCE"), langConfig.getString("tile.jungleFence.name", "Jungle Fence")));
        itemNames.add(new ItemName(Material.valueOf("DARK_OAK_FENCE"), langConfig.getString("tile.darkOakFence.name", "Dark Oak Fence")));
        itemNames.add(new ItemName(Material.valueOf("ACACIA_FENCE"), langConfig.getString("tile.acaciaFence.name", "Acacia Fence")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Block Names of 1.9
            itemNames.add(new ItemName(Material.valueOf("END_ROD"), langConfig.getString("tile.endRod.name", "End Rod")));
            itemNames.add(new ItemName(Material.valueOf("CHORUS_PLANT"), langConfig.getString("tile.chorusPlant.name", "Chorus Plant")));
            itemNames.add(new ItemName(Material.valueOf("CHORUS_FLOWER"), langConfig.getString("tile.chorusFlower.name", "Chorus Flower")));
            itemNames.add(new ItemName(Material.valueOf("PURPUR_BLOCK"), langConfig.getString("tile.purpurBlock.name", "Purpur Block")));
            itemNames.add(new ItemName(Material.valueOf("PURPUR_PILLAR"), langConfig.getString("tile.purpurPillar.name", "Purpur Pillar")));
            itemNames.add(new ItemName(Material.valueOf("PURPUR_STAIRS"), langConfig.getString("tile.stairsPurpur.name", "Purpur Stairs")));
            itemNames.add(new ItemName(Material.valueOf("PURPUR_SLAB"), langConfig.getString("tile.purpurSlab.name", "Purpur Slab")));
            itemNames.add(new ItemName(Material.valueOf("END_BRICKS"), langConfig.getString("tile.endBricks.name", "End Stone Bricks")));
            itemNames.add(new ItemName(Material.valueOf("GRASS_PATH"), langConfig.getString("tile.grassPath.name", "Grass Path")));
            itemNames.add(new ItemName(Material.valueOf("COMMAND_REPEATING"), langConfig.getString("tile.repeatingCommandBlock.name", "Repeating Command Block")));
            itemNames.add(new ItemName(Material.valueOf("COMMAND_CHAIN"), langConfig.getString("tile.chainCommandBlock.name", "Chain Command Block")));
            itemNames.add(new ItemName(Material.valueOf("STRUCTURE_BLOCK"), langConfig.getString("tile.structureBlock.name", "Structure Block")));
        }

        if (Utils.getMajorVersion() >= 10) {
            // Add Block Names of 1.10
            itemNames.add(new ItemName(Material.valueOf("MAGMA"), langConfig.getString("tile.magma.name", "Magma Block")));
            itemNames.add(new ItemName(Material.valueOf("NETHER_WART_BLOCK"), langConfig.getString("tile.netherWartBlock.name", "Nether Wart Block")));
            itemNames.add(new ItemName(Material.valueOf("RED_NETHER_BRICK"), langConfig.getString("tile.redNetherBrick.name", "Red Nether Brick")));
            itemNames.add(new ItemName(Material.valueOf("BONE_BLOCK"), langConfig.getString("tile.boneBlock.name", "Bone Block")));
            itemNames.add(new ItemName(Material.valueOf("STRUCTURE_VOID"), langConfig.getString("tile.structureVoid.name", "Structure Void")));
        }

        if (Utils.getMajorVersion() >= 11) {
            // Add Block Names of 1.11
            itemNames.add(new ItemName(Material.valueOf("OBSERVER"), langConfig.getString("tile.observer.name", "Observer")));
            itemNames.add(new ItemName(Material.valueOf("WHITE_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxWhite.name", "White Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("ORANGE_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxOrange.name", "Orange Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("MAGENTA_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxMagenta.name", "Magenta Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("LIGHT_BLUE_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxLightBlue.name", "Light Blue Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("YELLOW_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxYellow.name", "Yellow Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("LIME_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxLime.name", "Lime Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("PINK_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxPink.name", "Pink Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("GRAY_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxGray.name", "Gray Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("SILVER_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxSilver.name", "Light Gray Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("CYAN_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxCyan.name", "Cyan Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("PURPLE_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxPurple.name", "Purple Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("BLUE_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxBlue.name", "Blue Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("BROWN_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxBrown.name", "Brown Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("GREEN_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxGreen.name", "Green Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("RED_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxRed.name", "Red Shulker Box")));
            itemNames.add(new ItemName(Material.valueOf("BLACK_SHULKER_BOX"), langConfig.getString("tile.shulkerBoxBlack.name", "Black Shulker Box")));
        }

        if (Utils.getMajorVersion() >= 12) {
            // Add Block Names of 1.12
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), langConfig.getString("tile.concrete.white.name", "White Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 1, langConfig.getString("tile.concrete.orange.name", "Orange Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 2, langConfig.getString("tile.concrete.magenta.name", "Magenta Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 3, langConfig.getString("tile.concrete.lightBlue.name", "Light Blue Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 4, langConfig.getString("tile.concrete.yellow.name", "Yellow Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 5, langConfig.getString("tile.concrete.lime.name", "Lime Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 6, langConfig.getString("tile.concrete.pink.name", "Pink Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 7, langConfig.getString("tile.concrete.gray.name", "Gray Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 8, langConfig.getString("tile.concrete.silver.name", "Light Gray Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 9, langConfig.getString("tile.concrete.cyan.name", "Cyan Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 10, langConfig.getString("tile.concrete.purple.name", "Purple Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 11, langConfig.getString("tile.concrete.blue.name", "Blue Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 12, langConfig.getString("tile.concrete.brown.name", "Brown Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 13, langConfig.getString("tile.concrete.green.name", "Green Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 14, langConfig.getString("tile.concrete.red.name", "Red Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE"), 15, langConfig.getString("tile.concrete.black.name", "Black Concrete")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), langConfig.getString("tile.concretePowder.white.name", "White Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 1, langConfig.getString("tile.concretePowder.orange.name", "Orange Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 2, langConfig.getString("tile.concretePowder.magenta.name", "Magenta Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 3, langConfig.getString("tile.concretePowder.lightBlue.name", "Light Blue Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 4, langConfig.getString("tile.concretePowder.yellow.name", "Yellow Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 5, langConfig.getString("tile.concretePowder.lime.name", "Lime Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 6, langConfig.getString("tile.concretePowder.pink.name", "Pink Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 7, langConfig.getString("tile.concretePowder.gray.name", "Gray Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 8, langConfig.getString("tile.concretePowder.silver.name", "Light Gray Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 9, langConfig.getString("tile.concretePowder.cyan.name", "Cyan Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 10, langConfig.getString("tile.concretePowder.purple.name", "Purple Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 11, langConfig.getString("tile.concretePowder.blue.name", "Blue Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 12, langConfig.getString("tile.concretePowder.brown.name", "Brown Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 13, langConfig.getString("tile.concretePowder.green.name", "Green Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 14, langConfig.getString("tile.concretePowder.red.name", "Red Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("CONCRETE_POWDER"), 15, langConfig.getString("tile.concretePowder.black.name", "Black Concrete Powder")));
            itemNames.add(new ItemName(Material.valueOf("WHITE_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaWhite.name", "White Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("ORANGE_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaOrange.name", "Orange Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("MAGENTA_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaMagenta.name", "Magenta Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("LIGHT_BLUE_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaLightBlue.name", "Light Blue Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("YELLOW_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaYellow.name", "Yellow Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("LIME_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaLime.name", "Lime Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("PINK_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaPink.name", "Pink Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("GRAY_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaGray.name", "Gray Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("SILVER_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaSilver.name", "Light Gray Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("CYAN_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaCyan.name", "Cyan Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("PURPLE_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaPurple.name", "Purple Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("BLUE_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaBlue.name", "Blue Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("BROWN_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaBrown.name", "Brown Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("GREEN_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaGreen.name", "Green Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("RED_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaRed.name", "Red Glazed Terracotta")));
            itemNames.add(new ItemName(Material.valueOf("BLACK_GLAZED_TERRACOTTA"), langConfig.getString("tile.glazedTerracottaBlack.name", "Black Glazed Terracotta")));
        }

        // Add Item Names
        itemNames.add(new ItemName(Material.valueOf("IRON_SPADE"), langConfig.getString("item.shovelIron.name", "Iron Shovel")));
        itemNames.add(new ItemName(Material.valueOf("IRON_PICKAXE"), langConfig.getString("item.pickaxeIron.name", "Iron Pickaxe")));
        itemNames.add(new ItemName(Material.valueOf("IRON_AXE"), langConfig.getString("item.hatchetIron.name", "Iron Axe")));
        itemNames.add(new ItemName(Material.valueOf("FLINT_AND_STEEL"), langConfig.getString("item.flintAndSteel.name", "Flint and Steel")));
        itemNames.add(new ItemName(Material.valueOf("APPLE"), langConfig.getString("item.apple.name", "Apple")));
        itemNames.add(new ItemName(Material.valueOf("BOW"), langConfig.getString("item.bow.name", "Bow")));
        itemNames.add(new ItemName(Material.valueOf("ARROW"), langConfig.getString("item.arrow.name", "Arrow")));
        itemNames.add(new ItemName(Material.valueOf("COAL"), langConfig.getString("item.coal.name", "Coal")));
        itemNames.add(new ItemName(Material.valueOf("COAL"), 1, langConfig.getString("item.charcoal.name", "Charcoal")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND"), langConfig.getString("item.diamond.name", "Diamond")));
        itemNames.add(new ItemName(Material.valueOf("IRON_INGOT"), langConfig.getString("item.ingotIron.name", "Iron Ingot")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_INGOT"), langConfig.getString("item.ingotGold.name", "Gold Ingot")));
        itemNames.add(new ItemName(Material.valueOf("IRON_SWORD"), langConfig.getString("item.swordIron.name", "Iron Sword")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_SWORD"), langConfig.getString("item.swordWood.name", "Wooden Sword")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_SPADE"), langConfig.getString("item.shovelWood.name", "Wooden Shovel")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_PICKAXE"), langConfig.getString("item.pickaxeWood.name", "Wooden Pickaxe")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_AXE"), langConfig.getString("item.hatchetWood.name", "Wooden Axe")));
        itemNames.add(new ItemName(Material.valueOf("STONE_SWORD"), langConfig.getString("item.swordStone.name", "Stone Sword")));
        itemNames.add(new ItemName(Material.valueOf("STONE_SPADE"), langConfig.getString("item.shovelStone.name", "Stone Shovel")));
        itemNames.add(new ItemName(Material.valueOf("STONE_PICKAXE"), langConfig.getString("item.pickaxeStone.name", "Stone Pickaxe")));
        itemNames.add(new ItemName(Material.valueOf("STONE_AXE"), langConfig.getString("item.hatchetStone.name", "Stone Axe")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_SWORD"), langConfig.getString("item.swordDiamond.name", "Diamond Sword")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_SPADE"), langConfig.getString("item.shovelDiamond.name", "Diamond Shovel")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_PICKAXE"), langConfig.getString("item.pickaxeDiamond.name", "Diamond Pickaxe")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_AXE"), langConfig.getString("item.hatchetDiamond.name", "Diamond Axe")));
        itemNames.add(new ItemName(Material.valueOf("STICK"), langConfig.getString("item.stick.name", "Stick")));
        itemNames.add(new ItemName(Material.valueOf("BOWL"), langConfig.getString("item.bowl.name", "Bowl")));
        itemNames.add(new ItemName(Material.valueOf("MUSHROOM_SOUP"), langConfig.getString("item.mushroomStew.name", "Mushroom Stew")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_SWORD"), langConfig.getString("item.swordGold.name", "Golden Sword")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_SPADE"), langConfig.getString("item.shovelGold.name", "Golden Shovel")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_PICKAXE"), langConfig.getString("item.pickaxeGold.name", "Golden Pickaxe")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_AXE"), langConfig.getString("item.hatchetGold.name", "Golden Axe")));
        itemNames.add(new ItemName(Material.valueOf("STRING"), langConfig.getString("item.string.name", "String")));
        itemNames.add(new ItemName(Material.valueOf("FEATHER"), langConfig.getString("item.feather.name", "Feather")));
        itemNames.add(new ItemName(Material.valueOf("SULPHUR"), langConfig.getString("item.sulphur.name", "Gunpowder")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_HOE"), langConfig.getString("item.hoeWood.name", "Wooden Hoe")));
        itemNames.add(new ItemName(Material.valueOf("STONE_HOE"), langConfig.getString("item.hoeStone.name", "Stone Hoe")));
        itemNames.add(new ItemName(Material.valueOf("IRON_HOE"), langConfig.getString("item.hoeIron.name", "Iron Hoe")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_HOE"), langConfig.getString("item.hoeDiamond.name", "Diamond Hoe")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_HOE"), langConfig.getString("item.hoeGold.name", "Golden Hoe")));
        itemNames.add(new ItemName(Material.valueOf("SEEDS"), langConfig.getString("item.seeds.name", "Seeds")));
        itemNames.add(new ItemName(Material.valueOf("WHEAT"), langConfig.getString("item.wheat.name", "Wheat")));
        itemNames.add(new ItemName(Material.valueOf("BREAD"), langConfig.getString("item.bread.name", "Bread")));
        itemNames.add(new ItemName(Material.valueOf("LEATHER_HELMET"), langConfig.getString("item.helmetCloth.name", "Leather Cap")));
        itemNames.add(new ItemName(Material.valueOf("LEATHER_CHESTPLATE"), langConfig.getString("item.chestplateCloth.name", "Leather Tunic")));
        itemNames.add(new ItemName(Material.valueOf("LEATHER_LEGGINGS"), langConfig.getString("item.leggingsCloth.name", "Leather Pants")));
        itemNames.add(new ItemName(Material.valueOf("LEATHER_BOOTS"), langConfig.getString("item.bootsCloth.name", "Leather Boots")));
        itemNames.add(new ItemName(Material.valueOf("CHAINMAIL_HELMET"), langConfig.getString("item.helmetChain.name", "Chain Helmet")));
        itemNames.add(new ItemName(Material.valueOf("CHAINMAIL_CHESTPLATE"), langConfig.getString("item.chestplateChain.name", "Chain Chestplate")));
        itemNames.add(new ItemName(Material.valueOf("CHAINMAIL_LEGGINGS"), langConfig.getString("item.leggingsChain.name", "Chain Leggings")));
        itemNames.add(new ItemName(Material.valueOf("CHAINMAIL_BOOTS"), langConfig.getString("item.bootsChain.name", "Chain Boots")));
        itemNames.add(new ItemName(Material.valueOf("IRON_HELMET"), langConfig.getString("item.helmetIron.name", "Iron Helmet")));
        itemNames.add(new ItemName(Material.valueOf("IRON_CHESTPLATE"), langConfig.getString("item.chestplateIron.name", "Iron Chestplate")));
        itemNames.add(new ItemName(Material.valueOf("IRON_LEGGINGS"), langConfig.getString("item.leggingsIron.name", "Iron Leggings")));
        itemNames.add(new ItemName(Material.valueOf("IRON_BOOTS"), langConfig.getString("item.bootsIron.name", "Iron Boots")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_HELMET"), langConfig.getString("item.helmetDiamond.name", "Diamond Helmet")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_CHESTPLATE"), langConfig.getString("item.chestplateDiamond.name", "Diamond Chestplate")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_LEGGINGS"), langConfig.getString("item.leggingsDiamond.name", "Diamond Leggings")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_BOOTS"), langConfig.getString("item.bootsDiamond.name", "Diamond Boots")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_HELMET"), langConfig.getString("item.helmetGold.name", "Golden Helmet")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_CHESTPLATE"), langConfig.getString("item.chestplateGold.name", "Golden Chestplate")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_LEGGINGS"), langConfig.getString("item.leggingsGold.name", "Golden Leggings")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_BOOTS"), langConfig.getString("item.bootsGold.name", "Golden Boots")));
        itemNames.add(new ItemName(Material.valueOf("FLINT"), langConfig.getString("item.flint.name", "Flint")));
        itemNames.add(new ItemName(Material.valueOf("PORK"), langConfig.getString("item.porkchopRaw.name", "Raw Porkchop")));
        itemNames.add(new ItemName(Material.valueOf("GRILLED_PORK"), langConfig.getString("item.porkchopCooked.name", "Cooked Porkchop")));
        itemNames.add(new ItemName(Material.valueOf("PAINTING"), langConfig.getString("item.painting.name", "Painting")));
        itemNames.add(new ItemName(Material.valueOf("GOLDEN_APPLE"), langConfig.getString("item.appleGold.name", "Golden Apple")));
        itemNames.add(new ItemName(Material.valueOf("GOLDEN_APPLE"), 1, langConfig.getString("item.appleGold.name", "Golden Apple")));
        itemNames.add(new ItemName(Material.valueOf("SIGN"), langConfig.getString("item.sign.name", "Sign")));
        itemNames.add(new ItemName(Material.valueOf("WOOD_DOOR"), langConfig.getString("item.doorOak.name", "Oak Door")));
        itemNames.add(new ItemName(Material.valueOf("BUCKET"), langConfig.getString("item.bucket.name", "Bucket")));
        itemNames.add(new ItemName(Material.valueOf("WATER_BUCKET"), langConfig.getString("item.bucketWater.name", "Water Bucket")));
        itemNames.add(new ItemName(Material.valueOf("LAVA_BUCKET"), langConfig.getString("item.bucketLava.name", "Lava Bucket")));
        itemNames.add(new ItemName(Material.valueOf("MINECART"), langConfig.getString("item.minecart.name", "Minecart")));
        itemNames.add(new ItemName(Material.valueOf("SADDLE"), langConfig.getString("item.saddle.name", "Saddle")));
        itemNames.add(new ItemName(Material.valueOf("IRON_DOOR"), langConfig.getString("item.doorIron.name", "Iron Door")));
        itemNames.add(new ItemName(Material.valueOf("REDSTONE"), langConfig.getString("item.redstone.name", "Redstone")));
        itemNames.add(new ItemName(Material.valueOf("SNOW_BALL"), langConfig.getString("item.snowball.name", "Snowball")));
        itemNames.add(new ItemName(Material.valueOf("BOAT"), langConfig.getString("item.boat.oak.name", "Oak Boat")));
        itemNames.add(new ItemName(Material.valueOf("LEATHER"), langConfig.getString("item.leather.name", "Leather")));
        itemNames.add(new ItemName(Material.valueOf("MILK_BUCKET"), langConfig.getString("item.milk.name", "Milk")));
        itemNames.add(new ItemName(Material.valueOf("BRICK"), langConfig.getString("item.brick.name", "Brick")));
        itemNames.add(new ItemName(Material.valueOf("CLAY_BALL"), langConfig.getString("item.clay.name", "Clay")));
        itemNames.add(new ItemName(Material.valueOf("SUGAR_CANE"), langConfig.getString("item.reeds.name", "Sugar Canes")));
        itemNames.add(new ItemName(Material.valueOf("PAPER"), langConfig.getString("item.paper.name", "Paper")));
        itemNames.add(new ItemName(Material.valueOf("BOOK"), langConfig.getString("item.book.name", "Book")));
        itemNames.add(new ItemName(Material.valueOf("SLIME_BALL"), langConfig.getString("item.slimeball.name", "Slimeball")));
        itemNames.add(new ItemName(Material.valueOf("STORAGE_MINECART"), langConfig.getString("item.minecartChest.name", "Minecart with Chest")));
        itemNames.add(new ItemName(Material.valueOf("POWERED_MINECART"), langConfig.getString("item.minecartFurnace.name", "Minecart with Furnace")));
        itemNames.add(new ItemName(Material.valueOf("EGG"), langConfig.getString("item.egg.name", "Egg")));
        itemNames.add(new ItemName(Material.valueOf("COMPASS"), langConfig.getString("item.compass.name", "Compass")));
        itemNames.add(new ItemName(Material.valueOf("FISHING_ROD"), langConfig.getString("item.fishingRod.name", "Fishing Rod")));
        itemNames.add(new ItemName(Material.valueOf("WATCH"), langConfig.getString("item.clock.name", "Clock")));
        itemNames.add(new ItemName(Material.valueOf("GLOWSTONE_DUST"), langConfig.getString("item.yellowDust.name", "Glowstone Dust")));
        itemNames.add(new ItemName(Material.valueOf("RAW_FISH"), langConfig.getString("item.fish.cod.raw.name", "Raw Fish")));
        itemNames.add(new ItemName(Material.valueOf("RAW_FISH"), 1, langConfig.getString("item.fish.salmon.raw.name", "Raw Salmon")));
        itemNames.add(new ItemName(Material.valueOf("RAW_FISH"), 2, langConfig.getString("item.fish.clownfish.raw.name", "Clownfish")));
        itemNames.add(new ItemName(Material.valueOf("RAW_FISH"), 3, langConfig.getString("item.fish.pufferfish.raw.name", "Pufferfish")));
        itemNames.add(new ItemName(Material.valueOf("COOKED_FISH"), langConfig.getString("item.fish.cod.cooked.name", "Cooked Fish")));
        itemNames.add(new ItemName(Material.valueOf("COOKED_FISH"), 1, langConfig.getString("item.fish.salmon.cooked.name", "Cooked Salmon")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), langConfig.getString("item.dyePowder.black.name", "Ink Sac")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 1, langConfig.getString("item.dyePowder.red.name", "Rose Red")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 2, langConfig.getString("item.dyePowder.green.name", "Cactus Green")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 3, langConfig.getString("item.dyePowder.brown.name", "Cocoa Beans")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 4, langConfig.getString("item.dyePowder.blue.name", "Lapis Lazuli")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 5, langConfig.getString("item.dyePowder.purple.name", "Purple Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 6, langConfig.getString("item.dyePowder.cyan.name", "Cyan Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 7, langConfig.getString("item.dyePowder.silver.name", "Light Gray Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 8, langConfig.getString("item.dyePowder.gray.name", "Gray Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 9, langConfig.getString("item.dyePowder.pink.name", "Pink Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 10, langConfig.getString("item.dyePowder.lime.name", "Lime Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 11, langConfig.getString("item.dyePowder.yellow.name", "Dandelion Yellow")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 12, langConfig.getString("item.dyePowder.lightBlue.name", "Light Blue Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 13, langConfig.getString("item.dyePowder.magenta.name", "Magenta Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 14, langConfig.getString("item.dyePowder.orange.name", "Orange Dye")));
        itemNames.add(new ItemName(Material.valueOf("INK_SACK"), 15, langConfig.getString("item.dyePowder.white.name", "Bone Meal")));
        itemNames.add(new ItemName(Material.valueOf("BONE"), langConfig.getString("item.bone.name", "Bone")));
        itemNames.add(new ItemName(Material.valueOf("SUGAR"), langConfig.getString("item.sugar.name", "Sugar")));
        itemNames.add(new ItemName(Material.valueOf("CAKE"), langConfig.getString("item.cake.name", "Cake")));
        itemNames.add(new ItemName(Material.valueOf("DIODE"), langConfig.getString("item.diode.name", "Redstone Repeater")));
        itemNames.add(new ItemName(Material.valueOf("COOKIE"), langConfig.getString("item.cookie.name", "Cookie")));
        itemNames.add(new ItemName(Material.valueOf("MAP"), langConfig.getString("item.map.name", "Map")));
        itemNames.add(new ItemName(Material.valueOf("SHEARS"), langConfig.getString("item.shears.name", "Shears")));
        itemNames.add(new ItemName(Material.valueOf("MELON"), langConfig.getString("item.melon.name", "Melon")));
        itemNames.add(new ItemName(Material.valueOf("PUMPKIN_SEEDS"), langConfig.getString("item.seeds_pumpkin.name", "Pumpkin Seeds")));
        itemNames.add(new ItemName(Material.valueOf("MELON_SEEDS"), langConfig.getString("item.seeds_melon.name", "Melon Seeds")));
        itemNames.add(new ItemName(Material.valueOf("RAW_BEEF"), langConfig.getString("item.beefRaw.name", "Raw Beef")));
        itemNames.add(new ItemName(Material.valueOf("COOKED_BEEF"), langConfig.getString("item.beefCooked.name", "Steak")));
        itemNames.add(new ItemName(Material.valueOf("RAW_CHICKEN"), langConfig.getString("item.chickenRaw.name", "Raw Chicken")));
        itemNames.add(new ItemName(Material.valueOf("COOKED_CHICKEN"), langConfig.getString("item.chickenCooked.name", "Cooked Chicken")));
        itemNames.add(new ItemName(Material.valueOf("ROTTEN_FLESH"), langConfig.getString("item.rottenFlesh.name", "Rotten Flesh")));
        itemNames.add(new ItemName(Material.valueOf("ENDER_PEARL"), langConfig.getString("item.enderPearl.name", "Ender Pearl")));
        itemNames.add(new ItemName(Material.valueOf("BLAZE_ROD"), langConfig.getString("item.blazeRod.name", "Blaze Rod")));
        itemNames.add(new ItemName(Material.valueOf("GHAST_TEAR"), langConfig.getString("item.ghastTear.name", "Ghast Tear")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_NUGGET"), langConfig.getString("item.goldNugget.name", "Gold Nugget")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_WARTS"), langConfig.getString("item.netherStalkSeeds.name", "Nether Wart")));
        itemNames.add(new ItemName(Material.valueOf("POTION"), langConfig.getString("item.potion.name", "Potion")));
        itemNames.add(new ItemName(Material.valueOf("GLASS_BOTTLE"), langConfig.getString("item.glassBottle.name", "Glass Bottle")));
        itemNames.add(new ItemName(Material.valueOf("SPIDER_EYE"), langConfig.getString("item.spiderEye.name", "Spider Eye")));
        itemNames.add(new ItemName(Material.valueOf("FERMENTED_SPIDER_EYE"), langConfig.getString("item.fermentedSpiderEye.name", "Fermented Spider Eye")));
        itemNames.add(new ItemName(Material.valueOf("BLAZE_POWDER"), langConfig.getString("item.blazePowder.name", "Blaze Powder")));
        itemNames.add(new ItemName(Material.valueOf("MAGMA_CREAM"), langConfig.getString("item.magmaCream.name", "Magma Cream")));
        itemNames.add(new ItemName(Material.valueOf("BREWING_STAND_ITEM"), langConfig.getString("item.brewingStand.name", "Brewing Stand")));
        itemNames.add(new ItemName(Material.valueOf("CAULDRON_ITEM"), langConfig.getString("item.cauldron.name", "Cauldron")));
        itemNames.add(new ItemName(Material.valueOf("EYE_OF_ENDER"), langConfig.getString("item.eyeOfEnder.name", "Eye of Ender")));
        itemNames.add(new ItemName(Material.valueOf("SPECKLED_MELON"), langConfig.getString("item.speckledMelon.name", "Glistering Melon")));
        itemNames.add(new ItemName(Material.valueOf("MONSTER_EGG"), langConfig.getString("item.monsterPlacer.name", "Spawn")));
        itemNames.add(new ItemName(Material.valueOf("EXP_BOTTLE"), langConfig.getString("item.expBottle.name", "Bottle o' Enchanting")));
        itemNames.add(new ItemName(Material.valueOf("FIREWORK_CHARGE"), langConfig.getString("item.fireball.name", "Fire Charge")));
        itemNames.add(new ItemName(Material.valueOf("BOOK_AND_QUILL"), langConfig.getString("item.writingBook.name", "Book and Quill")));
        itemNames.add(new ItemName(Material.valueOf("WRITTEN_BOOK"), langConfig.getString("item.writtenBook.name", "Written Book")));
        itemNames.add(new ItemName(Material.valueOf("EMERALD"), langConfig.getString("item.emerald.name", "Emerald")));
        itemNames.add(new ItemName(Material.valueOf("ITEM_FRAME"), langConfig.getString("item.frame.name", "Item Frame")));
        itemNames.add(new ItemName(Material.valueOf("FLOWER_POT_ITEM"), langConfig.getString("item.flowerPot.name", "Flower Pot")));
        itemNames.add(new ItemName(Material.valueOf("CARROT_ITEM"), langConfig.getString("item.carrots.name", "Carrot")));
        itemNames.add(new ItemName(Material.valueOf("POTATO_ITEM"), langConfig.getString("item.potato.name", "Potato")));
        itemNames.add(new ItemName(Material.valueOf("BAKED_POTATO"), langConfig.getString("item.potatoBaked.name", "Baked Potato")));
        itemNames.add(new ItemName(Material.valueOf("POISONOUS_POTATO"), langConfig.getString("item.potatoPoisonous.name", "Poisonous Potato")));
        itemNames.add(new ItemName(Material.valueOf("EMPTY_MAP"), langConfig.getString("item.emptyMap.name", "Empty Map")));
        itemNames.add(new ItemName(Material.valueOf("GOLDEN_CARROT"), langConfig.getString("item.carrotGolden.name", "Golden Carrot")));
        itemNames.add(new ItemName(Material.valueOf("SKULL_ITEM"), langConfig.getString("item.skull.skeleton.name", "Skeleton Skull")));
        itemNames.add(new ItemName(Material.valueOf("SKULL_ITEM"), 1, langConfig.getString("item.skull.wither.name", "Wither Skeleton Skull")));
        itemNames.add(new ItemName(Material.valueOf("SKULL_ITEM"), 2, langConfig.getString("item.skull.zombie.name", "Zombie Head")));
        itemNames.add(new ItemName(Material.valueOf("SKULL_ITEM"), 3, langConfig.getString("item.skull.char.name", "Head")));
        itemNames.add(new ItemName(Material.valueOf("SKULL_ITEM"), 4, langConfig.getString("item.skull.creeper.name", "Creeper Head")));
        itemNames.add(new ItemName(Material.valueOf("SKULL_ITEM"), 5, langConfig.getString("item.skull.dragon.name", "Creeper Head")));
        itemNames.add(new ItemName(Material.valueOf("CARROT_STICK"), langConfig.getString("item.carrotOnAStick.name", "Carrot on a Stick")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_STAR"), langConfig.getString("item.netherStar.name", "Nether Star")));
        itemNames.add(new ItemName(Material.valueOf("PUMPKIN_PIE"), langConfig.getString("item.pumpkinPie.name", "Pumpkin Pie")));
        itemNames.add(new ItemName(Material.valueOf("FIREWORK"), langConfig.getString("item.fireworks.name", "Firework Rocket")));
        itemNames.add(new ItemName(Material.valueOf("FIREWORK_CHARGE"), langConfig.getString("item.fireworksCharge.name", "Firework Star")));
        itemNames.add(new ItemName(Material.valueOf("ENCHANTED_BOOK"), langConfig.getString("item.enchantedBook.name", "Enchanted Book")));
        itemNames.add(new ItemName(Material.valueOf("REDSTONE_COMPARATOR"), langConfig.getString("item.comparator.name", "Redstone Comparator")));
        itemNames.add(new ItemName(Material.valueOf("NETHER_BRICK_ITEM"), langConfig.getString("item.netherbrick.name", "Nether Brick")));
        itemNames.add(new ItemName(Material.valueOf("QUARTZ"), langConfig.getString("item.netherquartz.name", "Nether Quartz")));
        itemNames.add(new ItemName(Material.valueOf("EXPLOSIVE_MINECART"), langConfig.getString("item.minecartTnt.name", "Minecart with TNT")));
        itemNames.add(new ItemName(Material.valueOf("HOPPER_MINECART"), langConfig.getString("item.minecartHopper.name", "Minecart with Hopper")));
        itemNames.add(new ItemName(Material.valueOf("PRISMARINE_SHARD"), langConfig.getString("item.prismarineShard.name", "Prismarine Shard")));
        itemNames.add(new ItemName(Material.valueOf("PRISMARINE_CRYSTALS"), langConfig.getString("item.prismarineCrystals.name", "Prismarine Crystals")));
        itemNames.add(new ItemName(Material.valueOf("RABBIT"), langConfig.getString("item.rabbitRaw.name", "Raw Rabbit")));
        itemNames.add(new ItemName(Material.valueOf("COOKED_RABBIT"), langConfig.getString("item.rabbitCooked.name", "Cooked Rabbit")));
        itemNames.add(new ItemName(Material.valueOf("RABBIT_STEW"), langConfig.getString("item.rabbitStew.name", "Rabbit Stew")));
        itemNames.add(new ItemName(Material.valueOf("RABBIT_FOOT"), langConfig.getString("item.rabbitFoot.name", "Rabbit's Foot")));
        itemNames.add(new ItemName(Material.valueOf("RABBIT_HIDE"), langConfig.getString("item.rabbitHide.name", "Rabbit Hide")));
        itemNames.add(new ItemName(Material.valueOf("ARMOR_STAND"), langConfig.getString("item.armorStand.name", "Armor Stand")));
        itemNames.add(new ItemName(Material.valueOf("IRON_BARDING"), langConfig.getString("item.horsearmormetal.name", "Iron Horse Armor")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_BARDING"), langConfig.getString("item.horsearmorgold.name", "Gold Horse Armor")));
        itemNames.add(new ItemName(Material.valueOf("DIAMOND_BARDING"), langConfig.getString("item.horsearmordiamond.name", "Diamond Horse Armor")));
        itemNames.add(new ItemName(Material.valueOf("LEASH"), langConfig.getString("item.leash.name", "Lead")));
        itemNames.add(new ItemName(Material.valueOf("NAME_TAG"), langConfig.getString("item.nameTag.name", "Name Tag")));
        itemNames.add(new ItemName(Material.valueOf("COMMAND_MINECART"), langConfig.getString("item.minecartCommandBlock.name", "Minecart with Command Block")));
        itemNames.add(new ItemName(Material.valueOf("MUTTON"), langConfig.getString("item.muttonRaw.name", "Raw Mutton")));
        itemNames.add(new ItemName(Material.valueOf("COOKED_MUTTON"), langConfig.getString("item.muttonCooked.name", "Cooked Mutton")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), langConfig.getString("item.banner.black.name", "Black Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 1, langConfig.getString("item.banner.red.name", "Red Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 2, langConfig.getString("item.banner.green.name", "Green Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 3, langConfig.getString("item.banner.brown.name", "Brown Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 4, langConfig.getString("item.banner.blue.name", "Blue Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 5, langConfig.getString("item.banner.purple.name", "Purple Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 6, langConfig.getString("item.banner.cyan.name", "Cyan Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 7, langConfig.getString("item.banner.silver.name", "Light Gray Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 8, langConfig.getString("item.banner.gray.name", "Gray Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 9, langConfig.getString("item.banner.pink.name", "Pink Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 10, langConfig.getString("item.banner.lime.name", "Lime Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 11, langConfig.getString("item.banner.yellow.name", "Yellow Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 12, langConfig.getString("item.banner.lightBlue.name", "Light Blue Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 13, langConfig.getString("item.banner.magenta.name", "Magenta Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 14, langConfig.getString("item.banner.orange.name", "Orange Banner")));
        itemNames.add(new ItemName(Material.valueOf("BANNER"), 15, langConfig.getString("item.banner.white.name", "White Banner")));
        itemNames.add(new ItemName(Material.valueOf("SPRUCE_DOOR_ITEM"), langConfig.getString("item.doorSpruce.name", "Spruce Door")));
        itemNames.add(new ItemName(Material.valueOf("BIRCH_DOOR_ITEM"), langConfig.getString("item.doorBirch.name", "Birch Door")));
        itemNames.add(new ItemName(Material.valueOf("JUNGLE_DOOR_ITEM"), langConfig.getString("item.doorJungle.name", "Jungle Door")));
        itemNames.add(new ItemName(Material.valueOf("ACACIA_DOOR_ITEM"), langConfig.getString("item.doorAcacia.name", "Acacia Door")));
        itemNames.add(new ItemName(Material.valueOf("DARK_OAK_DOOR_ITEM"), langConfig.getString("item.doorDarkOak.name", "Dark Oak Door")));
        itemNames.add(new ItemName(Material.valueOf("GOLD_RECORD"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("GREEN_RECORD"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_3"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_4"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_5"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_6"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_7"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_8"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_9"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_10"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_11"), langConfig.getString("item.record.name", "Music Disc")));
        itemNames.add(new ItemName(Material.valueOf("RECORD_12"), langConfig.getString("item.record.name", "Music Disc")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Item names of 1.9
            itemNames.add(new ItemName(Material.valueOf("END_CRYSTAL"), langConfig.getString("item.end_crystal.name", "End Crystal")));
            itemNames.add(new ItemName(Material.valueOf("CHORUS_FRUIT"), langConfig.getString("item.chorusFruit.name", "Chorus Fruit")));
            itemNames.add(new ItemName(Material.valueOf("CHORUS_FRUIT_POPPED"), langConfig.getString("item.chorusFruitPopped.name", "Popped Chorus Fruit")));
            itemNames.add(new ItemName(Material.valueOf("BEETROOT"), langConfig.getString("item.beetroot.name", "Beetroot")));
            itemNames.add(new ItemName(Material.valueOf("BEETROOT_SEEDS"), langConfig.getString("item.beetroot_seeds.name", "Beetroot Seeds")));
            itemNames.add(new ItemName(Material.valueOf("BEETROOT_SOUP"), langConfig.getString("item.beetroot_soup.name", "Beetroot Soup")));
            itemNames.add(new ItemName(Material.valueOf("DRAGONS_BREATH"), langConfig.getString("item.dragon_breath.name", "Dragon's Breath")));
            itemNames.add(new ItemName(Material.valueOf("SPECTRAL_ARROW"), langConfig.getString("item.spectral_arrow.name", "Spectral Arrow")));
            itemNames.add(new ItemName(Material.valueOf("TIPPED_ARROW"), langConfig.getString("item.tipped_arrow.name", "Tipped Arrow")));
            itemNames.add(new ItemName(Material.valueOf("SHIELD"), langConfig.getString("item.shield.name", "Shield")));
            itemNames.add(new ItemName(Material.valueOf("ELYTRA"), langConfig.getString("item.elytra.name", "Elytra")));
            itemNames.add(new ItemName(Material.valueOf("BOAT_SPRUCE"), langConfig.getString("item.boat.spruce.name", "Spruce Boat")));
            itemNames.add(new ItemName(Material.valueOf("BOAT_BIRCH"), langConfig.getString("item.boat.birch.name", "Birch Boat")));
            itemNames.add(new ItemName(Material.valueOf("BOAT_JUNGLE"), langConfig.getString("item.boat.jungle.name", "Jungle Boat")));
            itemNames.add(new ItemName(Material.valueOf("BOAT_ACACIA"), langConfig.getString("item.boat.acacia.name", "Acacia Boat")));
            itemNames.add(new ItemName(Material.valueOf("BOAT_DARK_OAK"), langConfig.getString("item.boat.dark_oak.name", "Dark Oak Boat")));
        }

        if (Utils.getMajorVersion() >= 11) {
            // Add Item Names of 1.11
            itemNames.add(new ItemName(Material.valueOf("TOTEM"), langConfig.getString("item.totem.name", "Totem of Undying")));
            itemNames.add(new ItemName(Material.valueOf("SHULKER_SHELL"), langConfig.getString("item.shulkerShell.name", "Shulker Shell")));

            if (Utils.getRevision() >= 2 || Utils.getMajorVersion() > 11) {
                // Add Item Name of 1.11.2
                itemNames.add(new ItemName(Material.valueOf("IRON_NUGGET"), langConfig.getString("item.ironNugget.name", "Iron Nugget")));
            }
        }

        if (Utils.getMajorVersion() >= 12) {
            // Add Item Name of 1.12
            itemNames.add(new ItemName(Material.valueOf("KNOWLEDGE_BOOK"), langConfig.getString("item.knowledgeBook.name", "Knowledge Book")));
            itemNames.add(new ItemName(Material.valueOf("BED"), langConfig.getString("item.bed.white.name", "White Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 1, langConfig.getString("item.bed.orange.name", "Orange Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 2, langConfig.getString("item.bed.magenta.name", "Magenta Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 3, langConfig.getString("item.bed.lightBlue.name", "Light Blue Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 4, langConfig.getString("item.bed.yellow.name", "Yellow Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 5, langConfig.getString("item.bed.lime.name", "Lime Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 6, langConfig.getString("item.bed.pink.name", "Pink Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 7, langConfig.getString("item.bed.gray.name", "Gray Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 8, langConfig.getString("item.bed.silver.name", "Light Gray Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 9, langConfig.getString("item.bed.cyan.name", "Cyan Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 10, langConfig.getString("item.bed.purple.name", "Purple Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 11, langConfig.getString("item.bed.blue.name", "Blue Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 12, langConfig.getString("item.bed.brown.name", "Brown Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 13, langConfig.getString("item.bed.green.name", "Green Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 14, langConfig.getString("item.bed.red.name", "Red Bed")));
            itemNames.add(new ItemName(Material.valueOf("BED"), 15, langConfig.getString("item.bed.black.name", "Black Bed")));
        } else {
            // Before 1.12, bed is just called "Bed" without colors
            itemNames.add(new ItemName(Material.valueOf("BED"), langConfig.getString("item.bed.name", "Bed")));
        }

        // Add Enchantment Names
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_DAMAGE, langConfig.getString("enchantment.arrowDamage", "Power")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_FIRE, langConfig.getString("enchantment.arrowFire", "Flame")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_INFINITE, langConfig.getString("enchantment.arrowInfinite", "Infinity")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_KNOCKBACK, langConfig.getString("enchantment.arrowKnockback", "Punch")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DAMAGE_ALL, langConfig.getString("enchantment.damage.all", "Sharpness")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DAMAGE_ARTHROPODS, langConfig.getString("enchantment.damage.arthropods", "Bane of Arthropods")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DAMAGE_UNDEAD, langConfig.getString("enchantment.damage.undead", "Smite")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DIG_SPEED, langConfig.getString("enchantment.digging", "Efficiency")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DURABILITY, langConfig.getString("enchantment.durability", "Unbreaking")));
        enchantmentNames.add(new EnchantmentName(Enchantment.FIRE_ASPECT, langConfig.getString("enchantment.fire", "Fire Aspect")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LURE, langConfig.getString("enchantment.fishingSpeed", "Lure")));
        enchantmentNames.add(new EnchantmentName(Enchantment.KNOCKBACK, langConfig.getString("enchantment.knockback", "Knockback")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LOOT_BONUS_MOBS, langConfig.getString("enchantment.lootBonus", "Looting")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LOOT_BONUS_BLOCKS, langConfig.getString("enchantment.lootBonusDigger", "Fortune")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LUCK, langConfig.getString("enchantment.lootBonusFishing", "Luck of the Sea")));
        enchantmentNames.add(new EnchantmentName(Enchantment.OXYGEN, langConfig.getString("enchantment.oxygen", "Respiration")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_ENVIRONMENTAL, langConfig.getString("enchantment.protect.all", "Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_EXPLOSIONS, langConfig.getString("enchantment.protect.explosion", "Blast Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_FALL, langConfig.getString("enchantment.protect.fall", "Feather Falling")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_FIRE, langConfig.getString("enchantment.protect.fire", "Fire Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_PROJECTILE, langConfig.getString("enchantment.protect.projectile", "Projectile Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.THORNS, langConfig.getString("enchantment.thorns", "Thorns")));
        enchantmentNames.add(new EnchantmentName(Enchantment.SILK_TOUCH, langConfig.getString("enchantment.untouching", "Silk Touch")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DEPTH_STRIDER, langConfig.getString("enchantment.waterWalker", "Depth Strider")));
        enchantmentNames.add(new EnchantmentName(Enchantment.WATER_WORKER, langConfig.getString("enchantment.waterWorker", "Aqua Affinity")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Enchantment Names of 1.9
            enchantmentNames.add(new EnchantmentName(Enchantment.FROST_WALKER, langConfig.getString("enchantment.frostWalker", "Frost Walker")));
            enchantmentNames.add(new EnchantmentName(Enchantment.MENDING, langConfig.getString("enchantment.mending", "Mending")));
        }

        if (Utils.getMajorVersion() >= 11) {
            // Add Enchantment Names of 1.11
            enchantmentNames.add(new EnchantmentName(Enchantment.BINDING_CURSE, langConfig.getString("enchantment.binding_curse", "Curse of Binding")));
            enchantmentNames.add(new EnchantmentName(Enchantment.VANISHING_CURSE, langConfig.getString("enchantment.vanishing_curse", "Curse of Vanishing")));

            if (Utils.getRevision() >= 2 || Utils.getMajorVersion() > 11) {
                // Add Enchantment Name of 1.11.2
                enchantmentNames.add(new EnchantmentName(Enchantment.SWEEPING_EDGE, langConfig.getString("enchantment.sweeping", "Sweeping Edge")));
            }
        }

        // Add Enchantment Level Names
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(1, langConfig.getString("enchantment.level.1", "I")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(2, langConfig.getString("enchantment.level.2", "II")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(3, langConfig.getString("enchantment.level.3", "II")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(4, langConfig.getString("enchantment.level.4", "IV")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(5, langConfig.getString("enchantment.level.5", "V")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(6, langConfig.getString("enchantment.level.6", "VI")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(7, langConfig.getString("enchantment.level.7", "VII")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(8, langConfig.getString("enchantment.level.8", "VIII")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(9, langConfig.getString("enchantment.level.9", "IX")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(10, langConfig.getString("enchantment.level.10", "X")));

        // Add Entity Names
        String horseName = (Utils.getMajorVersion() >= 11 ? "entity.Horse.name" : "entity.EntityHorse.name");
        entityNames.add(new EntityName(EntityType.CREEPER, langConfig.getString("entity.Creeper.name", "Creeper")));
        entityNames.add(new EntityName(EntityType.SKELETON, langConfig.getString("entity.Skeleton.name", "Skeleton")));
        entityNames.add(new EntityName(EntityType.SPIDER, langConfig.getString("entity.Spider.name", "Spider")));
        entityNames.add(new EntityName(EntityType.ZOMBIE, langConfig.getString("entity.Zombie.name", "Zombie")));
        entityNames.add(new EntityName(EntityType.SLIME, langConfig.getString("entity.Slime.name", "Slime")));
        entityNames.add(new EntityName(EntityType.GHAST, langConfig.getString("entity.Ghast.name", "Ghast")));
        entityNames.add(new EntityName(EntityType.valueOf("PIG_ZOMBIE"), langConfig.getString("entity.PigZombie.name", "Zombie Pigman")));
        entityNames.add(new EntityName(EntityType.ENDERMAN, langConfig.getString("entity.Enderman.name", "Enderman")));
        entityNames.add(new EntityName(EntityType.CAVE_SPIDER, langConfig.getString("entity.CaveSpider.name", "Cave Spider")));
        entityNames.add(new EntityName(EntityType.SILVERFISH, langConfig.getString("entity.Silverfish.name", "Silverfish")));
        entityNames.add(new EntityName(EntityType.BLAZE, langConfig.getString("entity.Blaze.name", "Blaze")));
        entityNames.add(new EntityName(EntityType.MAGMA_CUBE, langConfig.getString("entity.LavaSlime.name", "Magma Cube")));
        entityNames.add(new EntityName(EntityType.BAT, langConfig.getString("entity.Bat.name", "Bat")));
        entityNames.add(new EntityName(EntityType.WITCH, langConfig.getString("entity.Witch.name", "Witch")));
        entityNames.add(new EntityName(EntityType.ENDERMITE, langConfig.getString("entity.Endermite.name", "Endermite")));
        entityNames.add(new EntityName(EntityType.GUARDIAN, langConfig.getString("entity.Guardian.name", "Guardian")));
        entityNames.add(new EntityName(EntityType.PIG, langConfig.getString("entity.Pig.name", "Pig")));
        entityNames.add(new EntityName(EntityType.SHEEP, langConfig.getString("entity.Sheep.name", "Sheep")));
        entityNames.add(new EntityName(EntityType.COW, langConfig.getString("entity.Cow.name", "Cow")));
        entityNames.add(new EntityName(EntityType.CHICKEN, langConfig.getString("entity.Chicken.name", "Chicken")));
        entityNames.add(new EntityName(EntityType.SQUID, langConfig.getString("entity.Squid.name", "Squid")));
        entityNames.add(new EntityName(EntityType.WOLF, langConfig.getString("entity.Wolf.name", "Wolf")));
        entityNames.add(new EntityName(EntityType.MUSHROOM_COW, langConfig.getString("entity.MushroomCow.name", "Mooshroom")));
        entityNames.add(new EntityName(EntityType.OCELOT, langConfig.getString("entity.Ozelot.name", "Ocelot")));
        entityNames.add(new EntityName(EntityType.HORSE, langConfig.getString(horseName, "Horse")));
        entityNames.add(new EntityName(EntityType.RABBIT, langConfig.getString("entity.Rabbit.name", "Rabbit")));
        entityNames.add(new EntityName(EntityType.VILLAGER, langConfig.getString("entity.Villager.name", "Villager")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Entity Names of 1.9
            entityNames.add(new EntityName(EntityType.SHULKER, langConfig.getString("entity.Shulker.name", "Shulker")));
        }

        if (Utils.getMajorVersion() >= 10) {
            // Add Entity Names of 1.10
            entityNames.add(new EntityName(EntityType.POLAR_BEAR, langConfig.getString("entity.PolarBear.name", "Polar Bear")));
        }

        if (Utils.getMajorVersion() >= 11) {
            // Add Entity Names of 1.11
            entityNames.add(new EntityName(EntityType.ZOMBIE_VILLAGER, langConfig.getString("entity.ZombieVillager.name", "Zombie Villager")));
            entityNames.add(new EntityName(EntityType.ELDER_GUARDIAN, langConfig.getString("entity.ElderGuardian.name", "Elder Guardian")));
            entityNames.add(new EntityName(EntityType.EVOKER, langConfig.getString("entity.EvocationIllager.name", "Evoker")));
            entityNames.add(new EntityName(EntityType.VEX, langConfig.getString("entity.Vex.name", "Vex")));
            entityNames.add(new EntityName(EntityType.VINDICATOR, langConfig.getString("entity.VindicationIllager.name", "Vindicator")));
            entityNames.add(new EntityName(EntityType.LLAMA, langConfig.getString("entity.Llama.name", "Llama")));
            entityNames.add(new EntityName(EntityType.WITHER_SKELETON, langConfig.getString("entity.WitherSkeleton.name", "Wither Skeleton")));
            entityNames.add(new EntityName(EntityType.STRAY, langConfig.getString("entity.Stray.name", "Stray")));
            entityNames.add(new EntityName(EntityType.ZOMBIE_HORSE, langConfig.getString("entity.ZombieHorse.name", "Zombie Horse")));
            entityNames.add(new EntityName(EntityType.SKELETON_HORSE, langConfig.getString("entity.SkeletonHorse.name", "Skeleton Horse")));
            entityNames.add(new EntityName(EntityType.DONKEY, langConfig.getString("entity.Donkey.name", "Donkey")));
            entityNames.add(new EntityName(EntityType.MULE, langConfig.getString("entity.Mule.name", "Mule")));
            entityNames.add(new EntityName(EntityType.HUSK, langConfig.getString("entity.Husk.name", "Husk")));
        }

        if (Utils.getMajorVersion() >= 12) {
            // Add Entity Names of 1.12
            entityNames.add(new EntityName(EntityType.PARROT, langConfig.getString("entity.Parrot.name", "Parrot")));
            entityNames.add(new EntityName(EntityType.ILLUSIONER, langConfig.getString("entity.IllusionIllager.name", "Illusioner")));
        }

        // Add Potion Effect Names
        potionEffectNames.add(new PotionEffectName(PotionEffectType.FIRE_RESISTANCE, langConfig.getString("effect.fireResistance", "Fire Resistance")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.HARM, langConfig.getString("effect.harm", "Instant Damage")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.HEAL, langConfig.getString("effect.heal", "Instant Health")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.INVISIBILITY, langConfig.getString("effect.invisibility", "Invisibility")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.JUMP, langConfig.getString("effect.jump", "Jump Boost")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.NIGHT_VISION, langConfig.getString("effect.nightVision", "Night Vision")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.POISON, langConfig.getString("effect.poison", "Poison")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.REGENERATION, langConfig.getString("effect.regeneration", "Regeneration")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SLOW, langConfig.getString("effect.moveSlowdown", "Slowness")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SPEED, langConfig.getString("effect.moveSpeed", "Speed")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.INCREASE_DAMAGE, langConfig.getString("effect.damageBoost", "Strength")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.WATER_BREATHING, langConfig.getString("effect.waterBreathing", "Water Breathing")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.WEAKNESS, langConfig.getString("effect.weakness", "Weakness")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Potion Effect Names of 1.9
            potionEffectNames.add(new PotionEffectName(PotionEffectType.LUCK, langConfig.getString("effect.luck", "Luck")));
        }

        // Add Potion Names
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.FIRE_RESISTANCE, langConfig.getString("potion.effect.fire_resistance", "Potion of Fire Resistance")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.INSTANT_DAMAGE, langConfig.getString("potion.effect.harming", "Potion of Harming")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.INSTANT_HEAL, langConfig.getString("potion.effect.healing", "Potion of Healing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.INVISIBILITY, langConfig.getString("potion.effect.invisibility", "Potion of Invisibility")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.JUMP, langConfig.getString("potion.effect.leaping", "Potion of Leaping")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.NIGHT_VISION, langConfig.getString("potion.effect.night_vision", "Potion of Night Vision")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.POISON, langConfig.getString("potion.effect.poison", "Potion of Poison")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.REGEN, langConfig.getString("potion.effect.regeneration", "Potion of Regeneration")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.SLOWNESS, langConfig.getString("potion.effect.slowness", "Potion of Slowness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.SPEED, langConfig.getString("potion.effect.swiftness", "Potion of Swiftness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.STRENGTH, langConfig.getString("potion.effect.strength", "Potion of Strength")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.WATER_BREATHING, langConfig.getString("potion.effect.water_breathing", "Potion of Water Breathing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.WEAKNESS, langConfig.getString("potion.effect.weakness", "Potion of Weakness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.WATER, langConfig.getString("potion.effect.water", "Water Bottle")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Potion Names of 1.9
            potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.AWKWARD, langConfig.getString("potion.effect.awkward", "Awkward Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.LUCK, langConfig.getString("potion.effect.luck", "Potion of Luck")));
            potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.MUNDANE, langConfig.getString("potion.effect.mundane", "Mundane Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.THICK, langConfig.getString("potion.effect.thick", "Thick Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.UNCRAFTABLE, langConfig.getString("potion.effect.empty", "Uncraftable Potion")));
        }

        if (Utils.getMajorVersion() >= 9) {
            // Add Tipped Arrow Names (implemented in Minecraft since 1.9)
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.AWKWARD, langConfig.getString("tipped_arrow.effect.awkward", "Tipped Arrow")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.FIRE_RESISTANCE, langConfig.getString("tipped_arrow.effect.fire_resistance", "Arrow of Fire Resistance")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.INSTANT_DAMAGE, langConfig.getString("tipped_arrow.effect.harming", "Arrow of Harming")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.INSTANT_HEAL, langConfig.getString("tipped_arrow.effect.healing", "Arrow of Healing")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.INVISIBILITY, langConfig.getString("tipped_arrow.effect.invisibility", "Arrow of Invisibility")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.JUMP, langConfig.getString("tipped_arrow.effect.leaping", "Arrow of Leaping")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.NIGHT_VISION, langConfig.getString("tipped_arrow.effect.night_vision", "Arrow of Night Vision")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.POISON, langConfig.getString("tipped_arrow.effect.poison", "Arrow of Poison")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.REGEN, langConfig.getString("tipped_arrow.effect.regeneration", "Arrow of Regeneration")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.SLOWNESS, langConfig.getString("tipped_arrow.effect.slowness", "Arrow of Slowness")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.SPEED, langConfig.getString("tipped_arrow.effect.swiftness", "Arrow of Swiftness")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.STRENGTH, langConfig.getString("tipped_arrow.effect.strength", "Arrow of Strength")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.WATER_BREATHING, langConfig.getString("tipped_arrow.effect.water_breathing", "Arrow of Water Breathing")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.WEAKNESS, langConfig.getString("tipped_arrow.effect.weakness", "Arrow of Weakness")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.WATER, langConfig.getString("tipped_arrow.effect.water", "Arrow of Splashing")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.LUCK, langConfig.getString("tipped_arrow.effect.luck", "Arrow of Luck")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.MUNDANE, langConfig.getString("tipped_arrow.effect.mundane", "Tipped Arrow")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.THICK, langConfig.getString("tipped_arrow.effect.thick", "Tipped Arrow")));
            potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.UNCRAFTABLE, langConfig.getString("tipped_arrow.effect.empty", "Uncraftable Tipped Arrow")));
        }

        // Add Splash Potion Names
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.FIRE_RESISTANCE, langConfig.getString("splash_potion.effect.fire_resistance", "Splash Potion of Fire Resistance")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.INSTANT_DAMAGE, langConfig.getString("splash_potion.effect.harming", "Splash Potion of Harming")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.INSTANT_HEAL, langConfig.getString("splash_potion.effect.healing", "Splash Potion of Healing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.INVISIBILITY, langConfig.getString("splash_potion.effect.invisibility", "Splash Potion of Invisibility")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.JUMP, langConfig.getString("splash_potion.effect.leaping", "Splash Potion of Leaping")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.NIGHT_VISION, langConfig.getString("splash_potion.effect.night_vision", "Splash Potion of Night Vision")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.POISON, langConfig.getString("splash_potion.effect.poison", "Splash Potion of Poison")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.REGEN, langConfig.getString("splash_potion.effect.regeneration", "Splash Potion of Regeneration")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.SLOWNESS, langConfig.getString("splash_potion.effect.slowness", "Splash Potion of Slowness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.SPEED, langConfig.getString("splash_potion.effect.swiftness", "Splash Potion of Swiftness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.STRENGTH, langConfig.getString("splash_potion.effect.strength", "Splash Potion of Strength")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.WATER_BREATHING, langConfig.getString("splash_potion.effect.water_breathing", "Splash Potion of Water Breathing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.WEAKNESS, langConfig.getString("splash_potion.effect.weakness", "Splash Potion of Weakness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.WATER, langConfig.getString("splash_potion.effect.water", "Splash Water Bottle")));

        if (Utils.getMajorVersion() >= 9) {
            // Add Splash Potion Names of 1.9
            potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.AWKWARD, langConfig.getString("splash_potion.effect.awkward", "Awkward Splash Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.LUCK, langConfig.getString("splash_potion.effect.luck", "Splash Potion of Luck")));
            potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.MUNDANE, langConfig.getString("splash_potion.effect.mundane", "Mundane Splash Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.THICK, langConfig.getString("splash_potion.effect.thick", "Thick Splash Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.UNCRAFTABLE, langConfig.getString("splash_potion.effect.empty", "Splash Uncraftable Potion")));
        }

        if (Utils.getMajorVersion() >= 9) {
            // Add Lingering Potion Names (implemented in Minecraft since 1.9)
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.AWKWARD, langConfig.getString("lingering_potion.effect.awkward", "Awkward Lingering Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.FIRE_RESISTANCE, langConfig.getString("lingering_potion.effect.fire_resistance", "Lingering Potion of Fire Resistance")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.INSTANT_DAMAGE, langConfig.getString("lingering_potion.effect.harming", "Lingering Potion of Harming")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.INSTANT_HEAL, langConfig.getString("lingering_potion.effect.healing", "Lingering Potion of Healing")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.INVISIBILITY, langConfig.getString("lingering_potion.effect.invisibility", "Lingering Potion of Invisibility")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.JUMP, langConfig.getString("lingering_potion.effect.leaping", "Lingering Potion of Leaping")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.NIGHT_VISION, langConfig.getString("lingering_potion.effect.night_vision", "Lingering Potion of Night Vision")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.POISON, langConfig.getString("lingering_potion.effect.poison", "Lingering Potion of Poison")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.REGEN, langConfig.getString("lingering_potion.effect.regeneration", "Lingering Potion of Regeneration")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.SLOWNESS, langConfig.getString("lingering_potion.effect.slowness", "Lingering Potion of Slowness")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.SPEED, langConfig.getString("lingering_potion.effect.swiftness", "Lingering Potion of Swiftness")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.STRENGTH, langConfig.getString("lingering_potion.effect.strength", "Lingering Potion of Strength")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.WATER_BREATHING, langConfig.getString("lingering_potion.effect.water_breathing", "Lingering Potion of Water Breathing")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.WEAKNESS, langConfig.getString("lingering_potion.effect.weakness", "Lingering Potion of Weakness")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.WATER, langConfig.getString("lingering_potion.effect.water", "Lingering Water Bottle")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.LUCK, langConfig.getString("lingering_potion.effect.luck", "Lingering Potion of Luck")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.MUNDANE, langConfig.getString("lingering_potion.effect.mundane", "Mundane Lingering Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.THICK, langConfig.getString("lingering_potion.effect.thick", "Thick Lingering Potion")));
            potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.UNCRAFTABLE, langConfig.getString("lingering_potion.effect.empty", "Lingering Uncraftable Potion")));
        }

        // Add Music Disc Titles
        musicDiscNames.add(new MusicDiscName(Material.valueOf("GOLD_RECORD"), langConfig.getString("item.record.13.desc", "C418 - 13")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("GREEN_RECORD"), langConfig.getString("item.record.cat.desc", "C418 - cat")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_3"), langConfig.getString("item.record.blocks.desc", "C418 - blocks")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_4"), langConfig.getString("item.record.chirp.desc", "C418 - chirp")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_5"), langConfig.getString("item.record.far.desc", "C418 - far")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_6"), langConfig.getString("item.record.mall.desc", "C418 - mall")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_7"), langConfig.getString("item.record.mellohi.desc", "C418 - mellohi")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_8"), langConfig.getString("item.record.stal.desc", "C418 - stal")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_9"), langConfig.getString("item.record.strad.desc", "C418 - strad")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_10"), langConfig.getString("item.record.ward.desc", "C418 - ward")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_11"), langConfig.getString("item.record.11.desc", "C418 - 11")));
        musicDiscNames.add(new MusicDiscName(Material.valueOf("RECORD_12"), langConfig.getString("item.record.wait.desc", "C418 - wait")));

        // Add Book Generation Names
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.ORIGINAL, langConfig.getString("book.generation.0", "Original")));
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.COPY_OF_ORIGINAL, langConfig.getString("book.generation.1", "Copy of original")));
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.COPY_OF_COPY, langConfig.getString("book.generation.2", "Copy of a copy")));
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.TATTERED, langConfig.getString("book.generation.3", "Tattered")));

        loadMessages();
    }

    public static void load() {
        langConfig = Config.langConfig;

        itemNames.clear();
        enchantmentNames.clear();
        enchantmentLevelNames.clear();
        potionEffectNames.clear();
        entityNames.clear();
        potionNames.clear();
        musicDiscNames.clear();
        generationNames.clear();
        messages.clear();

        if (Utils.getMajorVersion() < 13) {
            loadLegacy();
            return;
        }

        // Add Block/Item Names
        itemNames.add(new ItemName(Material.AIR, langConfig.getString("block.minecraft.air", "Air")));
        itemNames.add(new ItemName(Material.BARRIER, langConfig.getString("block.minecraft.barrier", "Barrier")));
        itemNames.add(new ItemName(Material.STONE, langConfig.getString("block.minecraft.stone", "Stone")));
        itemNames.add(new ItemName(Material.GRANITE, langConfig.getString("block.minecraft.granite", "Granite")));
        itemNames.add(new ItemName(Material.POLISHED_GRANITE, langConfig.getString("block.minecraft.polished_granite", "Polished Granite")));
        itemNames.add(new ItemName(Material.DIORITE, langConfig.getString("block.minecraft.diorite", "Diorite")));
        itemNames.add(new ItemName(Material.POLISHED_DIORITE, langConfig.getString("block.minecraft.polished_diorite", "Polished Diorite")));
        itemNames.add(new ItemName(Material.ANDESITE, langConfig.getString("block.minecraft.andesite", "Andesite")));
        itemNames.add(new ItemName(Material.POLISHED_ANDESITE, langConfig.getString("block.minecraft.polished_andesite", "Polished Andesite")));
        itemNames.add(new ItemName(Material.HAY_BLOCK, langConfig.getString("block.minecraft.hay_block", "Hay Bale")));
        itemNames.add(new ItemName(Material.GRASS_BLOCK, langConfig.getString("block.minecraft.grass_block", "Grass Block")));
        itemNames.add(new ItemName(Material.DIRT, langConfig.getString("block.minecraft.dirt", "Dirt")));
        itemNames.add(new ItemName(Material.COARSE_DIRT, langConfig.getString("block.minecraft.coarse_dirt", "Coarse Dirt")));
        itemNames.add(new ItemName(Material.PODZOL, langConfig.getString("block.minecraft.podzol", "Podzol")));
        itemNames.add(new ItemName(Material.COBBLESTONE, langConfig.getString("block.minecraft.cobblestone", "Cobblestone")));
        itemNames.add(new ItemName(Material.OAK_PLANKS, langConfig.getString("block.minecraft.oak_planks", "Oak Planks")));
        itemNames.add(new ItemName(Material.SPRUCE_PLANKS, langConfig.getString("block.minecraft.spruce_planks", "Spruce Planks")));
        itemNames.add(new ItemName(Material.BIRCH_PLANKS, langConfig.getString("block.minecraft.birch_planks", "Birch Planks")));
        itemNames.add(new ItemName(Material.JUNGLE_PLANKS, langConfig.getString("block.minecraft.jungle_planks", "Jungle Planks")));
        itemNames.add(new ItemName(Material.ACACIA_PLANKS, langConfig.getString("block.minecraft.acacia_planks", "Acacia Planks")));
        itemNames.add(new ItemName(Material.DARK_OAK_PLANKS, langConfig.getString("block.minecraft.dark_oak_planks", "Dark Oak Planks")));
        itemNames.add(new ItemName(Material.OAK_SAPLING, langConfig.getString("block.minecraft.oak_sapling", "Oak Sapling")));
        itemNames.add(new ItemName(Material.SPRUCE_SAPLING, langConfig.getString("block.minecraft.spruce_sapling", "Spruce Sapling")));
        itemNames.add(new ItemName(Material.BIRCH_SAPLING, langConfig.getString("block.minecraft.birch_sapling", "Birch Sapling")));
        itemNames.add(new ItemName(Material.JUNGLE_SAPLING, langConfig.getString("block.minecraft.jungle_sapling", "Jungle Sapling")));
        itemNames.add(new ItemName(Material.ACACIA_SAPLING, langConfig.getString("block.minecraft.acacia_sapling", "Acacia Sapling")));
        itemNames.add(new ItemName(Material.DARK_OAK_SAPLING, langConfig.getString("block.minecraft.dark_oak_sapling", "Dark Oak Sapling")));
        itemNames.add(new ItemName(Material.OAK_DOOR, langConfig.getString("block.minecraft.oak_door", "Oak Door")));
        itemNames.add(new ItemName(Material.SPRUCE_DOOR, langConfig.getString("block.minecraft.spruce_door", "Spruce Door")));
        itemNames.add(new ItemName(Material.BIRCH_DOOR, langConfig.getString("block.minecraft.birch_door", "Birch Door")));
        itemNames.add(new ItemName(Material.JUNGLE_DOOR, langConfig.getString("block.minecraft.jungle_door", "Jungle Door")));
        itemNames.add(new ItemName(Material.ACACIA_DOOR, langConfig.getString("block.minecraft.acacia_door", "Acacia Door")));
        itemNames.add(new ItemName(Material.DARK_OAK_DOOR, langConfig.getString("block.minecraft.dark_oak_door", "Dark Oak Door")));
        itemNames.add(new ItemName(Material.BEDROCK, langConfig.getString("block.minecraft.bedrock", "Bedrock")));
        itemNames.add(new ItemName(Material.WATER, langConfig.getString("block.minecraft.water", "Water")));
        itemNames.add(new ItemName(Material.LAVA, langConfig.getString("block.minecraft.lava", "Lava")));
        itemNames.add(new ItemName(Material.SAND, langConfig.getString("block.minecraft.sand", "Sand")));
        itemNames.add(new ItemName(Material.RED_SAND, langConfig.getString("block.minecraft.red_sand", "Red Sand")));
        itemNames.add(new ItemName(Material.SANDSTONE, langConfig.getString("block.minecraft.sandstone", "Sandstone")));
        itemNames.add(new ItemName(Material.CHISELED_SANDSTONE, langConfig.getString("block.minecraft.chiseled_sandstone", "Chiseled Sandstone")));
        itemNames.add(new ItemName(Material.CUT_SANDSTONE, langConfig.getString("block.minecraft.cut_sandstone", "Cut Sandstone")));
        itemNames.add(new ItemName(Material.RED_SANDSTONE, langConfig.getString("block.minecraft.red_sandstone", "Red Sandstone")));
        itemNames.add(new ItemName(Material.CHISELED_RED_SANDSTONE, langConfig.getString("block.minecraft.chiseled_red_sandstone", "Chiseled Red Sandstone")));
        itemNames.add(new ItemName(Material.CUT_RED_SANDSTONE, langConfig.getString("block.minecraft.cut_red_sandstone", "Cut Red Sandstone")));
        itemNames.add(new ItemName(Material.GRAVEL, langConfig.getString("block.minecraft.gravel", "Gravel")));
        itemNames.add(new ItemName(Material.GOLD_ORE, langConfig.getString("block.minecraft.gold_ore", "Gold Ore")));
        itemNames.add(new ItemName(Material.IRON_ORE, langConfig.getString("block.minecraft.iron_ore", "Iron Ore")));
        itemNames.add(new ItemName(Material.COAL_ORE, langConfig.getString("block.minecraft.coal_ore", "Coal Ore")));
        itemNames.add(new ItemName(Material.OAK_WOOD, langConfig.getString("block.minecraft.oak_wood", "Oak Wood")));
        itemNames.add(new ItemName(Material.SPRUCE_WOOD, langConfig.getString("block.minecraft.spruce_wood", "Spruce Wood")));
        itemNames.add(new ItemName(Material.BIRCH_WOOD, langConfig.getString("block.minecraft.birch_wood", "Birch Wood")));
        itemNames.add(new ItemName(Material.JUNGLE_WOOD, langConfig.getString("block.minecraft.jungle_wood", "Jungle Wood")));
        itemNames.add(new ItemName(Material.ACACIA_WOOD, langConfig.getString("block.minecraft.acacia_wood", "Acacia Wood")));
        itemNames.add(new ItemName(Material.DARK_OAK_WOOD, langConfig.getString("block.minecraft.dark_oak_wood", "Dark Oak Wood")));
        itemNames.add(new ItemName(Material.OAK_LOG, langConfig.getString("block.minecraft.oak_log", "Oak Log")));
        itemNames.add(new ItemName(Material.SPRUCE_LOG, langConfig.getString("block.minecraft.spruce_log", "Spruce Log")));
        itemNames.add(new ItemName(Material.BIRCH_LOG, langConfig.getString("block.minecraft.birch_log", "Birch Log")));
        itemNames.add(new ItemName(Material.JUNGLE_LOG, langConfig.getString("block.minecraft.jungle_log", "Jungle Log")));
        itemNames.add(new ItemName(Material.ACACIA_LOG, langConfig.getString("block.minecraft.acacia_log", "Acacia Log")));
        itemNames.add(new ItemName(Material.DARK_OAK_LOG, langConfig.getString("block.minecraft.dark_oak_log", "Dark Oak Log")));
        itemNames.add(new ItemName(Material.STRIPPED_OAK_LOG, langConfig.getString("block.minecraft.stripped_oak_log", "Stripped Oak Log")));
        itemNames.add(new ItemName(Material.STRIPPED_SPRUCE_LOG, langConfig.getString("block.minecraft.stripped_spruce_log", "Stripped Spruce Log")));
        itemNames.add(new ItemName(Material.STRIPPED_BIRCH_LOG, langConfig.getString("block.minecraft.stripped_birch_log", "Stripped Birch Log")));
        itemNames.add(new ItemName(Material.STRIPPED_JUNGLE_LOG, langConfig.getString("block.minecraft.stripped_jungle_log", "Stripped Jungle Log")));
        itemNames.add(new ItemName(Material.STRIPPED_ACACIA_LOG, langConfig.getString("block.minecraft.stripped_acacia_log", "Stripped Acacia Log")));
        itemNames.add(new ItemName(Material.STRIPPED_DARK_OAK_LOG, langConfig.getString("block.minecraft.stripped_dark_oak_log", "Stripped Dark Oak Log")));
        itemNames.add(new ItemName(Material.STRIPPED_OAK_WOOD, langConfig.getString("block.minecraft.stripped_oak_wood", "Stripped Oak Wood")));
        itemNames.add(new ItemName(Material.STRIPPED_SPRUCE_WOOD, langConfig.getString("block.minecraft.stripped_spruce_wood", "Stripped Spruce Wood")));
        itemNames.add(new ItemName(Material.STRIPPED_BIRCH_WOOD, langConfig.getString("block.minecraft.stripped_birch_wood", "Stripped Birch Wood")));
        itemNames.add(new ItemName(Material.STRIPPED_JUNGLE_WOOD, langConfig.getString("block.minecraft.stripped_jungle_wood", "Stripped Jungle Wood")));
        itemNames.add(new ItemName(Material.STRIPPED_ACACIA_WOOD, langConfig.getString("block.minecraft.stripped_acacia_wood", "Stripped Acacia Wood")));
        itemNames.add(new ItemName(Material.STRIPPED_DARK_OAK_WOOD, langConfig.getString("block.minecraft.stripped_dark_oak_wood", "Stripped Dark Oak Wood")));
        itemNames.add(new ItemName(Material.OAK_LEAVES, langConfig.getString("block.minecraft.oak_leaves", "Oak Leaves")));
        itemNames.add(new ItemName(Material.SPRUCE_LEAVES, langConfig.getString("block.minecraft.spruce_leaves", "Spruce Leaves")));
        itemNames.add(new ItemName(Material.BIRCH_LEAVES, langConfig.getString("block.minecraft.birch_leaves", "Birch Leaves")));
        itemNames.add(new ItemName(Material.JUNGLE_LEAVES, langConfig.getString("block.minecraft.jungle_leaves", "Jungle Leaves")));
        itemNames.add(new ItemName(Material.ACACIA_LEAVES, langConfig.getString("block.minecraft.acacia_leaves", "Acacia Leaves")));
        itemNames.add(new ItemName(Material.DARK_OAK_LEAVES, langConfig.getString("block.minecraft.dark_oak_leaves", "Dark Oak Leaves")));
        itemNames.add(new ItemName(Material.DEAD_BUSH, langConfig.getString("block.minecraft.dead_bush", "Dead Bush")));
        itemNames.add(new ItemName(Material.GRASS, langConfig.getString("block.minecraft.grass", "Grass")));
        itemNames.add(new ItemName(Material.FERN, langConfig.getString("block.minecraft.fern", "Fern")));
        itemNames.add(new ItemName(Material.SPONGE, langConfig.getString("block.minecraft.sponge", "Sponge")));
        itemNames.add(new ItemName(Material.WET_SPONGE, langConfig.getString("block.minecraft.wet_sponge", "Wet Sponge")));
        itemNames.add(new ItemName(Material.GLASS, langConfig.getString("block.minecraft.glass", "Glass")));
        itemNames.add(new ItemName(Material.KELP_PLANT, langConfig.getString("block.minecraft.kelp_plant", "Kelp Plant")));
        itemNames.add(new ItemName(Material.KELP, langConfig.getString("block.minecraft.kelp", "Kelp")));
        itemNames.add(new ItemName(Material.DRIED_KELP_BLOCK, langConfig.getString("block.minecraft.dried_kelp_block", "Dried Kelp Block")));
        itemNames.add(new ItemName(Material.WHITE_STAINED_GLASS, langConfig.getString("block.minecraft.white_stained_glass", "White Stained Glass")));
        itemNames.add(new ItemName(Material.ORANGE_STAINED_GLASS, langConfig.getString("block.minecraft.orange_stained_glass", "Orange Stained Glass")));
        itemNames.add(new ItemName(Material.MAGENTA_STAINED_GLASS, langConfig.getString("block.minecraft.magenta_stained_glass", "Magenta Stained Glass")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_STAINED_GLASS, langConfig.getString("block.minecraft.light_blue_stained_glass", "Light Blue Stained Glass")));
        itemNames.add(new ItemName(Material.YELLOW_STAINED_GLASS, langConfig.getString("block.minecraft.yellow_stained_glass", "Yellow Stained Glass")));
        itemNames.add(new ItemName(Material.LIME_STAINED_GLASS, langConfig.getString("block.minecraft.lime_stained_glass", "Lime Stained Glass")));
        itemNames.add(new ItemName(Material.PINK_STAINED_GLASS, langConfig.getString("block.minecraft.pink_stained_glass", "Pink Stained Glass")));
        itemNames.add(new ItemName(Material.GRAY_STAINED_GLASS, langConfig.getString("block.minecraft.gray_stained_glass", "Gray Stained Glass")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_STAINED_GLASS, langConfig.getString("block.minecraft.light_gray_stained_glass", "Light Gray Stained Glass")));
        itemNames.add(new ItemName(Material.CYAN_STAINED_GLASS, langConfig.getString("block.minecraft.cyan_stained_glass", "Cyan Stained Glass")));
        itemNames.add(new ItemName(Material.PURPLE_STAINED_GLASS, langConfig.getString("block.minecraft.purple_stained_glass", "Purple Stained Glass")));
        itemNames.add(new ItemName(Material.BLUE_STAINED_GLASS, langConfig.getString("block.minecraft.blue_stained_glass", "Blue Stained Glass")));
        itemNames.add(new ItemName(Material.BROWN_STAINED_GLASS, langConfig.getString("block.minecraft.brown_stained_glass", "Brown Stained Glass")));
        itemNames.add(new ItemName(Material.GREEN_STAINED_GLASS, langConfig.getString("block.minecraft.green_stained_glass", "Green Stained Glass")));
        itemNames.add(new ItemName(Material.RED_STAINED_GLASS, langConfig.getString("block.minecraft.red_stained_glass", "Red Stained Glass")));
        itemNames.add(new ItemName(Material.BLACK_STAINED_GLASS, langConfig.getString("block.minecraft.black_stained_glass", "Black Stained Glass")));
        itemNames.add(new ItemName(Material.WHITE_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.white_stained_glass_pane", "White Stained Glass Pane")));
        itemNames.add(new ItemName(Material.ORANGE_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.orange_stained_glass_pane", "Orange Stained Glass Pane")));
        itemNames.add(new ItemName(Material.MAGENTA_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.magenta_stained_glass_pane", "Magenta Stained Glass Pane")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.light_blue_stained_glass_pane", "Light Blue Stained Glass Pane")));
        itemNames.add(new ItemName(Material.YELLOW_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.yellow_stained_glass_pane", "Yellow Stained Glass Pane")));
        itemNames.add(new ItemName(Material.LIME_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.lime_stained_glass_pane", "Lime Stained Glass Pane")));
        itemNames.add(new ItemName(Material.PINK_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.pink_stained_glass_pane", "Pink Stained Glass Pane")));
        itemNames.add(new ItemName(Material.GRAY_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.gray_stained_glass_pane", "Gray Stained Glass Pane")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.light_gray_stained_glass_pane", "Light Gray Stained Glass Pane")));
        itemNames.add(new ItemName(Material.CYAN_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.cyan_stained_glass_pane", "Cyan Stained Glass Pane")));
        itemNames.add(new ItemName(Material.PURPLE_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.purple_stained_glass_pane", "Purple Stained Glass Pane")));
        itemNames.add(new ItemName(Material.BLUE_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.blue_stained_glass_pane", "Blue Stained Glass Pane")));
        itemNames.add(new ItemName(Material.BROWN_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.brown_stained_glass_pane", "Brown Stained Glass Pane")));
        itemNames.add(new ItemName(Material.GREEN_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.green_stained_glass_pane", "Green Stained Glass Pane")));
        itemNames.add(new ItemName(Material.RED_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.red_stained_glass_pane", "Red Stained Glass Pane")));
        itemNames.add(new ItemName(Material.BLACK_STAINED_GLASS_PANE, langConfig.getString("block.minecraft.black_stained_glass_pane", "Black Stained Glass Pane")));
        itemNames.add(new ItemName(Material.GLASS_PANE, langConfig.getString("block.minecraft.glass_pane", "Glass Pane")));
        itemNames.add(new ItemName(Material.DANDELION, langConfig.getString("block.minecraft.dandelion", "Dandelion")));
        itemNames.add(new ItemName(Material.POPPY, langConfig.getString("block.minecraft.poppy", "Poppy")));
        itemNames.add(new ItemName(Material.BLUE_ORCHID, langConfig.getString("block.minecraft.blue_orchid", "Blue Orchid")));
        itemNames.add(new ItemName(Material.ALLIUM, langConfig.getString("block.minecraft.allium", "Allium")));
        itemNames.add(new ItemName(Material.AZURE_BLUET, langConfig.getString("block.minecraft.azure_bluet", "Azure Bluet")));
        itemNames.add(new ItemName(Material.RED_TULIP, langConfig.getString("block.minecraft.red_tulip", "Red Tulip")));
        itemNames.add(new ItemName(Material.ORANGE_TULIP, langConfig.getString("block.minecraft.orange_tulip", "Orange Tulip")));
        itemNames.add(new ItemName(Material.WHITE_TULIP, langConfig.getString("block.minecraft.white_tulip", "White Tulip")));
        itemNames.add(new ItemName(Material.PINK_TULIP, langConfig.getString("block.minecraft.pink_tulip", "Pink Tulip")));
        itemNames.add(new ItemName(Material.OXEYE_DAISY, langConfig.getString("block.minecraft.oxeye_daisy", "Oxeye Daisy")));
        itemNames.add(new ItemName(Material.SUNFLOWER, langConfig.getString("block.minecraft.sunflower", "Sunflower")));
        itemNames.add(new ItemName(Material.LILAC, langConfig.getString("block.minecraft.lilac", "Lilac")));
        itemNames.add(new ItemName(Material.TALL_GRASS, langConfig.getString("block.minecraft.tall_grass", "Tall Grass")));
        itemNames.add(new ItemName(Material.TALL_SEAGRASS, langConfig.getString("block.minecraft.tall_seagrass", "Tall Seagrass")));
        itemNames.add(new ItemName(Material.LARGE_FERN, langConfig.getString("block.minecraft.large_fern", "Large Fern")));
        itemNames.add(new ItemName(Material.ROSE_BUSH, langConfig.getString("block.minecraft.rose_bush", "Rose Bush")));
        itemNames.add(new ItemName(Material.PEONY, langConfig.getString("block.minecraft.peony", "Peony")));
        itemNames.add(new ItemName(Material.SEAGRASS, langConfig.getString("block.minecraft.seagrass", "Seagrass")));
        itemNames.add(new ItemName(Material.SEA_PICKLE, langConfig.getString("block.minecraft.sea_pickle", "Sea Pickle")));
        itemNames.add(new ItemName(Material.BROWN_MUSHROOM, langConfig.getString("block.minecraft.brown_mushroom", "Brown Mushroom")));
        itemNames.add(new ItemName(Material.RED_MUSHROOM_BLOCK, langConfig.getString("block.minecraft.red_mushroom_block", "Red Mushroom Block")));
        itemNames.add(new ItemName(Material.BROWN_MUSHROOM_BLOCK, langConfig.getString("block.minecraft.brown_mushroom_block", "Brown Mushroom Block")));
        itemNames.add(new ItemName(Material.MUSHROOM_STEM, langConfig.getString("block.minecraft.mushroom_stem", "Mushroom Stem")));
        itemNames.add(new ItemName(Material.GOLD_BLOCK, langConfig.getString("block.minecraft.gold_block", "Block of Gold")));
        itemNames.add(new ItemName(Material.IRON_BLOCK, langConfig.getString("block.minecraft.iron_block", "Block of Iron")));
        itemNames.add(new ItemName(Material.SMOOTH_STONE, langConfig.getString("block.minecraft.smooth_stone", "Smooth Stone")));
        itemNames.add(new ItemName(Material.SMOOTH_SANDSTONE, langConfig.getString("block.minecraft.smooth_sandstone", "Smooth Sandstone")));
        itemNames.add(new ItemName(Material.SMOOTH_RED_SANDSTONE, langConfig.getString("block.minecraft.smooth_red_sandstone", "Smooth Red Sandstone")));
        itemNames.add(new ItemName(Material.SMOOTH_QUARTZ, langConfig.getString("block.minecraft.smooth_quartz", "Smooth Quartz")));
        itemNames.add(new ItemName(Material.STONE_SLAB, langConfig.getString("block.minecraft.stone_slab", "Stone Slab")));
        itemNames.add(new ItemName(Material.SANDSTONE_SLAB, langConfig.getString("block.minecraft.sandstone_slab", "Sandstone Slab")));
        itemNames.add(new ItemName(Material.RED_SANDSTONE_SLAB, langConfig.getString("block.minecraft.red_sandstone_slab", "Red Sandstone Slab")));
        itemNames.add(new ItemName(Material.PETRIFIED_OAK_SLAB, langConfig.getString("block.minecraft.petrified_oak_slab", "Petrified Oak Slab")));
        itemNames.add(new ItemName(Material.COBBLESTONE_SLAB, langConfig.getString("block.minecraft.cobblestone_slab", "Cobblestone Slab")));
        itemNames.add(new ItemName(Material.BRICK_SLAB, langConfig.getString("block.minecraft.brick_slab", "Brick Slab")));
        itemNames.add(new ItemName(Material.STONE_BRICK_SLAB, langConfig.getString("block.minecraft.stone_brick_slab", "Stone Brick Slab")));
        itemNames.add(new ItemName(Material.NETHER_BRICK_SLAB, langConfig.getString("block.minecraft.nether_brick_slab", "Nether Brick Slab")));
        itemNames.add(new ItemName(Material.QUARTZ_SLAB, langConfig.getString("block.minecraft.quartz_slab", "Quartz Slab")));
        itemNames.add(new ItemName(Material.OAK_SLAB, langConfig.getString("block.minecraft.oak_slab", "Oak Slab")));
        itemNames.add(new ItemName(Material.SPRUCE_SLAB, langConfig.getString("block.minecraft.spruce_slab", "Spruce Slab")));
        itemNames.add(new ItemName(Material.BIRCH_SLAB, langConfig.getString("block.minecraft.birch_slab", "Birch Slab")));
        itemNames.add(new ItemName(Material.JUNGLE_SLAB, langConfig.getString("block.minecraft.jungle_slab", "Jungle Slab")));
        itemNames.add(new ItemName(Material.ACACIA_SLAB, langConfig.getString("block.minecraft.acacia_slab", "Acacia Slab")));
        itemNames.add(new ItemName(Material.DARK_OAK_SLAB, langConfig.getString("block.minecraft.dark_oak_slab", "Dark Oak Slab")));
        itemNames.add(new ItemName(Material.DARK_PRISMARINE_SLAB, langConfig.getString("block.minecraft.dark_prismarine_slab", "Dark Prismarine Slab")));
        itemNames.add(new ItemName(Material.PRISMARINE_SLAB, langConfig.getString("block.minecraft.prismarine_slab", "Prismarine Slab")));
        itemNames.add(new ItemName(Material.PRISMARINE_BRICK_SLAB, langConfig.getString("block.minecraft.prismarine_brick_slab", "Prismarine Brick Slab")));
        itemNames.add(new ItemName(Material.BRICKS, langConfig.getString("block.minecraft.bricks", "Bricks")));
        itemNames.add(new ItemName(Material.TNT, langConfig.getString("block.minecraft.tnt", "TNT")));
        itemNames.add(new ItemName(Material.BOOKSHELF, langConfig.getString("block.minecraft.bookshelf", "Bookshelf")));
        itemNames.add(new ItemName(Material.MOSSY_COBBLESTONE, langConfig.getString("block.minecraft.mossy_cobblestone", "Mossy Cobblestone")));
        itemNames.add(new ItemName(Material.OBSIDIAN, langConfig.getString("block.minecraft.obsidian", "Obsidian")));
        itemNames.add(new ItemName(Material.TORCH, langConfig.getString("block.minecraft.torch", "Torch")));
        itemNames.add(new ItemName(Material.WALL_TORCH, langConfig.getString("block.minecraft.wall_torch", "Wall Torch")));
        itemNames.add(new ItemName(Material.FIRE, langConfig.getString("block.minecraft.fire", "Fire")));
        itemNames.add(new ItemName(Material.SPAWNER, langConfig.getString("block.minecraft.spawner", "Spawner")));
        itemNames.add(new ItemName(Material.OAK_STAIRS, langConfig.getString("block.minecraft.oak_stairs", "Oak Stairs")));
        itemNames.add(new ItemName(Material.SPRUCE_STAIRS, langConfig.getString("block.minecraft.spruce_stairs", "Spruce Stairs")));
        itemNames.add(new ItemName(Material.BIRCH_STAIRS, langConfig.getString("block.minecraft.birch_stairs", "Birch Stairs")));
        itemNames.add(new ItemName(Material.JUNGLE_STAIRS, langConfig.getString("block.minecraft.jungle_stairs", "Jungle Stairs")));
        itemNames.add(new ItemName(Material.ACACIA_STAIRS, langConfig.getString("block.minecraft.acacia_stairs", "Acacia Stairs")));
        itemNames.add(new ItemName(Material.DARK_OAK_STAIRS, langConfig.getString("block.minecraft.dark_oak_stairs", "Dark Oak Stairs")));
        itemNames.add(new ItemName(Material.DARK_PRISMARINE_STAIRS, langConfig.getString("block.minecraft.dark_prismarine_stairs", "Dark Prismarine Stairs")));
        itemNames.add(new ItemName(Material.PRISMARINE_STAIRS, langConfig.getString("block.minecraft.prismarine_stairs", "Prismarine Stairs")));
        itemNames.add(new ItemName(Material.PRISMARINE_BRICK_STAIRS, langConfig.getString("block.minecraft.prismarine_brick_stairs", "Prismarine Brick Stairs")));
        itemNames.add(new ItemName(Material.CHEST, langConfig.getString("block.minecraft.chest", "Chest")));
        itemNames.add(new ItemName(Material.TRAPPED_CHEST, langConfig.getString("block.minecraft.trapped_chest", "Trapped Chest")));
        itemNames.add(new ItemName(Material.REDSTONE_WIRE, langConfig.getString("block.minecraft.redstone_wire", "Redstone Dust")));
        itemNames.add(new ItemName(Material.DIAMOND_ORE, langConfig.getString("block.minecraft.diamond_ore", "Diamond Ore")));
        itemNames.add(new ItemName(Material.COAL_BLOCK, langConfig.getString("block.minecraft.coal_block", "Block of Coal")));
        itemNames.add(new ItemName(Material.DIAMOND_BLOCK, langConfig.getString("block.minecraft.diamond_block", "Block of Diamond")));
        itemNames.add(new ItemName(Material.CRAFTING_TABLE, langConfig.getString("block.minecraft.crafting_table", "Crafting Table")));
        itemNames.add(new ItemName(Material.WHEAT, langConfig.getString("block.minecraft.wheat", "Wheat Crops")));
        itemNames.add(new ItemName(Material.FARMLAND, langConfig.getString("block.minecraft.farmland", "Farmland")));
        itemNames.add(new ItemName(Material.FURNACE, langConfig.getString("block.minecraft.furnace", "Furnace")));
        itemNames.add(new ItemName(Material.LADDER, langConfig.getString("block.minecraft.ladder", "Ladder")));
        itemNames.add(new ItemName(Material.RAIL, langConfig.getString("block.minecraft.rail", "Rail")));
        itemNames.add(new ItemName(Material.POWERED_RAIL, langConfig.getString("block.minecraft.powered_rail", "Powered Rail")));
        itemNames.add(new ItemName(Material.ACTIVATOR_RAIL, langConfig.getString("block.minecraft.activator_rail", "Activator Rail")));
        itemNames.add(new ItemName(Material.DETECTOR_RAIL, langConfig.getString("block.minecraft.detector_rail", "Detector Rail")));
        itemNames.add(new ItemName(Material.COBBLESTONE_STAIRS, langConfig.getString("block.minecraft.cobblestone_stairs", "Cobblestone Stairs")));
        itemNames.add(new ItemName(Material.SANDSTONE_STAIRS, langConfig.getString("block.minecraft.sandstone_stairs", "Sandstone Stairs")));
        itemNames.add(new ItemName(Material.RED_SANDSTONE_STAIRS, langConfig.getString("block.minecraft.red_sandstone_stairs", "Red Sandstone Stairs")));
        itemNames.add(new ItemName(Material.LEVER, langConfig.getString("block.minecraft.lever", "Lever")));
        itemNames.add(new ItemName(Material.STONE_PRESSURE_PLATE, langConfig.getString("block.minecraft.stone_pressure_plate", "Stone Pressure Plate")));
        itemNames.add(new ItemName(Material.OAK_PRESSURE_PLATE, langConfig.getString("block.minecraft.oak_pressure_plate", "Oak Pressure Plate")));
        itemNames.add(new ItemName(Material.SPRUCE_PRESSURE_PLATE, langConfig.getString("block.minecraft.spruce_pressure_plate", "Spruce Pressure Plate")));
        itemNames.add(new ItemName(Material.BIRCH_PRESSURE_PLATE, langConfig.getString("block.minecraft.birch_pressure_plate", "Birch Pressure Plate")));
        itemNames.add(new ItemName(Material.JUNGLE_PRESSURE_PLATE, langConfig.getString("block.minecraft.jungle_pressure_plate", "Jungle Pressure Plate")));
        itemNames.add(new ItemName(Material.ACACIA_PRESSURE_PLATE, langConfig.getString("block.minecraft.acacia_pressure_plate", "Acacia Pressure Plate")));
        itemNames.add(new ItemName(Material.DARK_OAK_PRESSURE_PLATE, langConfig.getString("block.minecraft.dark_oak_pressure_plate", "Dark Oak Pressure Plate")));
        itemNames.add(new ItemName(Material.LIGHT_WEIGHTED_PRESSURE_PLATE, langConfig.getString("block.minecraft.light_weighted_pressure_plate", "Light Weighted Pressure Plate")));
        itemNames.add(new ItemName(Material.HEAVY_WEIGHTED_PRESSURE_PLATE, langConfig.getString("block.minecraft.heavy_weighted_pressure_plate", "Heavy Weighted Pressure Plate")));
        itemNames.add(new ItemName(Material.IRON_DOOR, langConfig.getString("block.minecraft.iron_door", "Iron Door")));
        itemNames.add(new ItemName(Material.REDSTONE_ORE, langConfig.getString("block.minecraft.redstone_ore", "Redstone Ore")));
        itemNames.add(new ItemName(Material.REDSTONE_TORCH, langConfig.getString("block.minecraft.redstone_torch", "Redstone Torch")));
        itemNames.add(new ItemName(Material.REDSTONE_WALL_TORCH, langConfig.getString("block.minecraft.redstone_wall_torch", "Redstone Wall Torch")));
        itemNames.add(new ItemName(Material.STONE_BUTTON, langConfig.getString("block.minecraft.stone_button", "Stone Button")));
        itemNames.add(new ItemName(Material.OAK_BUTTON, langConfig.getString("block.minecraft.oak_button", "Oak Button")));
        itemNames.add(new ItemName(Material.SPRUCE_BUTTON, langConfig.getString("block.minecraft.spruce_button", "Spruce Button")));
        itemNames.add(new ItemName(Material.BIRCH_BUTTON, langConfig.getString("block.minecraft.birch_button", "Birch Button")));
        itemNames.add(new ItemName(Material.JUNGLE_BUTTON, langConfig.getString("block.minecraft.jungle_button", "Jungle Button")));
        itemNames.add(new ItemName(Material.ACACIA_BUTTON, langConfig.getString("block.minecraft.acacia_button", "Acacia Button")));
        itemNames.add(new ItemName(Material.DARK_OAK_BUTTON, langConfig.getString("block.minecraft.dark_oak_button", "Dark Oak Button")));
        itemNames.add(new ItemName(Material.SNOW, langConfig.getString("block.minecraft.snow", "Snow")));
        itemNames.add(new ItemName(Material.WHITE_CARPET, langConfig.getString("block.minecraft.white_carpet", "White Carpet")));
        itemNames.add(new ItemName(Material.ORANGE_CARPET, langConfig.getString("block.minecraft.orange_carpet", "Orange Carpet")));
        itemNames.add(new ItemName(Material.MAGENTA_CARPET, langConfig.getString("block.minecraft.magenta_carpet", "Magenta Carpet")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_CARPET, langConfig.getString("block.minecraft.light_blue_carpet", "Light Blue Carpet")));
        itemNames.add(new ItemName(Material.YELLOW_CARPET, langConfig.getString("block.minecraft.yellow_carpet", "Yellow Carpet")));
        itemNames.add(new ItemName(Material.LIME_CARPET, langConfig.getString("block.minecraft.lime_carpet", "Lime Carpet")));
        itemNames.add(new ItemName(Material.PINK_CARPET, langConfig.getString("block.minecraft.pink_carpet", "Pink Carpet")));
        itemNames.add(new ItemName(Material.GRAY_CARPET, langConfig.getString("block.minecraft.gray_carpet", "Gray Carpet")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_CARPET, langConfig.getString("block.minecraft.light_gray_carpet", "Light Gray Carpet")));
        itemNames.add(new ItemName(Material.CYAN_CARPET, langConfig.getString("block.minecraft.cyan_carpet", "Cyan Carpet")));
        itemNames.add(new ItemName(Material.PURPLE_CARPET, langConfig.getString("block.minecraft.purple_carpet", "Purple Carpet")));
        itemNames.add(new ItemName(Material.BLUE_CARPET, langConfig.getString("block.minecraft.blue_carpet", "Blue Carpet")));
        itemNames.add(new ItemName(Material.BROWN_CARPET, langConfig.getString("block.minecraft.brown_carpet", "Brown Carpet")));
        itemNames.add(new ItemName(Material.GREEN_CARPET, langConfig.getString("block.minecraft.green_carpet", "Green Carpet")));
        itemNames.add(new ItemName(Material.RED_CARPET, langConfig.getString("block.minecraft.red_carpet", "Red Carpet")));
        itemNames.add(new ItemName(Material.BLACK_CARPET, langConfig.getString("block.minecraft.black_carpet", "Black Carpet")));
        itemNames.add(new ItemName(Material.ICE, langConfig.getString("block.minecraft.ice", "Ice")));
        itemNames.add(new ItemName(Material.FROSTED_ICE, langConfig.getString("block.minecraft.frosted_ice", "Frosted Ice")));
        itemNames.add(new ItemName(Material.PACKED_ICE, langConfig.getString("block.minecraft.packed_ice", "Packed Ice")));
        itemNames.add(new ItemName(Material.BLUE_ICE, langConfig.getString("block.minecraft.blue_ice", "Blue Ice")));
        itemNames.add(new ItemName(Material.CACTUS, langConfig.getString("block.minecraft.cactus", "Cactus")));
        itemNames.add(new ItemName(Material.CLAY, langConfig.getString("block.minecraft.clay", "Clay")));
        itemNames.add(new ItemName(Material.WHITE_TERRACOTTA, langConfig.getString("block.minecraft.white_terracotta", "White Terracotta")));
        itemNames.add(new ItemName(Material.ORANGE_TERRACOTTA, langConfig.getString("block.minecraft.orange_terracotta", "Orange Terracotta")));
        itemNames.add(new ItemName(Material.MAGENTA_TERRACOTTA, langConfig.getString("block.minecraft.magenta_terracotta", "Magenta Terracotta")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_TERRACOTTA, langConfig.getString("block.minecraft.light_blue_terracotta", "Light Blue Terracotta")));
        itemNames.add(new ItemName(Material.YELLOW_TERRACOTTA, langConfig.getString("block.minecraft.yellow_terracotta", "Yellow Terracotta")));
        itemNames.add(new ItemName(Material.LIME_TERRACOTTA, langConfig.getString("block.minecraft.lime_terracotta", "Lime Terracotta")));
        itemNames.add(new ItemName(Material.PINK_TERRACOTTA, langConfig.getString("block.minecraft.pink_terracotta", "Pink Terracotta")));
        itemNames.add(new ItemName(Material.GRAY_TERRACOTTA, langConfig.getString("block.minecraft.gray_terracotta", "Gray Terracotta")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_TERRACOTTA, langConfig.getString("block.minecraft.light_gray_terracotta", "Light Gray Terracotta")));
        itemNames.add(new ItemName(Material.CYAN_TERRACOTTA, langConfig.getString("block.minecraft.cyan_terracotta", "Cyan Terracotta")));
        itemNames.add(new ItemName(Material.PURPLE_TERRACOTTA, langConfig.getString("block.minecraft.purple_terracotta", "Purple Terracotta")));
        itemNames.add(new ItemName(Material.BLUE_TERRACOTTA, langConfig.getString("block.minecraft.blue_terracotta", "Blue Terracotta")));
        itemNames.add(new ItemName(Material.BROWN_TERRACOTTA, langConfig.getString("block.minecraft.brown_terracotta", "Brown Terracotta")));
        itemNames.add(new ItemName(Material.GREEN_TERRACOTTA, langConfig.getString("block.minecraft.green_terracotta", "Green Terracotta")));
        itemNames.add(new ItemName(Material.RED_TERRACOTTA, langConfig.getString("block.minecraft.red_terracotta", "Red Terracotta")));
        itemNames.add(new ItemName(Material.BLACK_TERRACOTTA, langConfig.getString("block.minecraft.black_terracotta", "Black Terracotta")));
        itemNames.add(new ItemName(Material.TERRACOTTA, langConfig.getString("block.minecraft.terracotta", "Terracotta")));
        itemNames.add(new ItemName(Material.SUGAR_CANE, langConfig.getString("block.minecraft.sugar_cane", "Sugar Cane")));
        itemNames.add(new ItemName(Material.JUKEBOX, langConfig.getString("block.minecraft.jukebox", "Jukebox")));
        itemNames.add(new ItemName(Material.OAK_FENCE, langConfig.getString("block.minecraft.oak_fence", "Oak Fence")));
        itemNames.add(new ItemName(Material.SPRUCE_FENCE, langConfig.getString("block.minecraft.spruce_fence", "Spruce Fence")));
        itemNames.add(new ItemName(Material.BIRCH_FENCE, langConfig.getString("block.minecraft.birch_fence", "Birch Fence")));
        itemNames.add(new ItemName(Material.JUNGLE_FENCE, langConfig.getString("block.minecraft.jungle_fence", "Jungle Fence")));
        itemNames.add(new ItemName(Material.DARK_OAK_FENCE, langConfig.getString("block.minecraft.dark_oak_fence", "Dark Oak Fence")));
        itemNames.add(new ItemName(Material.ACACIA_FENCE, langConfig.getString("block.minecraft.acacia_fence", "Acacia Fence")));
        itemNames.add(new ItemName(Material.OAK_FENCE_GATE, langConfig.getString("block.minecraft.oak_fence_gate", "Oak Fence Gate")));
        itemNames.add(new ItemName(Material.SPRUCE_FENCE_GATE, langConfig.getString("block.minecraft.spruce_fence_gate", "Spruce Fence Gate")));
        itemNames.add(new ItemName(Material.BIRCH_FENCE_GATE, langConfig.getString("block.minecraft.birch_fence_gate", "Birch Fence Gate")));
        itemNames.add(new ItemName(Material.JUNGLE_FENCE_GATE, langConfig.getString("block.minecraft.jungle_fence_gate", "Jungle Fence Gate")));
        itemNames.add(new ItemName(Material.DARK_OAK_FENCE_GATE, langConfig.getString("block.minecraft.dark_oak_fence_gate", "Dark Oak Fence Gate")));
        itemNames.add(new ItemName(Material.ACACIA_FENCE_GATE, langConfig.getString("block.minecraft.acacia_fence_gate", "Acacia Fence Gate")));
        itemNames.add(new ItemName(Material.PUMPKIN_STEM, langConfig.getString("block.minecraft.pumpkin_stem", "Pumpkin Stem")));
        itemNames.add(new ItemName(Material.ATTACHED_PUMPKIN_STEM, langConfig.getString("block.minecraft.attached_pumpkin_stem", "Attached Pumpkin Stem")));
        itemNames.add(new ItemName(Material.PUMPKIN, langConfig.getString("block.minecraft.pumpkin", "Pumpkin")));
        itemNames.add(new ItemName(Material.CARVED_PUMPKIN, langConfig.getString("block.minecraft.carved_pumpkin", "Carved Pumpkin")));
        itemNames.add(new ItemName(Material.JACK_O_LANTERN, langConfig.getString("block.minecraft.jack_o_lantern", "Jack o'Lantern")));
        itemNames.add(new ItemName(Material.NETHERRACK, langConfig.getString("block.minecraft.netherrack", "Netherrack")));
        itemNames.add(new ItemName(Material.SOUL_SAND, langConfig.getString("block.minecraft.soul_sand", "Soul Sand")));
        itemNames.add(new ItemName(Material.GLOWSTONE, langConfig.getString("block.minecraft.glowstone", "Glowstone")));
        itemNames.add(new ItemName(Material.NETHER_PORTAL, langConfig.getString("block.minecraft.nether_portal", "Nether Portal")));
        itemNames.add(new ItemName(Material.WHITE_WOOL, langConfig.getString("block.minecraft.white_wool", "White Wool")));
        itemNames.add(new ItemName(Material.ORANGE_WOOL, langConfig.getString("block.minecraft.orange_wool", "Orange Wool")));
        itemNames.add(new ItemName(Material.MAGENTA_WOOL, langConfig.getString("block.minecraft.magenta_wool", "Magenta Wool")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_WOOL, langConfig.getString("block.minecraft.light_blue_wool", "Light Blue Wool")));
        itemNames.add(new ItemName(Material.YELLOW_WOOL, langConfig.getString("block.minecraft.yellow_wool", "Yellow Wool")));
        itemNames.add(new ItemName(Material.LIME_WOOL, langConfig.getString("block.minecraft.lime_wool", "Lime Wool")));
        itemNames.add(new ItemName(Material.PINK_WOOL, langConfig.getString("block.minecraft.pink_wool", "Pink Wool")));
        itemNames.add(new ItemName(Material.GRAY_WOOL, langConfig.getString("block.minecraft.gray_wool", "Gray Wool")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_WOOL, langConfig.getString("block.minecraft.light_gray_wool", "Light Gray Wool")));
        itemNames.add(new ItemName(Material.CYAN_WOOL, langConfig.getString("block.minecraft.cyan_wool", "Cyan Wool")));
        itemNames.add(new ItemName(Material.PURPLE_WOOL, langConfig.getString("block.minecraft.purple_wool", "Purple Wool")));
        itemNames.add(new ItemName(Material.BLUE_WOOL, langConfig.getString("block.minecraft.blue_wool", "Blue Wool")));
        itemNames.add(new ItemName(Material.BROWN_WOOL, langConfig.getString("block.minecraft.brown_wool", "Brown Wool")));
        itemNames.add(new ItemName(Material.GREEN_WOOL, langConfig.getString("block.minecraft.green_wool", "Green Wool")));
        itemNames.add(new ItemName(Material.RED_WOOL, langConfig.getString("block.minecraft.red_wool", "Red Wool")));
        itemNames.add(new ItemName(Material.BLACK_WOOL, langConfig.getString("block.minecraft.black_wool", "Black Wool")));
        itemNames.add(new ItemName(Material.LAPIS_ORE, langConfig.getString("block.minecraft.lapis_ore", "Lapis Lazuli Ore")));
        itemNames.add(new ItemName(Material.LAPIS_BLOCK, langConfig.getString("block.minecraft.lapis_block", "Lapis Lazuli Block")));
        itemNames.add(new ItemName(Material.DISPENSER, langConfig.getString("block.minecraft.dispenser", "Dispenser")));
        itemNames.add(new ItemName(Material.DROPPER, langConfig.getString("block.minecraft.dropper", "Dropper")));
        itemNames.add(new ItemName(Material.NOTE_BLOCK, langConfig.getString("block.minecraft.note_block", "Note Block")));
        itemNames.add(new ItemName(Material.CAKE, langConfig.getString("block.minecraft.cake", "Cake")));
        itemNames.add(new ItemName(Material.OAK_TRAPDOOR, langConfig.getString("block.minecraft.oak_trapdoor", "Oak Trapdoor")));
        itemNames.add(new ItemName(Material.SPRUCE_TRAPDOOR, langConfig.getString("block.minecraft.spruce_trapdoor", "Spruce Trapdoor")));
        itemNames.add(new ItemName(Material.BIRCH_TRAPDOOR, langConfig.getString("block.minecraft.birch_trapdoor", "Birch Trapdoor")));
        itemNames.add(new ItemName(Material.JUNGLE_TRAPDOOR, langConfig.getString("block.minecraft.jungle_trapdoor", "Jungle Trapdoor")));
        itemNames.add(new ItemName(Material.ACACIA_TRAPDOOR, langConfig.getString("block.minecraft.acacia_trapdoor", "Acacia Trapdoor")));
        itemNames.add(new ItemName(Material.DARK_OAK_TRAPDOOR, langConfig.getString("block.minecraft.dark_oak_trapdoor", "Dark Oak Trapdoor")));
        itemNames.add(new ItemName(Material.IRON_TRAPDOOR, langConfig.getString("block.minecraft.iron_trapdoor", "Iron Trapdoor")));
        itemNames.add(new ItemName(Material.COBWEB, langConfig.getString("block.minecraft.cobweb", "Cobweb")));
        itemNames.add(new ItemName(Material.STONE_BRICKS, langConfig.getString("block.minecraft.stone_bricks", "Stone Bricks")));
        itemNames.add(new ItemName(Material.MOSSY_STONE_BRICKS, langConfig.getString("block.minecraft.mossy_stone_bricks", "Mossy Stone Bricks")));
        itemNames.add(new ItemName(Material.CRACKED_STONE_BRICKS, langConfig.getString("block.minecraft.cracked_stone_bricks", "Cracked Stone Bricks")));
        itemNames.add(new ItemName(Material.CHISELED_STONE_BRICKS, langConfig.getString("block.minecraft.chiseled_stone_bricks", "Chiseled Stone Bricks")));
        itemNames.add(new ItemName(Material.INFESTED_STONE, langConfig.getString("block.minecraft.infested_stone", "Infested Stone")));
        itemNames.add(new ItemName(Material.INFESTED_COBBLESTONE, langConfig.getString("block.minecraft.infested_cobblestone", "Infested Cobblestone")));
        itemNames.add(new ItemName(Material.INFESTED_STONE_BRICKS, langConfig.getString("block.minecraft.infested_stone_bricks", "Infested Stone Bricks")));
        itemNames.add(new ItemName(Material.INFESTED_MOSSY_STONE_BRICKS, langConfig.getString("block.minecraft.infested_mossy_stone_bricks", "Infested Mossy Stone Bricks")));
        itemNames.add(new ItemName(Material.INFESTED_CRACKED_STONE_BRICKS, langConfig.getString("block.minecraft.infested_cracked_stone_bricks", "Infested Cracked Stone Bricks")));
        itemNames.add(new ItemName(Material.INFESTED_CHISELED_STONE_BRICKS, langConfig.getString("block.minecraft.infested_chiseled_stone_bricks", "Infested Chiseled Stone Bricks")));
        itemNames.add(new ItemName(Material.PISTON, langConfig.getString("block.minecraft.piston", "Piston")));
        itemNames.add(new ItemName(Material.STICKY_PISTON, langConfig.getString("block.minecraft.sticky_piston", "Sticky Piston")));
        itemNames.add(new ItemName(Material.IRON_BARS, langConfig.getString("block.minecraft.iron_bars", "Iron Bars")));
        itemNames.add(new ItemName(Material.MELON, langConfig.getString("block.minecraft.melon", "Melon")));
        itemNames.add(new ItemName(Material.BRICK_STAIRS, langConfig.getString("block.minecraft.brick_stairs", "Brick Stairs")));
        itemNames.add(new ItemName(Material.STONE_BRICK_STAIRS, langConfig.getString("block.minecraft.stone_brick_stairs", "Stone Brick Stairs")));
        itemNames.add(new ItemName(Material.VINE, langConfig.getString("block.minecraft.vine", "Vines")));
        itemNames.add(new ItemName(Material.NETHER_BRICKS, langConfig.getString("block.minecraft.nether_bricks", "Nether Bricks")));
        itemNames.add(new ItemName(Material.NETHER_BRICK_FENCE, langConfig.getString("block.minecraft.nether_brick_fence", "Nether Brick Fence")));
        itemNames.add(new ItemName(Material.NETHER_BRICK_STAIRS, langConfig.getString("block.minecraft.nether_brick_stairs", "Nether Brick Stairs")));
        itemNames.add(new ItemName(Material.NETHER_WART, langConfig.getString("block.minecraft.nether_wart", "Nether Wart")));
        itemNames.add(new ItemName(Material.CAULDRON, langConfig.getString("block.minecraft.cauldron", "Cauldron")));
        itemNames.add(new ItemName(Material.ENCHANTING_TABLE, langConfig.getString("block.minecraft.enchanting_table", "Enchanting Table")));
        itemNames.add(new ItemName(Material.ANVIL, langConfig.getString("block.minecraft.anvil", "Anvil")));
        itemNames.add(new ItemName(Material.CHIPPED_ANVIL, langConfig.getString("block.minecraft.chipped_anvil", "Chipped Anvil")));
        itemNames.add(new ItemName(Material.DAMAGED_ANVIL, langConfig.getString("block.minecraft.damaged_anvil", "Damaged Anvil")));
        itemNames.add(new ItemName(Material.END_STONE, langConfig.getString("block.minecraft.end_stone", "End Stone")));
        itemNames.add(new ItemName(Material.END_PORTAL_FRAME, langConfig.getString("block.minecraft.end_portal_frame", "End Portal Frame")));
        itemNames.add(new ItemName(Material.MYCELIUM, langConfig.getString("block.minecraft.mycelium", "Mycelium")));
        itemNames.add(new ItemName(Material.LILY_PAD, langConfig.getString("block.minecraft.lily_pad", "Lily Pad")));
        itemNames.add(new ItemName(Material.DRAGON_EGG, langConfig.getString("block.minecraft.dragon_egg", "Dragon Egg")));
        itemNames.add(new ItemName(Material.REDSTONE_LAMP, langConfig.getString("block.minecraft.redstone_lamp", "Redstone Lamp")));
        itemNames.add(new ItemName(Material.COCOA, langConfig.getString("block.minecraft.cocoa", "Cocoa")));
        itemNames.add(new ItemName(Material.ENDER_CHEST, langConfig.getString("block.minecraft.ender_chest", "Ender Chest")));
        itemNames.add(new ItemName(Material.EMERALD_ORE, langConfig.getString("block.minecraft.emerald_ore", "Emerald Ore")));
        itemNames.add(new ItemName(Material.EMERALD_BLOCK, langConfig.getString("block.minecraft.emerald_block", "Block of Emerald")));
        itemNames.add(new ItemName(Material.REDSTONE_BLOCK, langConfig.getString("block.minecraft.redstone_block", "Block of Redstone")));
        itemNames.add(new ItemName(Material.TRIPWIRE, langConfig.getString("block.minecraft.tripwire", "Tripwire")));
        itemNames.add(new ItemName(Material.TRIPWIRE_HOOK, langConfig.getString("block.minecraft.tripwire_hook", "Tripwire Hook")));
        itemNames.add(new ItemName(Material.COMMAND_BLOCK, langConfig.getString("block.minecraft.command_block", "Command Block")));
        itemNames.add(new ItemName(Material.REPEATING_COMMAND_BLOCK, langConfig.getString("block.minecraft.repeating_command_block", "Repeating Command Block")));
        itemNames.add(new ItemName(Material.CHAIN_COMMAND_BLOCK, langConfig.getString("block.minecraft.chain_command_block", "Chain Command Block")));
        itemNames.add(new ItemName(Material.BEACON, langConfig.getString("block.minecraft.beacon", "Beacon")));
        itemNames.add(new ItemName(Material.COBBLESTONE_WALL, langConfig.getString("block.minecraft.cobblestone_wall", "Cobblestone Wall")));
        itemNames.add(new ItemName(Material.MOSSY_COBBLESTONE_WALL, langConfig.getString("block.minecraft.mossy_cobblestone_wall", "Mossy Cobblestone Wall")));
        itemNames.add(new ItemName(Material.CARROTS, langConfig.getString("block.minecraft.carrots", "Carrots")));
        itemNames.add(new ItemName(Material.POTATOES, langConfig.getString("block.minecraft.potatoes", "Potatoes")));
        itemNames.add(new ItemName(Material.DAYLIGHT_DETECTOR, langConfig.getString("block.minecraft.daylight_detector", "Daylight Detector")));
        itemNames.add(new ItemName(Material.NETHER_QUARTZ_ORE, langConfig.getString("block.minecraft.nether_quartz_ore", "Nether Quartz Ore")));
        itemNames.add(new ItemName(Material.HOPPER, langConfig.getString("block.minecraft.hopper", "Hopper")));
        itemNames.add(new ItemName(Material.QUARTZ_BLOCK, langConfig.getString("block.minecraft.quartz_block", "Block of Quartz")));
        itemNames.add(new ItemName(Material.CHISELED_QUARTZ_BLOCK, langConfig.getString("block.minecraft.chiseled_quartz_block", "Chiseled Quartz Block")));
        itemNames.add(new ItemName(Material.QUARTZ_PILLAR, langConfig.getString("block.minecraft.quartz_pillar", "Quartz Pillar")));
        itemNames.add(new ItemName(Material.QUARTZ_STAIRS, langConfig.getString("block.minecraft.quartz_stairs", "Quartz Stairs")));
        itemNames.add(new ItemName(Material.SLIME_BLOCK, langConfig.getString("block.minecraft.slime_block", "Slime Block")));
        itemNames.add(new ItemName(Material.PRISMARINE, langConfig.getString("block.minecraft.prismarine", "Prismarine")));
        itemNames.add(new ItemName(Material.PRISMARINE_BRICKS, langConfig.getString("block.minecraft.prismarine_bricks", "Prismarine Bricks")));
        itemNames.add(new ItemName(Material.DARK_PRISMARINE, langConfig.getString("block.minecraft.dark_prismarine", "Dark Prismarine")));
        itemNames.add(new ItemName(Material.SEA_LANTERN, langConfig.getString("block.minecraft.sea_lantern", "Sea Lantern")));
        itemNames.add(new ItemName(Material.END_ROD, langConfig.getString("block.minecraft.end_rod", "End Rod")));
        itemNames.add(new ItemName(Material.CHORUS_PLANT, langConfig.getString("block.minecraft.chorus_plant", "Chorus Plant")));
        itemNames.add(new ItemName(Material.CHORUS_FLOWER, langConfig.getString("block.minecraft.chorus_flower", "Chorus Flower")));
        itemNames.add(new ItemName(Material.PURPUR_BLOCK, langConfig.getString("block.minecraft.purpur_block", "Purpur Block")));
        itemNames.add(new ItemName(Material.PURPUR_PILLAR, langConfig.getString("block.minecraft.purpur_pillar", "Purpur Pillar")));
        itemNames.add(new ItemName(Material.PURPUR_STAIRS, langConfig.getString("block.minecraft.purpur_stairs", "Purpur Stairs")));
        itemNames.add(new ItemName(Material.PURPUR_SLAB, langConfig.getString("block.minecraft.purpur_slab", "Purpur Slab")));
        itemNames.add(new ItemName(Material.END_STONE_BRICKS, langConfig.getString("block.minecraft.end_stone_bricks", "End Stone Bricks")));
        itemNames.add(new ItemName(Material.BEETROOTS, langConfig.getString("block.minecraft.beetroots", "Beetroots")));
        itemNames.add(new ItemName(Material.MAGMA_BLOCK, langConfig.getString("block.minecraft.magma_block", "Magma Block")));
        itemNames.add(new ItemName(Material.NETHER_WART_BLOCK, langConfig.getString("block.minecraft.nether_wart_block", "Nether Wart Block")));
        itemNames.add(new ItemName(Material.RED_NETHER_BRICKS, langConfig.getString("block.minecraft.red_nether_bricks", "Red Nether Bricks")));
        itemNames.add(new ItemName(Material.BONE_BLOCK, langConfig.getString("block.minecraft.bone_block", "Bone Block")));
        itemNames.add(new ItemName(Material.OBSERVER, langConfig.getString("block.minecraft.observer", "Observer")));
        itemNames.add(new ItemName(Material.SHULKER_BOX, langConfig.getString("block.minecraft.shulker_box", "Shulker Box")));
        itemNames.add(new ItemName(Material.WHITE_SHULKER_BOX, langConfig.getString("block.minecraft.white_shulker_box", "White Shulker Box")));
        itemNames.add(new ItemName(Material.ORANGE_SHULKER_BOX, langConfig.getString("block.minecraft.orange_shulker_box", "Orange Shulker Box")));
        itemNames.add(new ItemName(Material.MAGENTA_SHULKER_BOX, langConfig.getString("block.minecraft.magenta_shulker_box", "Magenta Shulker Box")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_SHULKER_BOX, langConfig.getString("block.minecraft.light_blue_shulker_box", "Light Blue Shulker Box")));
        itemNames.add(new ItemName(Material.YELLOW_SHULKER_BOX, langConfig.getString("block.minecraft.yellow_shulker_box", "Yellow Shulker Box")));
        itemNames.add(new ItemName(Material.LIME_SHULKER_BOX, langConfig.getString("block.minecraft.lime_shulker_box", "Lime Shulker Box")));
        itemNames.add(new ItemName(Material.PINK_SHULKER_BOX, langConfig.getString("block.minecraft.pink_shulker_box", "Pink Shulker Box")));
        itemNames.add(new ItemName(Material.GRAY_SHULKER_BOX, langConfig.getString("block.minecraft.gray_shulker_box", "Gray Shulker Box")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_SHULKER_BOX, langConfig.getString("block.minecraft.light_gray_shulker_box", "Light Gray Shulker Box")));
        itemNames.add(new ItemName(Material.CYAN_SHULKER_BOX, langConfig.getString("block.minecraft.cyan_shulker_box", "Cyan Shulker Box")));
        itemNames.add(new ItemName(Material.PURPLE_SHULKER_BOX, langConfig.getString("block.minecraft.purple_shulker_box", "Purple Shulker Box")));
        itemNames.add(new ItemName(Material.BLUE_SHULKER_BOX, langConfig.getString("block.minecraft.blue_shulker_box", "Blue Shulker Box")));
        itemNames.add(new ItemName(Material.BROWN_SHULKER_BOX, langConfig.getString("block.minecraft.brown_shulker_box", "Brown Shulker Box")));
        itemNames.add(new ItemName(Material.GREEN_SHULKER_BOX, langConfig.getString("block.minecraft.green_shulker_box", "Green Shulker Box")));
        itemNames.add(new ItemName(Material.RED_SHULKER_BOX, langConfig.getString("block.minecraft.red_shulker_box", "Red Shulker Box")));
        itemNames.add(new ItemName(Material.BLACK_SHULKER_BOX, langConfig.getString("block.minecraft.black_shulker_box", "Black Shulker Box")));
        itemNames.add(new ItemName(Material.WHITE_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.white_glazed_terracotta", "White Glazed Terracotta")));
        itemNames.add(new ItemName(Material.ORANGE_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.orange_glazed_terracotta", "Orange Glazed Terracotta")));
        itemNames.add(new ItemName(Material.MAGENTA_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.magenta_glazed_terracotta", "Magenta Glazed Terracotta")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.light_blue_glazed_terracotta", "Light Blue Glazed Terracotta")));
        itemNames.add(new ItemName(Material.YELLOW_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.yellow_glazed_terracotta", "Yellow Glazed Terracotta")));
        itemNames.add(new ItemName(Material.LIME_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.lime_glazed_terracotta", "Lime Glazed Terracotta")));
        itemNames.add(new ItemName(Material.PINK_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.pink_glazed_terracotta", "Pink Glazed Terracotta")));
        itemNames.add(new ItemName(Material.GRAY_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.gray_glazed_terracotta", "Gray Glazed Terracotta")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.light_gray_glazed_terracotta", "Light Gray Glazed Terracotta")));
        itemNames.add(new ItemName(Material.CYAN_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.cyan_glazed_terracotta", "Cyan Glazed Terracotta")));
        itemNames.add(new ItemName(Material.PURPLE_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.purple_glazed_terracotta", "Purple Glazed Terracotta")));
        itemNames.add(new ItemName(Material.BLUE_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.blue_glazed_terracotta", "Blue Glazed Terracotta")));
        itemNames.add(new ItemName(Material.BROWN_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.brown_glazed_terracotta", "Brown Glazed Terracotta")));
        itemNames.add(new ItemName(Material.GREEN_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.green_glazed_terracotta", "Green Glazed Terracotta")));
        itemNames.add(new ItemName(Material.RED_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.red_glazed_terracotta", "Red Glazed Terracotta")));
        itemNames.add(new ItemName(Material.BLACK_GLAZED_TERRACOTTA, langConfig.getString("block.minecraft.black_glazed_terracotta", "Black Glazed Terracotta")));
        itemNames.add(new ItemName(Material.BLACK_CONCRETE, langConfig.getString("block.minecraft.black_concrete", "Black Concrete")));
        itemNames.add(new ItemName(Material.RED_CONCRETE, langConfig.getString("block.minecraft.red_concrete", "Red Concrete")));
        itemNames.add(new ItemName(Material.GREEN_CONCRETE, langConfig.getString("block.minecraft.green_concrete", "Green Concrete")));
        itemNames.add(new ItemName(Material.BROWN_CONCRETE, langConfig.getString("block.minecraft.brown_concrete", "Brown Concrete")));
        itemNames.add(new ItemName(Material.BLUE_CONCRETE, langConfig.getString("block.minecraft.blue_concrete", "Blue Concrete")));
        itemNames.add(new ItemName(Material.PURPLE_CONCRETE, langConfig.getString("block.minecraft.purple_concrete", "Purple Concrete")));
        itemNames.add(new ItemName(Material.CYAN_CONCRETE, langConfig.getString("block.minecraft.cyan_concrete", "Cyan Concrete")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_CONCRETE, langConfig.getString("block.minecraft.light_gray_concrete", "Light Gray Concrete")));
        itemNames.add(new ItemName(Material.GRAY_CONCRETE, langConfig.getString("block.minecraft.gray_concrete", "Gray Concrete")));
        itemNames.add(new ItemName(Material.PINK_CONCRETE, langConfig.getString("block.minecraft.pink_concrete", "Pink Concrete")));
        itemNames.add(new ItemName(Material.LIME_CONCRETE, langConfig.getString("block.minecraft.lime_concrete", "Lime Concrete")));
        itemNames.add(new ItemName(Material.YELLOW_CONCRETE, langConfig.getString("block.minecraft.yellow_concrete", "Yellow Concrete")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_CONCRETE, langConfig.getString("block.minecraft.light_blue_concrete", "Light Blue Concrete")));
        itemNames.add(new ItemName(Material.MAGENTA_CONCRETE, langConfig.getString("block.minecraft.magenta_concrete", "Magenta Concrete")));
        itemNames.add(new ItemName(Material.ORANGE_CONCRETE, langConfig.getString("block.minecraft.orange_concrete", "Orange Concrete")));
        itemNames.add(new ItemName(Material.WHITE_CONCRETE, langConfig.getString("block.minecraft.white_concrete", "White Concrete")));
        itemNames.add(new ItemName(Material.BLACK_CONCRETE_POWDER, langConfig.getString("block.minecraft.black_concrete_powder", "Black Concrete Powder")));
        itemNames.add(new ItemName(Material.RED_CONCRETE_POWDER, langConfig.getString("block.minecraft.red_concrete_powder", "Red Concrete Powder")));
        itemNames.add(new ItemName(Material.GREEN_CONCRETE_POWDER, langConfig.getString("block.minecraft.green_concrete_powder", "Green Concrete Powder")));
        itemNames.add(new ItemName(Material.BROWN_CONCRETE_POWDER, langConfig.getString("block.minecraft.brown_concrete_powder", "Brown Concrete Powder")));
        itemNames.add(new ItemName(Material.BLUE_CONCRETE_POWDER, langConfig.getString("block.minecraft.blue_concrete_powder", "Blue Concrete Powder")));
        itemNames.add(new ItemName(Material.PURPLE_CONCRETE_POWDER, langConfig.getString("block.minecraft.purple_concrete_powder", "Purple Concrete Powder")));
        itemNames.add(new ItemName(Material.CYAN_CONCRETE_POWDER, langConfig.getString("block.minecraft.cyan_concrete_powder", "Cyan Concrete Powder")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_CONCRETE_POWDER, langConfig.getString("block.minecraft.light_gray_concrete_powder", "Light Gray Concrete Powder")));
        itemNames.add(new ItemName(Material.GRAY_CONCRETE_POWDER, langConfig.getString("block.minecraft.gray_concrete_powder", "Gray Concrete Powder")));
        itemNames.add(new ItemName(Material.PINK_CONCRETE_POWDER, langConfig.getString("block.minecraft.pink_concrete_powder", "Pink Concrete Powder")));
        itemNames.add(new ItemName(Material.LIME_CONCRETE_POWDER, langConfig.getString("block.minecraft.lime_concrete_powder", "Lime Concrete Powder")));
        itemNames.add(new ItemName(Material.YELLOW_CONCRETE_POWDER, langConfig.getString("block.minecraft.yellow_concrete_powder", "Yellow Concrete Powder")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_CONCRETE_POWDER, langConfig.getString("block.minecraft.light_blue_concrete_powder", "Light Blue Concrete Powder")));
        itemNames.add(new ItemName(Material.MAGENTA_CONCRETE_POWDER, langConfig.getString("block.minecraft.magenta_concrete_powder", "Magenta Concrete Powder")));
        itemNames.add(new ItemName(Material.ORANGE_CONCRETE_POWDER, langConfig.getString("block.minecraft.orange_concrete_powder", "Orange Concrete Powder")));
        itemNames.add(new ItemName(Material.WHITE_CONCRETE_POWDER, langConfig.getString("block.minecraft.white_concrete_powder", "White Concrete Powder")));
        itemNames.add(new ItemName(Material.TURTLE_EGG, langConfig.getString("block.minecraft.turtle_egg", "Turtle Egg")));
        itemNames.add(new ItemName(Material.PISTON_HEAD, langConfig.getString("block.minecraft.piston_head", "Piston Head")));
        itemNames.add(new ItemName(Material.MOVING_PISTON, langConfig.getString("block.minecraft.moving_piston", "Moving Piston")));
        itemNames.add(new ItemName(Material.RED_MUSHROOM, langConfig.getString("block.minecraft.red_mushroom", "Red Mushroom")));
        itemNames.add(new ItemName(Material.SNOW_BLOCK, langConfig.getString("block.minecraft.snow_block", "Snow Block")));
        itemNames.add(new ItemName(Material.ATTACHED_MELON_STEM, langConfig.getString("block.minecraft.attached_melon_stem", "Attached Melon Stem")));
        itemNames.add(new ItemName(Material.MELON_STEM, langConfig.getString("block.minecraft.melon_stem", "Melon Stem")));
        itemNames.add(new ItemName(Material.BREWING_STAND, langConfig.getString("block.minecraft.brewing_stand", "Brewing Stand")));
        itemNames.add(new ItemName(Material.END_PORTAL, langConfig.getString("block.minecraft.end_portal", "End Portal")));
        itemNames.add(new ItemName(Material.FLOWER_POT, langConfig.getString("block.minecraft.flower_pot", "Flower Pot")));
        itemNames.add(new ItemName(Material.POTTED_OAK_SAPLING, langConfig.getString("block.minecraft.potted_oak_sapling", "Potted Oak Sapling")));
        itemNames.add(new ItemName(Material.POTTED_SPRUCE_SAPLING, langConfig.getString("block.minecraft.potted_spruce_sapling", "Potted Spruce Sapling")));
        itemNames.add(new ItemName(Material.POTTED_BIRCH_SAPLING, langConfig.getString("block.minecraft.potted_birch_sapling", "Potted Birch Sapling")));
        itemNames.add(new ItemName(Material.POTTED_JUNGLE_SAPLING, langConfig.getString("block.minecraft.potted_jungle_sapling", "Potted Jungle Sapling")));
        itemNames.add(new ItemName(Material.POTTED_ACACIA_SAPLING, langConfig.getString("block.minecraft.potted_acacia_sapling", "Potted Acacia Sapling")));
        itemNames.add(new ItemName(Material.POTTED_DARK_OAK_SAPLING, langConfig.getString("block.minecraft.potted_dark_oak_sapling", "Potted Dark Oak Sapling")));
        itemNames.add(new ItemName(Material.POTTED_FERN, langConfig.getString("block.minecraft.potted_fern", "Potted Fern")));
        itemNames.add(new ItemName(Material.POTTED_DANDELION, langConfig.getString("block.minecraft.potted_dandelion", "Potted Dandelion")));
        itemNames.add(new ItemName(Material.POTTED_POPPY, langConfig.getString("block.minecraft.potted_poppy", "Potted Poppy")));
        itemNames.add(new ItemName(Material.POTTED_BLUE_ORCHID, langConfig.getString("block.minecraft.potted_blue_orchid", "Potted Blue Orchid")));
        itemNames.add(new ItemName(Material.POTTED_ALLIUM, langConfig.getString("block.minecraft.potted_allium", "Potted Allium")));
        itemNames.add(new ItemName(Material.POTTED_AZURE_BLUET, langConfig.getString("block.minecraft.potted_azure_bluet", "Potted Azure Bluet")));
        itemNames.add(new ItemName(Material.POTTED_RED_TULIP, langConfig.getString("block.minecraft.potted_red_tulip", "Potted Red Tulip")));
        itemNames.add(new ItemName(Material.POTTED_ORANGE_TULIP, langConfig.getString("block.minecraft.potted_orange_tulip", "Potted Orange Tulip")));
        itemNames.add(new ItemName(Material.POTTED_WHITE_TULIP, langConfig.getString("block.minecraft.potted_white_tulip", "Potted White Tulip")));
        itemNames.add(new ItemName(Material.POTTED_PINK_TULIP, langConfig.getString("block.minecraft.potted_pink_tulip", "Potted Pink Tulip")));
        itemNames.add(new ItemName(Material.POTTED_OXEYE_DAISY, langConfig.getString("block.minecraft.potted_oxeye_daisy", "Potted Oxeye Daisy")));
        itemNames.add(new ItemName(Material.POTTED_RED_MUSHROOM, langConfig.getString("block.minecraft.potted_red_mushroom", "Potted Red Mushroom")));
        itemNames.add(new ItemName(Material.POTTED_BROWN_MUSHROOM, langConfig.getString("block.minecraft.potted_brown_mushroom", "Potted Brown Mushroom")));
        itemNames.add(new ItemName(Material.POTTED_DEAD_BUSH, langConfig.getString("block.minecraft.potted_dead_bush", "Potted Dead Bush")));
        itemNames.add(new ItemName(Material.POTTED_CACTUS, langConfig.getString("block.minecraft.potted_cactus", "Potted Cactus")));
        itemNames.add(new ItemName(Material.SKELETON_WALL_SKULL, langConfig.getString("block.minecraft.skeleton_wall_skull", "Skeleton Wall Skull")));
        itemNames.add(new ItemName(Material.SKELETON_SKULL, langConfig.getString("block.minecraft.skeleton_skull", "Skeleton Skull")));
        itemNames.add(new ItemName(Material.WITHER_SKELETON_WALL_SKULL, langConfig.getString("block.minecraft.wither_skeleton_wall_skull", "Wither Skeleton Wall Skull")));
        itemNames.add(new ItemName(Material.WITHER_SKELETON_SKULL, langConfig.getString("block.minecraft.wither_skeleton_skull", "Wither Skeleton Skull")));
        itemNames.add(new ItemName(Material.ZOMBIE_WALL_HEAD, langConfig.getString("block.minecraft.zombie_wall_head", "Zombie Wall Head")));
        itemNames.add(new ItemName(Material.ZOMBIE_HEAD, langConfig.getString("block.minecraft.zombie_head", "Zombie Head")));
        itemNames.add(new ItemName(Material.PLAYER_WALL_HEAD, langConfig.getString("block.minecraft.player_wall_head", "Player Wall Head")));
        itemNames.add(new ItemName(Material.PLAYER_HEAD, langConfig.getString("block.minecraft.player_head", "Player Head")));
        itemNames.add(new ItemName(Material.CREEPER_WALL_HEAD, langConfig.getString("block.minecraft.creeper_wall_head", "Creeper Wall Head")));
        itemNames.add(new ItemName(Material.CREEPER_HEAD, langConfig.getString("block.minecraft.creeper_head", "Creeper Head")));
        itemNames.add(new ItemName(Material.DRAGON_WALL_HEAD, langConfig.getString("block.minecraft.dragon_wall_head", "Dragon Wall Head")));
        itemNames.add(new ItemName(Material.DRAGON_HEAD, langConfig.getString("block.minecraft.dragon_head", "Dragon Head")));
        itemNames.add(new ItemName(Material.END_GATEWAY, langConfig.getString("block.minecraft.end_gateway", "End Gateway")));
        itemNames.add(new ItemName(Material.STRUCTURE_VOID, langConfig.getString("block.minecraft.structure_void", "Structure Void")));
        itemNames.add(new ItemName(Material.STRUCTURE_BLOCK, langConfig.getString("block.minecraft.structure_block", "Structure Block")));
        itemNames.add(new ItemName(Material.VOID_AIR, langConfig.getString("block.minecraft.void_air", "Void Air")));
        itemNames.add(new ItemName(Material.CAVE_AIR, langConfig.getString("block.minecraft.cave_air", "Cave Air")));
        itemNames.add(new ItemName(Material.BUBBLE_COLUMN, langConfig.getString("block.minecraft.bubble_column", "Bubble Column")));
        itemNames.add(new ItemName(Material.DEAD_TUBE_CORAL_BLOCK, langConfig.getString("block.minecraft.dead_tube_coral_block", "Dead Tube Coral Block")));
        itemNames.add(new ItemName(Material.DEAD_BRAIN_CORAL_BLOCK, langConfig.getString("block.minecraft.dead_brain_coral_block", "Dead Brain Coral Block")));
        itemNames.add(new ItemName(Material.DEAD_BUBBLE_CORAL_BLOCK, langConfig.getString("block.minecraft.dead_bubble_coral_block", "Dead Bubble Coral Block")));
        itemNames.add(new ItemName(Material.DEAD_FIRE_CORAL_BLOCK, langConfig.getString("block.minecraft.dead_fire_coral_block", "Dead Fire Coral Block")));
        itemNames.add(new ItemName(Material.DEAD_HORN_CORAL_BLOCK, langConfig.getString("block.minecraft.dead_horn_coral_block", "Dead Horn Coral Block")));
        itemNames.add(new ItemName(Material.TUBE_CORAL_BLOCK, langConfig.getString("block.minecraft.tube_coral_block", "Tube Coral Block")));
        itemNames.add(new ItemName(Material.BRAIN_CORAL_BLOCK, langConfig.getString("block.minecraft.brain_coral_block", "Brain Coral Block")));
        itemNames.add(new ItemName(Material.BUBBLE_CORAL_BLOCK, langConfig.getString("block.minecraft.bubble_coral_block", "Bubble Coral Block")));
        itemNames.add(new ItemName(Material.FIRE_CORAL_BLOCK, langConfig.getString("block.minecraft.fire_coral_block", "Fire Coral Block")));
        itemNames.add(new ItemName(Material.HORN_CORAL_BLOCK, langConfig.getString("block.minecraft.horn_coral_block", "Horn Coral Block")));
        itemNames.add(new ItemName(Material.TUBE_CORAL, langConfig.getString("block.minecraft.tube_coral", "Tube Coral")));
        itemNames.add(new ItemName(Material.BRAIN_CORAL, langConfig.getString("block.minecraft.brain_coral", "Brain Coral")));
        itemNames.add(new ItemName(Material.BUBBLE_CORAL, langConfig.getString("block.minecraft.bubble_coral", "Bubble Coral")));
        itemNames.add(new ItemName(Material.FIRE_CORAL, langConfig.getString("block.minecraft.fire_coral", "Fire Coral")));
        itemNames.add(new ItemName(Material.HORN_CORAL, langConfig.getString("block.minecraft.horn_coral", "Horn Coral")));
        itemNames.add(new ItemName(Material.TUBE_CORAL_FAN, langConfig.getString("block.minecraft.tube_coral_fan", "Tube Coral Fan")));
        itemNames.add(new ItemName(Material.BRAIN_CORAL_FAN, langConfig.getString("block.minecraft.brain_coral_fan", "Brain Coral Fan")));
        itemNames.add(new ItemName(Material.BUBBLE_CORAL_FAN, langConfig.getString("block.minecraft.bubble_coral_fan", "Bubble Coral Fan")));
        itemNames.add(new ItemName(Material.FIRE_CORAL_FAN, langConfig.getString("block.minecraft.fire_coral_fan", "Fire Coral Fan")));
        itemNames.add(new ItemName(Material.HORN_CORAL_FAN, langConfig.getString("block.minecraft.horn_coral_fan", "Horn Coral Fan")));
        itemNames.add(new ItemName(Material.CONDUIT, langConfig.getString("block.minecraft.conduit", "Conduit")));
        itemNames.add(new ItemName(Material.NAME_TAG, langConfig.getString("item.minecraft.name_tag", "Name Tag")));
        itemNames.add(new ItemName(Material.LEAD, langConfig.getString("item.minecraft.lead", "Lead")));
        itemNames.add(new ItemName(Material.IRON_SHOVEL, langConfig.getString("item.minecraft.iron_shovel", "Iron Shovel")));
        itemNames.add(new ItemName(Material.IRON_PICKAXE, langConfig.getString("item.minecraft.iron_pickaxe", "Iron Pickaxe")));
        itemNames.add(new ItemName(Material.IRON_AXE, langConfig.getString("item.minecraft.iron_axe", "Iron Axe")));
        itemNames.add(new ItemName(Material.FLINT_AND_STEEL, langConfig.getString("item.minecraft.flint_and_steel", "Flint and Steel")));
        itemNames.add(new ItemName(Material.APPLE, langConfig.getString("item.minecraft.apple", "Apple")));
        itemNames.add(new ItemName(Material.COOKIE, langConfig.getString("item.minecraft.cookie", "Cookie")));
        itemNames.add(new ItemName(Material.BOW, langConfig.getString("item.minecraft.bow", "Bow")));
        itemNames.add(new ItemName(Material.ARROW, langConfig.getString("item.minecraft.arrow", "Arrow")));
        itemNames.add(new ItemName(Material.SPECTRAL_ARROW, langConfig.getString("item.minecraft.spectral_arrow", "Spectral Arrow")));
        itemNames.add(new ItemName(Material.TIPPED_ARROW, langConfig.getString("item.minecraft.tipped_arrow", "Tipped Arrow")));
        itemNames.add(new ItemName(Material.DRIED_KELP, langConfig.getString("item.minecraft.dried_kelp", "Dried Kelp")));
        itemNames.add(new ItemName(Material.COAL, langConfig.getString("item.minecraft.coal", "Coal")));
        itemNames.add(new ItemName(Material.CHARCOAL, langConfig.getString("item.minecraft.charcoal", "Charcoal")));
        itemNames.add(new ItemName(Material.DIAMOND, langConfig.getString("item.minecraft.diamond", "Diamond")));
        itemNames.add(new ItemName(Material.EMERALD, langConfig.getString("item.minecraft.emerald", "Emerald")));
        itemNames.add(new ItemName(Material.IRON_INGOT, langConfig.getString("item.minecraft.iron_ingot", "Iron Ingot")));
        itemNames.add(new ItemName(Material.GOLD_INGOT, langConfig.getString("item.minecraft.gold_ingot", "Gold Ingot")));
        itemNames.add(new ItemName(Material.IRON_SWORD, langConfig.getString("item.minecraft.iron_sword", "Iron Sword")));
        itemNames.add(new ItemName(Material.WOODEN_SWORD, langConfig.getString("item.minecraft.wooden_sword", "Wooden Sword")));
        itemNames.add(new ItemName(Material.WOODEN_SHOVEL, langConfig.getString("item.minecraft.wooden_shovel", "Wooden Shovel")));
        itemNames.add(new ItemName(Material.WOODEN_PICKAXE, langConfig.getString("item.minecraft.wooden_pickaxe", "Wooden Pickaxe")));
        itemNames.add(new ItemName(Material.WOODEN_AXE, langConfig.getString("item.minecraft.wooden_axe", "Wooden Axe")));
        itemNames.add(new ItemName(Material.STONE_SWORD, langConfig.getString("item.minecraft.stone_sword", "Stone Sword")));
        itemNames.add(new ItemName(Material.STONE_SHOVEL, langConfig.getString("item.minecraft.stone_shovel", "Stone Shovel")));
        itemNames.add(new ItemName(Material.STONE_PICKAXE, langConfig.getString("item.minecraft.stone_pickaxe", "Stone Pickaxe")));
        itemNames.add(new ItemName(Material.STONE_AXE, langConfig.getString("item.minecraft.stone_axe", "Stone Axe")));
        itemNames.add(new ItemName(Material.DIAMOND_SWORD, langConfig.getString("item.minecraft.diamond_sword", "Diamond Sword")));
        itemNames.add(new ItemName(Material.DIAMOND_SHOVEL, langConfig.getString("item.minecraft.diamond_shovel", "Diamond Shovel")));
        itemNames.add(new ItemName(Material.DIAMOND_PICKAXE, langConfig.getString("item.minecraft.diamond_pickaxe", "Diamond Pickaxe")));
        itemNames.add(new ItemName(Material.DIAMOND_AXE, langConfig.getString("item.minecraft.diamond_axe", "Diamond Axe")));
        itemNames.add(new ItemName(Material.STICK, langConfig.getString("item.minecraft.stick", "Stick")));
        itemNames.add(new ItemName(Material.BOWL, langConfig.getString("item.minecraft.bowl", "Bowl")));
        itemNames.add(new ItemName(Material.MUSHROOM_STEW, langConfig.getString("item.minecraft.mushroom_stew", "Mushroom Stew")));
        itemNames.add(new ItemName(Material.GOLDEN_SWORD, langConfig.getString("item.minecraft.golden_sword", "Golden Sword")));
        itemNames.add(new ItemName(Material.GOLDEN_SHOVEL, langConfig.getString("item.minecraft.golden_shovel", "Golden Shovel")));
        itemNames.add(new ItemName(Material.GOLDEN_PICKAXE, langConfig.getString("item.minecraft.golden_pickaxe", "Golden Pickaxe")));
        itemNames.add(new ItemName(Material.GOLDEN_AXE, langConfig.getString("item.minecraft.golden_axe", "Golden Axe")));
        itemNames.add(new ItemName(Material.STRING, langConfig.getString("item.minecraft.string", "String")));
        itemNames.add(new ItemName(Material.FEATHER, langConfig.getString("item.minecraft.feather", "Feather")));
        itemNames.add(new ItemName(Material.GUNPOWDER, langConfig.getString("item.minecraft.gunpowder", "Gunpowder")));
        itemNames.add(new ItemName(Material.WOODEN_HOE, langConfig.getString("item.minecraft.wooden_hoe", "Wooden Hoe")));
        itemNames.add(new ItemName(Material.STONE_HOE, langConfig.getString("item.minecraft.stone_hoe", "Stone Hoe")));
        itemNames.add(new ItemName(Material.IRON_HOE, langConfig.getString("item.minecraft.iron_hoe", "Iron Hoe")));
        itemNames.add(new ItemName(Material.DIAMOND_HOE, langConfig.getString("item.minecraft.diamond_hoe", "Diamond Hoe")));
        itemNames.add(new ItemName(Material.GOLDEN_HOE, langConfig.getString("item.minecraft.golden_hoe", "Golden Hoe")));
        itemNames.add(new ItemName(Material.WHEAT_SEEDS, langConfig.getString("item.minecraft.wheat_seeds", "Wheat Seeds")));
        itemNames.add(new ItemName(Material.PUMPKIN_SEEDS, langConfig.getString("item.minecraft.pumpkin_seeds", "Pumpkin Seeds")));
        itemNames.add(new ItemName(Material.MELON_SEEDS, langConfig.getString("item.minecraft.melon_seeds", "Melon Seeds")));
        itemNames.add(new ItemName(Material.MELON_SLICE, langConfig.getString("item.minecraft.melon_slice", "Melon Slice")));
        itemNames.add(new ItemName(Material.WHEAT, langConfig.getString("item.minecraft.wheat", "Wheat")));
        itemNames.add(new ItemName(Material.BREAD, langConfig.getString("item.minecraft.bread", "Bread")));
        itemNames.add(new ItemName(Material.LEATHER_HELMET, langConfig.getString("item.minecraft.leather_helmet", "Leather Cap")));
        itemNames.add(new ItemName(Material.LEATHER_CHESTPLATE, langConfig.getString("item.minecraft.leather_chestplate", "Leather Tunic")));
        itemNames.add(new ItemName(Material.LEATHER_LEGGINGS, langConfig.getString("item.minecraft.leather_leggings", "Leather Pants")));
        itemNames.add(new ItemName(Material.LEATHER_BOOTS, langConfig.getString("item.minecraft.leather_boots", "Leather Boots")));
        itemNames.add(new ItemName(Material.CHAINMAIL_HELMET, langConfig.getString("item.minecraft.chainmail_helmet", "Chainmail Helmet")));
        itemNames.add(new ItemName(Material.CHAINMAIL_CHESTPLATE, langConfig.getString("item.minecraft.chainmail_chestplate", "Chainmail Chestplate")));
        itemNames.add(new ItemName(Material.CHAINMAIL_LEGGINGS, langConfig.getString("item.minecraft.chainmail_leggings", "Chainmail Leggings")));
        itemNames.add(new ItemName(Material.CHAINMAIL_BOOTS, langConfig.getString("item.minecraft.chainmail_boots", "Chainmail Boots")));
        itemNames.add(new ItemName(Material.IRON_HELMET, langConfig.getString("item.minecraft.iron_helmet", "Iron Helmet")));
        itemNames.add(new ItemName(Material.IRON_CHESTPLATE, langConfig.getString("item.minecraft.iron_chestplate", "Iron Chestplate")));
        itemNames.add(new ItemName(Material.IRON_LEGGINGS, langConfig.getString("item.minecraft.iron_leggings", "Iron Leggings")));
        itemNames.add(new ItemName(Material.IRON_BOOTS, langConfig.getString("item.minecraft.iron_boots", "Iron Boots")));
        itemNames.add(new ItemName(Material.DIAMOND_HELMET, langConfig.getString("item.minecraft.diamond_helmet", "Diamond Helmet")));
        itemNames.add(new ItemName(Material.DIAMOND_CHESTPLATE, langConfig.getString("item.minecraft.diamond_chestplate", "Diamond Chestplate")));
        itemNames.add(new ItemName(Material.DIAMOND_LEGGINGS, langConfig.getString("item.minecraft.diamond_leggings", "Diamond Leggings")));
        itemNames.add(new ItemName(Material.DIAMOND_BOOTS, langConfig.getString("item.minecraft.diamond_boots", "Diamond Boots")));
        itemNames.add(new ItemName(Material.GOLDEN_HELMET, langConfig.getString("item.minecraft.golden_helmet", "Golden Helmet")));
        itemNames.add(new ItemName(Material.GOLDEN_CHESTPLATE, langConfig.getString("item.minecraft.golden_chestplate", "Golden Chestplate")));
        itemNames.add(new ItemName(Material.GOLDEN_LEGGINGS, langConfig.getString("item.minecraft.golden_leggings", "Golden Leggings")));
        itemNames.add(new ItemName(Material.GOLDEN_BOOTS, langConfig.getString("item.minecraft.golden_boots", "Golden Boots")));
        itemNames.add(new ItemName(Material.FLINT, langConfig.getString("item.minecraft.flint", "Flint")));
        itemNames.add(new ItemName(Material.PORKCHOP, langConfig.getString("item.minecraft.porkchop", "Raw Porkchop")));
        itemNames.add(new ItemName(Material.COOKED_PORKCHOP, langConfig.getString("item.minecraft.cooked_porkchop", "Cooked Porkchop")));
        itemNames.add(new ItemName(Material.CHICKEN, langConfig.getString("item.minecraft.chicken", "Raw Chicken")));
        itemNames.add(new ItemName(Material.COOKED_CHICKEN, langConfig.getString("item.minecraft.cooked_chicken", "Cooked Chicken")));
        itemNames.add(new ItemName(Material.MUTTON, langConfig.getString("item.minecraft.mutton", "Raw Mutton")));
        itemNames.add(new ItemName(Material.COOKED_MUTTON, langConfig.getString("item.minecraft.cooked_mutton", "Cooked Mutton")));
        itemNames.add(new ItemName(Material.RABBIT, langConfig.getString("item.minecraft.rabbit", "Raw Rabbit")));
        itemNames.add(new ItemName(Material.COOKED_RABBIT, langConfig.getString("item.minecraft.cooked_rabbit", "Cooked Rabbit")));
        itemNames.add(new ItemName(Material.RABBIT_STEW, langConfig.getString("item.minecraft.rabbit_stew", "Rabbit Stew")));
        itemNames.add(new ItemName(Material.RABBIT_FOOT, langConfig.getString("item.minecraft.rabbit_foot", "Rabbit's Foot")));
        itemNames.add(new ItemName(Material.RABBIT_HIDE, langConfig.getString("item.minecraft.rabbit_hide", "Rabbit Hide")));
        itemNames.add(new ItemName(Material.BEEF, langConfig.getString("item.minecraft.beef", "Raw Beef")));
        itemNames.add(new ItemName(Material.COOKED_BEEF, langConfig.getString("item.minecraft.cooked_beef", "Steak")));
        itemNames.add(new ItemName(Material.PAINTING, langConfig.getString("item.minecraft.painting", "Painting")));
        itemNames.add(new ItemName(Material.ITEM_FRAME, langConfig.getString("item.minecraft.item_frame", "Item Frame")));
        itemNames.add(new ItemName(Material.GOLDEN_APPLE, langConfig.getString("item.minecraft.golden_apple", "Golden Apple")));
        itemNames.add(new ItemName(Material.ENCHANTED_GOLDEN_APPLE, langConfig.getString("item.minecraft.enchanted_golden_apple", "Enchanted Golden Apple")));
        itemNames.add(new ItemName(Material.BUCKET, langConfig.getString("item.minecraft.bucket", "Bucket")));
        itemNames.add(new ItemName(Material.WATER_BUCKET, langConfig.getString("item.minecraft.water_bucket", "Water Bucket")));
        itemNames.add(new ItemName(Material.LAVA_BUCKET, langConfig.getString("item.minecraft.lava_bucket", "Lava Bucket")));
        itemNames.add(new ItemName(Material.PUFFERFISH_BUCKET, langConfig.getString("item.minecraft.pufferfish_bucket", "Bucket of Pufferfish")));
        itemNames.add(new ItemName(Material.SALMON_BUCKET, langConfig.getString("item.minecraft.salmon_bucket", "Bucket of Salmon")));
        itemNames.add(new ItemName(Material.COD_BUCKET, langConfig.getString("item.minecraft.cod_bucket", "Bucket of Cod")));
        itemNames.add(new ItemName(Material.TROPICAL_FISH_BUCKET, langConfig.getString("item.minecraft.tropical_fish_bucket", "Bucket of Tropical Fish")));
        itemNames.add(new ItemName(Material.MINECART, langConfig.getString("item.minecraft.minecart", "Minecart")));
        itemNames.add(new ItemName(Material.SADDLE, langConfig.getString("item.minecraft.saddle", "Saddle")));
        itemNames.add(new ItemName(Material.REDSTONE, langConfig.getString("item.minecraft.redstone", "Redstone")));
        itemNames.add(new ItemName(Material.SNOWBALL, langConfig.getString("item.minecraft.snowball", "Snowball")));
        itemNames.add(new ItemName(Material.OAK_BOAT, langConfig.getString("item.minecraft.oak_boat", "Oak Boat")));
        itemNames.add(new ItemName(Material.SPRUCE_BOAT, langConfig.getString("item.minecraft.spruce_boat", "Spruce Boat")));
        itemNames.add(new ItemName(Material.BIRCH_BOAT, langConfig.getString("item.minecraft.birch_boat", "Birch Boat")));
        itemNames.add(new ItemName(Material.JUNGLE_BOAT, langConfig.getString("item.minecraft.jungle_boat", "Jungle Boat")));
        itemNames.add(new ItemName(Material.ACACIA_BOAT, langConfig.getString("item.minecraft.acacia_boat", "Acacia Boat")));
        itemNames.add(new ItemName(Material.DARK_OAK_BOAT, langConfig.getString("item.minecraft.dark_oak_boat", "Dark Oak Boat")));
        itemNames.add(new ItemName(Material.LEATHER, langConfig.getString("item.minecraft.leather", "Leather")));
        itemNames.add(new ItemName(Material.MILK_BUCKET, langConfig.getString("item.minecraft.milk_bucket", "Milk Bucket")));
        itemNames.add(new ItemName(Material.BRICK, langConfig.getString("item.minecraft.brick", "Brick")));
        itemNames.add(new ItemName(Material.CLAY, langConfig.getString("item.minecraft.clay_ball", "Clay")));
        itemNames.add(new ItemName(Material.PAPER, langConfig.getString("item.minecraft.paper", "Paper")));
        itemNames.add(new ItemName(Material.BOOK, langConfig.getString("item.minecraft.book", "Book")));
        itemNames.add(new ItemName(Material.SLIME_BALL, langConfig.getString("item.minecraft.slime_ball", "Slimeball")));
        itemNames.add(new ItemName(Material.CHEST_MINECART, langConfig.getString("item.minecraft.chest_minecart", "Minecart with Chest")));
        itemNames.add(new ItemName(Material.FURNACE_MINECART, langConfig.getString("item.minecraft.furnace_minecart", "Minecart with Furnace")));
        itemNames.add(new ItemName(Material.TNT_MINECART, langConfig.getString("item.minecraft.tnt_minecart", "Minecart with TNT")));
        itemNames.add(new ItemName(Material.HOPPER_MINECART, langConfig.getString("item.minecraft.hopper_minecart", "Minecart with Hopper")));
        itemNames.add(new ItemName(Material.COMMAND_BLOCK_MINECART, langConfig.getString("item.minecraft.command_block_minecart", "Minecart with Command Block")));
        itemNames.add(new ItemName(Material.EGG, langConfig.getString("item.minecraft.egg", "Egg")));
        itemNames.add(new ItemName(Material.COMPASS, langConfig.getString("item.minecraft.compass", "Compass")));
        itemNames.add(new ItemName(Material.FISHING_ROD, langConfig.getString("item.minecraft.fishing_rod", "Fishing Rod")));
        itemNames.add(new ItemName(Material.CLOCK, langConfig.getString("item.minecraft.clock", "Clock")));
        itemNames.add(new ItemName(Material.GLOWSTONE_DUST, langConfig.getString("item.minecraft.glowstone_dust", "Glowstone Dust")));
        itemNames.add(new ItemName(Material.COD, langConfig.getString("item.minecraft.cod", "Raw Cod")));
        itemNames.add(new ItemName(Material.SALMON, langConfig.getString("item.minecraft.salmon", "Raw Salmon")));
        itemNames.add(new ItemName(Material.PUFFERFISH, langConfig.getString("item.minecraft.pufferfish", "Pufferfish")));
        itemNames.add(new ItemName(Material.TROPICAL_FISH, langConfig.getString("item.minecraft.tropical_fish", "Tropical Fish")));
        itemNames.add(new ItemName(Material.COOKED_COD, langConfig.getString("item.minecraft.cooked_cod", "Cooked Cod")));
        itemNames.add(new ItemName(Material.COOKED_SALMON, langConfig.getString("item.minecraft.cooked_salmon", "Cooked Salmon")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_13, langConfig.getString("item.minecraft.music_disc_13", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_CAT, langConfig.getString("item.minecraft.music_disc_cat", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_BLOCKS, langConfig.getString("item.minecraft.music_disc_blocks", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_CHIRP, langConfig.getString("item.minecraft.music_disc_chirp", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_FAR, langConfig.getString("item.minecraft.music_disc_far", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_MALL, langConfig.getString("item.minecraft.music_disc_mall", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_MELLOHI, langConfig.getString("item.minecraft.music_disc_mellohi", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_STAL, langConfig.getString("item.minecraft.music_disc_stal", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_STRAD, langConfig.getString("item.minecraft.music_disc_strad", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_WARD, langConfig.getString("item.minecraft.music_disc_ward", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_11, langConfig.getString("item.minecraft.music_disc_11", "Music Disc")));
        itemNames.add(new ItemName(Material.MUSIC_DISC_WAIT, langConfig.getString("item.minecraft.music_disc_wait", "Music Disc")));
        itemNames.add(new ItemName(Material.BONE, langConfig.getString("item.minecraft.bone", "Bone")));
        itemNames.add(new ItemName(Material.INK_SAC, langConfig.getString("item.minecraft.ink_sac", "Ink Sac")));
        itemNames.add(new ItemName(Material.COCOA_BEANS, langConfig.getString("item.minecraft.cocoa_beans", "Cocoa Beans")));
        itemNames.add(new ItemName(Material.LAPIS_LAZULI, langConfig.getString("item.minecraft.lapis_lazuli", "Lapis Lazuli")));
        itemNames.add(new ItemName(Material.PURPLE_DYE, langConfig.getString("item.minecraft.purple_dye", "Purple Dye")));
        itemNames.add(new ItemName(Material.CYAN_DYE, langConfig.getString("item.minecraft.cyan_dye", "Cyan Dye")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_DYE, langConfig.getString("item.minecraft.light_gray_dye", "Light Gray Dye")));
        itemNames.add(new ItemName(Material.GRAY_DYE, langConfig.getString("item.minecraft.gray_dye", "Gray Dye")));
        itemNames.add(new ItemName(Material.PINK_DYE, langConfig.getString("item.minecraft.pink_dye", "Pink Dye")));
        itemNames.add(new ItemName(Material.LIME_DYE, langConfig.getString("item.minecraft.lime_dye", "Lime Dye")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_DYE, langConfig.getString("item.minecraft.light_blue_dye", "Light Blue Dye")));
        itemNames.add(new ItemName(Material.MAGENTA_DYE, langConfig.getString("item.minecraft.magenta_dye", "Magenta Dye")));
        itemNames.add(new ItemName(Material.ORANGE_DYE, langConfig.getString("item.minecraft.orange_dye", "Orange Dye")));
        itemNames.add(new ItemName(Material.BONE_MEAL, langConfig.getString("item.minecraft.bone_meal", "Bone Meal")));
        itemNames.add(new ItemName(Material.SUGAR, langConfig.getString("item.minecraft.sugar", "Sugar")));
        itemNames.add(new ItemName(Material.BLACK_BED, langConfig.getString("block.minecraft.black_bed", "Black Bed")));
        itemNames.add(new ItemName(Material.RED_BED, langConfig.getString("block.minecraft.red_bed", "Red Bed")));
        itemNames.add(new ItemName(Material.GREEN_BED, langConfig.getString("block.minecraft.green_bed", "Green Bed")));
        itemNames.add(new ItemName(Material.BROWN_BED, langConfig.getString("block.minecraft.brown_bed", "Brown Bed")));
        itemNames.add(new ItemName(Material.BLUE_BED, langConfig.getString("block.minecraft.blue_bed", "Blue Bed")));
        itemNames.add(new ItemName(Material.PURPLE_BED, langConfig.getString("block.minecraft.purple_bed", "Purple Bed")));
        itemNames.add(new ItemName(Material.CYAN_BED, langConfig.getString("block.minecraft.cyan_bed", "Cyan Bed")));
        itemNames.add(new ItemName(Material.LIGHT_GRAY_BED, langConfig.getString("block.minecraft.light_gray_bed", "Light Gray Bed")));
        itemNames.add(new ItemName(Material.GRAY_BED, langConfig.getString("block.minecraft.gray_bed", "Gray Bed")));
        itemNames.add(new ItemName(Material.PINK_BED, langConfig.getString("block.minecraft.pink_bed", "Pink Bed")));
        itemNames.add(new ItemName(Material.LIME_BED, langConfig.getString("block.minecraft.lime_bed", "Lime Bed")));
        itemNames.add(new ItemName(Material.YELLOW_BED, langConfig.getString("block.minecraft.yellow_bed", "Yellow Bed")));
        itemNames.add(new ItemName(Material.LIGHT_BLUE_BED, langConfig.getString("block.minecraft.light_blue_bed", "Light Blue Bed")));
        itemNames.add(new ItemName(Material.MAGENTA_BED, langConfig.getString("block.minecraft.magenta_bed", "Magenta Bed")));
        itemNames.add(new ItemName(Material.ORANGE_BED, langConfig.getString("block.minecraft.orange_bed", "Orange Bed")));
        itemNames.add(new ItemName(Material.WHITE_BED, langConfig.getString("block.minecraft.white_bed", "White Bed")));
        itemNames.add(new ItemName(Material.REPEATER, langConfig.getString("block.minecraft.repeater", "Redstone Repeater")));
        itemNames.add(new ItemName(Material.COMPARATOR, langConfig.getString("block.minecraft.comparator", "Redstone Comparator")));
        itemNames.add(new ItemName(Material.MAP, langConfig.getString("item.minecraft.filled_map", "Map")));
        itemNames.add(new ItemName(Material.SHEARS, langConfig.getString("item.minecraft.shears", "Shears")));
        itemNames.add(new ItemName(Material.ROTTEN_FLESH, langConfig.getString("item.minecraft.rotten_flesh", "Rotten Flesh")));
        itemNames.add(new ItemName(Material.ENDER_PEARL, langConfig.getString("item.minecraft.ender_pearl", "Ender Pearl")));
        itemNames.add(new ItemName(Material.BLAZE_ROD, langConfig.getString("item.minecraft.blaze_rod", "Blaze Rod")));
        itemNames.add(new ItemName(Material.GHAST_TEAR, langConfig.getString("item.minecraft.ghast_tear", "Ghast Tear")));
        itemNames.add(new ItemName(Material.NETHER_WART, langConfig.getString("item.minecraft.nether_wart", "Nether Wart")));
        itemNames.add(new ItemName(Material.POTION, langConfig.getString("item.minecraft.potion", "Potion")));
        itemNames.add(new ItemName(Material.SPLASH_POTION, langConfig.getString("item.minecraft.splash_potion", "Splash Potion")));
        itemNames.add(new ItemName(Material.LINGERING_POTION, langConfig.getString("item.minecraft.lingering_potion", "Lingering Potion")));
        itemNames.add(new ItemName(Material.END_CRYSTAL, langConfig.getString("item.minecraft.end_crystal", "End Crystal")));
        itemNames.add(new ItemName(Material.GOLD_NUGGET, langConfig.getString("item.minecraft.gold_nugget", "Gold Nugget")));
        itemNames.add(new ItemName(Material.GLASS_BOTTLE, langConfig.getString("item.minecraft.glass_bottle", "Glass Bottle")));
        itemNames.add(new ItemName(Material.SPIDER_EYE, langConfig.getString("item.minecraft.spider_eye", "Spider Eye")));
        itemNames.add(new ItemName(Material.FERMENTED_SPIDER_EYE, langConfig.getString("item.minecraft.fermented_spider_eye", "Fermented Spider Eye")));
        itemNames.add(new ItemName(Material.BLAZE_POWDER, langConfig.getString("item.minecraft.blaze_powder", "Blaze Powder")));
        itemNames.add(new ItemName(Material.MAGMA_CREAM, langConfig.getString("item.minecraft.magma_cream", "Magma Cream")));
        itemNames.add(new ItemName(Material.CAULDRON, langConfig.getString("item.minecraft.cauldron", "Cauldron")));
        itemNames.add(new ItemName(Material.BREWING_STAND, langConfig.getString("item.minecraft.brewing_stand", "Brewing Stand")));
        itemNames.add(new ItemName(Material.ENDER_EYE, langConfig.getString("item.minecraft.ender_eye", "Eye of Ender")));
        itemNames.add(new ItemName(Material.GLISTERING_MELON_SLICE, langConfig.getString("item.minecraft.glistering_melon_slice", "Glistering Melon Slice")));
        itemNames.add(new ItemName(Material.BAT_SPAWN_EGG, langConfig.getString("item.minecraft.bat_spawn_egg", "Bat Spawn Egg")));
        itemNames.add(new ItemName(Material.BLAZE_SPAWN_EGG, langConfig.getString("item.minecraft.blaze_spawn_egg", "Blaze Spawn Egg")));
        itemNames.add(new ItemName(Material.CAVE_SPIDER_SPAWN_EGG, langConfig.getString("item.minecraft.cave_spider_spawn_egg", "Cave Spider Spawn Egg")));
        itemNames.add(new ItemName(Material.CHICKEN_SPAWN_EGG, langConfig.getString("item.minecraft.chicken_spawn_egg", "Chicken Spawn Egg")));
        itemNames.add(new ItemName(Material.COD_SPAWN_EGG, langConfig.getString("item.minecraft.cod_spawn_egg", "Cod Spawn Egg")));
        itemNames.add(new ItemName(Material.COW_SPAWN_EGG, langConfig.getString("item.minecraft.cow_spawn_egg", "Cow Spawn Egg")));
        itemNames.add(new ItemName(Material.CREEPER_SPAWN_EGG, langConfig.getString("item.minecraft.creeper_spawn_egg", "Creeper Spawn Egg")));
        itemNames.add(new ItemName(Material.DOLPHIN_SPAWN_EGG, langConfig.getString("item.minecraft.dolphin_spawn_egg", "Dolphin Spawn Egg")));
        itemNames.add(new ItemName(Material.DONKEY_SPAWN_EGG, langConfig.getString("item.minecraft.donkey_spawn_egg", "Donkey Spawn Egg")));
        itemNames.add(new ItemName(Material.DROWNED_SPAWN_EGG, langConfig.getString("item.minecraft.drowned_spawn_egg", "Drowned Spawn Egg")));
        itemNames.add(new ItemName(Material.ELDER_GUARDIAN_SPAWN_EGG, langConfig.getString("item.minecraft.elder_guardian_spawn_egg", "Elder Guardian Spawn Egg")));
        itemNames.add(new ItemName(Material.ENDERMAN_SPAWN_EGG, langConfig.getString("item.minecraft.enderman_spawn_egg", "Enderman Spawn Egg")));
        itemNames.add(new ItemName(Material.ENDERMITE_SPAWN_EGG, langConfig.getString("item.minecraft.endermite_spawn_egg", "Endermite Spawn Egg")));
        itemNames.add(new ItemName(Material.EVOKER_SPAWN_EGG, langConfig.getString("item.minecraft.evoker_spawn_egg", "Evoker Spawn Egg")));
        itemNames.add(new ItemName(Material.GHAST_SPAWN_EGG, langConfig.getString("item.minecraft.ghast_spawn_egg", "Ghast Spawn Egg")));
        itemNames.add(new ItemName(Material.GUARDIAN_SPAWN_EGG, langConfig.getString("item.minecraft.guardian_spawn_egg", "Guardian Spawn Egg")));
        itemNames.add(new ItemName(Material.HORSE_SPAWN_EGG, langConfig.getString("item.minecraft.horse_spawn_egg", "Horse Spawn Egg")));
        itemNames.add(new ItemName(Material.HUSK_SPAWN_EGG, langConfig.getString("item.minecraft.husk_spawn_egg", "Husk Spawn Egg")));
        itemNames.add(new ItemName(Material.LLAMA_SPAWN_EGG, langConfig.getString("item.minecraft.llama_spawn_egg", "Llama Spawn Egg")));
        itemNames.add(new ItemName(Material.MAGMA_CUBE_SPAWN_EGG, langConfig.getString("item.minecraft.magma_cube_spawn_egg", "Magma Cube Spawn Egg")));
        itemNames.add(new ItemName(Material.MOOSHROOM_SPAWN_EGG, langConfig.getString("item.minecraft.mooshroom_spawn_egg", "Mooshroom Spawn Egg")));
        itemNames.add(new ItemName(Material.MULE_SPAWN_EGG, langConfig.getString("item.minecraft.mule_spawn_egg", "Mule Spawn Egg")));
        itemNames.add(new ItemName(Material.OCELOT_SPAWN_EGG, langConfig.getString("item.minecraft.ocelot_spawn_egg", "Ocelot Spawn Egg")));
        itemNames.add(new ItemName(Material.PARROT_SPAWN_EGG, langConfig.getString("item.minecraft.parrot_spawn_egg", "Parrot Spawn Egg")));
        itemNames.add(new ItemName(Material.PIG_SPAWN_EGG, langConfig.getString("item.minecraft.pig_spawn_egg", "Pig Spawn Egg")));
        itemNames.add(new ItemName(Material.PHANTOM_SPAWN_EGG, langConfig.getString("item.minecraft.phantom_spawn_egg", "Phantom Spawn Egg")));
        itemNames.add(new ItemName(Material.POLAR_BEAR_SPAWN_EGG, langConfig.getString("item.minecraft.polar_bear_spawn_egg", "Polar Bear Spawn Egg")));
        itemNames.add(new ItemName(Material.PUFFERFISH_SPAWN_EGG, langConfig.getString("item.minecraft.pufferfish_spawn_egg", "Pufferfish Spawn Egg")));
        itemNames.add(new ItemName(Material.RABBIT_SPAWN_EGG, langConfig.getString("item.minecraft.rabbit_spawn_egg", "Rabbit Spawn Egg")));
        itemNames.add(new ItemName(Material.SALMON_SPAWN_EGG, langConfig.getString("item.minecraft.salmon_spawn_egg", "Salmon Spawn Egg")));
        itemNames.add(new ItemName(Material.SHEEP_SPAWN_EGG, langConfig.getString("item.minecraft.sheep_spawn_egg", "Sheep Spawn Egg")));
        itemNames.add(new ItemName(Material.SHULKER_SPAWN_EGG, langConfig.getString("item.minecraft.shulker_spawn_egg", "Shulker Spawn Egg")));
        itemNames.add(new ItemName(Material.SILVERFISH_SPAWN_EGG, langConfig.getString("item.minecraft.silverfish_spawn_egg", "Silverfish Spawn Egg")));
        itemNames.add(new ItemName(Material.SKELETON_SPAWN_EGG, langConfig.getString("item.minecraft.skeleton_spawn_egg", "Skeleton Spawn Egg")));
        itemNames.add(new ItemName(Material.SKELETON_HORSE_SPAWN_EGG, langConfig.getString("item.minecraft.skeleton_horse_spawn_egg", "Skeleton Horse Spawn Egg")));
        itemNames.add(new ItemName(Material.SLIME_SPAWN_EGG, langConfig.getString("item.minecraft.slime_spawn_egg", "Slime Spawn Egg")));
        itemNames.add(new ItemName(Material.SPIDER_SPAWN_EGG, langConfig.getString("item.minecraft.spider_spawn_egg", "Spider Spawn Egg")));
        itemNames.add(new ItemName(Material.SQUID_SPAWN_EGG, langConfig.getString("item.minecraft.squid_spawn_egg", "Squid Spawn Egg")));
        itemNames.add(new ItemName(Material.STRAY_SPAWN_EGG, langConfig.getString("item.minecraft.stray_spawn_egg", "Stray Spawn Egg")));
        itemNames.add(new ItemName(Material.TROPICAL_FISH_SPAWN_EGG, langConfig.getString("item.minecraft.tropical_fish_spawn_egg", "Tropical Fish Spawn Egg")));
        itemNames.add(new ItemName(Material.TURTLE_SPAWN_EGG, langConfig.getString("item.minecraft.turtle_spawn_egg", "Turtle Spawn Egg")));
        itemNames.add(new ItemName(Material.VEX_SPAWN_EGG, langConfig.getString("item.minecraft.vex_spawn_egg", "Vex Spawn Egg")));
        itemNames.add(new ItemName(Material.VILLAGER_SPAWN_EGG, langConfig.getString("item.minecraft.villager_spawn_egg", "Villager Spawn Egg")));
        itemNames.add(new ItemName(Material.VINDICATOR_SPAWN_EGG, langConfig.getString("item.minecraft.vindicator_spawn_egg", "Vindicator Spawn Egg")));
        itemNames.add(new ItemName(Material.WITCH_SPAWN_EGG, langConfig.getString("item.minecraft.witch_spawn_egg", "Witch Spawn Egg")));
        itemNames.add(new ItemName(Material.WITHER_SKELETON_SPAWN_EGG, langConfig.getString("item.minecraft.wither_skeleton_spawn_egg", "Wither Skeleton Spawn Egg")));
        itemNames.add(new ItemName(Material.WOLF_SPAWN_EGG, langConfig.getString("item.minecraft.wolf_spawn_egg", "Wolf Spawn Egg")));
        itemNames.add(new ItemName(Material.ZOMBIE_SPAWN_EGG, langConfig.getString("item.minecraft.zombie_spawn_egg", "Zombie Spawn Egg")));
        itemNames.add(new ItemName(Material.ZOMBIE_HORSE_SPAWN_EGG, langConfig.getString("item.minecraft.zombie_horse_spawn_egg", "Zombie Horse Spawn Egg")));
        itemNames.add(new ItemName(Material.ZOMBIE_VILLAGER_SPAWN_EGG, langConfig.getString("item.minecraft.zombie_villager_spawn_egg", "Zombie Villager Spawn Egg")));
        itemNames.add(new ItemName(Material.EXPERIENCE_BOTTLE, langConfig.getString("item.minecraft.experience_bottle", "Bottle o' Enchanting")));
        itemNames.add(new ItemName(Material.FIRE_CHARGE, langConfig.getString("item.minecraft.fire_charge", "Fire Charge")));
        itemNames.add(new ItemName(Material.WRITABLE_BOOK, langConfig.getString("item.minecraft.writable_book", "Book and Quill")));
        itemNames.add(new ItemName(Material.WRITTEN_BOOK, langConfig.getString("item.minecraft.written_book", "Written Book")));
        itemNames.add(new ItemName(Material.FLOWER_POT, langConfig.getString("item.minecraft.flower_pot", "Flower Pot")));
        itemNames.add(new ItemName(Material.MAP, langConfig.getString("item.minecraft.map", "Empty Map")));
        itemNames.add(new ItemName(Material.CARROT, langConfig.getString("item.minecraft.carrot", "Carrot")));
        itemNames.add(new ItemName(Material.GOLDEN_CARROT, langConfig.getString("item.minecraft.golden_carrot", "Golden Carrot")));
        itemNames.add(new ItemName(Material.POTATO, langConfig.getString("item.minecraft.potato", "Potato")));
        itemNames.add(new ItemName(Material.BAKED_POTATO, langConfig.getString("item.minecraft.baked_potato", "Baked Potato")));
        itemNames.add(new ItemName(Material.POISONOUS_POTATO, langConfig.getString("item.minecraft.poisonous_potato", "Poisonous Potato")));
        itemNames.add(new ItemName(Material.SKELETON_SKULL, langConfig.getString("item.minecraft.skeleton_skull", "Skeleton Skull")));
        itemNames.add(new ItemName(Material.WITHER_SKELETON_SKULL, langConfig.getString("item.minecraft.wither_skeleton_skull", "Wither Skeleton Skull")));
        itemNames.add(new ItemName(Material.ZOMBIE_HEAD, langConfig.getString("item.minecraft.zombie_head", "Zombie Head")));
        itemNames.add(new ItemName(Material.CREEPER_HEAD, langConfig.getString("item.minecraft.creeper_head", "Creeper Head")));
        itemNames.add(new ItemName(Material.DRAGON_HEAD, langConfig.getString("item.minecraft.dragon_head", "Dragon Head")));
        itemNames.add(new ItemName(Material.CARROT_ON_A_STICK, langConfig.getString("item.minecraft.carrot_on_a_stick", "Carrot on a Stick")));
        itemNames.add(new ItemName(Material.NETHER_STAR, langConfig.getString("item.minecraft.nether_star", "Nether Star")));
        itemNames.add(new ItemName(Material.PUMPKIN_PIE, langConfig.getString("item.minecraft.pumpkin_pie", "Pumpkin Pie")));
        itemNames.add(new ItemName(Material.ENCHANTED_BOOK, langConfig.getString("item.minecraft.enchanted_book", "Enchanted Book")));
        itemNames.add(new ItemName(Material.FIREWORK_ROCKET, langConfig.getString("item.minecraft.firework_rocket", "Firework Rocket")));
        itemNames.add(new ItemName(Material.FIREWORK_STAR, langConfig.getString("item.minecraft.firework_star", "Firework Star")));
        itemNames.add(new ItemName(Material.NETHER_BRICK, langConfig.getString("item.minecraft.nether_brick", "Nether Brick")));
        itemNames.add(new ItemName(Material.QUARTZ, langConfig.getString("item.minecraft.quartz", "Nether Quartz")));
        itemNames.add(new ItemName(Material.ARMOR_STAND, langConfig.getString("item.minecraft.armor_stand", "Armor Stand")));
        itemNames.add(new ItemName(Material.IRON_HORSE_ARMOR, langConfig.getString("item.minecraft.iron_horse_armor", "Iron Horse Armor")));
        itemNames.add(new ItemName(Material.GOLDEN_HORSE_ARMOR, langConfig.getString("item.minecraft.golden_horse_armor", "Golden Horse Armor")));
        itemNames.add(new ItemName(Material.DIAMOND_HORSE_ARMOR, langConfig.getString("item.minecraft.diamond_horse_armor", "Diamond Horse Armor")));
        itemNames.add(new ItemName(Material.PRISMARINE_SHARD, langConfig.getString("item.minecraft.prismarine_shard", "Prismarine Shard")));
        itemNames.add(new ItemName(Material.PRISMARINE_CRYSTALS, langConfig.getString("item.minecraft.prismarine_crystals", "Prismarine Crystals")));
        itemNames.add(new ItemName(Material.CHORUS_FRUIT, langConfig.getString("item.minecraft.chorus_fruit", "Chorus Fruit")));
        itemNames.add(new ItemName(Material.POPPED_CHORUS_FRUIT, langConfig.getString("item.minecraft.popped_chorus_fruit", "Popped Chorus Fruit")));
        itemNames.add(new ItemName(Material.BEETROOT, langConfig.getString("item.minecraft.beetroot", "Beetroot")));
        itemNames.add(new ItemName(Material.BEETROOT_SEEDS, langConfig.getString("item.minecraft.beetroot_seeds", "Beetroot Seeds")));
        itemNames.add(new ItemName(Material.BEETROOT_SOUP, langConfig.getString("item.minecraft.beetroot_soup", "Beetroot Soup")));
        itemNames.add(new ItemName(Material.DRAGON_BREATH, langConfig.getString("item.minecraft.dragon_breath", "Dragon's Breath")));
        itemNames.add(new ItemName(Material.ELYTRA, langConfig.getString("item.minecraft.elytra", "Elytra")));
        itemNames.add(new ItemName(Material.TOTEM_OF_UNDYING, langConfig.getString("item.minecraft.totem_of_undying", "Totem of Undying")));
        itemNames.add(new ItemName(Material.SHULKER_SHELL, langConfig.getString("item.minecraft.shulker_shell", "Shulker Shell")));
        itemNames.add(new ItemName(Material.IRON_NUGGET, langConfig.getString("item.minecraft.iron_nugget", "Iron Nugget")));
        itemNames.add(new ItemName(Material.KNOWLEDGE_BOOK, langConfig.getString("item.minecraft.knowledge_book", "Knowledge Book")));
        itemNames.add(new ItemName(Material.DEBUG_STICK, langConfig.getString("item.minecraft.debug_stick", "Debug Stick")));
        itemNames.add(new ItemName(Material.TRIDENT, langConfig.getString("item.minecraft.trident", "Trident")));
        itemNames.add(new ItemName(Material.SCUTE, langConfig.getString("item.minecraft.scute", "Scute")));
        itemNames.add(new ItemName(Material.TURTLE_HELMET, langConfig.getString("item.minecraft.turtle_helmet", "Turtle Shell")));
        itemNames.add(new ItemName(Material.PHANTOM_MEMBRANE, langConfig.getString("item.minecraft.phantom_membrane", "Phantom Membrane")));
        itemNames.add(new ItemName(Material.NAUTILUS_SHELL, langConfig.getString("item.minecraft.nautilus_shell", "Nautilus Shell")));
        itemNames.add(new ItemName(Material.HEART_OF_THE_SEA, langConfig.getString("item.minecraft.heart_of_the_sea", "Heart of the Sea")));

        if (Utils.getMajorVersion() >= 14) {
            // Add 1.14 item names
            itemNames.add(new ItemName(Material.ACACIA_SIGN, langConfig.getString("block.minecraft.acacia_sign", "Acacia Sign")));
            itemNames.add(new ItemName(Material.ACACIA_WALL_SIGN, langConfig.getString("block.minecraft.acacia_wall_sign", "Acacia Wall Sign")));
            itemNames.add(new ItemName(Material.ANDESITE_SLAB, langConfig.getString("block.minecraft.andesite_slab", "Andesite Slab")));
            itemNames.add(new ItemName(Material.ANDESITE_STAIRS, langConfig.getString("block.minecraft.andesite_stairs", "Andesite Stairs")));
            itemNames.add(new ItemName(Material.ANDESITE_WALL, langConfig.getString("block.minecraft.andesite_wall", "Andesite Wall")));
            itemNames.add(new ItemName(Material.BAMBOO, langConfig.getString("block.minecraft.bamboo", "Bamboo")));
            itemNames.add(new ItemName(Material.BAMBOO_SAPLING, langConfig.getString("block.minecraft.bamboo_sapling", "Bamboo Sapling")));
            itemNames.add(new ItemName(Material.BARREL, langConfig.getString("block.minecraft.barrel", "Barrel")));
            itemNames.add(new ItemName(Material.BELL, langConfig.getString("block.minecraft.bell", "Bell")));
            itemNames.add(new ItemName(Material.BIRCH_SIGN, langConfig.getString("block.minecraft.birch_sign", "Birch Sign")));
            itemNames.add(new ItemName(Material.BIRCH_WALL_SIGN, langConfig.getString("block.minecraft.birch_wall_sign", "Birch Wall Sign")));
            itemNames.add(new ItemName(Material.BLACK_DYE, langConfig.getString("item.minecraft.black_dye", "Black Dye")));
            itemNames.add(new ItemName(Material.BLAST_FURNACE, langConfig.getString("block.minecraft.blast_furnace", "Blast Furnace")));
            itemNames.add(new ItemName(Material.BLUE_DYE, langConfig.getString("item.minecraft.blue_dye", "Blue Dye")));
            itemNames.add(new ItemName(Material.BRICK_WALL, langConfig.getString("block.minecraft.brick_wall", "Brick Wall")));
            itemNames.add(new ItemName(Material.BROWN_DYE, langConfig.getString("item.minecraft.brown_dye", "Brown Dye")));
            itemNames.add(new ItemName(Material.CAMPFIRE, langConfig.getString("block.minecraft.campfire", "Campfire")));
            itemNames.add(new ItemName(Material.CARTOGRAPHY_TABLE, langConfig.getString("block.minecraft.cartography_table", "Cartography Table")));
            itemNames.add(new ItemName(Material.CAT_SPAWN_EGG, langConfig.getString("item.minecraft.cat_spawn_egg", "Cat Spawn Egg")));
            itemNames.add(new ItemName(Material.COMPOSTER, langConfig.getString("block.minecraft.composter", "Composter")));
            itemNames.add(new ItemName(Material.CORNFLOWER, langConfig.getString("block.minecraft.cornflower", "Cornflower")));
            itemNames.add(new ItemName(Material.CREEPER_BANNER_PATTERN, langConfig.getString("item.minecraft.creeper_banner_pattern", "Banner Pattern")));
            itemNames.add(new ItemName(Material.CROSSBOW, langConfig.getString("item.minecraft.crossbow", "Crossbow")));
            itemNames.add(new ItemName(Material.CUT_RED_SANDSTONE_SLAB, langConfig.getString("block.minecraft.cut_red_sandstone_slab", "Cut Red Sandstone Slab")));
            itemNames.add(new ItemName(Material.CUT_SANDSTONE_SLAB, langConfig.getString("block.minecraft.cut_sandstone_slab", "Cut Sandstone Slab")));
            itemNames.add(new ItemName(Material.DARK_OAK_SIGN, langConfig.getString("block.minecraft.dark_oak_sign", "Dark Oak Sign")));
            itemNames.add(new ItemName(Material.DARK_OAK_WALL_SIGN, langConfig.getString("block.minecraft.dark_oak_wall_sign", "Dark Oak Wall Sign")));
            itemNames.add(new ItemName(Material.DEAD_BRAIN_CORAL, langConfig.getString("block.minecraft.dead_brain_coral", "Dead Brain Coral")));
            itemNames.add(new ItemName(Material.DEAD_BUBBLE_CORAL, langConfig.getString("block.minecraft.dead_bubble_coral", "Dead Bubble Coral")));
            itemNames.add(new ItemName(Material.DEAD_FIRE_CORAL, langConfig.getString("block.minecraft.dead_fire_coral", "Dead Fire Coral")));
            itemNames.add(new ItemName(Material.DEAD_HORN_CORAL, langConfig.getString("block.minecraft.dead_horn_coral", "Dead Horn Coral")));
            itemNames.add(new ItemName(Material.DEAD_TUBE_CORAL, langConfig.getString("block.minecraft.dead_tube_coral", "Dead Tube Coral")));
            itemNames.add(new ItemName(Material.DIORITE_SLAB, langConfig.getString("block.minecraft.diorite_slab", "Diorite Slab")));
            itemNames.add(new ItemName(Material.DIORITE_STAIRS, langConfig.getString("block.minecraft.diorite_stairs", "Diorite Stairs")));
            itemNames.add(new ItemName(Material.DIORITE_WALL, langConfig.getString("block.minecraft.diorite_wall", "Diorite Wall")));
            itemNames.add(new ItemName(Material.END_STONE_BRICK_SLAB, langConfig.getString("block.minecraft.end_stone_brick_slab", "End Stone Brick Slab")));
            itemNames.add(new ItemName(Material.END_STONE_BRICK_STAIRS, langConfig.getString("block.minecraft.end_stone_brick_stairs", "End Stone Brick Stairs")));
            itemNames.add(new ItemName(Material.END_STONE_BRICK_WALL, langConfig.getString("block.minecraft.end_stone_brick_wall", "End Stone Brick Wall")));
            itemNames.add(new ItemName(Material.FLETCHING_TABLE, langConfig.getString("block.minecraft.fletching_table", "Fletching Table")));
            itemNames.add(new ItemName(Material.FLOWER_BANNER_PATTERN, langConfig.getString("item.minecraft.flower_banner_pattern", "Banner Pattern")));
            itemNames.add(new ItemName(Material.FOX_SPAWN_EGG, langConfig.getString("item.minecraft.fox_spawn_egg", "Fox Spawn Egg")));
            itemNames.add(new ItemName(Material.GLOBE_BANNER_PATTERN, langConfig.getString("item.minecraft.globe_banner_pattern", "Banner Pattern")));
            itemNames.add(new ItemName(Material.GRANITE_SLAB, langConfig.getString("block.minecraft.granite_slab", "Granite Slab")));
            itemNames.add(new ItemName(Material.GRANITE_STAIRS, langConfig.getString("block.minecraft.granite_stairs", "Granite Stairs")));
            itemNames.add(new ItemName(Material.GRANITE_WALL, langConfig.getString("block.minecraft.granite_wall", "Granite Wall")));
            itemNames.add(new ItemName(Material.GREEN_DYE, langConfig.getString("item.minecraft.green_dye", "Green Dye")));
            itemNames.add(new ItemName(Material.GRINDSTONE, langConfig.getString("block.minecraft.grindstone", "Grindstone")));
            itemNames.add(new ItemName(Material.JIGSAW, langConfig.getString("block.minecraft.jigsaw", "Jigsaw")));
            itemNames.add(new ItemName(Material.JUNGLE_SIGN, langConfig.getString("block.minecraft.jungle_sign", "Jungle Sign")));
            itemNames.add(new ItemName(Material.JUNGLE_WALL_SIGN, langConfig.getString("block.minecraft.jungle_wall_sign", "Jungle Wall Sign")));
            itemNames.add(new ItemName(Material.LANTERN, langConfig.getString("block.minecraft.lantern", "Lantern")));
            itemNames.add(new ItemName(Material.LEATHER_HORSE_ARMOR, langConfig.getString("item.minecraft.leather_horse_armor", "Leather Horse Armor")));
            itemNames.add(new ItemName(Material.LECTERN, langConfig.getString("block.minecraft.lectern", "Lectern")));
            itemNames.add(new ItemName(Material.LILY_OF_THE_VALLEY, langConfig.getString("block.minecraft.lily_of_the_valley", "Lily of the Valley")));
            itemNames.add(new ItemName(Material.LOOM, langConfig.getString("block.minecraft.loom", "Loom")));
            itemNames.add(new ItemName(Material.MOJANG_BANNER_PATTERN, langConfig.getString("item.minecraft.mojang_banner_pattern", "Banner Pattern")));
            itemNames.add(new ItemName(Material.MOSSY_COBBLESTONE_SLAB, langConfig.getString("block.minecraft.mossy_cobblestone_slab", "Mossy Cobblestone Slab")));
            itemNames.add(new ItemName(Material.MOSSY_COBBLESTONE_STAIRS, langConfig.getString("block.minecraft.mossy_cobblestone_stairs", "Mossy Cobblestone Stairs")));
            itemNames.add(new ItemName(Material.MOSSY_STONE_BRICK_SLAB, langConfig.getString("block.minecraft.mossy_stone_brick_slab", "Mossy Stone Brick Slab")));
            itemNames.add(new ItemName(Material.MOSSY_STONE_BRICK_STAIRS, langConfig.getString("block.minecraft.mossy_stone_brick_stairs", "Mossy Stone Brick Stairs")));
            itemNames.add(new ItemName(Material.MOSSY_STONE_BRICK_WALL, langConfig.getString("block.minecraft.mossy_stone_brick_wall", "Mossy Stone Brick Wall")));
            itemNames.add(new ItemName(Material.NETHER_BRICK_WALL, langConfig.getString("block.minecraft.nether_brick_wall", "Nether Brick Wall")));
            itemNames.add(new ItemName(Material.OAK_SIGN, langConfig.getString("block.minecraft.oak_sign", "Oak Sign")));
            itemNames.add(new ItemName(Material.OAK_WALL_SIGN, langConfig.getString("block.minecraft.oak_wall_sign", "Oak Wall Sign")));
            itemNames.add(new ItemName(Material.PANDA_SPAWN_EGG, langConfig.getString("item.minecraft.panda_spawn_egg", "Panda Spawn Egg")));
            itemNames.add(new ItemName(Material.PILLAGER_SPAWN_EGG, langConfig.getString("item.minecraft.pillager_spawn_egg", "Pillager Spawn Egg")));
            itemNames.add(new ItemName(Material.POLISHED_ANDESITE_SLAB, langConfig.getString("block.minecraft.polished_andesite_slab", "Polished Andesite Slab")));
            itemNames.add(new ItemName(Material.POLISHED_ANDESITE_STAIRS, langConfig.getString("block.minecraft.polished_andesite_stairs", "Polished Andesite Stairs")));
            itemNames.add(new ItemName(Material.POLISHED_DIORITE_SLAB, langConfig.getString("block.minecraft.polished_diorite_slab", "Polished Diorite Slab")));
            itemNames.add(new ItemName(Material.POLISHED_DIORITE_STAIRS, langConfig.getString("block.minecraft.polished_diorite_stairs", "Polished Diorite Stairs")));
            itemNames.add(new ItemName(Material.POLISHED_GRANITE_SLAB, langConfig.getString("block.minecraft.polished_granite_slab", "Polished Granite Slab")));
            itemNames.add(new ItemName(Material.POLISHED_GRANITE_STAIRS, langConfig.getString("block.minecraft.polished_granite_stairs", "Polished Granite Stairs")));
            itemNames.add(new ItemName(Material.POTTED_BAMBOO, langConfig.getString("block.minecraft.potted_bamboo", "Potted Bamboo")));
            itemNames.add(new ItemName(Material.POTTED_CORNFLOWER, langConfig.getString("block.minecraft.potted_cornflower", "Potted Cornflower")));
            itemNames.add(new ItemName(Material.POTTED_LILY_OF_THE_VALLEY, langConfig.getString("block.minecraft.potted_lily_of_the_valley", "Potted Lily of the Valley")));
            itemNames.add(new ItemName(Material.POTTED_WITHER_ROSE, langConfig.getString("block.minecraft.potted_wither_rose", "Potted Wither Rose")));
            itemNames.add(new ItemName(Material.PRISMARINE_WALL, langConfig.getString("block.minecraft.prismarine_wall", "Prismarine Wall")));
            itemNames.add(new ItemName(Material.RAVAGER_SPAWN_EGG, langConfig.getString("item.minecraft.ravager_spawn_egg", "Ravager Spawn Egg")));
            itemNames.add(new ItemName(Material.RED_DYE, langConfig.getString("item.minecraft.red_dye", "Red Dye")));
            itemNames.add(new ItemName(Material.RED_NETHER_BRICK_SLAB, langConfig.getString("block.minecraft.red_nether_brick_slab", "Red Nether Brick Slab")));
            itemNames.add(new ItemName(Material.RED_NETHER_BRICK_STAIRS, langConfig.getString("block.minecraft.red_nether_brick_stairs", "Red Nether Brick Stairs")));
            itemNames.add(new ItemName(Material.RED_NETHER_BRICK_WALL, langConfig.getString("block.minecraft.red_nether_brick_wall", "Red Nether Brick Wall")));
            itemNames.add(new ItemName(Material.RED_SANDSTONE_WALL, langConfig.getString("block.minecraft.red_sandstone_wall", "Red Sandstone Wall")));
            itemNames.add(new ItemName(Material.SANDSTONE_WALL, langConfig.getString("block.minecraft.sandstone_wall", "Sandstone Wall")));
            itemNames.add(new ItemName(Material.SCAFFOLDING, langConfig.getString("block.minecraft.scaffolding", "Scaffolding")));
            itemNames.add(new ItemName(Material.SKULL_BANNER_PATTERN, langConfig.getString("item.minecraft.skull_banner_pattern", "Banner Pattern")));
            itemNames.add(new ItemName(Material.SMITHING_TABLE, langConfig.getString("block.minecraft.smithing_table", "Smithing Table")));
            itemNames.add(new ItemName(Material.SMOKER, langConfig.getString("block.minecraft.smoker", "Smoker")));
            itemNames.add(new ItemName(Material.SMOOTH_QUARTZ_SLAB, langConfig.getString("block.minecraft.smooth_quartz_slab", "Smooth Quartz Slab")));
            itemNames.add(new ItemName(Material.SMOOTH_QUARTZ_STAIRS, langConfig.getString("block.minecraft.smooth_quartz_stairs", "Smooth Quartz Stairs")));
            itemNames.add(new ItemName(Material.SMOOTH_RED_SANDSTONE_SLAB, langConfig.getString("block.minecraft.smooth_red_sandstone_slab", "Smooth Red Sandstone Slab")));
            itemNames.add(new ItemName(Material.SMOOTH_RED_SANDSTONE_STAIRS, langConfig.getString("block.minecraft.smooth_red_sandstone_stairs", "Smooth Red Sandstone Stairs")));
            itemNames.add(new ItemName(Material.SMOOTH_SANDSTONE_SLAB, langConfig.getString("block.minecraft.smooth_sandstone_slab", "Smooth Sandstone Slab")));
            itemNames.add(new ItemName(Material.SMOOTH_SANDSTONE_STAIRS, langConfig.getString("block.minecraft.smooth_sandstone_stairs", "Smooth Sandstone Stairs")));
            itemNames.add(new ItemName(Material.SMOOTH_STONE_SLAB, langConfig.getString("block.minecraft.smooth_stone_slab", "Smooth Stone Slab")));
            itemNames.add(new ItemName(Material.SPRUCE_SIGN, langConfig.getString("block.minecraft.spruce_sign", "Spruce Sign")));
            itemNames.add(new ItemName(Material.SPRUCE_WALL_SIGN, langConfig.getString("block.minecraft.spruce_wall_sign", "Spruce Wall Sign")));
            itemNames.add(new ItemName(Material.STONE_BRICK_WALL, langConfig.getString("block.minecraft.stone_brick_wall", "Stone Brick Wall")));
            itemNames.add(new ItemName(Material.STONECUTTER, langConfig.getString("block.minecraft.stonecutter", "Stonecutter")));
            itemNames.add(new ItemName(Material.SUSPICIOUS_STEW, langConfig.getString("item.minecraft.suspicious_stew", "Suspicious Stew")));
            itemNames.add(new ItemName(Material.SWEET_BERRIES, langConfig.getString("item.minecraft.sweet_berries", "Sweet Berries")));
            itemNames.add(new ItemName(Material.SWEET_BERRY_BUSH, langConfig.getString("block.minecraft.sweet_berry_bush", "Sweet Berry Bush")));
            itemNames.add(new ItemName(Material.TRADER_LLAMA_SPAWN_EGG, langConfig.getString("item.minecraft.trader_llama_spawn_egg", "Trader Llama Spawn Egg")));
            itemNames.add(new ItemName(Material.WANDERING_TRADER_SPAWN_EGG, langConfig.getString("item.minecraft.wandering_trader_spawn_egg", "Wandering Trader Spawn Egg")));
            itemNames.add(new ItemName(Material.WHITE_DYE, langConfig.getString("item.minecraft.white_dye", "White Dye")));
            itemNames.add(new ItemName(Material.WITHER_ROSE, langConfig.getString("block.minecraft.wither_rose", "Wither Rose")));
            itemNames.add(new ItemName(Material.YELLOW_DYE, langConfig.getString("item.minecraft.yellow_dye", "Yellow Dye")));
        } else {
            // Add pre-1.14 item names that don't exist anymore
            itemNames.add(new ItemName(Material.valueOf("CACTUS_GREEN"), langConfig.getString("item.minecraft.cactus_green", "Cactus Green")));
            itemNames.add(new ItemName(Material.valueOf("DANDELION_YELLOW"), langConfig.getString("item.minecraft.dandelion_yellow", "Dandelion Yellow")));
            itemNames.add(new ItemName(Material.valueOf("ROSE_RED"), langConfig.getString("item.minecraft.rose_red", "Rose Red")));
            itemNames.add(new ItemName(Material.valueOf("SIGN"), langConfig.getString("item.minecraft.sign", "Sign")));
            itemNames.add(new ItemName(Material.valueOf("WALL_SIGN"), langConfig.getString("block.minecraft.wall_sign", "Wall Sign")));
        }

        if (Utils.getMajorVersion() >= 15) {
            itemNames.add(new ItemName(Material.BEE_NEST, langConfig.getString("block.minecraft.bee_nest", "Bee Nest")));
            itemNames.add(new ItemName(Material.BEE_SPAWN_EGG, langConfig.getString("item.minecraft.bee_spawn_egg", "Bee Spawn Egg")));
            itemNames.add(new ItemName(Material.BEEHIVE, langConfig.getString("block.minecraft.beehive", "Beehive")));
            itemNames.add(new ItemName(Material.HONEY_BLOCK, langConfig.getString("block.minecraft.honey_block", "Honey Block")));
            itemNames.add(new ItemName(Material.HONEY_BOTTLE, langConfig.getString("item.minecraft.honey_bottle", "Honey Bottle")));
            itemNames.add(new ItemName(Material.HONEYCOMB, langConfig.getString("item.minecraft.honeycomb", "Honeycomb")));
            itemNames.add(new ItemName(Material.HONEYCOMB_BLOCK, langConfig.getString("block.minecraft.honeycomb_block", "Honeycomb Block")));
        }

        if (Utils.getMajorVersion() >= 16) {
            itemNames.add(new ItemName(Material.ANCIENT_DEBRIS, langConfig.getString("block.minecraft.ancient_debris", "Ancient Debris")));
            itemNames.add(new ItemName(Material.BASALT, langConfig.getString("block.minecraft.basalt", "Basalt")));
            itemNames.add(new ItemName(Material.BLACKSTONE, langConfig.getString("block.minecraft.blackstone", "Blackstone")));
            itemNames.add(new ItemName(Material.BLACKSTONE_SLAB, langConfig.getString("block.minecraft.blackstone_slab", "Blackstone Slab")));
            itemNames.add(new ItemName(Material.BLACKSTONE_STAIRS, langConfig.getString("block.minecraft.blackstone_stairs", "Blackstone Stairs")));
            itemNames.add(new ItemName(Material.BLACKSTONE_WALL, langConfig.getString("block.minecraft.blackstone_wall", "Blackstone Wall")));
            itemNames.add(new ItemName(Material.CHAIN, langConfig.getString("block.minecraft.chain", "Chain")));
            itemNames.add(new ItemName(Material.CHISELED_NETHER_BRICKS, langConfig.getString("block.minecraft.chiseled_nether_bricks", "Chiseled Nether Bricks")));
            itemNames.add(new ItemName(Material.CHISELED_POLISHED_BLACKSTONE, langConfig.getString("block.minecraft.chiseled_polished_blackstone", "Chiseled Polished Blackstone")));
            itemNames.add(new ItemName(Material.CRACKED_NETHER_BRICKS, langConfig.getString("block.minecraft.cracked_nether_bricks", "Cracked Nether Bricks")));
            itemNames.add(new ItemName(Material.CRACKED_POLISHED_BLACKSTONE_BRICKS, langConfig.getString("block.minecraft.cracked_polished_blackstone_bricks", "Cracked Polished Blackstone Bricks")));
            itemNames.add(new ItemName(Material.CRIMSON_BUTTON, langConfig.getString("block.minecraft.crimson_button", "Crimson Button")));
            itemNames.add(new ItemName(Material.CRIMSON_DOOR, langConfig.getString("block.minecraft.crimson_door", "Crimson Door")));
            itemNames.add(new ItemName(Material.CRIMSON_FENCE, langConfig.getString("block.minecraft.crimson_fence", "Crimson Fence")));
            itemNames.add(new ItemName(Material.CRIMSON_FENCE_GATE, langConfig.getString("block.minecraft.crimson_fence_gate", "Crimson Fence Gate")));
            itemNames.add(new ItemName(Material.CRIMSON_FUNGUS, langConfig.getString("block.minecraft.crimson_fungus", "Crimson Fungus")));
            itemNames.add(new ItemName(Material.CRIMSON_HYPHAE, langConfig.getString("block.minecraft.crimson_hyphae", "Crimson Hyphae")));
            itemNames.add(new ItemName(Material.CRIMSON_NYLIUM, langConfig.getString("block.minecraft.crimson_nylium", "Crimson Nylium")));
            itemNames.add(new ItemName(Material.CRIMSON_PLANKS, langConfig.getString("block.minecraft.crimson_planks", "Crimson Planks")));
            itemNames.add(new ItemName(Material.CRIMSON_PRESSURE_PLATE, langConfig.getString("block.minecraft.crimson_pressure_plate", "Crimson Pressure Plate")));
            itemNames.add(new ItemName(Material.CRIMSON_ROOTS, langConfig.getString("block.minecraft.crimson_roots", "Crimson Roots")));
            itemNames.add(new ItemName(Material.CRIMSON_SIGN, langConfig.getString("block.minecraft.crimson_sign", "Crimson Sign")));
            itemNames.add(new ItemName(Material.CRIMSON_SLAB, langConfig.getString("block.minecraft.crimson_slab", "Crimson Slab")));
            itemNames.add(new ItemName(Material.CRIMSON_STAIRS, langConfig.getString("block.minecraft.crimson_stairs", "Crimson Stairs")));
            itemNames.add(new ItemName(Material.CRIMSON_STEM, langConfig.getString("block.minecraft.crimson_stem", "Crimson Stem")));
            itemNames.add(new ItemName(Material.CRIMSON_TRAPDOOR, langConfig.getString("block.minecraft.crimson_trapdoor", "Crimson Trapdoor")));
            itemNames.add(new ItemName(Material.CRIMSON_WALL_SIGN, langConfig.getString("block.minecraft.crimson_wall_sign", "Crimson Wall Sign")));
            itemNames.add(new ItemName(Material.CRYING_OBSIDIAN, langConfig.getString("block.minecraft.crying_obsidian", "Crying Obsidian")));
            itemNames.add(new ItemName(Material.GILDED_BLACKSTONE, langConfig.getString("block.minecraft.gilded_blackstone", "Gilded Blackstone")));
            itemNames.add(new ItemName(Material.HOGLIN_SPAWN_EGG, langConfig.getString("item.minecraft.hoglin_spawn_egg", "Hoglin Spawn Egg")));
            itemNames.add(new ItemName(Material.LODESTONE, langConfig.getString("block.minecraft.lodestone", "Lodestone")));
            // itemNames.add(new ItemName(Material.LODESTONE_COMPASS, langConfig.getString("item.minecraft.lodestone_compass", "Lodestone Compass")));
            itemNames.add(new ItemName(Material.MUSIC_DISC_PIGSTEP, langConfig.getString("item.minecraft.music_disc_pigstep", "Music Disc")));
            itemNames.add(new ItemName(Material.NETHER_GOLD_ORE, langConfig.getString("block.minecraft.nether_gold_ore", "Nether Gold Ore")));
            itemNames.add(new ItemName(Material.NETHER_SPROUTS, langConfig.getString("block.minecraft.nether_sprouts", "Nether Sprouts")));
            itemNames.add(new ItemName(Material.NETHERITE_AXE, langConfig.getString("item.minecraft.netherite_axe", "Netherite Axe")));
            itemNames.add(new ItemName(Material.NETHERITE_BLOCK, langConfig.getString("block.minecraft.netherite_block", "Netherite Block")));
            itemNames.add(new ItemName(Material.NETHERITE_BOOTS, langConfig.getString("item.minecraft.netherite_boots", "Netherite Boots")));
            itemNames.add(new ItemName(Material.NETHERITE_CHESTPLATE, langConfig.getString("item.minecraft.netherite_chestplate", "Netherite Chestplate")));
            itemNames.add(new ItemName(Material.NETHERITE_HELMET, langConfig.getString("item.minecraft.netherite_helmet", "Netherite Helmet")));
            itemNames.add(new ItemName(Material.NETHERITE_HOE, langConfig.getString("item.minecraft.netherite_hoe", "Netherite Hoe")));
            itemNames.add(new ItemName(Material.NETHERITE_INGOT, langConfig.getString("item.minecraft.netherite_ingot", "Netherite Ingot")));
            itemNames.add(new ItemName(Material.NETHERITE_LEGGINGS, langConfig.getString("item.minecraft.netherite_leggings", "Netherite Leggings")));
            itemNames.add(new ItemName(Material.NETHERITE_PICKAXE, langConfig.getString("item.minecraft.netherite_pickaxe", "Netherite Pickaxe")));
            itemNames.add(new ItemName(Material.NETHERITE_SCRAP, langConfig.getString("item.minecraft.netherite_scrap", "Netherite Scrap")));
            itemNames.add(new ItemName(Material.NETHERITE_SHOVEL, langConfig.getString("item.minecraft.netherite_shovel", "Netherite Shovel")));
            itemNames.add(new ItemName(Material.NETHERITE_SWORD, langConfig.getString("item.minecraft.netherite_sword", "Netherite Sword")));
            itemNames.add(new ItemName(Material.PIGLIN_SPAWN_EGG, langConfig.getString("item.minecraft.piglin_spawn_egg", "Piglin Spawn Egg")));
            itemNames.add(new ItemName(Material.POLISHED_BASALT, langConfig.getString("block.minecraft.polished_basalt", "Polished Basalt")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE, langConfig.getString("block.minecraft.polished_blackstone", "Polished Blackstone")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_BRICK_SLAB, langConfig.getString("block.minecraft.polished_blackstone_brick_slab", "Polished Blackstone Brick Slab")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_BRICK_STAIRS, langConfig.getString("block.minecraft.polished_blackstone_brick_stairs", "Polished Blackstone Brick Stairs")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_BRICK_WALL, langConfig.getString("block.minecraft.polished_blackstone_brick_wall", "Polished Blackstone Brick Wall")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_BRICKS, langConfig.getString("block.minecraft.polished_blackstone_bricks", "Polished Blackstone Bricks")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_BUTTON, langConfig.getString("block.minecraft.polished_blackstone_button", "Polished Blackstone Button")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_PRESSURE_PLATE, langConfig.getString("block.minecraft.polished_blackstone_pressure_plate", "Polished Blackstone Pressure Plate")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_SLAB, langConfig.getString("block.minecraft.polished_blackstone_slab", "Polished Blackstone Slab")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_STAIRS, langConfig.getString("block.minecraft.polished_blackstone_stairs", "Polished Blackstone Stairs")));
            itemNames.add(new ItemName(Material.POLISHED_BLACKSTONE_WALL, langConfig.getString("block.minecraft.polished_blackstone_wall", "Polished Blackstone Wall")));
            itemNames.add(new ItemName(Material.POTTED_CRIMSON_FUNGUS, langConfig.getString("block.minecraft.potted_crimson_fungus", "Potted Crimson Fungus")));
            itemNames.add(new ItemName(Material.POTTED_CRIMSON_ROOTS, langConfig.getString("block.minecraft.potted_crimson_roots", "Potted Crimson Roots")));
            itemNames.add(new ItemName(Material.POTTED_WARPED_FUNGUS, langConfig.getString("block.minecraft.potted_warped_fungus", "Potted Warped Fungus")));
            itemNames.add(new ItemName(Material.POTTED_WARPED_ROOTS, langConfig.getString("block.minecraft.potted_warped_roots", "Potted Warped Roots")));
            itemNames.add(new ItemName(Material.QUARTZ_BRICKS, langConfig.getString("block.minecraft.quartz_bricks", "Quartz Bricks")));
            itemNames.add(new ItemName(Material.RESPAWN_ANCHOR, langConfig.getString("block.minecraft.respawn_anchor", "Respawn Anchor")));
            itemNames.add(new ItemName(Material.SHROOMLIGHT, langConfig.getString("block.minecraft.shroomlight", "Shroomlight")));
            itemNames.add(new ItemName(Material.SOUL_CAMPFIRE, langConfig.getString("block.minecraft.soul_campfire", "Soul Campfire")));
            itemNames.add(new ItemName(Material.SOUL_FIRE, langConfig.getString("block.minecraft.soul_fire", "Soul Fire")));
            itemNames.add(new ItemName(Material.SOUL_LANTERN, langConfig.getString("block.minecraft.soul_lantern", "Soul Lantern")));
            itemNames.add(new ItemName(Material.SOUL_SOIL, langConfig.getString("block.minecraft.soul_soil", "Soul Soil")));
            itemNames.add(new ItemName(Material.SOUL_TORCH, langConfig.getString("block.minecraft.soul_torch", "Soul Torch")));
            itemNames.add(new ItemName(Material.SOUL_WALL_TORCH, langConfig.getString("block.minecraft.soul_wall_torch", "Soul Wall Torch")));
            itemNames.add(new ItemName(Material.STRIDER_SPAWN_EGG, langConfig.getString("item.minecraft.strider_spawn_egg", "Strider Spawn Egg")));
            itemNames.add(new ItemName(Material.STRIPPED_CRIMSON_HYPHAE, langConfig.getString("block.minecraft.stripped_crimson_hyphae", "Stripped Crimson Hyphae")));
            itemNames.add(new ItemName(Material.STRIPPED_CRIMSON_STEM, langConfig.getString("block.minecraft.stripped_crimson_stem", "Stripped Crimson Stem")));
            itemNames.add(new ItemName(Material.STRIPPED_WARPED_HYPHAE, langConfig.getString("block.minecraft.stripped_warped_hyphae", "Stripped Warped Hyphae")));
            itemNames.add(new ItemName(Material.STRIPPED_WARPED_STEM, langConfig.getString("block.minecraft.stripped_warped_stem", "Stripped Warped Stem")));
            itemNames.add(new ItemName(Material.TARGET, langConfig.getString("block.minecraft.target", "Target")));
            itemNames.add(new ItemName(Material.TWISTING_VINES, langConfig.getString("block.minecraft.twisting_vines", "Twisting Vines")));
            itemNames.add(new ItemName(Material.TWISTING_VINES_PLANT, langConfig.getString("block.minecraft.twisting_vines_plant", "Twisting Vines Plant")));
            itemNames.add(new ItemName(Material.WARPED_BUTTON, langConfig.getString("block.minecraft.warped_button", "Warped Button")));
            itemNames.add(new ItemName(Material.WARPED_DOOR, langConfig.getString("block.minecraft.warped_door", "Warped Door")));
            itemNames.add(new ItemName(Material.WARPED_FENCE, langConfig.getString("block.minecraft.warped_fence", "Warped Fence")));
            itemNames.add(new ItemName(Material.WARPED_FENCE_GATE, langConfig.getString("block.minecraft.warped_fence_gate", "Warped Fence Gate")));
            itemNames.add(new ItemName(Material.WARPED_FUNGUS, langConfig.getString("block.minecraft.warped_fungus", "Warped Fungus")));
            itemNames.add(new ItemName(Material.WARPED_FUNGUS_ON_A_STICK, langConfig.getString("item.minecraft.warped_fungus_on_a_stick", "Warped Fungus on a Stick")));
            itemNames.add(new ItemName(Material.WARPED_HYPHAE, langConfig.getString("block.minecraft.warped_hyphae", "Warped Hyphae")));
            itemNames.add(new ItemName(Material.WARPED_NYLIUM, langConfig.getString("block.minecraft.warped_nylium", "Warped Nylium")));
            itemNames.add(new ItemName(Material.WARPED_PLANKS, langConfig.getString("block.minecraft.warped_planks", "Warped Planks")));
            itemNames.add(new ItemName(Material.WARPED_PRESSURE_PLATE, langConfig.getString("block.minecraft.warped_pressure_plate", "Warped Pressure Plate")));
            itemNames.add(new ItemName(Material.WARPED_ROOTS, langConfig.getString("block.minecraft.warped_roots", "Warped Roots")));
            itemNames.add(new ItemName(Material.WARPED_SIGN, langConfig.getString("block.minecraft.warped_sign", "Warped Sign")));
            itemNames.add(new ItemName(Material.WARPED_SLAB, langConfig.getString("block.minecraft.warped_slab", "Warped Slab")));
            itemNames.add(new ItemName(Material.WARPED_STAIRS, langConfig.getString("block.minecraft.warped_stairs", "Warped Stairs")));
            itemNames.add(new ItemName(Material.WARPED_STEM, langConfig.getString("block.minecraft.warped_stem", "Warped Stem")));
            itemNames.add(new ItemName(Material.WARPED_TRAPDOOR, langConfig.getString("block.minecraft.warped_trapdoor", "Warped Trapdoor")));
            itemNames.add(new ItemName(Material.WARPED_WALL_SIGN, langConfig.getString("block.minecraft.warped_wall_sign", "Warped Wall Sign")));
            itemNames.add(new ItemName(Material.WARPED_WART_BLOCK, langConfig.getString("block.minecraft.warped_wart_block", "Warped Wart Block")));
            itemNames.add(new ItemName(Material.WEEPING_VINES, langConfig.getString("block.minecraft.weeping_vines", "Weeping Vines")));
            itemNames.add(new ItemName(Material.WEEPING_VINES_PLANT, langConfig.getString("block.minecraft.weeping_vines_plant", "Weeping Vines Plant")));
            itemNames.add(new ItemName(Material.ZOGLIN_SPAWN_EGG, langConfig.getString("item.minecraft.zoglin_spawn_egg", "Zoglin Spawn Egg")));
            itemNames.add(new ItemName(Material.ZOMBIFIED_PIGLIN_SPAWN_EGG, langConfig.getString("item.minecraft.zombified_piglin_spawn_egg", "Zombified Piglin Spawn Egg")));

            if (Utils.getMajorVersion() > 16 || Utils.getRevision() >= 2) {
                // Add 1.16.2 item names
                itemNames.add(new ItemName(Material.PIGLIN_BRUTE_SPAWN_EGG, langConfig.getString("item.minecraft.piglin_brute_spawn_egg", "Piglin Brute Spawn Egg")));
            }
        } else {
            // Add pre-1.16 item names that don't exist anymore
            itemNames.add(new ItemName(Material.valueOf("ZOMBIE_PIGMAN_SPAWN_EGG"), langConfig.getString("item.minecraft.zombie_pigman_spawn_egg", "Zombie Pigman Spawn Egg")));
        }

        if (Utils.getMajorVersion() >= 17) {
            itemNames.add(new ItemName(Material.AMETHYST_BLOCK, langConfig.getString("block.minecraft.amethyst_block", "Block of Amethyst")));
            itemNames.add(new ItemName(Material.AMETHYST_CLUSTER, langConfig.getString("block.minecraft.amethyst_cluster", "Amethyst Cluster")));
            itemNames.add(new ItemName(Material.AZALEA, langConfig.getString("block.minecraft.azalea", "Azalea")));
            itemNames.add(new ItemName(Material.AZALEA_LEAVES, langConfig.getString("block.minecraft.azalea_leaves", "Azalea Leaves")));
            itemNames.add(new ItemName(Material.BIG_DRIPLEAF, langConfig.getString("block.minecraft.big_dripleaf", "Big Dripleaf")));
            itemNames.add(new ItemName(Material.BIG_DRIPLEAF_STEM, langConfig.getString("block.minecraft.big_dripleaf_stem", "Big Dripleaf Stem")));
            itemNames.add(new ItemName(Material.BLACK_BANNER, langConfig.getString("block.minecraft.black_banner", "Black Banner")));
            itemNames.add(new ItemName(Material.BLACK_CANDLE, langConfig.getString("block.minecraft.black_candle", "Black Candle")));
            itemNames.add(new ItemName(Material.BLACK_CANDLE_CAKE, langConfig.getString("block.minecraft.black_candle_cake", "Cake with Black Candle")));
            itemNames.add(new ItemName(Material.BLUE_BANNER, langConfig.getString("block.minecraft.blue_banner", "Blue Banner")));
            itemNames.add(new ItemName(Material.BLUE_CANDLE, langConfig.getString("block.minecraft.blue_candle", "Blue Candle")));
            itemNames.add(new ItemName(Material.BLUE_CANDLE_CAKE, langConfig.getString("block.minecraft.blue_candle_cake", "Cake with Blue Candle")));
            itemNames.add(new ItemName(Material.BRAIN_CORAL_WALL_FAN, langConfig.getString("block.minecraft.brain_coral_wall_fan", "Brain Coral Wall Fan")));
            itemNames.add(new ItemName(Material.BROWN_BANNER, langConfig.getString("block.minecraft.brown_banner", "Brown Banner")));
            itemNames.add(new ItemName(Material.BROWN_CANDLE, langConfig.getString("block.minecraft.brown_candle", "Brown Candle")));
            itemNames.add(new ItemName(Material.BROWN_CANDLE_CAKE, langConfig.getString("block.minecraft.brown_candle_cake", "Cake with Brown Candle")));
            itemNames.add(new ItemName(Material.BUBBLE_CORAL_WALL_FAN, langConfig.getString("block.minecraft.bubble_coral_wall_fan", "Bubble Coral Wall Fan")));
            itemNames.add(new ItemName(Material.BUDDING_AMETHYST, langConfig.getString("block.minecraft.budding_amethyst", "Budding Amethyst")));
            itemNames.add(new ItemName(Material.CALCITE, langConfig.getString("block.minecraft.calcite", "Calcite")));
            itemNames.add(new ItemName(Material.CANDLE, langConfig.getString("block.minecraft.candle", "Candle")));
            itemNames.add(new ItemName(Material.CANDLE_CAKE, langConfig.getString("block.minecraft.candle_cake", "Cake with Candle")));
            itemNames.add(new ItemName(Material.CAVE_VINES, langConfig.getString("block.minecraft.cave_vines", "Cave Vines")));
            itemNames.add(new ItemName(Material.CAVE_VINES_PLANT, langConfig.getString("block.minecraft.cave_vines_plant", "Cave Vines Plant")));
            itemNames.add(new ItemName(Material.CHISELED_DEEPSLATE, langConfig.getString("block.minecraft.chiseled_deepslate", "Chiseled Deepslate")));
            itemNames.add(new ItemName(Material.COBBLED_DEEPSLATE, langConfig.getString("block.minecraft.cobbled_deepslate", "Cobbled Deepslate")));
            itemNames.add(new ItemName(Material.COBBLED_DEEPSLATE_SLAB, langConfig.getString("block.minecraft.cobbled_deepslate_slab", "Cobbled Deepslate Slab")));
            itemNames.add(new ItemName(Material.COBBLED_DEEPSLATE_STAIRS, langConfig.getString("block.minecraft.cobbled_deepslate_stairs", "Cobbled Deepslate Stairs")));
            itemNames.add(new ItemName(Material.COBBLED_DEEPSLATE_WALL, langConfig.getString("block.minecraft.cobbled_deepslate_wall", "Cobbled Deepslate Wall")));
            itemNames.add(new ItemName(Material.COPPER_BLOCK, langConfig.getString("block.minecraft.copper_block", "Block of Copper")));
            itemNames.add(new ItemName(Material.COPPER_ORE, langConfig.getString("block.minecraft.copper_ore", "Copper Ore")));
            itemNames.add(new ItemName(Material.CRACKED_DEEPSLATE_BRICKS, langConfig.getString("block.minecraft.cracked_deepslate_bricks", "Cracked Deepslate Bricks")));
            itemNames.add(new ItemName(Material.CRACKED_DEEPSLATE_TILES, langConfig.getString("block.minecraft.cracked_deepslate_tiles", "Cracked Deepslate Tiles")));
            itemNames.add(new ItemName(Material.CUT_COPPER, langConfig.getString("block.minecraft.cut_copper", "Cut Copper")));
            itemNames.add(new ItemName(Material.CUT_COPPER_SLAB, langConfig.getString("block.minecraft.cut_copper_slab", "Cut Copper Slab")));
            itemNames.add(new ItemName(Material.CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.cut_copper_stairs", "Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.CYAN_BANNER, langConfig.getString("block.minecraft.cyan_banner", "Cyan Banner")));
            itemNames.add(new ItemName(Material.CYAN_CANDLE, langConfig.getString("block.minecraft.cyan_candle", "Cyan Candle")));
            itemNames.add(new ItemName(Material.CYAN_CANDLE_CAKE, langConfig.getString("block.minecraft.cyan_candle_cake", "Cake with Cyan Candle")));
            itemNames.add(new ItemName(Material.DEAD_BRAIN_CORAL_FAN, langConfig.getString("block.minecraft.dead_brain_coral_fan", "Dead Brain Coral Fan")));
            itemNames.add(new ItemName(Material.DEAD_BRAIN_CORAL_WALL_FAN, langConfig.getString("block.minecraft.dead_brain_coral_wall_fan", "Dead Brain Coral Wall Fan")));
            itemNames.add(new ItemName(Material.DEAD_BUBBLE_CORAL_FAN, langConfig.getString("block.minecraft.dead_bubble_coral_fan", "Dead Bubble Coral Fan")));
            itemNames.add(new ItemName(Material.DEAD_BUBBLE_CORAL_WALL_FAN, langConfig.getString("block.minecraft.dead_bubble_coral_wall_fan", "Dead Bubble Coral Wall Fan")));
            itemNames.add(new ItemName(Material.DEAD_FIRE_CORAL_FAN, langConfig.getString("block.minecraft.dead_fire_coral_fan", "Dead Fire Coral Fan")));
            itemNames.add(new ItemName(Material.DEAD_FIRE_CORAL_WALL_FAN, langConfig.getString("block.minecraft.dead_fire_coral_wall_fan", "Dead Fire Coral Wall Fan")));
            itemNames.add(new ItemName(Material.DEAD_HORN_CORAL_FAN, langConfig.getString("block.minecraft.dead_horn_coral_fan", "Dead Horn Coral Fan")));
            itemNames.add(new ItemName(Material.DEAD_HORN_CORAL_WALL_FAN, langConfig.getString("block.minecraft.dead_horn_coral_wall_fan", "Dead Horn Coral Wall Fan")));
            itemNames.add(new ItemName(Material.DEAD_TUBE_CORAL_FAN, langConfig.getString("block.minecraft.dead_tube_coral_fan", "Dead Tube Coral Fan")));
            itemNames.add(new ItemName(Material.DEAD_TUBE_CORAL_WALL_FAN, langConfig.getString("block.minecraft.dead_tube_coral_wall_fan", "Dead Tube Coral Wall Fan")));
            itemNames.add(new ItemName(Material.DEEPSLATE, langConfig.getString("block.minecraft.deepslate", "Deepslate")));
            itemNames.add(new ItemName(Material.DEEPSLATE_BRICK_SLAB, langConfig.getString("block.minecraft.deepslate_brick_slab", "Deepslate Brick Slab")));
            itemNames.add(new ItemName(Material.DEEPSLATE_BRICK_STAIRS, langConfig.getString("block.minecraft.deepslate_brick_stairs", "Deepslate Brick Stairs")));
            itemNames.add(new ItemName(Material.DEEPSLATE_BRICK_WALL, langConfig.getString("block.minecraft.deepslate_brick_wall", "Deepslate Brick Wall")));
            itemNames.add(new ItemName(Material.DEEPSLATE_BRICKS, langConfig.getString("block.minecraft.deepslate_bricks", "Deepslate Bricks")));
            itemNames.add(new ItemName(Material.DEEPSLATE_COAL_ORE, langConfig.getString("block.minecraft.deepslate_coal_ore", "Deepslate Coal Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_COPPER_ORE, langConfig.getString("block.minecraft.deepslate_copper_ore", "Deepslate Copper Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_DIAMOND_ORE, langConfig.getString("block.minecraft.deepslate_diamond_ore", "Deepslate Diamond Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_EMERALD_ORE, langConfig.getString("block.minecraft.deepslate_emerald_ore", "Deepslate Emerald Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_GOLD_ORE, langConfig.getString("block.minecraft.deepslate_gold_ore", "Deepslate Gold Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_IRON_ORE, langConfig.getString("block.minecraft.deepslate_iron_ore", "Deepslate Iron Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_LAPIS_ORE, langConfig.getString("block.minecraft.deepslate_lapis_ore", "Deepslate Lapis Lazuli Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_REDSTONE_ORE, langConfig.getString("block.minecraft.deepslate_redstone_ore", "Deepslate Redstone Ore")));
            itemNames.add(new ItemName(Material.DEEPSLATE_TILE_SLAB, langConfig.getString("block.minecraft.deepslate_tile_slab", "Deepslate Tile Slab")));
            itemNames.add(new ItemName(Material.DEEPSLATE_TILE_STAIRS, langConfig.getString("block.minecraft.deepslate_tile_stairs", "Deepslate Tile Stairs")));
            itemNames.add(new ItemName(Material.DEEPSLATE_TILE_WALL, langConfig.getString("block.minecraft.deepslate_tile_wall", "Deepslate Tile Wall")));
            itemNames.add(new ItemName(Material.DEEPSLATE_TILES, langConfig.getString("block.minecraft.deepslate_tiles", "Deepslate Tiles")));
            itemNames.add(new ItemName(Material.DIRT_PATH, langConfig.getString("block.minecraft.dirt_path", "Dirt Path")));
            itemNames.add(new ItemName(Material.DRIPSTONE_BLOCK, langConfig.getString("block.minecraft.dripstone_block", "Dripstone Block")));
            itemNames.add(new ItemName(Material.EXPOSED_COPPER, langConfig.getString("block.minecraft.exposed_copper", "Exposed Copper")));
            itemNames.add(new ItemName(Material.EXPOSED_CUT_COPPER, langConfig.getString("block.minecraft.exposed_cut_copper", "Exposed Cut Copper")));
            itemNames.add(new ItemName(Material.EXPOSED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.exposed_cut_copper_slab", "Exposed Cut Copper Slab")));
            itemNames.add(new ItemName(Material.EXPOSED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.exposed_cut_copper_stairs", "Exposed Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.FIRE_CORAL_WALL_FAN, langConfig.getString("block.minecraft.fire_coral_wall_fan", "Fire Coral Wall Fan")));
            itemNames.add(new ItemName(Material.FLOWERING_AZALEA, langConfig.getString("block.minecraft.flowering_azalea", "Flowering Azalea")));
            itemNames.add(new ItemName(Material.FLOWERING_AZALEA_LEAVES, langConfig.getString("block.minecraft.flowering_azalea_leaves", "Flowering Azalea Leaves")));
            itemNames.add(new ItemName(Material.GLOW_LICHEN, langConfig.getString("block.minecraft.glow_lichen", "Glow Lichen")));
            itemNames.add(new ItemName(Material.GRAY_BANNER, langConfig.getString("block.minecraft.gray_banner", "Gray Banner")));
            itemNames.add(new ItemName(Material.GRAY_CANDLE, langConfig.getString("block.minecraft.gray_candle", "Gray Candle")));
            itemNames.add(new ItemName(Material.GRAY_CANDLE_CAKE, langConfig.getString("block.minecraft.gray_candle_cake", "Cake with Gray Candle")));
            itemNames.add(new ItemName(Material.GREEN_BANNER, langConfig.getString("block.minecraft.green_banner", "Green Banner")));
            itemNames.add(new ItemName(Material.GREEN_CANDLE, langConfig.getString("block.minecraft.green_candle", "Green Candle")));
            itemNames.add(new ItemName(Material.GREEN_CANDLE_CAKE, langConfig.getString("block.minecraft.green_candle_cake", "Cake with Green Candle")));
            itemNames.add(new ItemName(Material.HANGING_ROOTS, langConfig.getString("block.minecraft.hanging_roots", "Hanging Roots")));
            itemNames.add(new ItemName(Material.HORN_CORAL_WALL_FAN, langConfig.getString("block.minecraft.horn_coral_wall_fan", "Horn Coral Wall Fan")));
            itemNames.add(new ItemName(Material.INFESTED_DEEPSLATE, langConfig.getString("block.minecraft.infested_deepslate", "Infested Deepslate")));
            itemNames.add(new ItemName(Material.LARGE_AMETHYST_BUD, langConfig.getString("block.minecraft.large_amethyst_bud", "Large Amethyst Bud")));
            itemNames.add(new ItemName(Material.LAVA_CAULDRON, langConfig.getString("block.minecraft.lava_cauldron", "Lava Cauldron")));
            itemNames.add(new ItemName(Material.LIGHT, langConfig.getString("block.minecraft.light", "Light")));
            itemNames.add(new ItemName(Material.LIGHT_BLUE_BANNER, langConfig.getString("block.minecraft.light_blue_banner", "Light Blue Banner")));
            itemNames.add(new ItemName(Material.LIGHT_BLUE_CANDLE, langConfig.getString("block.minecraft.light_blue_candle", "Light Blue Candle")));
            itemNames.add(new ItemName(Material.LIGHT_BLUE_CANDLE_CAKE, langConfig.getString("block.minecraft.light_blue_candle_cake", "Cake with Light Blue Candle")));
            itemNames.add(new ItemName(Material.LIGHT_GRAY_BANNER, langConfig.getString("block.minecraft.light_gray_banner", "Light Gray Banner")));
            itemNames.add(new ItemName(Material.LIGHT_GRAY_CANDLE, langConfig.getString("block.minecraft.light_gray_candle", "Light Gray Candle")));
            itemNames.add(new ItemName(Material.LIGHT_GRAY_CANDLE_CAKE, langConfig.getString("block.minecraft.light_gray_candle_cake", "Cake with Light Gray Candle")));
            itemNames.add(new ItemName(Material.LIGHTNING_ROD, langConfig.getString("block.minecraft.lightning_rod", "Lightning Rod")));
            itemNames.add(new ItemName(Material.LIME_BANNER, langConfig.getString("block.minecraft.lime_banner", "Lime Banner")));
            itemNames.add(new ItemName(Material.LIME_CANDLE, langConfig.getString("block.minecraft.lime_candle", "Lime Candle")));
            itemNames.add(new ItemName(Material.LIME_CANDLE_CAKE, langConfig.getString("block.minecraft.lime_candle_cake", "Cake with Lime Candle")));
            itemNames.add(new ItemName(Material.MAGENTA_BANNER, langConfig.getString("block.minecraft.magenta_banner", "Magenta Banner")));
            itemNames.add(new ItemName(Material.MAGENTA_CANDLE, langConfig.getString("block.minecraft.magenta_candle", "Magenta Candle")));
            itemNames.add(new ItemName(Material.MAGENTA_CANDLE_CAKE, langConfig.getString("block.minecraft.magenta_candle_cake", "Cake with Magenta Candle")));
            itemNames.add(new ItemName(Material.MEDIUM_AMETHYST_BUD, langConfig.getString("block.minecraft.medium_amethyst_bud", "Medium Amethyst Bud")));
            itemNames.add(new ItemName(Material.MOSS_BLOCK, langConfig.getString("block.minecraft.moss_block", "Moss Block")));
            itemNames.add(new ItemName(Material.MOSS_CARPET, langConfig.getString("block.minecraft.moss_carpet", "Moss Carpet")));
            itemNames.add(new ItemName(Material.ORANGE_BANNER, langConfig.getString("block.minecraft.orange_banner", "Orange Banner")));
            itemNames.add(new ItemName(Material.ORANGE_CANDLE, langConfig.getString("block.minecraft.orange_candle", "Orange Candle")));
            itemNames.add(new ItemName(Material.ORANGE_CANDLE_CAKE, langConfig.getString("block.minecraft.orange_candle_cake", "Cake with Orange Candle")));
            itemNames.add(new ItemName(Material.OXIDIZED_COPPER, langConfig.getString("block.minecraft.oxidized_copper", "Oxidized Copper")));
            itemNames.add(new ItemName(Material.OXIDIZED_CUT_COPPER, langConfig.getString("block.minecraft.oxidized_cut_copper", "Oxidized Cut Copper")));
            itemNames.add(new ItemName(Material.OXIDIZED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.oxidized_cut_copper_slab", "Oxidized Cut Copper Slab")));
            itemNames.add(new ItemName(Material.OXIDIZED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.oxidized_cut_copper_stairs", "Oxidized Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.PINK_BANNER, langConfig.getString("block.minecraft.pink_banner", "Pink Banner")));
            itemNames.add(new ItemName(Material.PINK_CANDLE, langConfig.getString("block.minecraft.pink_candle", "Pink Candle")));
            itemNames.add(new ItemName(Material.PINK_CANDLE_CAKE, langConfig.getString("block.minecraft.pink_candle_cake", "Cake with Pink Candle")));
            itemNames.add(new ItemName(Material.POINTED_DRIPSTONE, langConfig.getString("block.minecraft.pointed_dripstone", "Pointed Dripstone")));
            itemNames.add(new ItemName(Material.POLISHED_DEEPSLATE, langConfig.getString("block.minecraft.polished_deepslate", "Polished Deepslate")));
            itemNames.add(new ItemName(Material.POLISHED_DEEPSLATE_SLAB, langConfig.getString("block.minecraft.polished_deepslate_slab", "Polished Deepslate Slab")));
            itemNames.add(new ItemName(Material.POLISHED_DEEPSLATE_STAIRS, langConfig.getString("block.minecraft.polished_deepslate_stairs", "Polished Deepslate Stairs")));
            itemNames.add(new ItemName(Material.POLISHED_DEEPSLATE_WALL, langConfig.getString("block.minecraft.polished_deepslate_wall", "Polished Deepslate Wall")));
            itemNames.add(new ItemName(Material.POTTED_AZALEA_BUSH, langConfig.getString("block.minecraft.potted_azalea_bush", "Potted Azalea Bush")));
            itemNames.add(new ItemName(Material.POTTED_FLOWERING_AZALEA_BUSH, langConfig.getString("block.minecraft.potted_flowering_azalea_bush", "Potted Flowering Azalea")));
            itemNames.add(new ItemName(Material.POWDER_SNOW, langConfig.getString("block.minecraft.powder_snow", "Powder Snow")));
            itemNames.add(new ItemName(Material.POWDER_SNOW_CAULDRON, langConfig.getString("block.minecraft.powder_snow_cauldron", "Powder Snow Cauldron")));
            itemNames.add(new ItemName(Material.PURPLE_BANNER, langConfig.getString("block.minecraft.purple_banner", "Purple Banner")));
            itemNames.add(new ItemName(Material.PURPLE_CANDLE, langConfig.getString("block.minecraft.purple_candle", "Purple Candle")));
            itemNames.add(new ItemName(Material.PURPLE_CANDLE_CAKE, langConfig.getString("block.minecraft.purple_candle_cake", "Cake with Purple Candle")));
            itemNames.add(new ItemName(Material.RAW_COPPER_BLOCK, langConfig.getString("block.minecraft.raw_copper_block", "Block of Raw Copper")));
            itemNames.add(new ItemName(Material.RAW_GOLD_BLOCK, langConfig.getString("block.minecraft.raw_gold_block", "Block of Raw Gold")));
            itemNames.add(new ItemName(Material.RAW_IRON_BLOCK, langConfig.getString("block.minecraft.raw_iron_block", "Block of Raw Iron")));
            itemNames.add(new ItemName(Material.RED_BANNER, langConfig.getString("block.minecraft.red_banner", "Red Banner")));
            itemNames.add(new ItemName(Material.RED_CANDLE, langConfig.getString("block.minecraft.red_candle", "Red Candle")));
            itemNames.add(new ItemName(Material.RED_CANDLE_CAKE, langConfig.getString("block.minecraft.red_candle_cake", "Cake with Red Candle")));
            itemNames.add(new ItemName(Material.ROOTED_DIRT, langConfig.getString("block.minecraft.rooted_dirt", "Rooted Dirt")));
            itemNames.add(new ItemName(Material.SCULK_SENSOR, langConfig.getString("block.minecraft.sculk_sensor", "Sculk Sensor")));
            itemNames.add(new ItemName(Material.SMALL_AMETHYST_BUD, langConfig.getString("block.minecraft.small_amethyst_bud", "Small Amethyst Bud")));
            itemNames.add(new ItemName(Material.SMALL_DRIPLEAF, langConfig.getString("block.minecraft.small_dripleaf", "Small Dripleaf")));
            itemNames.add(new ItemName(Material.SMOOTH_BASALT, langConfig.getString("block.minecraft.smooth_basalt", "Smooth Basalt")));
            itemNames.add(new ItemName(Material.SPORE_BLOSSOM, langConfig.getString("block.minecraft.spore_blossom", "Spore Blossom")));
            itemNames.add(new ItemName(Material.STONE_STAIRS, langConfig.getString("block.minecraft.stone_stairs", "Stone Stairs")));
            itemNames.add(new ItemName(Material.TINTED_GLASS, langConfig.getString("block.minecraft.tinted_glass", "Tinted Glass")));
            itemNames.add(new ItemName(Material.TUBE_CORAL_WALL_FAN, langConfig.getString("block.minecraft.tube_coral_wall_fan", "Tube Coral Wall Fan")));
            itemNames.add(new ItemName(Material.TUFF, langConfig.getString("block.minecraft.tuff", "Tuff")));
            itemNames.add(new ItemName(Material.WATER_CAULDRON, langConfig.getString("block.minecraft.water_cauldron", "Water Cauldron")));
            itemNames.add(new ItemName(Material.WAXED_COPPER_BLOCK, langConfig.getString("block.minecraft.waxed_copper_block", "Waxed Block of Copper")));
            itemNames.add(new ItemName(Material.WAXED_CUT_COPPER, langConfig.getString("block.minecraft.waxed_cut_copper", "Waxed Cut Copper")));
            itemNames.add(new ItemName(Material.WAXED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.waxed_cut_copper_slab", "Waxed Cut Copper Slab")));
            itemNames.add(new ItemName(Material.WAXED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.waxed_cut_copper_stairs", "Waxed Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.WAXED_EXPOSED_COPPER, langConfig.getString("block.minecraft.waxed_exposed_copper", "Waxed Exposed Copper")));
            itemNames.add(new ItemName(Material.WAXED_EXPOSED_CUT_COPPER, langConfig.getString("block.minecraft.waxed_exposed_cut_copper", "Waxed Exposed Cut Copper")));
            itemNames.add(new ItemName(Material.WAXED_EXPOSED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.waxed_exposed_cut_copper_slab", "Waxed Exposed Cut Copper Slab")));
            itemNames.add(new ItemName(Material.WAXED_EXPOSED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.waxed_exposed_cut_copper_stairs", "Waxed Exposed Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.WAXED_OXIDIZED_COPPER, langConfig.getString("block.minecraft.waxed_oxidized_copper", "Waxed Oxidized Copper")));
            itemNames.add(new ItemName(Material.WAXED_OXIDIZED_CUT_COPPER, langConfig.getString("block.minecraft.waxed_oxidized_cut_copper", "Waxed Oxidized Cut Copper")));
            itemNames.add(new ItemName(Material.WAXED_OXIDIZED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.waxed_oxidized_cut_copper_slab", "Waxed Oxidized Cut Copper Slab")));
            itemNames.add(new ItemName(Material.WAXED_OXIDIZED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.waxed_oxidized_cut_copper_stairs", "Waxed Oxidized Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.WAXED_WEATHERED_COPPER, langConfig.getString("block.minecraft.waxed_weathered_copper", "Waxed Weathered Copper")));
            itemNames.add(new ItemName(Material.WAXED_WEATHERED_CUT_COPPER, langConfig.getString("block.minecraft.waxed_weathered_cut_copper", "Waxed Weathered Cut Copper")));
            itemNames.add(new ItemName(Material.WAXED_WEATHERED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.waxed_weathered_cut_copper_slab", "Waxed Weathered Cut Copper Slab")));
            itemNames.add(new ItemName(Material.WAXED_WEATHERED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.waxed_weathered_cut_copper_stairs", "Waxed Weathered Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.WEATHERED_COPPER, langConfig.getString("block.minecraft.weathered_copper", "Weathered Copper")));
            itemNames.add(new ItemName(Material.WEATHERED_CUT_COPPER, langConfig.getString("block.minecraft.weathered_cut_copper", "Weathered Cut Copper")));
            itemNames.add(new ItemName(Material.WEATHERED_CUT_COPPER_SLAB, langConfig.getString("block.minecraft.weathered_cut_copper_slab", "Weathered Cut Copper Slab")));
            itemNames.add(new ItemName(Material.WEATHERED_CUT_COPPER_STAIRS, langConfig.getString("block.minecraft.weathered_cut_copper_stairs", "Weathered Cut Copper Stairs")));
            itemNames.add(new ItemName(Material.WHITE_BANNER, langConfig.getString("block.minecraft.white_banner", "White Banner")));
            itemNames.add(new ItemName(Material.WHITE_CANDLE, langConfig.getString("block.minecraft.white_candle", "White Candle")));
            itemNames.add(new ItemName(Material.WHITE_CANDLE_CAKE, langConfig.getString("block.minecraft.white_candle_cake", "Cake with White Candle")));
            itemNames.add(new ItemName(Material.YELLOW_BANNER, langConfig.getString("block.minecraft.yellow_banner", "Yellow Banner")));
            itemNames.add(new ItemName(Material.YELLOW_CANDLE, langConfig.getString("block.minecraft.yellow_candle", "Yellow Candle")));
            itemNames.add(new ItemName(Material.YELLOW_CANDLE_CAKE, langConfig.getString("block.minecraft.yellow_candle_cake", "Cake with Yellow Candle")));
            itemNames.add(new ItemName(Material.AMETHYST_SHARD, langConfig.getString("item.minecraft.amethyst_shard", "Amethyst Shard")));
            itemNames.add(new ItemName(Material.AXOLOTL_BUCKET, langConfig.getString("item.minecraft.axolotl_bucket", "Bucket of Axolotl")));
            itemNames.add(new ItemName(Material.AXOLOTL_SPAWN_EGG, langConfig.getString("item.minecraft.axolotl_spawn_egg", "Axolotl Spawn Egg")));
            itemNames.add(new ItemName(Material.BUNDLE, langConfig.getString("item.minecraft.bundle", "Bundle")));
            itemNames.add(new ItemName(Material.COPPER_INGOT, langConfig.getString("item.minecraft.copper_ingot", "Copper Ingot")));
            itemNames.add(new ItemName(Material.GLOW_BERRIES, langConfig.getString("item.minecraft.glow_berries", "Glow Berries")));
            itemNames.add(new ItemName(Material.GLOW_INK_SAC, langConfig.getString("item.minecraft.glow_ink_sac", "Glow Ink Sac")));
            itemNames.add(new ItemName(Material.GLOW_ITEM_FRAME, langConfig.getString("item.minecraft.glow_item_frame", "Glow Item Frame")));
            itemNames.add(new ItemName(Material.GLOW_SQUID_SPAWN_EGG, langConfig.getString("item.minecraft.glow_squid_spawn_egg", "Glow Squid Spawn Egg")));
            itemNames.add(new ItemName(Material.GOAT_SPAWN_EGG, langConfig.getString("item.minecraft.goat_spawn_egg", "Goat Spawn Egg")));
            itemNames.add(new ItemName(Material.PIGLIN_BANNER_PATTERN, langConfig.getString("item.minecraft.piglin_banner_pattern", "Banner Pattern")));
            itemNames.add(new ItemName(Material.POWDER_SNOW_BUCKET, langConfig.getString("item.minecraft.powder_snow_bucket", "Powder Snow Bucket")));
            itemNames.add(new ItemName(Material.RAW_COPPER, langConfig.getString("item.minecraft.raw_copper", "Raw Copper")));
            itemNames.add(new ItemName(Material.RAW_GOLD, langConfig.getString("item.minecraft.raw_gold", "Raw Gold")));
            itemNames.add(new ItemName(Material.RAW_IRON, langConfig.getString("item.minecraft.raw_iron", "Raw Iron")));
            itemNames.add(new ItemName(Material.SHIELD, langConfig.getString("item.minecraft.shield", "Shield")));
            itemNames.add(new ItemName(Material.SPYGLASS, langConfig.getString("item.minecraft.spyglass", "Spyglass")));
        } else {
            itemNames.add(new ItemName(Material.valueOf("GRASS_PATH"), langConfig.getString("block.minecraft.grass_path", "Grass Path")));
        }

        // Add Enchantment Names
        enchantmentNames.add(new EnchantmentName(Enchantment.DAMAGE_ALL, langConfig.getString("enchantment.minecraft.sharpness", "Sharpness")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DAMAGE_UNDEAD, langConfig.getString("enchantment.minecraft.smite", "Smite")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DAMAGE_ARTHROPODS, langConfig.getString("enchantment.minecraft.bane_of_arthropods", "Bane of Arthropods")));
        enchantmentNames.add(new EnchantmentName(Enchantment.KNOCKBACK, langConfig.getString("enchantment.minecraft.knockback", "Knockback")));
        enchantmentNames.add(new EnchantmentName(Enchantment.FIRE_ASPECT, langConfig.getString("enchantment.minecraft.fire_aspect", "Fire Aspect")));
        enchantmentNames.add(new EnchantmentName(Enchantment.SWEEPING_EDGE, langConfig.getString("enchantment.minecraft.sweeping", "Sweeping Edge")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_ENVIRONMENTAL, langConfig.getString("enchantment.minecraft.protection", "Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_FIRE, langConfig.getString("enchantment.minecraft.fire_protection", "Fire Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_FALL, langConfig.getString("enchantment.minecraft.feather_falling", "Feather Falling")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_EXPLOSIONS, langConfig.getString("enchantment.minecraft.blast_protection", "Blast Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.PROTECTION_PROJECTILE, langConfig.getString("enchantment.minecraft.projectile_protection", "Projectile Protection")));
        enchantmentNames.add(new EnchantmentName(Enchantment.OXYGEN, langConfig.getString("enchantment.minecraft.respiration", "Respiration")));
        enchantmentNames.add(new EnchantmentName(Enchantment.WATER_WORKER, langConfig.getString("enchantment.minecraft.aqua_affinity", "Aqua Affinity")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DEPTH_STRIDER, langConfig.getString("enchantment.minecraft.depth_strider", "Depth Strider")));
        enchantmentNames.add(new EnchantmentName(Enchantment.FROST_WALKER, langConfig.getString("enchantment.minecraft.frost_walker", "Frost Walker")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DIG_SPEED, langConfig.getString("enchantment.minecraft.efficiency", "Efficiency")));
        enchantmentNames.add(new EnchantmentName(Enchantment.SILK_TOUCH, langConfig.getString("enchantment.minecraft.silk_touch", "Silk Touch")));
        enchantmentNames.add(new EnchantmentName(Enchantment.DURABILITY, langConfig.getString("enchantment.minecraft.unbreaking", "Unbreaking")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LOOT_BONUS_MOBS, langConfig.getString("enchantment.minecraft.looting", "Looting")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LOOT_BONUS_BLOCKS, langConfig.getString("enchantment.minecraft.fortune", "Fortune")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LUCK, langConfig.getString("enchantment.minecraft.luck_of_the_sea", "Luck of the Sea")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LURE, langConfig.getString("enchantment.minecraft.lure", "Lure")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_DAMAGE, langConfig.getString("enchantment.minecraft.power", "Power")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_FIRE, langConfig.getString("enchantment.minecraft.flame", "Flame")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_KNOCKBACK, langConfig.getString("enchantment.minecraft.punch", "Punch")));
        enchantmentNames.add(new EnchantmentName(Enchantment.ARROW_INFINITE, langConfig.getString("enchantment.minecraft.infinity", "Infinity")));
        enchantmentNames.add(new EnchantmentName(Enchantment.THORNS, langConfig.getString("enchantment.minecraft.thorns", "Thorns")));
        enchantmentNames.add(new EnchantmentName(Enchantment.MENDING, langConfig.getString("enchantment.minecraft.mending", "Mending")));
        enchantmentNames.add(new EnchantmentName(Enchantment.BINDING_CURSE, langConfig.getString("enchantment.minecraft.binding_curse", "Curse of Binding")));
        enchantmentNames.add(new EnchantmentName(Enchantment.VANISHING_CURSE, langConfig.getString("enchantment.minecraft.vanishing_curse", "Curse of Vanishing")));
        enchantmentNames.add(new EnchantmentName(Enchantment.LOYALTY, langConfig.getString("enchantment.minecraft.loyalty", "Loyalty")));
        enchantmentNames.add(new EnchantmentName(Enchantment.IMPALING, langConfig.getString("enchantment.minecraft.impaling", "Impaling")));
        enchantmentNames.add(new EnchantmentName(Enchantment.RIPTIDE, langConfig.getString("enchantment.minecraft.riptide", "Riptide")));
        enchantmentNames.add(new EnchantmentName(Enchantment.CHANNELING, langConfig.getString("enchantment.minecraft.channeling", "Channeling")));

        if (Utils.getMajorVersion() >= 17) {
            // Add 1.17 enchantment name
            enchantmentNames.add(new EnchantmentName(Enchantment.SOUL_SPEED, langConfig.getString("enchantment.minecraft.soul_speed", "Soul Speed")));
        }

        if (Utils.getMajorVersion() >= 14) {
            // Add 1.14 enchantment names
            enchantmentNames.add(new EnchantmentName(Enchantment.MULTISHOT, langConfig.getString("enchantment.minecraft.multishot", "Multishot")));
            enchantmentNames.add(new EnchantmentName(Enchantment.QUICK_CHARGE, langConfig.getString("enchantment.minecraft.quick_charge", "Quick Charge")));
            enchantmentNames.add(new EnchantmentName(Enchantment.PIERCING, langConfig.getString("enchantment.minecraft.piercing", "Piercing")));
        }

        // Add Enchantment Level Names
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(1, langConfig.getString("enchantment.level.1", "I")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(2, langConfig.getString("enchantment.level.2", "II")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(3, langConfig.getString("enchantment.level.3", "II")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(4, langConfig.getString("enchantment.level.4", "IV")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(5, langConfig.getString("enchantment.level.5", "V")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(6, langConfig.getString("enchantment.level.6", "VI")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(7, langConfig.getString("enchantment.level.7", "VII")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(8, langConfig.getString("enchantment.level.8", "VIII")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(9, langConfig.getString("enchantment.level.9", "IX")));
        enchantmentLevelNames.add(new EnchantmentName.EnchantmentLevelName(10, langConfig.getString("enchantment.level.10", "X")));

        // Add Potion Effect Names
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SPEED, langConfig.getString("effect.minecraft.speed", "Speed")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SLOW, langConfig.getString("effect.minecraft.slowness", "Slowness")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.FAST_DIGGING, langConfig.getString("effect.minecraft.haste", "Haste")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SLOW_DIGGING, langConfig.getString("effect.minecraft.mining_fatigue", "Mining Fatigue")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.INCREASE_DAMAGE, langConfig.getString("effect.minecraft.strength", "Strength")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.HEAL, langConfig.getString("effect.minecraft.instant_health", "Instant Health")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.HARM, langConfig.getString("effect.minecraft.instant_damage", "Instant Damage")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.JUMP, langConfig.getString("effect.minecraft.jump_boost", "Jump Boost")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.CONFUSION, langConfig.getString("effect.minecraft.nausea", "Nausea")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.REGENERATION, langConfig.getString("effect.minecraft.regeneration", "Regeneration")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.DAMAGE_RESISTANCE, langConfig.getString("effect.minecraft.resistance", "Resistance")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.FIRE_RESISTANCE, langConfig.getString("effect.minecraft.fire_resistance", "Fire Resistance")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.WATER_BREATHING, langConfig.getString("effect.minecraft.water_breathing", "Water Breathing")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.INVISIBILITY, langConfig.getString("effect.minecraft.invisibility", "Invisibility")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.BLINDNESS, langConfig.getString("effect.minecraft.blindness", "Blindness")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.NIGHT_VISION, langConfig.getString("effect.minecraft.night_vision", "Night Vision")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.HUNGER, langConfig.getString("effect.minecraft.hunger", "Hunger")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.WEAKNESS, langConfig.getString("effect.minecraft.weakness", "Weakness")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.POISON, langConfig.getString("effect.minecraft.poison", "Poison")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.WITHER, langConfig.getString("effect.minecraft.wither", "Wither")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.HEALTH_BOOST, langConfig.getString("effect.minecraft.health_boost", "Health Boost")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.ABSORPTION, langConfig.getString("effect.minecraft.absorption", "Absorption")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SATURATION, langConfig.getString("effect.minecraft.saturation", "Saturation")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.GLOWING, langConfig.getString("effect.minecraft.glowing", "Glowing")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.LUCK, langConfig.getString("effect.minecraft.luck", "Luck")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.UNLUCK, langConfig.getString("effect.minecraft.unluck", "Bad Luck")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.LEVITATION, langConfig.getString("effect.minecraft.levitation", "Levitation")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.SLOW_FALLING, langConfig.getString("effect.minecraft.slow_falling", "Slow Falling")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.CONDUIT_POWER, langConfig.getString("effect.minecraft.conduit_power", "Conduit Power")));
        potionEffectNames.add(new PotionEffectName(PotionEffectType.DOLPHINS_GRACE, langConfig.getString("effect.minecraft.dolphins_grace", "Dolphin's Grace")));


        if (Utils.getMajorVersion() >= 14) {
            // Add 1.14 potion effect names
            potionEffectNames.add(new PotionEffectName(PotionEffectType.BAD_OMEN, langConfig.getString("effect.minecraft.bad_omen", "Bad Omen")));
            potionEffectNames.add(new PotionEffectName(PotionEffectType.HERO_OF_THE_VILLAGE, langConfig.getString("effect.minecraft.hero_of_the_village", "Hero of the Village")));

        }

        // Add Potion Names
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.UNCRAFTABLE, langConfig.getString("item.minecraft.potion.effect.empty", "Uncraftable Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.WATER, langConfig.getString("item.minecraft.potion.effect.water", "Water Bottle")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.MUNDANE, langConfig.getString("item.minecraft.potion.effect.mundane", "Mundane Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.THICK, langConfig.getString("item.minecraft.potion.effect.thick", "Thick Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.AWKWARD, langConfig.getString("item.minecraft.potion.effect.awkward", "Awkward Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.NIGHT_VISION, langConfig.getString("item.minecraft.potion.effect.night_vision", "Potion of Night Vision")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.INVISIBILITY, langConfig.getString("item.minecraft.potion.effect.invisibility", "Potion of Invisibility")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.JUMP, langConfig.getString("item.minecraft.potion.effect.leaping", "Potion of Leaping")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.FIRE_RESISTANCE, langConfig.getString("item.minecraft.potion.effect.fire_resistance", "Potion of Fire Resistance")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.SPEED, langConfig.getString("item.minecraft.potion.effect.swiftness", "Potion of Swiftness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.SLOWNESS, langConfig.getString("item.minecraft.potion.effect.slowness", "Potion of Slowness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.WATER_BREATHING, langConfig.getString("item.minecraft.potion.effect.water_breathing", "Potion of Water Breathing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.INSTANT_HEAL, langConfig.getString("item.minecraft.potion.effect.healing", "Potion of Healing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.INSTANT_DAMAGE, langConfig.getString("item.minecraft.potion.effect.harming", "Potion of Harming")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.POISON, langConfig.getString("item.minecraft.potion.effect.poison", "Potion of Poison")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.REGEN, langConfig.getString("item.minecraft.potion.effect.regeneration", "Potion of Regeneration")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.STRENGTH, langConfig.getString("item.minecraft.potion.effect.strength", "Potion of Strength")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.WEAKNESS, langConfig.getString("item.minecraft.potion.effect.weakness", "Potion of Weakness")));
        //potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.LEVITATION, langConfig.getString("item.minecraft.potion.effect.levitation", "Potion of Levitation")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.LUCK, langConfig.getString("item.minecraft.potion.effect.luck", "Potion of Luck")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.TURTLE_MASTER, langConfig.getString("item.minecraft.potion.effect.turtle_master", "Potion of the Turtle Master")));
        potionNames.add(new PotionName(PotionName.PotionItemType.POTION, PotionType.SLOW_FALLING, langConfig.getString("item.minecraft.potion.effect.slow_falling", "Potion of Slow Falling")));

        // Add Splash Potion Names
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.UNCRAFTABLE, langConfig.getString("item.minecraft.splash_potion.effect.empty", "Splash Uncraftable Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.WATER, langConfig.getString("item.minecraft.splash_potion.effect.water", "Splash Water Bottle")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.MUNDANE, langConfig.getString("item.minecraft.splash_potion.effect.mundane", "Mundane Splash Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.THICK, langConfig.getString("item.minecraft.splash_potion.effect.thick", "Thick Splash Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.AWKWARD, langConfig.getString("item.minecraft.splash_potion.effect.awkward", "Awkward Splash Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.NIGHT_VISION, langConfig.getString("item.minecraft.splash_potion.effect.night_vision", "Splash Potion of Night Vision")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.INVISIBILITY, langConfig.getString("item.minecraft.splash_potion.effect.invisibility", "Splash Potion of Invisibility")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.JUMP, langConfig.getString("item.minecraft.splash_potion.effect.leaping", "Splash Potion of Leaping")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.FIRE_RESISTANCE, langConfig.getString("item.minecraft.splash_potion.effect.fire_resistance", "Splash Potion of Fire Resistance")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.SPEED, langConfig.getString("item.minecraft.splash_potion.effect.swiftness", "Splash Potion of Swiftness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.SLOWNESS, langConfig.getString("item.minecraft.splash_potion.effect.slowness", "Splash Potion of Slowness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.WATER_BREATHING, langConfig.getString("item.minecraft.splash_potion.effect.water_breathing", "Splash Potion of Water Breathing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.INSTANT_HEAL, langConfig.getString("item.minecraft.splash_potion.effect.healing", "Splash Potion of Healing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.INSTANT_DAMAGE, langConfig.getString("item.minecraft.splash_potion.effect.harming", "Splash Potion of Harming")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.POISON, langConfig.getString("item.minecraft.splash_potion.effect.poison", "Splash Potion of Poison")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.REGEN, langConfig.getString("item.minecraft.splash_potion.effect.regeneration", "Splash Potion of Regeneration")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.STRENGTH, langConfig.getString("item.minecraft.splash_potion.effect.strength", "Splash Potion of Strength")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.WEAKNESS, langConfig.getString("item.minecraft.splash_potion.effect.weakness", "Splash Potion of Weakness")));
        //potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.LEVITATION, langConfig.getString("item.minecraft.splash_potion.effect.levitation", "Splash Potion of Levitation")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.LUCK, langConfig.getString("item.minecraft.splash_potion.effect.luck", "Splash Potion of Luck")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.TURTLE_MASTER, langConfig.getString("item.minecraft.splash_potion.effect.turtle_master", "Splash Potion of the Turtle Master")));
        potionNames.add(new PotionName(PotionName.PotionItemType.SPLASH_POTION, PotionType.SLOW_FALLING, langConfig.getString("item.minecraft.splash_potion.effect.slow_falling", "Splash Potion of Slow Falling")));

        // Add Lingering Potion Names
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.UNCRAFTABLE, langConfig.getString("item.minecraft.lingering_potion.effect.empty", "Lingering Uncraftable Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.WATER, langConfig.getString("item.minecraft.lingering_potion.effect.water", "Lingering Water Bottle")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.MUNDANE, langConfig.getString("item.minecraft.lingering_potion.effect.mundane", "Mundane Lingering Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.THICK, langConfig.getString("item.minecraft.lingering_potion.effect.thick", "Thick Lingering Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.AWKWARD, langConfig.getString("item.minecraft.lingering_potion.effect.awkward", "Awkward Lingering Potion")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.NIGHT_VISION, langConfig.getString("item.minecraft.lingering_potion.effect.night_vision", "Lingering Potion of Night Vision")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.INVISIBILITY, langConfig.getString("item.minecraft.lingering_potion.effect.invisibility", "Lingering Potion of Invisibility")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.JUMP, langConfig.getString("item.minecraft.lingering_potion.effect.leaping", "Lingering Potion of Leaping")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.FIRE_RESISTANCE, langConfig.getString("item.minecraft.lingering_potion.effect.fire_resistance", "Lingering Potion of Fire Resistance")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.SPEED, langConfig.getString("item.minecraft.lingering_potion.effect.swiftness", "Lingering Potion of Swiftness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.SLOWNESS, langConfig.getString("item.minecraft.lingering_potion.effect.slowness", "Lingering Potion of Slowness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.WATER_BREATHING, langConfig.getString("item.minecraft.lingering_potion.effect.water_breathing", "Lingering Potion of Water Breathing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.INSTANT_HEAL, langConfig.getString("item.minecraft.lingering_potion.effect.healing", "Lingering Potion of Healing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.INSTANT_DAMAGE, langConfig.getString("item.minecraft.lingering_potion.effect.harming", "Lingering Potion of Harming")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.POISON, langConfig.getString("item.minecraft.lingering_potion.effect.poison", "Lingering Potion of Poison")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.REGEN, langConfig.getString("item.minecraft.lingering_potion.effect.regeneration", "Lingering Potion of Regeneration")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.STRENGTH, langConfig.getString("item.minecraft.lingering_potion.effect.strength", "Lingering Potion of Strength")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.WEAKNESS, langConfig.getString("item.minecraft.lingering_potion.effect.weakness", "Lingering Potion of Weakness")));
        //potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.LEVITATION, langConfig.getString("item.minecraft.lingering_potion.effect.levitation", "Lingering Potion of Levitation")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.LUCK, langConfig.getString("item.minecraft.lingering_potion.effect.luck", "Lingering Potion of Luck")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.TURTLE_MASTER, langConfig.getString("item.minecraft.lingering_potion.effect.turtle_master", "Lingering Potion of the Turtle Master")));
        potionNames.add(new PotionName(PotionName.PotionItemType.LINGERING_POTION, PotionType.SLOW_FALLING, langConfig.getString("item.minecraft.lingering_potion.effect.slow_falling", "Lingering Potion of Slow Falling")));
        
        // Add Tipped Arrow Names
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.UNCRAFTABLE, langConfig.getString("item.minecraft.tipped_arrow.effect.empty", "Uncraftable Tipped Arrow")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.WATER, langConfig.getString("item.minecraft.tipped_arrow.effect.water", "Arrow of Splashing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.MUNDANE, langConfig.getString("item.minecraft.tipped_arrow.effect.mundane", "Tipped Arrow")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.THICK, langConfig.getString("item.minecraft.tipped_arrow.effect.thick", "Tipped Arrow")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.AWKWARD, langConfig.getString("item.minecraft.tipped_arrow.effect.awkward", "Tipped Arrow")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.NIGHT_VISION, langConfig.getString("item.minecraft.tipped_arrow.effect.night_vision", "Arrow of Night Vision")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.INVISIBILITY, langConfig.getString("item.minecraft.tipped_arrow.effect.invisibility", "Arrow of Invisibility")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.JUMP, langConfig.getString("item.minecraft.tipped_arrow.effect.leaping", "Arrow of Leaping")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.FIRE_RESISTANCE, langConfig.getString("item.minecraft.tipped_arrow.effect.fire_resistance", "Arrow of Fire Resistance")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.SPEED, langConfig.getString("item.minecraft.tipped_arrow.effect.swiftness", "Arrow of Swiftness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.SLOWNESS, langConfig.getString("item.minecraft.tipped_arrow.effect.slowness", "Arrow of Slowness")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.WATER_BREATHING, langConfig.getString("item.minecraft.tipped_arrow.effect.water_breathing", "Arrow of Water Breathing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.INSTANT_HEAL, langConfig.getString("item.minecraft.tipped_arrow.effect.healing", "Arrow of Healing")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.INSTANT_DAMAGE, langConfig.getString("item.minecraft.tipped_arrow.effect.harming", "Arrow of Harming")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.POISON, langConfig.getString("item.minecraft.tipped_arrow.effect.poison", "Arrow of Poison")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.REGEN, langConfig.getString("item.minecraft.tipped_arrow.effect.regeneration", "Arrow of Regeneration")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.STRENGTH, langConfig.getString("item.minecraft.tipped_arrow.effect.strength", "Arrow of Strength")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.WEAKNESS, langConfig.getString("item.minecraft.tipped_arrow.effect.weakness", "Arrow of Weakness")));
        //potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.LEVITATION, langConfig.getString("item.minecraft.tipped_arrow.effect.levitation", "Arrow of Levitation")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.LUCK, langConfig.getString("item.minecraft.tipped_arrow.effect.luck", "Arrow of Luck")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.TURTLE_MASTER, langConfig.getString("item.minecraft.tipped_arrow.effect.turtle_master", "Arrow of the Turtle Master")));
        potionNames.add(new PotionName(PotionName.PotionItemType.TIPPED_ARROW, PotionType.SLOW_FALLING, langConfig.getString("item.minecraft.tipped_arrow.effect.slow_falling", "Arrow of Slow Falling")));
        
        // Add Music Disc Titles
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_13, langConfig.getString("item.minecraft.music_disc_13.desc", "C418 - 13")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_CAT, langConfig.getString("item.minecraft.music_disc_cat.desc", "C418 - cat")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_BLOCKS, langConfig.getString("item.minecraft.music_disc_blocks.desc", "C418 - blocks")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_CHIRP, langConfig.getString("item.minecraft.music_disc_chirp.desc", "C418 - chirp")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_FAR, langConfig.getString("item.minecraft.music_disc_far.desc", "C418 - far")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_MALL, langConfig.getString("item.minecraft.music_disc_mall.desc", "C418 - mall")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_MELLOHI, langConfig.getString("item.minecraft.music_disc_mellohi.desc", "C418 - mellohi")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_STAL, langConfig.getString("item.minecraft.music_disc_stal.desc", "C418 - stal")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_STRAD, langConfig.getString("item.minecraft.music_disc_strad.desc", "C418 - strad")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_WARD, langConfig.getString("item.minecraft.music_disc_ward.desc", "C418 - ward")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_11, langConfig.getString("item.minecraft.music_disc_11.desc", "C418 - 11")));
        musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_WAIT, langConfig.getString("item.minecraft.music_disc_wait.desc", "C418 - wait")));

        if (Utils.getMajorVersion() >= 16) {
            musicDiscNames.add(new MusicDiscName(Material.MUSIC_DISC_PIGSTEP, langConfig.getString("item.minecraft.music_disc_pigstep.desc", "Lena Raine - Pigstep")));
        }

        if (Utils.getMajorVersion() >= 14) {
            // Add Banner Pattern Names
            bannerPatternNames.add(new BannerPatternName(Material.CREEPER_BANNER_PATTERN, langConfig.getString("item.minecraft.creeper_banner_pattern.desc", "Creeper Charge")));
            bannerPatternNames.add(new BannerPatternName(Material.SKULL_BANNER_PATTERN, langConfig.getString("item.minecraft.skull_banner_pattern.desc", "Skull Charge")));
            bannerPatternNames.add(new BannerPatternName(Material.FLOWER_BANNER_PATTERN, langConfig.getString("item.minecraft.flower_banner_pattern.desc", "Flower Charge")));
            bannerPatternNames.add(new BannerPatternName(Material.MOJANG_BANNER_PATTERN, langConfig.getString("item.minecraft.mojang_banner_pattern.desc", "Thing")));
            bannerPatternNames.add(new BannerPatternName(Material.GLOBE_BANNER_PATTERN, langConfig.getString("item.minecraft.globe_banner_pattern.desc", "Globe")));

            if (Utils.getMajorVersion() >= 16) {
                bannerPatternNames.add(new BannerPatternName(Material.PIGLIN_BANNER_PATTERN, langConfig.getString("item.minecraft.piglin_banner_pattern.desc", "Snout")));
            }
        }

        // Add Book Generation Names
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.ORIGINAL, langConfig.getString("book.generation.0", "Original")));
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.COPY_OF_ORIGINAL, langConfig.getString("book.generation.1", "Copy of original")));
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.COPY_OF_COPY, langConfig.getString("book.generation.2", "Copy of a copy")));
        generationNames.add(new BookGenerationName(CustomBookMeta.Generation.TATTERED, langConfig.getString("book.generation.3", "Tattered")));

        loadMessages();
    }

    private static void loadMessages() {
        // Add ShopChest Messages
        messages.add(new LocalizedMessage(Message.SHOP_CREATED, langConfig.getString("message.shop-created", "&6You were withdrawn &c%CREATION-PRICE% &6to create this shop.")));
        messages.add(new LocalizedMessage(Message.ADMIN_SHOP_CREATED, langConfig.getString("message.admin-shop-created", "&6You were withdrawn &c%CREATION-PRICE% &6to create this admin shop.")));
        messages.add(new LocalizedMessage(Message.CHEST_ALREADY_SHOP, langConfig.getString("message.chest-already-shop", "&cChest already shop.")));
        messages.add(new LocalizedMessage(Message.CHEST_BLOCKED, langConfig.getString("message.chest-blocked", "&cThere must not be a block above the chest.")));
        messages.add(new LocalizedMessage(Message.DOUBLE_CHEST_BLOCKED, langConfig.getString("message.double-chest-blocked", "&cThere must not be a block above the chest.")));
        messages.add(new LocalizedMessage(Message.SHOP_REMOVED, langConfig.getString("message.shop-removed", "&6Shop removed.")));
        messages.add(new LocalizedMessage(Message.SHOP_REMOVED_REFUND, langConfig.getString("message.shop-removed-refund", "&6Shop removed. You were refunded &c%CREATION-PRICE%&6.")));
        messages.add(new LocalizedMessage(Message.ALL_SHOPS_REMOVED, langConfig.getString("message.all-shops-removed", "&6Removed all (&c%AMOUNT%&6) shop/s of &c%VENDOR%&6.")));
        messages.add(new LocalizedMessage(Message.CHEST_NO_SHOP, langConfig.getString("message.chest-no-shop", "&cChest is not a shop.")));
        messages.add(new LocalizedMessage(Message.SHOP_CREATE_NOT_ENOUGH_MONEY, langConfig.getString("message.shop-create-not-enough-money", "&cNot enough money. You need &6%CREATION-PRICE% &cto create a shop.")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_VENDOR, langConfig.getString("message.shopInfo.vendor", "&6Vendor: &e%VENDOR%")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_PRODUCT, langConfig.getString("message.shopInfo.product", "&6Product: &e%AMOUNT% x %ITEMNAME%")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_STOCK, langConfig.getString("message.shopInfo.stock", "&6In Stock: &e%STOCK%")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_CHEST_SPACE, langConfig.getString("message.shopInfo.chest-space", "&6Space in chest: &e%CHEST-SPACE%")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_PRICE, langConfig.getString("message.shopInfo.price", "&6Price: Buy: &e%BUY-PRICE%&6 Sell: &e%SELL-PRICE%")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_DISABLED, langConfig.getString("message.shopInfo.disabled", "&7Disabled")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_NORMAL, langConfig.getString("message.shopInfo.is-normal", "&6Type: &eNormal")));
        messages.add(new LocalizedMessage(Message.SHOP_INFO_ADMIN, langConfig.getString("message.shopInfo.is-admin", "&6Type: &eAdmin")));
        messages.add(new LocalizedMessage(Message.BUY_SELL_DISABLED, langConfig.getString("message.buy-and-sell-disabled", "&cYou can't create a shop with buying and selling disabled.")));
        messages.add(new LocalizedMessage(Message.BUY_SUCCESS, langConfig.getString("message.buy-success", "&aYou bought &6%AMOUNT% x %ITEMNAME%&a for &6%BUY-PRICE%&a from &6%VENDOR%&a.")));
        messages.add(new LocalizedMessage(Message.BUY_SUCCESS_ADMIN, langConfig.getString("message.buy-success-admin", "&aYou bought &6%AMOUNT% x %ITEMNAME%&a for &6%BUY-PRICE%&a.")));
        messages.add(new LocalizedMessage(Message.SELL_SUCCESS, langConfig.getString("message.sell-success", "&aYou sold &6%AMOUNT% x %ITEMNAME%&a for &6%SELL-PRICE%&a to &6%VENDOR%&a.")));
        messages.add(new LocalizedMessage(Message.SELL_SUCCESS_ADMIN, langConfig.getString("message.sell-success-admin", "&aYou sold &6%AMOUNT% x %ITEMNAME%&a for &6%SELL-PRICE%&a.")));
        messages.add(new LocalizedMessage(Message.SOMEONE_BOUGHT, langConfig.getString("message.someone-bought", "&6%PLAYER% &abought &6%AMOUNT% x %ITEMNAME%&a for &6%BUY-PRICE%&a from your shop.")));
        messages.add(new LocalizedMessage(Message.SOMEONE_SOLD, langConfig.getString("message.someone-sold", "&6%PLAYER% &asold &6%AMOUNT% x %ITEMNAME%&a for &6%SELL-PRICE%&a to your shop.")));
        messages.add(new LocalizedMessage(Message.REVENUE_WHILE_OFFLINE, langConfig.getString("message.revenue-while-offline", "&6While you were offline, your shops have made a revenue of &c%REVENUE%&6.")));
        messages.add(new LocalizedMessage(Message.NOT_ENOUGH_INVENTORY_SPACE, langConfig.getString("message.not-enough-inventory-space", "&cNot enough space in inventory.")));
        messages.add(new LocalizedMessage(Message.CHEST_NOT_ENOUGH_INVENTORY_SPACE, langConfig.getString("message.chest-not-enough-inventory-space", "&cShop is full.")));
        messages.add(new LocalizedMessage(Message.NOT_ENOUGH_MONEY, langConfig.getString("message.not-enough-money", "&cNot enough money.")));
        messages.add(new LocalizedMessage(Message.NOT_ENOUGH_ITEMS, langConfig.getString("message.not-enough-items", "&cNot enough items.")));
        messages.add(new LocalizedMessage(Message.VENDOR_NOT_ENOUGH_MONEY, langConfig.getString("message.vendor-not-enough-money", "&cVendor has not enough money.")));
        messages.add(new LocalizedMessage(Message.OUT_OF_STOCK, langConfig.getString("message.out-of-stock", "&cShop out of stock.")));
        messages.add(new LocalizedMessage(Message.VENDOR_OUT_OF_STOCK, langConfig.getString("message.vendor-out-of-stock", "&cYour shop that sells &6%AMOUNT% x %ITEMNAME% &cis out of stock.")));
        messages.add(new LocalizedMessage(Message.ERROR_OCCURRED, langConfig.getString("message.error-occurred", "&cAn error occurred: %ERROR%")));
        messages.add(new LocalizedMessage(Message.AMOUNT_PRICE_NOT_NUMBER, langConfig.getString("message.amount-and-price-not-number", "&cAmount and price must be a number.")));
        messages.add(new LocalizedMessage(Message.AMOUNT_IS_ZERO, langConfig.getString("message.amount-is-zero", "&cAmount must be greater than 0.")));
        messages.add(new LocalizedMessage(Message.PRICES_CONTAIN_DECIMALS, langConfig.getString("message.prices-contain-decimals", "&cPrices must not contain decimals.")));
        messages.add(new LocalizedMessage(Message.NO_ITEM_IN_HAND, langConfig.getString("message.no-item-in-hand", "&cNo item in hand")));
        messages.add(new LocalizedMessage(Message.CLICK_CHEST_CREATE, langConfig.getString("message.click-chest-to-create-shop", "&aClick a chest within 15 seconds to create a shop.")));
        messages.add(new LocalizedMessage(Message.CLICK_CHEST_REMOVE, langConfig.getString("message.click-chest-to-remove-shop", "&aClick a shop within 15 seconds to remove it.")));
        messages.add(new LocalizedMessage(Message.CLICK_CHEST_INFO, langConfig.getString("message.click-chest-for-info", "&aClick a shop within 15 seconds to retrieve information.")));
        messages.add(new LocalizedMessage(Message.CLICK_CHEST_OPEN, langConfig.getString("message.click-chest-to-open-shop", "&aClick a shop within 15 seconds to open it.")));
        messages.add(new LocalizedMessage(Message.CLICK_TO_CONFIRM, langConfig.getString("message.click-to-confirm", "&aClick again to confirm.")));
        messages.add(new LocalizedMessage(Message.OPENED_SHOP, langConfig.getString("message.opened-shop", "&aYou opened %VENDOR%'s shop.")));
        messages.add(new LocalizedMessage(Message.CANNOT_BREAK_SHOP, langConfig.getString("message.cannot-break-shop", "&cYou can't break a shop.")));
        messages.add(new LocalizedMessage(Message.CANNOT_SELL_BROKEN_ITEM, langConfig.getString("message.cannot-sell-broken-item", "&cYou can't sell a broken item.")));
        messages.add(new LocalizedMessage(Message.BUY_PRICE_TOO_LOW, langConfig.getString("message.buy-price-too-low", "&cThe buy price must be higher than %MIN-PRICE%.")));
        messages.add(new LocalizedMessage(Message.SELL_PRICE_TOO_LOW, langConfig.getString("message.sell-price-too-low", "&cThe sell price must be higher than %MIN-PRICE%.")));
        messages.add(new LocalizedMessage(Message.BUY_PRICE_TOO_HIGH, langConfig.getString("message.buy-price-too-high", "&cThe buy price must be lower than %MAX-PRICE%.")));
        messages.add(new LocalizedMessage(Message.SELL_PRICE_TOO_HIGH, langConfig.getString("message.sell-price-too-high", "&cThe sell price must be lower than %MAX-PRICE%.")));
        messages.add(new LocalizedMessage(Message.BUYING_DISABLED, langConfig.getString("message.buying-disabled", "&cBuying is disabled at this shop.")));
        messages.add(new LocalizedMessage(Message.SELLING_DISABLED, langConfig.getString("message.selling-disabled", "&cSelling is disabled at this shop.")));
        messages.add(new LocalizedMessage(Message.RELOADED_SHOPS, langConfig.getString("message.reloaded-shops", "&aSuccessfully reloaded %AMOUNT% shop/s.")));
        messages.add(new LocalizedMessage(Message.SHOP_LIMIT_REACHED, langConfig.getString("message.shop-limit-reached", "&cYou reached your limit of &6%LIMIT% &cshop/s.")));
        messages.add(new LocalizedMessage(Message.OCCUPIED_SHOP_SLOTS, langConfig.getString("message.occupied-shop-slots", "&6You have &c%AMOUNT%/%LIMIT% &6shop slot/s occupied.")));
        messages.add(new LocalizedMessage(Message.CANNOT_SELL_ITEM, langConfig.getString("message.cannot-sell-item", "&cYou cannot create a shop with this item.")));
        messages.add(new LocalizedMessage(Message.USE_IN_CREATIVE, langConfig.getString("message.use-in-creative", "&cYou cannot use a shop in creative mode.")));
        messages.add(new LocalizedMessage(Message.SELECT_ITEM, langConfig.getString("message.select-item", "&aOpen your inventory, and drop an item to select it.")));
        messages.add(new LocalizedMessage(Message.ITEM_SELECTED, langConfig.getString("message.item-selected", "&aItem has been selected: &6%ITEMNAME%")));
        messages.add(new LocalizedMessage(Message.CREATION_CANCELLED, langConfig.getString("message.creation-cancelled", "&cShop creation has been cancelled.")));
        messages.add(new LocalizedMessage(Message.UPDATE_AVAILABLE, langConfig.getString("message.update.update-available", "&6&lVersion &c%VERSION% &6of &cShopChest &6is available &chere.")));
        messages.add(new LocalizedMessage(Message.UPDATE_CLICK_TO_DOWNLOAD, langConfig.getString("message.update.click-to-download", "Click to download")));
        messages.add(new LocalizedMessage(Message.UPDATE_NO_UPDATE, langConfig.getString("message.update.no-update", "&6&lNo new update available.")));
        messages.add(new LocalizedMessage(Message.UPDATE_CHECKING, langConfig.getString("message.update.checking", "&6&lChecking for updates...")));
        messages.add(new LocalizedMessage(Message.UPDATE_ERROR, langConfig.getString("message.update.error", "&c&lError while checking for updates.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_CREATE, langConfig.getString("message.noPermission.create", "&cYou don't have permission to create a shop.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_CREATE_ADMIN, langConfig.getString("message.noPermission.create-admin", "&cYou don't have permission to create an admin shop.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_CREATE_PROTECTED, langConfig.getString("message.noPermission.create-protected", "&cYou don't have permission to create a shop on a protected chest.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_OPEN_OTHERS, langConfig.getString("message.noPermission.open-others", "&cYou don't have permission to open this chest.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_BUY, langConfig.getString("message.noPermission.buy", "&cYou don't have permission to buy something.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_SELL, langConfig.getString("message.noPermission.sell", "&cYou don't have permission to sell something.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_BUY_HERE, langConfig.getString("message.noPermission.buy-here", "&cYou don't have permission to buy something here.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_SELL_HERE, langConfig.getString("message.noPermission.sell-here", "&cYou don't have permission to sell something here.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_REMOVE_OTHERS, langConfig.getString("message.noPermission.remove-others", "&cYou don't have permission to remove this shop.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_REMOVE_ADMIN, langConfig.getString("message.noPermission.remove-admin", "&cYou don't have permission to remove an admin shop.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_RELOAD, langConfig.getString("message.noPermission.reload", "&cYou don't have permission to reload the shops.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_UPDATE, langConfig.getString("message.noPermission.update", "&cYou don't have permission to check for updates.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_CONFIG, langConfig.getString("message.noPermission.config", "&cYou don't have permission to change configuration values.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_EXTEND_OTHERS, langConfig.getString("message.noPermission.extend-others", "&cYou don't have permission to extend this chest.")));
        messages.add(new LocalizedMessage(Message.NO_PERMISSION_EXTEND_PROTECTED, langConfig.getString("message.noPermission.extend-protected", "&cYou don't have permission to extend this chest to here.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_HEADER, langConfig.getString("message.commandDescription.header", "&6==== &c/%COMMAND% &6Help")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_FOOTER, langConfig.getString("message.commandDescription.footer", "&6==== End")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_CREATE, langConfig.getString("message.commandDescription.create", "&a/%COMMAND% create <amount> <buy-price> <sell-price> - Create a shop.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_CREATE_ADMIN, langConfig.getString("message.commandDescription.create-admin", "&a/%COMMAND% create <amount> <buy-price> <sell-price> [admin] - Create a shop.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_REMOVE, langConfig.getString("message.commandDescription.remove", "&a/%COMMAND% remove - Remove a shop.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_INFO, langConfig.getString("message.commandDescription.info", "&a/%COMMAND% info - Retrieve shop information.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_REMOVEALL, langConfig.getString("message.commandDescription.removeall", "&a/%COMMAND% removeall - Remove all shops of a player.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_RELOAD, langConfig.getString("message.commandDescription.reload", "&a/%COMMAND% reload - Reload shops.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_UPDATE, langConfig.getString("message.commandDescription.update", "&a/%COMMAND% update - Check for Updates.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_LIMITS, langConfig.getString("message.commandDescription.limits", "&a/%COMMAND% limits - View shop limits.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_OPEN, langConfig.getString("message.commandDescription.open", "&a/%COMMAND% open - Open a shop.")));
        messages.add(new LocalizedMessage(Message.COMMAND_DESC_CONFIG, langConfig.getString("message.commandDescription.config", "&a/%COMMAND% config <set|add|remove> <property> <value> - Change configuration values.")));
        messages.add(new LocalizedMessage(Message.CHANGED_CONFIG_SET, langConfig.getString("message.config.set", "&6Changed &a%PROPERTY% &6to &a%VALUE%&6.")));
        messages.add(new LocalizedMessage(Message.CHANGED_CONFIG_REMOVED, langConfig.getString("message.config.removed", "&6Removed &a%VALUE% &6from &a%PROPERTY%&6.")));
        messages.add(new LocalizedMessage(Message.CHANGED_CONFIG_ADDED, langConfig.getString("message.config.added", "&6Added &a%VALUE% &6to &a%PROPERTY%&6.")));
    }

    /**
     * @param stack Item whose name to lookup
     * @return Localized Name of the Item, the custom name, or if <i>stack</i> is a book, the title of the book
     */
    public static String getItemName(ItemStack stack) {
        if (stack == null) return null;
        
        if (stack.hasItemMeta()) {
            ItemMeta meta = stack.getItemMeta();
            if (meta.getDisplayName() != null && !meta.getDisplayName().isEmpty()) {
                return meta.getDisplayName();
            } else if (meta instanceof BookMeta && ((BookMeta) meta).hasTitle()) {
                return ((BookMeta) meta).getTitle();
            } else if (meta instanceof SkullMeta) {
                if (((SkullMeta) meta).hasOwner()) {
                    if (Utils.getMajorVersion() >= 13) {
                        return String.format(langConfig.getString("block.minecraft.player_head.named", "%s's Head"), ((SkullMeta) meta).getOwningPlayer().getName());
                    } else {
                        return String.format(langConfig.getString("item.skull.player.name", "%s's Head"), ((SkullMeta) meta).getOwner());
                    }
                }
            }
        }

        Material material = stack.getType();

        if (stack.getItemMeta() instanceof PotionMeta) {
            PotionMeta meta = (PotionMeta) stack.getItemMeta();
            PotionType potionType;
            String upgradeString;

            if (Utils.getMajorVersion() < 9) {
                Potion potion = Potion.fromItemStack(stack);
                potionType = potion.getType();
                upgradeString = potion.getLevel() == 2 && Config.appendPotionLevelToItemName ? " II" : "";
            } else {
                potionType = meta.getBasePotionData().getType();
                upgradeString = (meta.getBasePotionData().isUpgraded() && Config.appendPotionLevelToItemName ? " II" : "");
            }

            for (PotionName potionName : potionNames) {
                if (material == Material.POTION) {
                    if (Utils.getMajorVersion() < 9) {
                        if (Potion.fromItemStack(stack).isSplash()) {
                            if (potionName.getPotionItemType() == PotionName.PotionItemType.SPLASH_POTION && potionName.getPotionType() == potionType) {
                                return potionName.getLocalizedName() + upgradeString;
                            }
                        } else {
                            if (potionName.getPotionItemType() == PotionName.PotionItemType.POTION && potionName.getPotionType() == potionType) {
                                return potionName.getLocalizedName() + upgradeString;
                            }
                        }
                    } else {
                        if (potionName.getPotionItemType() == PotionName.PotionItemType.POTION && potionName.getPotionType() == potionType) {
                            return potionName.getLocalizedName() + upgradeString;
                        }
                    }
                } else {
                    if (Utils.getMajorVersion() >= 9) {
                        if (material == Material.LINGERING_POTION) {
                            if (potionName.getPotionItemType() == PotionName.PotionItemType.LINGERING_POTION && potionName.getPotionType() == potionType) {
                                return potionName.getLocalizedName() + upgradeString;
                            }
                        } else if (material == Material.TIPPED_ARROW) {
                            if (potionName.getPotionItemType() == PotionName.PotionItemType.TIPPED_ARROW && potionName.getPotionType() == potionType) {
                                return potionName.getLocalizedName() + upgradeString;
                            }
                        } else if (material == Material.SPLASH_POTION) {
                            if (potionName.getPotionItemType() == PotionName.PotionItemType.SPLASH_POTION && potionName.getPotionType() == potionType) {
                                return potionName.getLocalizedName() + upgradeString;
                            }
                        }
                    }
                }
            }
        }

        for (ItemName itemName : itemNames) {
            if (itemName.getMaterial() != material) {
                continue;
            }

            if (Utils.getMajorVersion() < 13) {
                if (material.toString().equals("MONSTER_EGG")) {
                    EntityType spawnedType = SpawnEggMeta.getEntityTypeFromItemStack(plugin, stack);

                    for (EntityName entityName : entityNames) {
                        if (entityName.getEntityType() == spawnedType) {
                            return itemName.getLocalizedName() + " " + entityName.getLocalizedName();
                        }
                    }

                    return itemName.getLocalizedName() + " " + formatDefaultString(String.valueOf(spawnedType));
                } 
            
                if (itemName.getSubId() == stack.getDurability()) {
                    return itemName.getLocalizedName();
                }
            } else {
                return itemName.getLocalizedName();
            }
        }

        return formatDefaultString(String.valueOf(material));
    }

    /**
     * @param enchantment Enchantment whose name should be looked up
     * @param level       Level of the enchantment
     * @return Localized Name of the enchantment with the given level afterwards
     */
    public static String getEnchantmentName(Enchantment enchantment, int level) {
        if (enchantment == null) return null;

        String levelString = langConfig.getString("enchantment.level." + level, String.valueOf(level));
        String enchantmentString = formatDefaultString(Utils.getMajorVersion() < 13
                ? enchantment.getName() : enchantment.getKey().getKey());

        for (EnchantmentName enchantmentName : enchantmentNames) {
            if (enchantmentName.getEnchantment().equals(enchantment)) {
                enchantmentString = enchantmentName.getLocalizedName();
            }
        }

        for (EnchantmentName.EnchantmentLevelName enchantmentLevelName : enchantmentLevelNames) {
            if (enchantmentLevelName.getLevel() == level) {
                levelString = enchantmentLevelName.getLocalizedName();
            }
        }

        return enchantmentString + " " + levelString;
    }

    /**
     * @param enchantmentMap Map of enchantments of an item
     * @return Comma separated list of localized enchantments
     */
    public static String getEnchantmentString(Map<Enchantment, Integer> enchantmentMap) {
        if (enchantmentMap == null) return null;
        StringJoiner joiner = new StringJoiner(", ");

        for (Enchantment enchantment : enchantmentMap.keySet()) {
            joiner.add(LanguageUtils.getEnchantmentName(enchantment, enchantmentMap.get(enchantment)));
        }

        return joiner.toString();
    }

    /**
     * @param itemStack Potion Item whose base effect name should be looked up
     * @return Localized name of the base potion effect
     */
    public static String getPotionEffectName(ItemStack itemStack) {
        if (itemStack == null) return null;
        if (!(itemStack.getItemMeta() instanceof PotionMeta)) return "";

        PotionMeta potionMeta = (PotionMeta) itemStack.getItemMeta();
        PotionEffectType potionEffect;
        boolean upgraded;

        if (Utils.getMajorVersion() < 9) {
            Potion potion = Potion.fromItemStack(itemStack);
            potionEffect = potion.getType().getEffectType();
            upgraded = potion.getLevel() == 2;
        } else {
            potionEffect = potionMeta.getBasePotionData().getType().getEffectType();
            upgraded = potionMeta.getBasePotionData().isUpgraded();
        }

        String potionEffectString = formatDefaultString(String.valueOf(potionEffect));

        for (PotionEffectName potionEffectName : potionEffectNames) {
            if (potionEffectName.getEffect() == potionEffect) {
                potionEffectString = potionEffectName.getLocalizedName();
            }
        }

        return potionEffectString + (upgraded ? " II" : "");
    }

    /**
     * @param musicDiscMaterial Material of the Music Disc whose name should be looked up
     * @return Localized title of the Music Disc
     */
    public static String getMusicDiscName(Material musicDiscMaterial) {
        if (musicDiscMaterial == null) return null;
        for (MusicDiscName musicDiscName : musicDiscNames) {
            if (musicDiscMaterial == musicDiscName.getMusicDiscMaterial()) {
                return musicDiscName.getLocalizedName();
            }
        }

        return "";
    }

    /**
     * @param bannerPatternMaterial Material of the Music Disc whose name should be looked up
     * @return Localized title of the Music Disc
     */
    public static String getBannerPatternName(Material bannerPatternMaterial) {
        if (bannerPatternMaterial == null) return null;
        for (BannerPatternName bannerPatternName : bannerPatternNames) {
            if (bannerPatternMaterial == bannerPatternName.getBannerPatternMaterial()) {
                return bannerPatternName.getLocalizedName();
            }
        }

        return "";
    }

    /**
     * @param is ItemStack that should be of type {@link Material#WRITTEN_BOOK}
     * @return Localized name of the generation or {@code null} if the item is not a written book
     */
    public static String getBookGenerationName(ItemStack is) {
        if (is.getType() != Material.WRITTEN_BOOK) {
            return null;
        }

        BookMeta meta = (BookMeta) is.getItemMeta();
        CustomBookMeta.Generation generation = null;

        if ((Utils.getMajorVersion() == 9 && Utils.getRevision() == 1) || Utils.getMajorVersion() == 8) {
            generation = CustomBookMeta.getGeneration(is);
        } else  if (meta.getGeneration() != null) {
            generation = CustomBookMeta.Generation.valueOf(meta.getGeneration().toString());
        }

        if (generation == null) {
            generation = CustomBookMeta.Generation.ORIGINAL;
        }

        for (BookGenerationName generationName : generationNames) {
            if (generation == generationName.getGeneration()) {
                return generationName.getLocalizedName();
            }
        }

        return formatDefaultString(String.valueOf(generation));
    }

    /**
     * @param message Message which should be translated
     * @param replacements Replacements of placeholders which might be required to be replaced in the message
     * @return Localized Message
     */
    public static String getMessage(Message message, Replacement... replacements) {
        String finalMessage = ChatColor.RED + "An error occurred: Message not found: " + message.toString();

        for (LocalizedMessage localizedMessage : messages) {
            if (localizedMessage.getMessage() == message) {
                finalMessage = localizedMessage.getLocalizedString();

                for (Replacement replacement : replacements) {
                    Placeholder placeholder = replacement.getPlaceholder();
                    String toReplace = replacement.getReplacement();

                    if (placeholder == Placeholder.BUY_PRICE || placeholder == Placeholder.SELL_PRICE || placeholder == Placeholder.MIN_PRICE || placeholder == Placeholder.CREATION_PRICE || placeholder == Placeholder.REVENUE) {
                        if (!toReplace.equals(getMessage(Message.SHOP_INFO_DISABLED))) {
                            double price = Double.parseDouble(toReplace);
                            toReplace = plugin.getEconomy().format(price);
                        }
                    }

                    finalMessage = finalMessage.replace(placeholder.toString(), toReplace);
                }
            }
        }

        return finalMessage;
    }

    /**
     * Underscores will be replaced by spaces and the first letter of each word will be capitalized
     *
     * @param string String to format
     * @return Formatted String with underscores replaced by spaces and the first letter of each word capitalized
     */
    private static String formatDefaultString(String string) {
        string = string.replace("_", " ");
        String newString = "";

        if (string.contains(" ")) {
            for (int i = 0; i < string.split(" ").length; i++) {
                String part = string.split(" ")[i].toLowerCase();
                part = part.substring(0, 1).toUpperCase() + part.substring(1);
                newString = newString + part + (i == string.split(" ").length - 1 ? "" : " ");
            }

            return newString;
        } else {
            newString = string.substring(0, 1).toUpperCase() + string.substring(1).toLowerCase();
        }

        return newString;
    }


} public class AreaShopListener implements Listener {

    private ShopChest plugin;

    public AreaShopListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler
    public void onRegionDeleted(DeletedRegionEvent e) {
        if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("DELETE")) {
            removeShopsInRegion(e.getRegion());
        }
    }

    @EventHandler
    public void onRegionUnrented(UnrentedRegionEvent e) {
        if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("UNRENT")) {
            removeShopsInRegion(e.getRegion());
        }
    }

    @EventHandler
    public void onRegionResold(ResoldRegionEvent e) {
        if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("RESELL")) {
            removeShopsInRegion(e.getRegion());
        }
    }

    @EventHandler
    public void onRegionSold(SoldRegionEvent e) {
        if (Config.enableAreaShopIntegration && Config.areashopRemoveShopEvents.contains("SELL")) {
            removeShopsInRegion(e.getRegion());
        }
    }

    private void removeShopsInRegion(GeneralRegion generalRegion) {
        if (!plugin.hasWorldGuard()) return;

        for (Shop shop : plugin.getShopUtils().getShops()) {
            if (!shop.getLocation().getWorld().getName().equals(generalRegion.getWorldName())) continue;

            for (IWrappedRegion r : WorldGuardWrapper.getInstance().getRegions(shop.getLocation())) {
                if (generalRegion.getLowerCaseName().equals(r.getId())) {
                    plugin.getShopUtils().removeShopById(shop.getID(), true);
                    break;
                }
            }
        }

    }

} public class BentoBoxListener implements Listener {
    private ShopChest plugin;

    public BentoBoxListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.MONITOR)
    public void onIslandDeleted(IslandDeletedEvent e) {
        deleteShops(e.getDeletedIslandInfo());
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onIslandDeleteChunks(IslandDeleteChunksEvent e) {
        deleteShops(e.getDeletedIslandInfo());
    }

    @EventHandler(priority = EventPriority.MONITOR)
    public void onIslandResetted(IslandResettedEvent e) {
        deleteShops(e.getIsland(), null);
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onIslandBan(IslandBanEvent e) {
        deleteShops(e.getIsland(), e.getPlayerUUID());
    }
    
    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onTeamKick(TeamKickEvent e) {
        deleteShops(e.getIsland(), e.getPlayerUUID());
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onTeamLeave(TeamLeaveEvent e) {
        deleteShops(e.getIsland(), e.getPlayerUUID());
    }

    private void deleteShops(IslandDeletion deletedIsland) {
        deleteShops(deletedIsland.getWorld(), deletedIsland.getBox(), null);
    }

    private void deleteShops(Island island, UUID vendorUuid) {
        deleteShops(island.getWorld(), island.getBoundingBox(), vendorUuid);
    }

    private void deleteShops(World world, BoundingBox box, UUID vendorUuid) {
        if (!Config.enableBentoBoxIntegration)
            return;
            
        Collection<Shop> shops = plugin.getShopUtils().getShops();
        for (Shop shop : shops) {
            if (!shop.getLocation().getWorld().getName().equals(world.getName())) {
                continue;
            }

            if (vendorUuid != null && !shop.getVendor().getUniqueId().equals(vendorUuid)) {
                continue;
            }

            int x = shop.getLocation().getBlockX();
            int z = shop.getLocation().getBlockZ();
            if (box.contains(x, 0, z)) {
                plugin.getShopUtils().removeShop(shop, true);
            }
        }
    }
    
} public class BlockExplodeListener implements Listener {

    private ShopChest plugin;

    public BlockExplodeListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler
    public void onBlockExplode(BlockExplodeEvent e) {
        ArrayList<Block> bl = new ArrayList<>(e.blockList());
        for (Block b : bl) {
            if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) {
                if (plugin.getShopUtils().isShop(b.getLocation())) e.blockList().remove(b);
            }
        }
    }

} public class ChestProtectListener implements Listener {

    private ShopChest plugin;
    private ShopUtils shopUtils;

    public ChestProtectListener(ShopChest plugin) {
        this.plugin = plugin;
        this.shopUtils = plugin.getShopUtils();
    }

    private void remove(final Shop shop, final Block b, final Player p) {
        if (shop.getInventoryHolder() instanceof DoubleChest) {
            DoubleChest dc = (DoubleChest) shop.getInventoryHolder();
            final Chest l = (Chest) dc.getLeftSide();
            final Chest r = (Chest) dc.getRightSide();

            Location loc = (b.getLocation().equals(l.getLocation()) ? r.getLocation() : l.getLocation());
            final Shop newShop = new Shop(shop.getID(), plugin, shop.getVendor(), shop.getProduct(), loc, shop.getBuyPrice(), shop.getSellPrice(), shop.getShopType());

            shopUtils.removeShop(shop, true, new Callback<Void>(plugin) {
                @Override
                public void onResult(Void result) {
                    newShop.create(true);
                    shopUtils.addShop(newShop, true);
                }
            });
        } else {
            double creationPrice = shop.getShopType() == ShopType.ADMIN ? Config.shopCreationPriceAdmin : Config.shopCreationPriceNormal;
            if (creationPrice > 0 && Config.refundShopCreation && p.getUniqueId().equals(shop.getVendor().getUniqueId())) {
                EconomyResponse r = plugin.getEconomy().depositPlayer(p, shop.getLocation().getWorld().getName(), creationPrice);
                if (!r.transactionSuccess()) {
                    plugin.debug("Economy transaction failed: " + r.errorMessage);
                    p.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED,
                            new Replacement(Placeholder.ERROR, r.errorMessage)));
                    p.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED_REFUND,
                            new Replacement(Placeholder.CREATION_PRICE, 0)));
                } else {
                    p.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED_REFUND,
                        new Replacement(Placeholder.CREATION_PRICE, creationPrice)));
                }
            } else {
                p.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED));
            }   

            shopUtils.removeShop(shop, true);
            plugin.debug(String.format("%s broke %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));
        }
    }

    @EventHandler(ignoreCancelled = true)
    public void onBlockBreak(BlockBreakEvent e) {
        final Block b = e.getBlock();

        if (shopUtils.isShop(b.getLocation())) {
            final Shop shop = shopUtils.getShop(e.getBlock().getLocation());
            Player p = e.getPlayer();

            if (p.isSneaking() && Utils.hasAxeInHand(p)) {
                plugin.debug(String.format("%s tries to break %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));

                if (shop.getShopType() == Shop.ShopType.ADMIN) {
                    if (p.hasPermission(Permissions.REMOVE_ADMIN)) {
                        remove(shop, b, p);
                        return;
                    }
                } else {
                    if (shop.getVendor().getUniqueId().equals(p.getUniqueId()) || p.hasPermission(Permissions.REMOVE_OTHER)) {
                        remove(shop, b, p);
                        return;
                    }
                }
            }

            if (shop.getItem() != null) {
                shop.getItem().resetForPlayer(p);
            }

            e.setCancelled(true);
            e.getPlayer().sendMessage(LanguageUtils.getMessage(Message.CANNOT_BREAK_SHOP));
        }
    }

    @EventHandler(ignoreCancelled = true)
    public void onEntityExplode(EntityExplodeEvent e) {
        ArrayList<Block> bl = new ArrayList<>(e.blockList());
        for (Block b : bl) {
            if (b.getType().equals(Material.CHEST) || b.getType().equals(Material.TRAPPED_CHEST)) {
                if (shopUtils.isShop(b.getLocation())) e.blockList().remove(b);
            }
        }
    }

    @EventHandler(ignoreCancelled = true)
    public void onBlockPlace(BlockPlaceEvent e) {
        final Player p = e.getPlayer();
        final Block b = e.getBlockPlaced();

        if (!b.getType().equals(Material.CHEST) && !b.getType().equals(Material.TRAPPED_CHEST)) {
            return;
        }
        
        Chest c = (Chest) b.getState();
        Block b2;

        // Can't use Utils::getChestLocations since inventory holder
        // has not been updated yet in this event (for 1.13+)

        if (Utils.getMajorVersion() < 13) {
            InventoryHolder ih = c.getInventory().getHolder();
            if (!(ih instanceof DoubleChest)) {
                return;
            }

            DoubleChest dc = (DoubleChest) ih;
            Chest l = (Chest) dc.getLeftSide();
            Chest r = (Chest) dc.getRightSide();

            if (b.getLocation().equals(l.getLocation())) {
                b2 = r.getBlock();
            } else {
                b2 = l.getBlock();
            }
        } else {
            org.bukkit.block.data.type.Chest data = (org.bukkit.block.data.type.Chest) c.getBlockData();

            if (data.getType() == Type.SINGLE) {
                return;
            }

            BlockFace neighborFacing;

            switch (data.getFacing()) {
                case NORTH:
                    neighborFacing = data.getType() == Type.LEFT ? BlockFace.EAST : BlockFace.WEST;
                    break;
                case EAST:
                    neighborFacing = data.getType() == Type.LEFT ? BlockFace.SOUTH : BlockFace.NORTH;
                    break;
                case SOUTH:
                    neighborFacing = data.getType() == Type.LEFT ? BlockFace.WEST : BlockFace.EAST;
                    break;
                case WEST:
                    neighborFacing = data.getType() == Type.LEFT ? BlockFace.NORTH : BlockFace.SOUTH;
                    break;
                default:
                    neighborFacing = null;
            }

            b2 = b.getRelative(neighborFacing);
        }

        final Shop shop = shopUtils.getShop(b2.getLocation());
        if (shop == null)
            return;

        plugin.debug(String.format("%s tries to extend %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));

        ShopExtendEvent event = new ShopExtendEvent(p, shop, b.getLocation());
        Bukkit.getPluginManager().callEvent(event);
        if (event.isCancelled() && !p.hasPermission(Permissions.EXTEND_PROTECTED)) {
            e.setCancelled(true);
            p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_EXTEND_PROTECTED));
            return;
        }

        if (!p.getUniqueId().equals(shop.getVendor().getUniqueId()) && !p.hasPermission(Permissions.EXTEND_OTHER)) {
            e.setCancelled(true);
            p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_EXTEND_OTHERS));
            return;
        }

        if (!ItemUtils.isAir(b.getRelative(BlockFace.UP).getType())) {
            e.setCancelled(true);
            p.sendMessage(LanguageUtils.getMessage(Message.CHEST_BLOCKED));
            return;
        }

        final Shop newShop = new Shop(shop.getID(), plugin, shop.getVendor(), shop.getProduct(), shop.getLocation(), shop.getBuyPrice(), shop.getSellPrice(), shop.getShopType());

        shopUtils.removeShop(shop, true, new Callback<Void>(plugin) {
            @Override
            public void onResult(Void result) {
                newShop.create(true);
                shopUtils.addShop(newShop, true);
                plugin.debug(String.format("%s extended %s's shop (#%d)", p.getName(), shop.getVendor().getName(), shop.getID()));
            }
        });
    }

    @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
    public void onItemMove(InventoryMoveItemEvent e) {
        if ((e.getSource().getType().equals(InventoryType.CHEST)) && (!e.getInitiator().getType().equals(InventoryType.PLAYER))) {

            if (e.getSource().getHolder() instanceof DoubleChest) {
                DoubleChest dc = (DoubleChest) e.getSource().getHolder();
                Chest r = (Chest) dc.getRightSide();
                Chest l = (Chest) dc.getLeftSide();

                if (shopUtils.isShop(r.getLocation()) || shopUtils.isShop(l.getLocation())) e.setCancelled(true);

            } else if (e.getSource().getHolder() instanceof Chest) {
                Chest c = (Chest) e.getSource().getHolder();

                if (shopUtils.isShop(c.getLocation())) e.setCancelled(true);
            }
        }
    }

} public class CreativeModeListener implements Listener {
    private ShopChest plugin;

    public CreativeModeListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onInventoryClick(InventoryClickEvent e) {
        HumanEntity entity = e.getWhoClicked();
        if (!(entity instanceof Player))
            return;

        Player p = (Player) entity;

        ClickType clickType = ClickType.getPlayerClickType(p);
        if (clickType instanceof SelectClickType) {
            e.setCancelled(true);

            if (e.getCursor() == null || e.getCursor().getType() == Material.AIR)
                return;

            ClickType.removePlayerClickType(p);
            ((SelectClickType) clickType).setItem(e.getCursor());
            p.closeInventory();

            p.sendMessage(LanguageUtils.getMessage(Message.ITEM_SELECTED,
                    new Replacement(Placeholder.ITEM_NAME, LanguageUtils.getItemName(e.getCursor()))));
            plugin.getShopCommand().createShopAfterSelected(p, (SelectClickType) clickType);
        }
    }

    @EventHandler
    public void onPlayerCloseInventory(InventoryCloseEvent e) {
        HumanEntity entity = e.getPlayer();
        if (!(entity instanceof Player))
            return;

        Player p = (Player) entity;

        ClickType clickType = ClickType.getPlayerClickType(p);
        if (!(clickType instanceof SelectClickType))
            return;

        ClickType.removePlayerClickType(p);
        p.sendMessage(LanguageUtils.getMessage(Message.CREATION_CANCELLED));
    }
    
    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent e) {
        // Reset game mode on quit if SelectClickType is set
        Player p = e.getPlayer();
        ClickType.removePlayerClickType(p);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onInventoryDrag(InventoryDragEvent e) {
        // Cancel any inventory drags if SelectClickType is set
        HumanEntity entity = e.getWhoClicked();
        if (!(entity instanceof Player))
            return;

        ClickType clickType = ClickType.getPlayerClickType((Player) entity);
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onInventoryMove(InventoryMoveItemEvent e) {
        // Cancel any inventory movement if SelectClickType is set
        if (e.getSource().getHolder() instanceof Player) {
            Player p = (Player) e.getSource().getHolder();

            ClickType clickType = ClickType.getPlayerClickType(p);
            if (clickType instanceof SelectClickType)
                e.setCancelled(true);
        }
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onPlayerPickup(PlayerPickupItemEvent e) {
        // Cancel any item pickups if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onBlockBreak(BlockBreakEvent e) {
        // Cancel any block breaks if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onBlockPlace(BlockPlaceEvent e) {
        // Cancel any block places if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onBlockMultiPlace(BlockMultiPlaceEvent e) {
        // Cancel any block places if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onPlayerInteract(PlayerInteractEvent e) {
        // Cancel any interactions if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent e) {
        // Cancel any entity interactions if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onPlayerDamageEntity(EntityDamageByEntityEvent e) {
        // Cancel any entity damaging if SelectClickType is set
        Entity entity = e.getDamager();
        if (!(entity instanceof Player))
            return;

        ClickType clickType = ClickType.getPlayerClickType((Player) entity);
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGHEST)
    public void onPlayerMove(PlayerMoveEvent e) {
        // Cancel any player movement if SelectClickType is set
        ClickType clickType = ClickType.getPlayerClickType(e.getPlayer());
        if (clickType instanceof SelectClickType)
            e.setCancelled(true);
    }

} public class NotifyPlayerOnJoinListener implements Listener {

    private ShopChest plugin;

    public NotifyPlayerOnJoinListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent e) {
        final Player p = e.getPlayer();

        if (plugin.isUpdateNeeded() && Config.enableUpdateChecker) {
            if (p.hasPermission(Permissions.UPDATE_NOTIFICATION)) {
                Utils.sendUpdateMessage(plugin, p);
            }
        }

        plugin.getShopDatabase().getLastLogout(p, new Callback<Long>(plugin) {
            @Override
            public void onResult(Long result) {
                if (result < 0) {
                    // No logout saved, probably first time joining.
                    return;
                }

                plugin.getShopDatabase().getRevenue(p, result, new Callback<Double>(plugin) {
                    @Override
                    public void onResult(Double result) {
                        if (result != 0) {
                            p.sendMessage(LanguageUtils.getMessage(Message.REVENUE_WHILE_OFFLINE,
                                    new Replacement(Placeholder.REVENUE, String.valueOf(result))));
                        }
                    }
                });
            }
        });
    }

    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent e) {
        plugin.getShopDatabase().logLogout(e.getPlayer(), null);
    }

} public class ShopInteractListener implements Listener {
    private static final Pattern COLOR_CODE_PATTERN = Pattern.compile(".*([§]([a-fA-F0-9]))");
    private static final Pattern FORMAT_CODE_PATTERN = Pattern.compile(".*([§]([l-oL-OkK]))");

    private ShopChest plugin;
    private Economy econ;
    private Database database;
    private ShopUtils shopUtils;

    public ShopInteractListener(ShopChest plugin) {
        this.plugin = plugin;
        this.econ = plugin.getEconomy();
        this.database = plugin.getShopDatabase();
        this.shopUtils = plugin.getShopUtils();
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onInventoryClick(InventoryClickEvent e) {
        if (!plugin.getHologramFormat().isDynamic()) return;

        Inventory chestInv = e.getInventory();

        if (!(chestInv.getHolder() instanceof Chest || chestInv.getHolder() instanceof DoubleChest)) {
            return;
        }

        Location loc = null;
        if (chestInv.getHolder() instanceof Chest) {
            loc = ((Chest) chestInv.getHolder()).getLocation();
        } else if (chestInv.getHolder() instanceof DoubleChest) {
            loc = ((DoubleChest) chestInv.getHolder()).getLocation();
        }

        final Shop shop = plugin.getShopUtils().getShop(loc);
        if (shop == null) return;

        new BukkitRunnable() {
            @Override
            public void run() {
                shop.updateHologramText();
            }
        }.runTaskLater(plugin, 1L);
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onPlayerInteractCreate(PlayerInteractEvent e) {
        Player p = e.getPlayer();
        Block b = e.getClickedBlock();

        if (e.getAction() != Action.RIGHT_CLICK_BLOCK)
            return;

        if (!(ClickType.getPlayerClickType(p) instanceof CreateClickType))
            return;

        if (b.getType() != Material.CHEST && b.getType() != Material.TRAPPED_CHEST)
            return;

        if (ClickType.getPlayerClickType(p).getClickType() != ClickType.EnumClickType.CREATE)
            return;

        if (Config.enableAuthMeIntegration && plugin.hasAuthMe() && !AuthMeApi.getInstance().isAuthenticated(p))
            return;

        if (e.isCancelled() && !p.hasPermission(Permissions.CREATE_PROTECTED)) {
            p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_CREATE_PROTECTED));
            plugin.debug(p.getName() + " is not allowed to create a shop on the selected chest");
        } else if (shopUtils.isShop(b.getLocation())) {
            p.sendMessage(LanguageUtils.getMessage(Message.CHEST_ALREADY_SHOP));
            plugin.debug("Chest is already a shop");
        } else if (!ItemUtils.isAir(b.getRelative(BlockFace.UP).getType())) {
            p.sendMessage(LanguageUtils.getMessage(Message.CHEST_BLOCKED));
            plugin.debug("Chest is blocked");
        } else {
            CreateClickType clickType = (CreateClickType) ClickType.getPlayerClickType(p);
            ShopProduct product = clickType.getProduct();
            double buyPrice = clickType.getBuyPrice();
            double sellPrice = clickType.getSellPrice();
            ShopType shopType = clickType.getShopType();
    
            create(p, b.getLocation(), product, buyPrice, sellPrice, shopType);
        }

        e.setCancelled(true);
        ClickType.removePlayerClickType(p);
    }

    private Map<UUID, Set<Integer>> needsConfirmation = new HashMap<>();

    private void handleInteractEvent(PlayerInteractEvent e) {
        Block b = e.getClickedBlock();
        Player p = e.getPlayer();
        boolean inverted = Config.invertMouseButtons;

        if (Utils.getMajorVersion() >= 9 && e.getHand() == EquipmentSlot.OFF_HAND)
            return;

        if (e.getAction() != Action.RIGHT_CLICK_BLOCK && e.getAction() != Action.LEFT_CLICK_BLOCK)
            return;
        
        if (b.getType() != Material.CHEST && b.getType() != Material.TRAPPED_CHEST)
            return;
        
        ClickType clickType = ClickType.getPlayerClickType(p);
        if (clickType != null) {
            if (e.getAction() != Action.RIGHT_CLICK_BLOCK)
                return;

            Shop shop = shopUtils.getShop(b.getLocation());
            switch (clickType.getClickType()) {
                case CREATE:
                case SELECT_ITEM:
                    break;
                default: 
                    if (shop == null) {
                        p.sendMessage(LanguageUtils.getMessage(Message.CHEST_NO_SHOP));
                        plugin.debug("Chest is not a shop");
                        return;
                    }
            }

            switch (clickType.getClickType()) {
                case INFO:
                    info(p, shop);
                    break;
                case REMOVE:
                    remove(p, shop);
                    break;
                case OPEN:
                    open(p, shop, true);
                    break;
                default: return;
            }

            e.setCancelled(true);
            ClickType.removePlayerClickType(p);
        } else {
            Shop shop = shopUtils.getShop(b.getLocation());

            if (shop == null)
                return;

            boolean confirmed = needsConfirmation.containsKey(p.getUniqueId()) && needsConfirmation.get(p.getUniqueId()).contains(shop.getID());
            
            if (e.getAction() == Action.LEFT_CLICK_BLOCK && p.isSneaking() && Utils.hasAxeInHand(p)) {
                return;
            }

            ItemStack infoItem = Config.shopInfoItem;
            if (infoItem != null) {
                if (e.getAction() == Action.RIGHT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_BLOCK) {
                    ItemStack item = Utils.getItemInMainHand(p);

                    if (item == null || !(infoItem.getType() == item.getType() && infoItem.getDurability() == item.getDurability())) {
                        item = Utils.getItemInOffHand(p);

                        if (item != null && infoItem.getType() == item.getType() && infoItem.getDurability() == item.getDurability()) {
                            e.setCancelled(true);
                            info(p, shop);
                            return;
                        }
                    } else {
                        e.setCancelled(true);
                        info(p, shop);
                        return;
                    }
                }
            }

            if (e.getAction() == Action.RIGHT_CLICK_BLOCK && p.getUniqueId().equals(shop.getVendor().getUniqueId()) && shop.getShopType() != ShopType.ADMIN) {
                return;
            }

            if (p.getGameMode() == GameMode.CREATIVE) {
                e.setCancelled(true);
                p.sendMessage(LanguageUtils.getMessage(Message.USE_IN_CREATIVE));
                return;
            }

            if ((e.getAction() == Action.RIGHT_CLICK_BLOCK && !inverted) || (e.getAction() == Action.LEFT_CLICK_BLOCK && inverted)) {
                e.setCancelled(true);

                if (shop.getShopType() == ShopType.ADMIN || !shop.getVendor().getUniqueId().equals(p.getUniqueId())) {
                    plugin.debug(p.getName() + " wants to buy");

                    if (shop.getBuyPrice() > 0) {
                        if (p.hasPermission(Permissions.BUY)) {
                            // TODO: Outsource shop use external permission
                            boolean externalPluginsAllowed = true;

                            if (plugin.hasPlotSquared() && Config.enablePlotsquaredIntegration) {
                                try {
                                    Class.forName("com.plotsquared.core.PlotSquared");
                                    com.plotsquared.core.location.Location plotLocation =
                                            com.plotsquared.core.location.Location.at(b.getWorld().getName(), b.getX(), b.getY(), b.getZ());
                                    com.plotsquared.core.plot.Plot plot = plotLocation.getOwnedPlot();
                                    externalPluginsAllowed = PlotSquaredShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredShopFlag.USE_SHOP, p);
                                } catch (ClassNotFoundException ex) {
                                    com.github.intellectualsites.plotsquared.plot.object.Location plotLocation =
                                            new com.github.intellectualsites.plotsquared.plot.object.Location(b.getWorld().getName(), b.getX(), b.getY(), b.getZ());
                                    com.github.intellectualsites.plotsquared.plot.object.Plot plot = plotLocation.getOwnedPlot();
                                    externalPluginsAllowed = PlotSquaredOldShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredOldShopFlag.USE_SHOP, p);
                                }
                            }

                            if (externalPluginsAllowed && plugin.hasWorldGuard() && Config.enableWorldGuardIntegration) {
                                String flagName = (shop.getShopType() == ShopType.ADMIN ? "use-admin-shop" : "use-shop");
                                WorldGuardWrapper wgWrapper = WorldGuardWrapper.getInstance();
                                Optional<IWrappedFlag<WrappedState>> flag = wgWrapper.getFlag(flagName, WrappedState.class);
                                if (!flag.isPresent()) plugin.debug("WorldGuard flag '" + flagName + "' is not present!");
                                WrappedState state = flag.map(f -> wgWrapper.queryFlag(p, b.getLocation(), f).orElse(WrappedState.DENY)).orElse(WrappedState.DENY);
                                externalPluginsAllowed = state == WrappedState.ALLOW;
                            }
                            
                            if (shop.getShopType() == ShopType.ADMIN) {
                                if (externalPluginsAllowed || p.hasPermission(Permissions.BYPASS_EXTERNAL_PLUGIN)) {
                                    if (confirmed || !Config.confirmShopping) {
                                        buy(p, shop, p.isSneaking());
                                        if (Config.confirmShopping) {
                                            Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                            ids.remove(shop.getID());
                                            if (ids.isEmpty()) needsConfirmation.remove(p.getUniqueId());
                                            else needsConfirmation.put(p.getUniqueId(), ids);
                                        }
                                    } else {
                                        plugin.debug("Needs confirmation");
                                        p.sendMessage(LanguageUtils.getMessage(Message.CLICK_TO_CONFIRM));
                                        Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                        ids.add(shop.getID());
                                        needsConfirmation.put(p.getUniqueId(), ids);
                                    }
                                } else {
                                    plugin.debug(p.getName() + " doesn't have external plugin's permission");
                                    p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_BUY_HERE));
                                }
                            } else {
                                if (externalPluginsAllowed || p.hasPermission(Permissions.BYPASS_EXTERNAL_PLUGIN)) {
                                    Chest c = (Chest) b.getState();
                                    ItemStack itemStack = shop.getProduct().getItemStack();
                                    int amount = (p.isSneaking() ? itemStack.getMaxStackSize() : shop.getProduct().getAmount());

                                    if (Utils.getAmount(c.getInventory(), itemStack) >= amount) {
                                        if (confirmed || !Config.confirmShopping) {
                                            buy(p, shop, p.isSneaking());
                                            if (Config.confirmShopping) {
                                                Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                                ids.remove(shop.getID());
                                                if (ids.isEmpty()) needsConfirmation.remove(p.getUniqueId());
                                                else needsConfirmation.put(p.getUniqueId(), ids);
                                            }
                                        } else {
                                            plugin.debug("Needs confirmation");
                                            p.sendMessage(LanguageUtils.getMessage(Message.CLICK_TO_CONFIRM));
                                            Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                            ids.add(shop.getID());
                                            needsConfirmation.put(p.getUniqueId(), ids);
                                        }
                                    } else {
                                        if (Config.autoCalculateItemAmount && Utils.getAmount(c.getInventory(), itemStack) > 0) {
                                            if (confirmed || !Config.confirmShopping) {
                                                buy(p, shop, p.isSneaking());
                                                if (Config.confirmShopping) {
                                                    Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                                    ids.remove(shop.getID());
                                                    if (ids.isEmpty()) needsConfirmation.remove(p.getUniqueId());
                                                    else needsConfirmation.put(p.getUniqueId(), ids);
                                                }
                                            } else {
                                                plugin.debug("Needs confirmation");
                                                p.sendMessage(LanguageUtils.getMessage(Message.CLICK_TO_CONFIRM));
                                                Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                                ids.add(shop.getID());
                                                needsConfirmation.put(p.getUniqueId(), ids);
                                            }
                                        } else {
                                            p.sendMessage(LanguageUtils.getMessage(Message.OUT_OF_STOCK));
                                            if (shop.getVendor().isOnline() && Config.enableVendorMessages) {
                                                shop.getVendor().getPlayer().sendMessage(LanguageUtils.getMessage(Message.VENDOR_OUT_OF_STOCK,
                                                        new Replacement(Placeholder.AMOUNT, String.valueOf(shop.getProduct().getAmount())),
                                                                new Replacement(Placeholder.ITEM_NAME, shop.getProduct().getLocalizedName())));
                                            } else if(!shop.getVendor().isOnline() && Config.enableVendorBungeeMessages){
                                                String message = LanguageUtils.getMessage(Message.VENDOR_OUT_OF_STOCK,
                                                        new Replacement(Placeholder.AMOUNT, String.valueOf(shop.getProduct().getAmount())),
                                                        new Replacement(Placeholder.ITEM_NAME, shop.getProduct().getLocalizedName()));
                                                sendBungeeMessage(shop.getVendor().getName(), message);
                                            }
                                            plugin.debug("Shop is out of stock");
                                        }
                                    }
                                } else {
                                    plugin.debug(p.getName() + " doesn't have external plugin's permission");
                                    p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_BUY_HERE));
                                }
                            }
                        } else {
                            p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_BUY));
                            plugin.debug(p.getName() + " is not permitted to buy");
                        }
                    } else {
                        p.sendMessage(LanguageUtils.getMessage(Message.BUYING_DISABLED));
                        plugin.debug("Buying is disabled");
                    }
                }

            } else if ((e.getAction() == Action.LEFT_CLICK_BLOCK && !inverted) || (e.getAction() == Action.RIGHT_CLICK_BLOCK && inverted)) {
                e.setCancelled(true);

                if ((shop.getShopType() == ShopType.ADMIN) || (!shop.getVendor().getUniqueId().equals(p.getUniqueId()))) {
                    plugin.debug(p.getName() + " wants to sell");

                    if (shop.getSellPrice() > 0) {
                        if (p.hasPermission(Permissions.SELL)) {
                            // TODO: Outsource shop use external permission
                            boolean externalPluginsAllowed = true;

                            if (plugin.hasPlotSquared() && Config.enablePlotsquaredIntegration) {
                                try {
                                    Class.forName("com.plotsquared.core.PlotSquared");
                                    com.plotsquared.core.location.Location plotLocation =
                                            com.plotsquared.core.location.Location.at(b.getWorld().getName(), b.getX(), b.getY(), b.getZ());
                                    com.plotsquared.core.plot.Plot plot = plotLocation.getOwnedPlot();
                                    externalPluginsAllowed = PlotSquaredShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredShopFlag.USE_SHOP, p);
                                } catch (ClassNotFoundException ex) {
                                    com.github.intellectualsites.plotsquared.plot.object.Location plotLocation =
                                            new com.github.intellectualsites.plotsquared.plot.object.Location(b.getWorld().getName(), b.getX(), b.getY(), b.getZ());
                                    com.github.intellectualsites.plotsquared.plot.object.Plot plot = plotLocation.getOwnedPlot();
                                    externalPluginsAllowed = PlotSquaredOldShopFlag.isFlagAllowedOnPlot(plot, PlotSquaredOldShopFlag.USE_SHOP, p);
                                }
                            }

                            if (externalPluginsAllowed && plugin.hasWorldGuard() && Config.enableWorldGuardIntegration) {
                                String flagName = (shop.getShopType() == ShopType.ADMIN ? "use-admin-shop" : "use-shop");
                                WorldGuardWrapper wgWrapper = WorldGuardWrapper.getInstance();
                                Optional<IWrappedFlag<WrappedState>> flag = wgWrapper.getFlag(flagName, WrappedState.class);
                                if (!flag.isPresent()) plugin.debug("WorldGuard flag '" + flagName + "' is not present!");
                                WrappedState state = flag.map(f -> wgWrapper.queryFlag(p, b.getLocation(), f).orElse(WrappedState.DENY)).orElse(WrappedState.DENY);
                                externalPluginsAllowed = state == WrappedState.ALLOW;
                            }

                            ItemStack itemStack = shop.getProduct().getItemStack();

                            if (externalPluginsAllowed || p.hasPermission(Permissions.BYPASS_EXTERNAL_PLUGIN)) {
                                boolean stack = p.isSneaking() && !Utils.hasAxeInHand(p);
                                int amount = stack ? itemStack.getMaxStackSize() : shop.getProduct().getAmount();

                                if (Utils.getAmount(p.getInventory(), itemStack) >= amount) {
                                    if (confirmed || !Config.confirmShopping) {
                                        sell(p, shop, stack);
                                        if (Config.confirmShopping) {
                                            Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                            ids.remove(shop.getID());
                                            if (ids.isEmpty()) needsConfirmation.remove(p.getUniqueId());
                                            else needsConfirmation.put(p.getUniqueId(), ids);
                                        }
                                    } else {
                                        plugin.debug("Needs confirmation");
                                        p.sendMessage(LanguageUtils.getMessage(Message.CLICK_TO_CONFIRM));
                                        Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                        ids.add(shop.getID());
                                        needsConfirmation.put(p.getUniqueId(), ids);
                                    }
                                } else {
                                    if (Config.autoCalculateItemAmount && Utils.getAmount(p.getInventory(), itemStack) > 0) {
                                        if (confirmed || !Config.confirmShopping) {
                                            sell(p, shop, stack);
                                            if (Config.confirmShopping) {
                                                Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                                ids.remove(shop.getID());
                                                if (ids.isEmpty()) needsConfirmation.remove(p.getUniqueId());
                                                else needsConfirmation.put(p.getUniqueId(), ids);
                                            }
                                        } else {
                                            plugin.debug("Needs confirmation");
                                            p.sendMessage(LanguageUtils.getMessage(Message.CLICK_TO_CONFIRM));
                                            Set<Integer> ids = needsConfirmation.containsKey(p.getUniqueId()) ? needsConfirmation.get(p.getUniqueId()) : new HashSet<Integer>();
                                            ids.add(shop.getID());
                                            needsConfirmation.put(p.getUniqueId(), ids);
                                        }
                                    } else {
                                        p.sendMessage(LanguageUtils.getMessage(Message.NOT_ENOUGH_ITEMS));
                                        plugin.debug(p.getName() + " doesn't have enough items");
                                    }
                                }
                            } else {
                                plugin.debug(p.getName() + " doesn't have external plugin's permission");
                                p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_SELL_HERE));
                            }
                        } else {
                            p.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_SELL));
                            plugin.debug(p.getName() + " is not permitted to sell");
                        }
                    } else {
                        p.sendMessage(LanguageUtils.getMessage(Message.SELLING_DISABLED));
                        plugin.debug("Selling is disabled");
                    }
                }
            }
        }
    }

    @EventHandler
    public void onPlayerInteract(PlayerInteractEvent e) {
        if (Config.enableAuthMeIntegration && plugin.hasAuthMe() && !AuthMeApi.getInstance().isAuthenticated(e.getPlayer())) return;
        handleInteractEvent(e);
    }

    /**
     * Create a new shop
     *
     * @param executor  Player, who executed the command, will receive the message and become the vendor of the shop
     * @param location  Where the shop will be located
     * @param product   Product of the Shop
     * @param buyPrice  Buy price
     * @param sellPrice Sell price
     * @param shopType  Type of the shop
     */
    private void create(final Player executor, final Location location, final ShopProduct product, final double buyPrice, final double sellPrice, final ShopType shopType) {
        plugin.debug(executor.getName() + " is creating new shop...");

        if (!executor.hasPermission(Permissions.CREATE)) {
            executor.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_CREATE));
            plugin.debug(executor.getName() + " is not permitted to create the shop");
            return;
        }

        double creationPrice = (shopType == ShopType.NORMAL) ? Config.shopCreationPriceNormal : Config.shopCreationPriceAdmin;
        Shop shop = new Shop(plugin, executor, product, location, buyPrice, sellPrice, shopType);

        ShopCreateEvent event = new ShopCreateEvent(executor, shop, creationPrice);
        Bukkit.getPluginManager().callEvent(event);
        if (event.isCancelled() && !executor.hasPermission(Permissions.CREATE_PROTECTED)) {
            plugin.debug("Create event cancelled");
            executor.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_CREATE_PROTECTED));
            return;
        }

        if (creationPrice > 0) {
            EconomyResponse r = plugin.getEconomy().withdrawPlayer(executor, location.getWorld().getName(), creationPrice);
            if (!r.transactionSuccess()) {
                plugin.debug("Economy transaction failed: " + r.errorMessage);
                executor.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED, new Replacement(Placeholder.ERROR, r.errorMessage)));
                return;
            }
        }

        shop.create(true);

        plugin.debug("Shop created");
        shopUtils.addShop(shop, true);

        Message message = shopType == ShopType.ADMIN ? Message.ADMIN_SHOP_CREATED : Message.SHOP_CREATED;
        executor.sendMessage(LanguageUtils.getMessage(message, new Replacement(Placeholder.CREATION_PRICE, creationPrice)));
    }

    /**
     * Remove a shop
     * @param executor Player, who executed the command and will receive the message
     * @param shop Shop to be removed
     */
    private void remove(Player executor, Shop shop) {
        if (shop.getShopType() == ShopType.ADMIN && !executor.hasPermission(Permissions.REMOVE_ADMIN)) {
            executor.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_REMOVE_ADMIN));
            return;
        }

        if (shop.getShopType() == ShopType.NORMAL && !executor.getUniqueId().equals(shop.getVendor().getUniqueId())
                && !executor.hasPermission(Permissions.REMOVE_OTHER)) {
            executor.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_REMOVE_OTHERS));
            return;
        }

        plugin.debug(executor.getName() + " is removing " + shop.getVendor().getName() + "'s shop (#" + shop.getID() + ")");
        ShopRemoveEvent event = new ShopRemoveEvent(executor, shop);
        Bukkit.getPluginManager().callEvent(event);
        if (event.isCancelled()) {
            plugin.debug("Remove event cancelled (#" + shop.getID() + ")");
            return;
        }

        double creationPrice = shop.getShopType() == ShopType.ADMIN ? Config.shopCreationPriceAdmin : Config.shopCreationPriceNormal;
        if (creationPrice > 0 && Config.refundShopCreation && executor.getUniqueId().equals(shop.getVendor().getUniqueId())) {
            EconomyResponse r = plugin.getEconomy().depositPlayer(executor, shop.getLocation().getWorld().getName(), creationPrice);
            if (!r.transactionSuccess()) {
                plugin.debug("Economy transaction failed: " + r.errorMessage);
                executor.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED,
                        new Replacement(Placeholder.ERROR, r.errorMessage)));
                executor.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED_REFUND,
                        new Replacement(Placeholder.CREATION_PRICE, 0)));
            } else {
                executor.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED_REFUND,
                    new Replacement(Placeholder.CREATION_PRICE, creationPrice)));
            }
        } else {
            executor.sendMessage(LanguageUtils.getMessage(Message.SHOP_REMOVED));
        }

        shopUtils.removeShop(shop, true);
        plugin.debug("Removed shop (#" + shop.getID() + ")");
    }

    /**
     * Open a shop
     * @param executor Player, who executed the command and will receive the message
     * @param shop Shop to be opened
     * @param message Whether the player should receive the {@link Message#OPENED_SHOP} message
     */
    private void open(Player executor, Shop shop, boolean message) {
        if (!executor.getUniqueId().equals(shop.getVendor().getUniqueId()) && !executor.hasPermission(Permissions.OPEN_OTHER)) {
            executor.sendMessage(LanguageUtils.getMessage(Message.NO_PERMISSION_OPEN_OTHERS));
            return;
        }

        plugin.debug(executor.getName() + " is opening " + shop.getVendor().getName() + "'s shop (#" + shop.getID() + ")");
        ShopOpenEvent event = new ShopOpenEvent(executor, shop);
        Bukkit.getPluginManager().callEvent(event);
        if (event.isCancelled()) {
            plugin.debug("Open event cancelled (#" + shop.getID() + ")");
            return;
        }

        executor.openInventory(shop.getInventoryHolder().getInventory());
        plugin.debug("Opened shop (#" + shop.getID() + ")");
        if (message) executor.sendMessage(LanguageUtils.getMessage(Message.OPENED_SHOP,
                new Replacement(Placeholder.VENDOR, shop.getVendor().getName())));
    }

    /**
     *
     * @param executor Player, who executed the command and will retrieve the information
     * @param shop Shop from which the information will be retrieved
     */
    private void info(Player executor, Shop shop) {
        plugin.debug(executor.getName() + " is retrieving shop info (#" + shop.getID() + ")");
        ShopInfoEvent event = new ShopInfoEvent(executor, shop);
        Bukkit.getPluginManager().callEvent(event);

        if (event.isCancelled()) {
            plugin.debug("Info event cancelled (#" + shop.getID() + ")");
            return;
        }

        Chest c = (Chest) shop.getLocation().getBlock().getState();
        ItemStack itemStack = shop.getProduct().getItemStack();
        int amount = Utils.getAmount(c.getInventory(), itemStack);
        int space = Utils.getFreeSpaceForItem(c.getInventory(), itemStack);

        String vendorName = (shop.getVendor().getName() == null ?
                shop.getVendor().getUniqueId().toString() : shop.getVendor().getName());

        String vendorString = LanguageUtils.getMessage(Message.SHOP_INFO_VENDOR,
                new Replacement(Placeholder.VENDOR, vendorName));

        // Make JSON message with item preview
        JsonBuilder jb = getProductJson(shop.getProduct());

        String disabled = LanguageUtils.getMessage(Message.SHOP_INFO_DISABLED);

        String priceString = LanguageUtils.getMessage(Message.SHOP_INFO_PRICE,
                new Replacement(Placeholder.BUY_PRICE, (shop.getBuyPrice() > 0 ? String.valueOf(shop.getBuyPrice()) : disabled)),
                new Replacement(Placeholder.SELL_PRICE, (shop.getSellPrice() > 0 ? String.valueOf(shop.getSellPrice()) : disabled)));

        String shopType = LanguageUtils.getMessage(shop.getShopType() == ShopType.NORMAL ?
                Message.SHOP_INFO_NORMAL : Message.SHOP_INFO_ADMIN);

        String stock = LanguageUtils.getMessage(Message.SHOP_INFO_STOCK,
                new Replacement(Placeholder.STOCK, amount));

        String chestSpace = LanguageUtils.getMessage(Message.SHOP_INFO_CHEST_SPACE,
                new Replacement(Placeholder.CHEST_SPACE, space));

        executor.sendMessage(" ");
        if (shop.getShopType() != ShopType.ADMIN) executor.sendMessage(vendorString);
        jb.sendJson(executor);
        if (shop.getShopType() != ShopType.ADMIN && shop.getBuyPrice() > 0) executor.sendMessage(stock);
        if (shop.getShopType() != ShopType.ADMIN && shop.getSellPrice() > 0) executor.sendMessage(chestSpace);
        executor.sendMessage(priceString);
        executor.sendMessage(shopType);
        executor.sendMessage(" ");
    }

    /**
     * Create a {@link JsonBuilder} containing the shop info message for the product
     * in which you can hover the item name to get a preview.
     * @param product The product of the shop
     * @return A {@link JsonBuilder} that can send the message via {@link JsonBuilder#sendJson(Player)}
     */
    private JsonBuilder getProductJson(ShopProduct product) {
        // Add spaces at start and end, so there will always be a part before and after
        // the item name after splitting at Placeholder.ITEM_NAME
        String productString = " " + LanguageUtils.getMessage(Message.SHOP_INFO_PRODUCT,
                new Replacement(Placeholder.AMOUNT, String.valueOf(product.getAmount()))) + " ";

        String[] parts = productString.split(Placeholder.ITEM_NAME.toString());
        String productName = product.getLocalizedName();
        String jsonItem = "";
        JsonBuilder jb = new JsonBuilder(plugin);
        JsonBuilder.PartArray rootArray = new JsonBuilder.PartArray();
        
        try {
            OBCClassResolver obcClassResolver = new OBCClassResolver();
            NMSClassResolver nmsClassResolver = new NMSClassResolver();

            Class<?> craftItemStackClass = obcClassResolver.resolveSilent("inventory.CraftItemStack");	
            Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, product.getItemStack());	
            Class<?> nbtTagCompoundClass = nmsClassResolver.resolveSilent("nbt.NBTTagCompound");
            Object nbtTagCompound = nbtTagCompoundClass.getConstructor().newInstance();
            nmsStack.getClass().getMethod("save", nbtTagCompoundClass).invoke(nmsStack, nbtTagCompound);
            jsonItem = new JsonPrimitive(nbtTagCompound.toString()).toString();
        } catch (Exception e) {
            plugin.getLogger().severe("Failed to create JSON from item. Product preview will not be available.");
            plugin.debug("Failed to create JSON from item:");
            plugin.debug(e);
            jb.setRootPart(new JsonBuilder.Part(productString.replace(Placeholder.ITEM_NAME.toString(), productName)));
            return jb;
        }

        for (int i = 0; i < parts.length; i++) {
            String part = parts[i];

            // Remove spaces at start and end that were added before
            if (i == 0 && part.startsWith(" ")) {
                part = part.substring(1);
            } else if (i == parts.length - 1 && part.endsWith(" ")) {
                part = part.substring(0, part.length() - 1);
            }

            String formatPrefix = "";

            // A color code resets all format codes, so only format codes
            // after the last color code have to be found.
            int lastColorGroupEndIndex = 0;

            Matcher colorMatcher = COLOR_CODE_PATTERN.matcher(part);
            if (colorMatcher.find()) {
                formatPrefix = colorMatcher.group(1);
                lastColorGroupEndIndex = colorMatcher.end();
            }
            
            Matcher formatMatcher = FORMAT_CODE_PATTERN.matcher(part);
            while (formatMatcher.find(lastColorGroupEndIndex)) {
                formatPrefix += formatMatcher.group(1);
            }

            rootArray.addPart(new JsonBuilder.Part(part));

            if (i < parts.length - 1) {
                JsonBuilder.PartMap hoverEvent = new JsonBuilder.PartMap();
                hoverEvent.setValue("action", new JsonBuilder.Part("show_item"));
                hoverEvent.setValue("value", new JsonBuilder.Part(jsonItem, false));

                JsonBuilder.PartMap itemNameMap = JsonBuilder.parse(formatPrefix + productName).toMap();
                itemNameMap.setValue("hoverEvent", hoverEvent);

                rootArray.addPart(itemNameMap);
            }
        }

        jb.setRootPart(rootArray);
        return jb;
    }

    /**
     * A player buys from a shop
     * @param executor Player, who executed the command and will buy the product
     * @param shop Shop, from which the player buys
     * @param stack Whether a whole stack should be bought
     */
    private void buy(Player executor, final Shop shop, boolean stack) {
        plugin.debug(executor.getName() + " is buying (#" + shop.getID() + ")");

        ItemStack itemStack = shop.getProduct().getItemStack();
        int amount = shop.getProduct().getAmount();
        if (stack) amount = itemStack.getMaxStackSize();

        String worldName = shop.getLocation().getWorld().getName();

        double price = shop.getBuyPrice();
        if (stack) price = (price / shop.getProduct().getAmount()) * amount;

        if (econ.getBalance(executor, worldName) >= price || Config.autoCalculateItemAmount) {

            int amountForMoney = (int) (amount / price * econ.getBalance(executor, worldName));

            if (amountForMoney == 0 && Config.autoCalculateItemAmount) {
                executor.sendMessage(LanguageUtils.getMessage(Message.NOT_ENOUGH_MONEY));
                return;
            }

            plugin.debug(executor.getName() + " has enough money for " + amountForMoney + " item(s) (#" + shop.getID() + ")");

            Block b = shop.getLocation().getBlock();
            Chest c = (Chest) b.getState();

            int amountForChestItems = Utils.getAmount(c.getInventory(), itemStack);

            if (amountForChestItems == 0 && shop.getShopType() != ShopType.ADMIN) {
                executor.sendMessage(LanguageUtils.getMessage(Message.OUT_OF_STOCK));
                return;
            }

            ItemStack product = new ItemStack(itemStack);
            if (stack) product.setAmount(amount);

            Inventory inventory = executor.getInventory();

            int freeSpace = Utils.getFreeSpaceForItem(inventory, product);

            if (freeSpace == 0) {
                executor.sendMessage(LanguageUtils.getMessage(Message.NOT_ENOUGH_INVENTORY_SPACE));
                return;
            }

            int newAmount = amount;

            if (Config.autoCalculateItemAmount) {
                if (shop.getShopType() == ShopType.ADMIN)
                    newAmount = Math.min(amountForMoney, freeSpace);
                else
                    newAmount = Math.min(Math.min(amountForMoney, amountForChestItems), freeSpace);
            }

            if (newAmount > amount) newAmount = amount;

            ShopProduct newProduct = new ShopProduct(product, newAmount);
            double newPrice = (price / amount) * newAmount;

            if (freeSpace >= newAmount) {
                plugin.debug(executor.getName() + " has enough inventory space for " + freeSpace + " items (#" + shop.getID() + ")");

                EconomyResponse r = econ.withdrawPlayer(executor, worldName, newPrice);

                if (r.transactionSuccess()) {
                    EconomyResponse r2 = (shop.getShopType() != ShopType.ADMIN) ? econ.depositPlayer(shop.getVendor(), worldName, newPrice) : null;

                    if (r2 != null) {
                        if (r2.transactionSuccess()) {
                            ShopBuySellEvent event = new ShopBuySellEvent(executor, shop, ShopBuySellEvent.Type.BUY, newAmount, newPrice);
                            Bukkit.getPluginManager().callEvent(event);

                            if (event.isCancelled()) {
                                econ.depositPlayer(executor, worldName, newPrice);
                                econ.withdrawPlayer(shop.getVendor(), worldName, newPrice);
                                plugin.debug("Buy event cancelled (#" + shop.getID() + ")");
                                return;
                            }

                            database.logEconomy(executor, shop, newProduct, newPrice, ShopBuySellEvent.Type.BUY, null);

                            addToInventory(inventory, newProduct);
                            removeFromInventory(c.getInventory(), newProduct);
                            executor.updateInventory();

                            new BukkitRunnable() {
                                @Override
                                public void run() {
                                    if (plugin.getHologramFormat().isDynamic()) {
                                        shop.updateHologramText();
                                    }
                                }
                            }.runTaskLater(plugin, 1L);

                            String vendorName = (shop.getVendor().getName() == null ? shop.getVendor().getUniqueId().toString() : shop.getVendor().getName());
                            executor.sendMessage(LanguageUtils.getMessage(Message.BUY_SUCCESS, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                    new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.BUY_PRICE, String.valueOf(newPrice)),
                                    new Replacement(Placeholder.VENDOR, vendorName)));

                            plugin.debug(executor.getName() + " successfully bought (#" + shop.getID() + ")");

                            if (shop.getVendor().isOnline() && Config.enableVendorMessages) {
                                shop.getVendor().getPlayer().sendMessage(LanguageUtils.getMessage(Message.SOMEONE_BOUGHT, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                        new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.BUY_PRICE, String.valueOf(newPrice)),
                                        new Replacement(Placeholder.PLAYER, executor.getName())));
                            } else if(!shop.getVendor().isOnline() && Config.enableVendorBungeeMessages){
                                String message = LanguageUtils.getMessage( Message.SOMEONE_BOUGHT, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                        new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.BUY_PRICE, String.valueOf(newPrice)),
                                        new Replacement(Placeholder.PLAYER, executor.getName()));
                                sendBungeeMessage(shop.getVendor().getName(),message);
                            }

                        } else {
                            plugin.debug("Economy transaction failed (r2): " + r2.errorMessage + " (#" + shop.getID() + ")");
                            executor.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED, new Replacement(Placeholder.ERROR, r2.errorMessage)));
                            econ.withdrawPlayer(shop.getVendor(), worldName, newPrice);
                            econ.depositPlayer(executor, worldName, newPrice);
                        }
                    } else {
                        ShopBuySellEvent event = new ShopBuySellEvent(executor, shop, ShopBuySellEvent.Type.BUY, newAmount, newPrice);
                        Bukkit.getPluginManager().callEvent(event);

                        if (event.isCancelled()) {
                            econ.depositPlayer(executor, worldName, newPrice);
                            plugin.debug("Buy event cancelled (#" + shop.getID() + ")");
                            return;
                        }

                        database.logEconomy(executor, shop, newProduct, newPrice, ShopBuySellEvent.Type.BUY, null);

                        addToInventory(inventory, newProduct);
                        executor.updateInventory();

                        new BukkitRunnable() {
                            @Override
                            public void run() {
                                if (plugin.getHologramFormat().isDynamic()) {
                                    shop.updateHologramText();
                                }
                            }
                        }.runTaskLater(plugin, 1L);

                        executor.sendMessage(LanguageUtils.getMessage(Message.BUY_SUCCESS_ADMIN, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.BUY_PRICE, String.valueOf(newPrice))));

                        plugin.debug(executor.getName() + " successfully bought (#" + shop.getID() + ")");
                    }
                } else {
                    plugin.debug("Economy transaction failed (r): " + r.errorMessage + " (#" + shop.getID() + ")");
                    executor.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED, new Replacement(Placeholder.ERROR, r.errorMessage)));
                    econ.depositPlayer(executor, worldName, newPrice);
                }
            } else {
                executor.sendMessage(LanguageUtils.getMessage(Message.NOT_ENOUGH_INVENTORY_SPACE));
            }
        } else {
            executor.sendMessage(LanguageUtils.getMessage(Message.NOT_ENOUGH_MONEY));
        }
    }

    /**
     * A player sells to a shop
     * @param executor Player, who executed the command and will sell the product
     * @param shop Shop, to which the player sells
     */
    private void sell(Player executor, final Shop shop, boolean stack) {
        plugin.debug(executor.getName() + " is selling (#" + shop.getID() + ")");

        ItemStack itemStack = shop.getProduct().getItemStack();
        int amount = shop.getProduct().getAmount();
        if (stack) amount = itemStack.getMaxStackSize();

        double price = shop.getSellPrice();
        if (stack) price = (price / shop.getProduct().getAmount()) * amount;

        String worldName = shop.getLocation().getWorld().getName();

        if (shop.getShopType() == ShopType.ADMIN || econ.getBalance(shop.getVendor(), worldName) >= price || Config.autoCalculateItemAmount) {
            int amountForMoney = 1;
            
            if (shop.getShopType() != ShopType.ADMIN) {
                 amountForMoney = (int) (amount / price * econ.getBalance(shop.getVendor(), worldName));
            }

            plugin.debug("Vendor has enough money for " + amountForMoney + " item(s) (#" + shop.getID() + ")");

            if (amountForMoney == 0 && Config.autoCalculateItemAmount && shop.getShopType() != ShopType.ADMIN) {
                executor.sendMessage(LanguageUtils.getMessage(Message.VENDOR_NOT_ENOUGH_MONEY));
                return;
            }

            Block block = shop.getLocation().getBlock();
            Chest chest = (Chest) block.getState();

            int amountForItemCount = Utils.getAmount(executor.getInventory(), itemStack);

            if (amountForItemCount == 0) {
                executor.sendMessage(LanguageUtils.getMessage(Message.NOT_ENOUGH_ITEMS));
                return;
            }

            ItemStack product = new ItemStack(itemStack);
            if (stack) product.setAmount(amount);

            Inventory inventory = chest.getInventory();

            int freeSpace = Utils.getFreeSpaceForItem(inventory, product);

            if (freeSpace == 0 && shop.getShopType() != ShopType.ADMIN) {
                executor.sendMessage(LanguageUtils.getMessage(Message.CHEST_NOT_ENOUGH_INVENTORY_SPACE));
                return;
            }

            int newAmount = amount;

            if (Config.autoCalculateItemAmount) {
                if (shop.getShopType() == ShopType.ADMIN)
                    newAmount = amountForItemCount;
                else
                    newAmount = Math.min(Math.min(amountForMoney, amountForItemCount), freeSpace);
            }

            if (newAmount > amount) newAmount = amount;

            ShopProduct newProduct = new ShopProduct(product, newAmount);
            double newPrice = (price / amount) * newAmount;

            if (freeSpace >= newAmount || shop.getShopType() == ShopType.ADMIN) {
                plugin.debug("Chest has enough inventory space for " + freeSpace + " items (#" + shop.getID() + ")");

                EconomyResponse r = econ.depositPlayer(executor, worldName, newPrice);

                if (r.transactionSuccess()) {
                    EconomyResponse r2 = (shop.getShopType() != ShopType.ADMIN) ? econ.withdrawPlayer(shop.getVendor(), worldName, newPrice) : null;

                    if (r2 != null) {
                        if (r2.transactionSuccess()) {
                            ShopBuySellEvent event = new ShopBuySellEvent(executor, shop, ShopBuySellEvent.Type.SELL, newAmount, newPrice);
                            Bukkit.getPluginManager().callEvent(event);

                            if (event.isCancelled()) {
                                econ.withdrawPlayer(executor, worldName, newPrice);
                                econ.depositPlayer(shop.getVendor(), worldName, newPrice);
                                plugin.debug("Sell event cancelled (#" + shop.getID() + ")");
                                return;
                            }

                            database.logEconomy(executor, shop, newProduct, newPrice, ShopBuySellEvent.Type.SELL, null);

                            addToInventory(inventory, newProduct);
                            removeFromInventory(executor.getInventory(), newProduct);
                            executor.updateInventory();

                            new BukkitRunnable() {
                                @Override
                                public void run() {
                                    if (plugin.getHologramFormat().isDynamic()) {
                                        shop.updateHologramText();
                                    }
                                }
                            }.runTaskLater(plugin, 1L);

                            String vendorName = (shop.getVendor().getName() == null ? shop.getVendor().getUniqueId().toString() : shop.getVendor().getName());
                            executor.sendMessage(LanguageUtils.getMessage(Message.SELL_SUCCESS, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                    new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.SELL_PRICE, String.valueOf(newPrice)),
                                    new Replacement(Placeholder.VENDOR, vendorName)));

                            plugin.debug(executor.getName() + " successfully sold (#" + shop.getID() + ")");

                            if (shop.getVendor().isOnline() && Config.enableVendorMessages) {
                                shop.getVendor().getPlayer().sendMessage(LanguageUtils.getMessage(Message.SOMEONE_SOLD, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                        new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.SELL_PRICE, String.valueOf(newPrice)),
                                        new Replacement(Placeholder.PLAYER, executor.getName())));
                            } else if(!shop.getVendor().isOnline() && Config.enableVendorBungeeMessages){
                                String message = LanguageUtils.getMessage( Message.SOMEONE_SOLD, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                        new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.SELL_PRICE, String.valueOf(newPrice)),
                                        new Replacement(Placeholder.PLAYER, executor.getName()));
                                sendBungeeMessage(shop.getVendor().getName(),message);
                            }

                        } else {
                            plugin.debug("Economy transaction failed (r2): " + r2.errorMessage + " (#" + shop.getID() + ")");
                            executor.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED, new Replacement(Placeholder.ERROR, r2.errorMessage)));
                            econ.withdrawPlayer(executor, worldName, newPrice);
                            econ.depositPlayer(shop.getVendor(), worldName, newPrice);
                        }

                    } else {
                        ShopBuySellEvent event = new ShopBuySellEvent(executor, shop, ShopBuySellEvent.Type.SELL, newAmount, newPrice);
                        Bukkit.getPluginManager().callEvent(event);

                        if (event.isCancelled()) {
                            econ.withdrawPlayer(executor, worldName, newPrice);
                            plugin.debug("Sell event cancelled (#" + shop.getID() + ")");
                            return;
                        }

                        database.logEconomy(executor, shop, newProduct, newPrice, ShopBuySellEvent.Type.SELL, null);

                        removeFromInventory(executor.getInventory(), newProduct);
                        executor.updateInventory();

                        new BukkitRunnable() {
                            @Override
                            public void run() {
                                if (plugin.getHologramFormat().isDynamic()) {
                                    shop.updateHologramText();
                                }
                            }
                        }.runTaskLater(plugin, 1L);

                        executor.sendMessage(LanguageUtils.getMessage(Message.SELL_SUCCESS_ADMIN, new Replacement(Placeholder.AMOUNT, String.valueOf(newAmount)),
                                new Replacement(Placeholder.ITEM_NAME, newProduct.getLocalizedName()), new Replacement(Placeholder.SELL_PRICE, String.valueOf(newPrice))));

                        plugin.debug(executor.getName() + " successfully sold (#" + shop.getID() + ")");
                    }

                } else {
                    plugin.debug("Economy transaction failed (r): " + r.errorMessage + " (#" + shop.getID() + ")");
                    executor.sendMessage(LanguageUtils.getMessage(Message.ERROR_OCCURRED, new Replacement(Placeholder.ERROR, r.errorMessage)));
                    econ.withdrawPlayer(executor, worldName, newPrice);
                }

            } else {
                executor.sendMessage(LanguageUtils.getMessage(Message.CHEST_NOT_ENOUGH_INVENTORY_SPACE));
            }

        } else {
            executor.sendMessage(LanguageUtils.getMessage(Message.VENDOR_NOT_ENOUGH_MONEY));
        }
    }

    /**
     * Adds items to an inventory
     * @param inventory The inventory, to which the items will be added
     * @param itemStack Items to add
     * @return Whether all items were added to the inventory
     */
    private boolean addToInventory(Inventory inventory, ShopProduct product) {
        plugin.debug("Adding items to inventory...");

        HashMap<Integer, ItemStack> inventoryItems = new HashMap<>();
        ItemStack itemStack = product.getItemStack();
        int amount = product.getAmount();
        int added = 0;

        if (inventory instanceof PlayerInventory) {
            if (Utils.getMajorVersion() >= 9) {
                inventoryItems.put(40, inventory.getItem(40));
            }

            for (int i = 0; i < 36; i++) {
                inventoryItems.put(i, inventory.getItem(i));
            }

        } else {
            for (int i = 0; i < inventory.getSize(); i++) {
                inventoryItems.put(i, inventory.getItem(i));
            }
        }

        slotLoop:
        for (int slot : inventoryItems.keySet()) {
            while (added < amount) {
                ItemStack item = inventory.getItem(slot);

                if (item != null && item.getType() != Material.AIR) {
                    if (Utils.isItemSimilar(item, itemStack)) {
                        if (item.getAmount() != item.getMaxStackSize()) {
                            ItemStack newItemStack = new ItemStack(item);
                            newItemStack.setAmount(item.getAmount() + 1);
                            inventory.setItem(slot, newItemStack);
                            added++;
                        } else {
                            continue slotLoop;
                        }
                    } else {
                        continue slotLoop;
                    }
                } else {
                    ItemStack newItemStack = new ItemStack(itemStack);
                    newItemStack.setAmount(1);
                    inventory.setItem(slot, newItemStack);
                    added++;
                }
            }
        }

        return (added == amount);
    }

    /**
     * Removes items to from an inventory
     * @param inventory The inventory, from which the items will be removed
     * @param itemStack Items to remove
     * @return Whether all items were removed from the inventory
     */
    private boolean removeFromInventory(Inventory inventory, ShopProduct product) {
        plugin.debug("Removing items from inventory...");

        HashMap<Integer, ItemStack> inventoryItems = new HashMap<>();
        ItemStack itemStack = product.getItemStack();
        int amount = product.getAmount();
        int removed = 0;

        if (inventory instanceof PlayerInventory) {
            if (Utils.getMajorVersion() >= 9) {
                inventoryItems.put(40, inventory.getItem(40));
            }

            for (int i = 0; i < 36; i++) {
                inventoryItems.put(i, inventory.getItem(i));
            }

        } else {
            for (int i = 0; i < inventory.getSize(); i++) {
                inventoryItems.put(i, inventory.getItem(i));
            }
        }

        slotLoop:
        for (int slot : inventoryItems.keySet()) {
            while (removed < amount) {
                ItemStack item = inventory.getItem(slot);

                if (item != null && item.getType() != Material.AIR) {
                    if (Utils.isItemSimilar(item, itemStack)) {
                        if (item.getAmount() > 0) {
                            int newAmount = item.getAmount() - 1;

                            ItemStack newItemStack = new ItemStack(item);
                            newItemStack.setAmount(newAmount);

                            if (newAmount == 0)
                                inventory.setItem(slot, null);
                            else
                                inventory.setItem(slot, newItemStack);

                            removed++;
                        } else {
                            continue slotLoop;
                        }
                    } else {
                        continue slotLoop;
                    }
                } else {
                    continue slotLoop;
                }

            }
        }

        return (removed == amount);
    }

    public void sendBungeeMessage(String player, String message) {
        try {
            ByteArrayOutputStream b = new ByteArrayOutputStream();
            DataOutputStream out = new DataOutputStream(b);

            out.writeUTF("Message");
            out.writeUTF(player);
            out.writeUTF(message);

            if (!plugin.getServer().getOnlinePlayers().isEmpty()) {
                plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
                    Player p = plugin.getServer().getOnlinePlayers().iterator().next();
                    p.sendPluginMessage(plugin, "BungeeCord", b.toByteArray());
                });
            }
        } catch (Exception e) {
            plugin.debug("Failed to send bungee message");
            plugin.debug(e);
            plugin.getLogger().warning("Failed to send BungeeCord message");
        }
    }
} public class ShopItemListener implements Listener {

    private ShopUtils shopUtils;

    public ShopItemListener(ShopChest plugin) {
        this.shopUtils = plugin.getShopUtils();
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBlockPlace(BlockPlaceEvent e) {
        Block b = e.getBlockPlaced();
        Block below = b.getRelative(BlockFace.DOWN);

        if (shopUtils.isShop(below.getLocation())) {
            Shop shop = shopUtils.getShop(below.getLocation());
            if (shop.getItem() != null) {
                shop.getItem().resetForPlayer(e.getPlayer());
            }
            e.setCancelled(true);
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onMultiBlockPlace(BlockMultiPlaceEvent e) {
        for (BlockState blockState : e.getReplacedBlockStates()) {
            Block below = blockState.getBlock().getRelative(BlockFace.DOWN);

            if (shopUtils.isShop(below.getLocation())) {
                Shop shop = shopUtils.getShop(below.getLocation());
                if (shop.getItem() != null) {
                    shop.getItem().resetForPlayer(e.getPlayer());
                }
                e.setCancelled(true);
            }
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onPistonExtend(BlockPistonExtendEvent e) {
        // If the piston would only move itself
        Block airAfterPiston = e.getBlock().getRelative(e.getDirection());
        Block belowAir = airAfterPiston.getRelative(BlockFace.DOWN);
        if (shopUtils.isShop(belowAir.getLocation())) {
            e.setCancelled(true);
            return;
        }

        for (Block b : e.getBlocks()) {
            Block newBlock = b.getRelative(e.getDirection());
            Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
            if (shopUtils.isShop(belowNewBlock.getLocation())) e.setCancelled(true);
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onPistonRetract(BlockPistonRetractEvent e) {
        for (Block b : e.getBlocks()) {
            Block newBlock = b.getRelative(e.getDirection());
            Block belowNewBlock = newBlock.getRelative(BlockFace.DOWN);
            if (shopUtils.isShop(belowNewBlock.getLocation())) {
                e.setCancelled(true);
                for (Player p : Bukkit.getOnlinePlayers()) {
                    Shop shop = shopUtils.getShop(belowNewBlock.getLocation());
                    if (shop.getItem() != null) {
                        shop.getItem().resetForPlayer(p);
                    }
                }
            }
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onLiquidFlow(BlockFromToEvent e) {
        Block b = e.getToBlock();
        Block below = b.getRelative(BlockFace.DOWN);

        if (shopUtils.isShop(below.getLocation())) e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBucketEmpty(PlayerBucketEmptyEvent e) {
        Block clicked = e.getBlockClicked();
        Block underWater = clicked.getRelative(BlockFace.DOWN).getRelative(e.getBlockFace());

        if (shopUtils.isShop(clicked.getLocation())) {
            if (e.getBucket() == Material.LAVA_BUCKET) {
                Shop shop = shopUtils.getShop(clicked.getLocation());
                if (shop.getItem() != null) {
                    shop.getItem().resetForPlayer(e.getPlayer());
                }
            }
        } else if (shopUtils.isShop(underWater.getLocation())) {
            if (e.getBucket() == Material.LAVA_BUCKET) {
                Shop shop = shopUtils.getShop(underWater.getLocation());
                if (shop.getItem() != null) {
                    shop.getItem().resetForPlayer(e.getPlayer());
                }
            }
        } else {
            return;
        }

        e.setCancelled(true);
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onStructureGrow(StructureGrowEvent e) {
        for (BlockState state : e.getBlocks()) {
            Block newBlock = state.getBlock();
            if (shopUtils.isShop(newBlock.getLocation()) || shopUtils.isShop(newBlock.getRelative(BlockFace.DOWN).getLocation())) {
                e.setCancelled(true);
            }
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBlockGrow(BlockGrowEvent e) {
        Block newBlock = e.getNewState().getBlock();
        if (shopUtils.isShop(newBlock.getLocation()) || shopUtils.isShop(newBlock.getRelative(BlockFace.DOWN).getLocation())) {
            e.setCancelled(true);
        }
    }

    @EventHandler(priority = EventPriority.HIGH)
    public void onBlockSpread(BlockSpreadEvent e) {
        Block newBlock = e.getNewState().getBlock();
        if (shopUtils.isShop(newBlock.getLocation()) || shopUtils.isShop(newBlock.getRelative(BlockFace.DOWN).getLocation())) {
            e.setCancelled(true);
        }
    }

} public class ShopUpdateListener implements Listener {

    private final ShopChest plugin;
    private final Set<Chunk> newLoadedChunks = new HashSet<>();

    public ShopUpdateListener(ShopChest plugin) {
        this.plugin = plugin;
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onInventoryUpdate(InventoryMoveItemEvent e) {
        if (!plugin.getHologramFormat().isDynamic()) return;

        Location loc = null;

        if (e.getSource().getHolder() instanceof Chest) {
            loc =  ((Chest) e.getSource().getHolder()).getLocation();
        } else if (e.getSource().getHolder() instanceof DoubleChest) {
            loc =  ((DoubleChest) e.getSource().getHolder()).getLocation();
        } else if (e.getDestination().getHolder() instanceof Chest) {
            loc =  ((Chest) e.getDestination().getHolder()).getLocation();
        } else if (e.getDestination().getHolder() instanceof DoubleChest) {
            loc =  ((DoubleChest) e.getDestination().getHolder()).getLocation();
        }

        if (loc != null) {
            Shop shop = plugin.getShopUtils().getShop(loc);
            if (shop != null) shop.updateHologramText();
        }
    }

    @EventHandler
    public void onPlayerLeave(PlayerQuitEvent e) {
        // If done without delay, Bukkit#getOnlinePlayers() would still
        // contain the player even though he left, so the shop updater
        // would show the shop again.
        new BukkitRunnable(){
            @Override
            public void run() {
                for (Shop shop : plugin.getShopUtils().getShops()) {
                    if (shop.hasItem()) {
                        shop.getItem().resetVisible(e.getPlayer());
                    }
                    if (shop.hasHologram()) {
                        shop.getHologram().resetVisible(e.getPlayer());
                    }
                }
        
                plugin.getShopUtils().resetPlayerLocation(e.getPlayer());
            }
        }.runTaskLater(plugin, 1L);
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onPlayerTeleport(PlayerTeleportEvent e) {
        Location from = e.getFrom();
        Location to = e.getTo();
        final Player p = e.getPlayer();

        // Wait till the chunk should have loaded on the client
        if (!from.getWorld().getName().equals(to.getWorld().getName())
                || from.getChunk().getX() != to.getChunk().getX()
                || from.getChunk().getZ() != to.getChunk().getZ()) {
            new BukkitRunnable() {
                @Override
                public void run() {
                    plugin.getUpdater().queue(() -> {
                        if (p.isOnline()) {
                            for (Shop shop : plugin.getShopUtils().getShops()) {
                                if (shop.hasItem()) {
                                    shop.getItem().hidePlayer(p);
                                }
                                if (shop.hasHologram()) {
                                    shop.getHologram().hidePlayer(p);
                                }
                            }
                            plugin.getShopUtils().resetPlayerLocation(p);
                        }
                    });
                    plugin.getUpdater().updateShops(p);
                }
            }.runTaskLater(plugin, 15L);
        }
    }

    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
    public void onPlayerMove(PlayerMoveEvent e) {
        plugin.getUpdater().updateShops(e.getPlayer());
    }

    @EventHandler
    public void onChunkLoad(ChunkLoadEvent e) {
        if (!plugin.getShopDatabase().isInitialized()) {
            return;
        }

        // Wait 10 ticks after first event is triggered, so that multiple
        // chunk loads can be handled at the same time without having to
        // send a database request for each chunk.
        if (newLoadedChunks.isEmpty()) {
            new BukkitRunnable(){
                @Override
                public void run() {
                    int chunkCount = newLoadedChunks.size();
                    plugin.getShopUtils().loadShops(newLoadedChunks.toArray(new Chunk[chunkCount]), new Callback<Integer>(plugin) {
                        @Override
                        public void onResult(Integer result) {
                            if (result == 0) {
                                return;
                            }
                            plugin.debug("Loaded " + result + " shops in " + chunkCount + " chunks");
                        }
            
                        @Override
                        public void onError(Throwable throwable) {
                            // Database connection probably failed => disable plugin to prevent more errors
                            plugin.getLogger().severe("Failed to load shops in newly loaded chunks");
                            plugin.debug("Failed to load shops in newly loaded chunks");
                            if (throwable != null) plugin.debug(throwable);
                        }
                    });
                    newLoadedChunks.clear();
                }
            }.runTaskLater(plugin, 10L);
        }

        newLoadedChunks.add(e.getChunk());
    }
} public class WorldGuardListener implements Listener {

    private ShopChest plugin;

    public WorldGuardListener(ShopChest plugin) {
        this.plugin = plugin;
    }


    private boolean isAllowed(Player player, Location location) {
        ClickType clickType = ClickType.getPlayerClickType(player);

        if (clickType != null && clickType.getClickType() == EnumClickType.CREATE) {
            // If the player is about to create a shop, but does not have
            // access to the chest, show the 'permission denied' message
            // (if not previously set to allowed by another plugin).
            // If the player can open the chest, that message should be hidden.
            WorldGuardWrapper wgWrapper = WorldGuardWrapper.getInstance();
            Optional<IWrappedFlag<WrappedState>> flag = wgWrapper.getFlag("chest-access", WrappedState.class);
            if (!flag.isPresent()) plugin.debug("WorldGuard flag 'chest-access' is not present!");
            WrappedState state = flag.map(f -> wgWrapper.queryFlag(player, location, f).orElse(WrappedState.DENY)).orElse(WrappedState.DENY);
            return state == WrappedState.ALLOW;
        }

        Shop shop = plugin.getShopUtils().getShop(location);

        if (shop != null) {
            // Don't show 'permission denied' messages for any kind of
            // shop interaction even if block interaction is not
            // allowed in the region.
            return true;
        }

        return false;
    }

    @EventHandler(priority = EventPriority.LOW)
    public void onUseBlock(WrappedUseBlockEvent event) {
        if (Config.enableWorldGuardIntegration) {
            Player player = event.getPlayer();

            if (event.getOriginalEvent() instanceof PlayerInteractEvent) {
                Block block = event.getBlocks().get(0);
                Material type = block.getType();
                
                if (type == Material.CHEST || type == Material.TRAPPED_CHEST) {
                    if (isAllowed(player, block.getLocation())) {
                        event.setResult(Result.ALLOW);
                    }
                }
            } else if (event.getOriginalEvent() instanceof InventoryOpenEvent) {
                InventoryOpenEvent orig = (InventoryOpenEvent) event.getOriginalEvent();

                if (orig.getInventory().getHolder() instanceof Chest) {
                    if (isAllowed(player, ((Chest) orig.getInventory().getHolder()).getLocation())) {
                        event.setResult(Result.ALLOW);
                    }
                }
            }
        }
    }

} public class Shop {

    public enum ShopType {
        NORMAL,
        ADMIN,
    }

    private static class PreCreateResult {
        private final Inventory inventory;
        private final Chest[] chests;
        private final BlockFace face;

        private PreCreateResult(Inventory inventory, Chest[] chests, BlockFace face) {
            this.inventory = inventory;
            this.chests = chests;
            this.face = face;
        }
    }

    private final ShopChest plugin;
    private final OfflinePlayer vendor;
    private final ShopProduct product;
    private final Location location;
    private final double buyPrice;
    private final double sellPrice;
    private final ShopType shopType;

    private boolean created;
    private int id;
    private Hologram hologram;
    private Location holoLocation;
    private ShopItem item;

    public Shop(int id, ShopChest plugin, OfflinePlayer vendor, ShopProduct product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
        this.id = id;
        this.plugin = plugin;
        this.vendor = vendor;
        this.product = product;
        this.location = location;
        this.buyPrice = buyPrice;
        this.sellPrice = sellPrice;
        this.shopType = shopType;
    }

    public Shop(ShopChest plugin, OfflinePlayer vendor, ShopProduct product, Location location, double buyPrice, double sellPrice, ShopType shopType) {
        this(-1, plugin, vendor, product, location, buyPrice, sellPrice, shopType);
    }

    /**
     * Test if this shop is equals to another
     *
     * @param o Other object to test against
     * @return true if we are sure they are the same, false otherwise
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Shop shop = (Shop) o;

        // id = -1 means temp shop
        return id != -1 && id == shop.id;
    }

    @Override
    public int hashCode() {
        return id != -1 ? id : super.hashCode();
    }

    /**
     * Create the shop
     *
     * @param showConsoleMessages to log exceptions to console
     * @return Whether is was created or not
     */
    public boolean create(boolean showConsoleMessages) {
        if (created) return false;

        plugin.debug("Creating shop (#" + id + ")");

        Block b = location.getBlock();
        if (b.getType() != Material.CHEST && b.getType() != Material.TRAPPED_CHEST) {
            ChestNotFoundException ex = new ChestNotFoundException(String.format("No Chest found in world '%s' at location: %d; %d; %d",
                    b.getWorld().getName(), b.getX(), b.getY(), b.getZ()));
            plugin.getShopUtils().removeShop(this, Config.removeShopOnError);
            if (showConsoleMessages) plugin.getLogger().severe(ex.getMessage());
            plugin.debug("Failed to create shop (#" + id + ")");
            plugin.debug(ex);
            return false;
        } else if ((!ItemUtils.isAir(b.getRelative(BlockFace.UP).getType()))) {
            NotEnoughSpaceException ex = new NotEnoughSpaceException(String.format("No space above chest in world '%s' at location: %d; %d; %d",
                    b.getWorld().getName(), b.getX(), b.getY(), b.getZ()));
            plugin.getShopUtils().removeShop(this, Config.removeShopOnError);
            if (showConsoleMessages) plugin.getLogger().severe(ex.getMessage());
            plugin.debug("Failed to create shop (#" + id + ")");
            plugin.debug(ex);
            return false;
        }

        PreCreateResult preResult = preCreateHologram();

        if (preResult == null) {
            return false;
        }

        plugin.getShopCreationThreadPool().execute(() -> {
            if (hologram == null || !hologram.exists()) createHologram(preResult);
            if (item == null) createItem();

            // Update shops for players in the same world after creation has finished
            plugin.getUpdater().queue(() -> {
                for (Player player : location.getWorld().getPlayers()) {
                    plugin.getShopUtils().resetPlayerLocation(player);
                }
            });
            plugin.getUpdater().updateShops(location.getWorld());
        });

        created = true;
        return true;
    }

    /**
     * Removes the hologram of the shop
     */
    public void removeHologram() {
        if (hologram != null && hologram.exists()) {
            plugin.debug("Removing hologram (#" + id + ")");
            hologram.remove();
        }
    }

    /**
     * Removes the floating item of the shop
     */
    public void removeItem() {
        if (item != null) {
            plugin.debug("Removing shop item (#" + id + ")");
            item.remove();
        }
    }

    /**
     * <p>Creates the floating item of the shop</p>
     * <b>Call this after {@link #createHologram()}, because it depends on the hologram's location</b>
     */
    private void createItem() {
        plugin.debug("Creating item (#" + id + ")");

        Location itemLocation;

        itemLocation = new Location(location.getWorld(), holoLocation.getX(), location.getY() + 0.9, holoLocation.getZ());
        item = new ShopItem(plugin, product.getItemStack(), itemLocation);
    }

    /**
     * Runs everything that needs to be called synchronously in order 
     * to prepare creating the hologram.
     */
    private PreCreateResult preCreateHologram() {
        plugin.debug("Creating hologram (#" + id + ")");

        InventoryHolder ih = getInventoryHolder();

        if (ih == null) return null;

        Chest[] chests = new Chest[2];
        BlockFace face;

        if (ih instanceof DoubleChest) {
            DoubleChest dc = (DoubleChest) ih;
            Chest r = (Chest) dc.getRightSide();
            Chest l = (Chest) dc.getLeftSide();

            chests[0] = r;
            chests[1] = l;
        } else {
            chests[0] = (Chest) ih;
        }

        if (Utils.getMajorVersion() < 13) {
            face = ((org.bukkit.material.Directional) chests[0].getData()).getFacing();
        } else {
            face = ((Directional) chests[0].getBlockData()).getFacing();
        }

        return new PreCreateResult(ih.getInventory(), chests, face);
    }

    /**
     * Acuatlly creates the hologram (async)
     */
    private void createHologram(PreCreateResult preResult) {
        String[] holoText = getHologramText(preResult.inventory);
        holoLocation = getHologramLocation(preResult.chests, preResult.face);

        new BukkitRunnable(){
            @Override
            public void run() {
                hologram = new Hologram(plugin, holoText, holoLocation);
            }
        }.runTask(plugin);
    }

    /**
     * Keep hologram text up to date.
     * <p><b>Has to be called synchronously!</b></p>
     */
    public void updateHologramText() {
        String[] lines = getHologramText(getInventoryHolder().getInventory());
        String[] currentLines = hologram.getLines();

        int max = Math.max(lines.length, currentLines.length);

        for (int i = 0; i < max; i++) {
            if (i < lines.length) {
                hologram.setLine(i, lines[i]);
            } else {
                hologram.removeLine(i);
            }
        }
    }

    private String[] getHologramText(Inventory inventory) {
        List<String> lines = new ArrayList<>();

        ItemStack itemStack = getProduct().getItemStack();

        Map<HologramFormat.Requirement, Object> requirements = new EnumMap<>(HologramFormat.Requirement.class);
        requirements.put(HologramFormat.Requirement.VENDOR, getVendor().getName());
        requirements.put(HologramFormat.Requirement.AMOUNT, getProduct().getAmount());
        requirements.put(HologramFormat.Requirement.ITEM_TYPE, itemStack.getType() + (itemStack.getDurability() > 0 ? ":" + itemStack.getDurability() : ""));
        requirements.put(HologramFormat.Requirement.ITEM_NAME, itemStack.hasItemMeta() ? itemStack.getItemMeta().getDisplayName() : null);
        requirements.put(HologramFormat.Requirement.HAS_ENCHANTMENT, !LanguageUtils.getEnchantmentString(ItemUtils.getEnchantments(itemStack)).isEmpty());
        requirements.put(HologramFormat.Requirement.BUY_PRICE, getBuyPrice());
        requirements.put(HologramFormat.Requirement.SELL_PRICE, getSellPrice());
        requirements.put(HologramFormat.Requirement.HAS_POTION_EFFECT, ItemUtils.getPotionEffect(itemStack) != null);
        requirements.put(HologramFormat.Requirement.IS_MUSIC_DISC, itemStack.getType().isRecord());
        requirements.put(HologramFormat.Requirement.IS_POTION_EXTENDED, ItemUtils.isExtendedPotion(itemStack));
        requirements.put(HologramFormat.Requirement.IS_WRITTEN_BOOK, itemStack.getType() == Material.WRITTEN_BOOK);
        requirements.put(HologramFormat.Requirement.IS_BANNER_PATTERN, ItemUtils.isBannerPattern(itemStack));
        requirements.put(HologramFormat.Requirement.ADMIN_SHOP, getShopType() == ShopType.ADMIN);
        requirements.put(HologramFormat.Requirement.NORMAL_SHOP, getShopType() == ShopType.NORMAL);
        requirements.put(HologramFormat.Requirement.IN_STOCK, Utils.getAmount(inventory, itemStack));
        requirements.put(HologramFormat.Requirement.MAX_STACK, itemStack.getMaxStackSize());
        requirements.put(HologramFormat.Requirement.CHEST_SPACE, Utils.getFreeSpaceForItem(inventory, itemStack));
        requirements.put(HologramFormat.Requirement.DURABILITY, itemStack.getDurability());

        Map<Placeholder, Object> placeholders = new EnumMap<>(Placeholder.class);
        placeholders.put(Placeholder.VENDOR, getVendor().getName());
        placeholders.put(Placeholder.AMOUNT, getProduct().getAmount());
        placeholders.put(Placeholder.ITEM_NAME, getProduct().getLocalizedName());
        placeholders.put(Placeholder.ENCHANTMENT, LanguageUtils.getEnchantmentString(ItemUtils.getEnchantments(itemStack)));
        placeholders.put(Placeholder.BUY_PRICE, getBuyPrice());
        placeholders.put(Placeholder.SELL_PRICE, getSellPrice());
        placeholders.put(Placeholder.POTION_EFFECT, LanguageUtils.getPotionEffectName(itemStack));
        placeholders.put(Placeholder.MUSIC_TITLE, LanguageUtils.getMusicDiscName(itemStack.getType()));
        placeholders.put(Placeholder.BANNER_PATTERN_NAME, LanguageUtils.getBannerPatternName(itemStack.getType()));
        placeholders.put(Placeholder.GENERATION, LanguageUtils.getBookGenerationName(itemStack));
        placeholders.put(Placeholder.STOCK, Utils.getAmount(inventory, itemStack));
        placeholders.put(Placeholder.MAX_STACK, itemStack.getMaxStackSize());
        placeholders.put(Placeholder.CHEST_SPACE, Utils.getFreeSpaceForItem(inventory, itemStack));
        placeholders.put(Placeholder.DURABILITY, itemStack.getDurability());

        int lineCount = plugin.getHologramFormat().getLineCount();

        for (int i = 0; i < lineCount; i++) {
            String format = plugin.getHologramFormat().getFormat(i, requirements, placeholders);
            for (Placeholder placeholder : placeholders.keySet()) {
                String replace;

                switch (placeholder) {
                    case BUY_PRICE:
                        replace = plugin.getEconomy().format(getBuyPrice());
                        break;
                    case SELL_PRICE:
                        replace = plugin.getEconomy().format(getSellPrice());
                        break;
                    default:
                        replace = String.valueOf(placeholders.get(placeholder));
                }

                format = format.replace(placeholder.toString(), replace);
            }

            if (!format.isEmpty()) {
                lines.add(format);
            }
        }

        return lines.toArray(new String[0]);
    }

    private Location getHologramLocation(Chest[] chests, BlockFace face) {
        World w = location.getWorld();
        int x = location.getBlockX();
        int y  = location.getBlockY();
        int z = location.getBlockZ();

        Location holoLocation = new Location(w, x, y, z);

        double deltaY = -0.6;

        if (Config.hologramFixedBottom) deltaY = -0.85;

        if (chests[1] != null) {
            Chest c1 = Utils.getMajorVersion() >= 13 && (face == BlockFace.NORTH || face == BlockFace.EAST) ? chests[1] : chests[0];
            Chest c2 = Utils.getMajorVersion() >= 13 && (face == BlockFace.NORTH || face == BlockFace.EAST) ? chests[0] : chests[1];

            if (holoLocation.equals(c1.getLocation())) {
                if (c1.getX() != c2.getX()) {
                    holoLocation.add(0, deltaY, 0.5);
                } else if (c1.getZ() != c2.getZ()) {
                    holoLocation.add(0.5, deltaY, 0);
                } else {
                    holoLocation.add(0.5, deltaY, 0.5);
                }
            } else {
                if (c1.getX() != c2.getX()) {
                    holoLocation.add(1, deltaY, 0.5);
                } else if (c1.getZ() != c2.getZ()) {
                    holoLocation.add(0.5, deltaY, 1);
                } else {
                    holoLocation.add(0.5, deltaY, 0.5);
                }
            }
        } else {
            holoLocation.add(0.5, deltaY, 0.5);
        }

        holoLocation.add(0, Config.hologramLift, 0);

        return holoLocation;
    }

    /**
     * @return Whether an ID has been assigned to the shop
     */
    public boolean hasId() {
        return id != -1;
    }

    /**
     * <p>Assign an ID to the shop.</p>
     * Only works for the first time!
     * @param id ID to set for this shop
     */
    public void setId(int id) {
        if (this.id == -1) {
            this.id = id;
        }
    }

    /**
     * @return Whether the shop has already been created
     */
    public boolean isCreated() {
        return created;
    }

    /**
     * @return The ID of the shop
     */
    public int getID() {
        return id;
    }

    /**
     * @return Vendor of the shop; probably the creator of it
     */
    public OfflinePlayer getVendor() {
        return vendor;
    }

    /**
     * @return Product the shop sells (or buys)
     */
    public ShopProduct getProduct() {
        return product;
    }

    /**
     * @return Location of (one of) the shop's chest
     */
    public Location getLocation() {
        return location;
    }

    /**
     * @return Buy price of the shop
     */
    public double getBuyPrice() {
        return buyPrice;
    }

    /**
     * @return Sell price of the shop
     */
    public double getSellPrice() {
        return sellPrice;
    }

    /**
     * @return Type of the shop
     */
    public ShopType getShopType() {
        return shopType;
    }

    /**
     * @return Hologram of the shop
     */
    public Hologram getHologram() {
        return hologram;
    }

    /**
     * @return Floating {@link ShopItem} of the shop
     */
    public ShopItem getItem() {
        return item;
    }

    public boolean hasHologram() {
        return hologram != null;
    }

    public boolean hasItem() {
        return item != null;
    }

    /**
     * @return {@link InventoryHolder} of the shop or <b>null</b> if the shop has no chest.
     */
    public InventoryHolder getInventoryHolder() {
        Block b = getLocation().getBlock();

        if (b.getType() == Material.CHEST || b.getType() == Material.TRAPPED_CHEST) {
            Chest chest = (Chest) b.getState();
            return chest.getInventory().getHolder();
        }

        return null;
    }

} public enum ShopType {
    NORMAL,
    ADMIN,
} public abstract class Database {
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private boolean initialized;

    String tableShops;
    String tableLogs;
    String tableLogouts;
    String tableFields;

    ShopChest plugin;
    HikariDataSource dataSource;

    protected Database(ShopChest plugin) {
        this.plugin = plugin;
    }

    abstract HikariDataSource getDataSource();

    abstract String getQueryCreateTableShops();

    abstract String getQueryCreateTableLog();

    abstract String getQueryCreateTableLogout();

    abstract String getQueryCreateTableFields();

    abstract String getQueryGetTable();

    private int getDatabaseVersion() throws SQLException {
        try (Connection con = dataSource.getConnection()) {
            try (Statement s = con.createStatement()) {
                ResultSet rs = s.executeQuery("SELECT value FROM " + tableFields + " WHERE field='version'");
                if (rs.next()) {
                    return rs.getInt("value");
                }
            }
        }
        return 0;
    }

    private void setDatabaseVersion(int version) throws SQLException {
        String queryUpdateVersion = "REPLACE INTO " + tableFields + " VALUES ('version', ?)";
        try (Connection con = dataSource.getConnection()) {
            try (PreparedStatement ps = con.prepareStatement(queryUpdateVersion)) {
                ps.setInt(1, version);
                ps.executeUpdate();
            }
        }
    }

    private boolean update() throws SQLException {
        String queryGetTable = getQueryGetTable();

        try (Connection con = dataSource.getConnection()) {
            boolean needsUpdate1 = false; // update "shop_log" to "economy_logs" and update "shops" with prefixes
            boolean needsUpdate2 = false; // create field table and set database version

            try (PreparedStatement ps = con.prepareStatement(queryGetTable)) {
                ps.setString(1, "shop_log");
                ResultSet rs = ps.executeQuery();
                if (rs.next()) {
                    needsUpdate1 = true;
                }
            }

            try (PreparedStatement ps = con.prepareStatement(queryGetTable)) {
                ps.setString(1, tableFields);
                ResultSet rs = ps.executeQuery();
                if (!rs.next()) {
                    needsUpdate2 = true;
                }
            }

            if (needsUpdate1) {
                String queryRenameTableLogouts = "ALTER TABLE player_logout RENAME TO " + tableLogouts;
                String queryRenameTableLogs = "ALTER TABLE shop_log RENAME TO backup_shop_log"; // for backup
                String queryRenameTableShops = "ALTER TABLE shops RENAME TO backup_shops"; // for backup

                plugin.getLogger().info("Updating database... (#1)");

                // Rename logout table
                try (Statement s = con.createStatement()) {
                    s.executeUpdate(queryRenameTableLogouts);
                }

                // Backup shops table
                try (Statement s = con.createStatement()) {
                    s.executeUpdate(queryRenameTableShops);
                }

                // Backup log table
                try (Statement s = con.createStatement()) {
                    s.executeUpdate(queryRenameTableLogs);
                }

                // Create new shops table
                try (Statement s = con.createStatement()) {
                    s.executeUpdate(getQueryCreateTableShops());
                }

                // Create new log table
                try (Statement s = con.createStatement()) {
                    s.executeUpdate(getQueryCreateTableLog());
                }

                // Convert shop table
                try (Statement s = con.createStatement()) {
                    ResultSet rs = s.executeQuery("SELECT id,product FROM backup_shops");
                    while (rs.next()) {
                        ItemStack is = Utils.decode(rs.getString("product"));
                        int amount = is.getAmount();
                        is.setAmount(1);
                        String product = Utils.encode(is);
                        
                        String insertQuery = "INSERT INTO " + tableShops + " SELECT id,vendor,?,?,world,x,y,z,buyprice,sellprice,shoptype FROM backup_shops WHERE id = ?";
                        try (PreparedStatement ps = con.prepareStatement(insertQuery)) {
                            ps.setString(1, product);
                            ps.setInt(2, amount);
                            ps.setInt(3, rs.getInt("id"));
                            ps.executeUpdate();
                        }
                    }
                }

                // Convert log table
                try (Statement s = con.createStatement()) {
                    ResultSet rs = s.executeQuery("SELECT id,timestamp,executor,product,vendor FROM backup_shop_log");
                    while (rs.next()) {
                        String timestamp = rs.getString("timestamp");
                        long time = 0L;

                        try {
                            time = dateFormat.parse(timestamp).getTime();
                        } catch (ParseException e) {
                            plugin.debug("Failed to parse timestamp '" + timestamp + "': Time is set to 0");
                            plugin.debug(e);
                        }

                        String player = rs.getString("executor");
                        String playerUuid = player.substring(0, 36);
                        String playerName = player.substring(38, player.length() - 1);

                        String oldProduct = rs.getString("product");
                        String product = oldProduct.split(" x ")[1];
                        int amount = Integer.valueOf(oldProduct.split(" x ")[0]);

                        String vendor = rs.getString("vendor");
                        String vendorUuid = vendor.substring(0, 36);
                        String vendorName = vendor.substring(38).replaceAll("\\)( \\(ADMIN\\))?", "");
                        boolean admin = vendor.endsWith("(ADMIN)");
                        
                        String insertQuery = "INSERT INTO " + tableLogs + " SELECT id,-1,timestamp,?,?,?,?,'Unknown',?,?,?,?,world,x,y,z,price,type FROM backup_shop_log WHERE id = ?";
                        try (PreparedStatement ps = con.prepareStatement(insertQuery)) {
                            ps.setLong(1, time);
                            ps.setString(2, playerName);
                            ps.setString(3, playerUuid);
                            ps.setString(4, product);
                            ps.setInt(5, amount);
                            ps.setString(6, vendorName);
                            ps.setString(7, vendorUuid);
                            ps.setBoolean(8, admin);
                            ps.setInt(9, rs.getInt("id"));
                            ps.executeUpdate();
                        }
                    }
                }
            }

            if (needsUpdate2) {
                plugin.getLogger().info("Updating database... (#2)");

                // Create fields table
                try (Statement s = con.createStatement()) {
                    s.executeUpdate(getQueryCreateTableFields());
                }

                setDatabaseVersion(2);
            }
            
            int databaseVersion = getDatabaseVersion();

            if (databaseVersion < 3) {
                // plugin.getLogger().info("Updating database... (#3)");

                // Update database structure...

                // setDatabaseVersion(3);
            }

            int newDatabaseVersion = getDatabaseVersion();
            return needsUpdate1 || needsUpdate2 || newDatabaseVersion > databaseVersion;
        }
    }

    /**
     * <p>(Re-)Connects to the the database and initializes it.</p>
     * 
     * All tables are created if necessary and if the database
     * structure has to be updated, that is done as well.
     * 
     * @param callback Callback that - if succeeded - returns the amount of shops
     *                 that were found (as {@code int})
     */
    public void connect(final Callback<Integer> callback) {
        if (!Config.databaseTablePrefix.matches("^([a-zA-Z0-9\\-\\_]+)?$")) {
            // Only letters, numbers dashes and underscores are allowed
            plugin.getLogger().severe("Database table prefix contains illegal letters, using 'shopchest_' prefix.");
            Config.databaseTablePrefix = "shopchest_";
        }

        this.tableShops = Config.databaseTablePrefix + "shops";
        this.tableLogs = Config.databaseTablePrefix + "economy_logs";
        this.tableLogouts = Config.databaseTablePrefix + "player_logouts";
        this.tableFields = Config.databaseTablePrefix + "fields";

        new BukkitRunnable() {
            @Override
            public void run() {
                disconnect();

                try {
                    dataSource = getDataSource();
                } catch (Exception e) {
                    callback.onError(e);
                    plugin.debug(e);
                    return;
                }

                if (dataSource == null) {
                    Exception e = new IllegalStateException("Data source is null");
                    callback.onError(e);
                    plugin.debug(e);
                    return;
                }

                try (Connection con = dataSource.getConnection()) {
                    // Update database structure if necessary
                    if (update()) {
                        plugin.getLogger().info("Updating database finished");
                    }

                    // Create shop table
                    try (Statement s = con.createStatement()) {
                        s.executeUpdate(getQueryCreateTableShops());
                    }

                    // Create log table
                    try (Statement s = con.createStatement()) {
                        s.executeUpdate(getQueryCreateTableLog());
                    }

                    // Create logout table
                    try (Statement s = con.createStatement()) {
                        s.executeUpdate(getQueryCreateTableLogout());
                    }

                    // Create fields table
                    try (Statement s = con.createStatement()) {
                        s.executeUpdate(getQueryCreateTableFields());
                    }

                    // Clean up economy log
                    if (Config.cleanupEconomyLogDays > 0) {
                        cleanUpEconomy(false);
                    }

                    // Count shops entries in database
                    try (Statement s = con.createStatement()) {
                        ResultSet rs = s.executeQuery("SELECT COUNT(id) FROM " + tableShops);
                        if (rs.next()) {
                            int count = rs.getInt(1);
                            initialized = true;
                            
                            plugin.debug("Initialized database with " + count + " entries");

                            if (callback != null) {
                                callback.callSyncResult(count);
                            }
                        } else {
                            throw new SQLException("Count result set has no entries");
                        }
                    }
                } catch (SQLException e) {
                    if (callback != null) {
                        callback.callSyncError(e);
                    }
                    
                    plugin.getLogger().severe("Failed to initialize or connect to database");
                    plugin.debug("Failed to initialize or connect to database");
                    plugin.debug(e);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Remove a shop from the database
     *
     * @param shop     Shop to remove
     * @param callback Callback that - if succeeded - returns {@code null}
     */
    public void removeShop(final Shop shop, final Callback<Void> callback) {
        new BukkitRunnable() {
            @Override
            public void run() {
                try (Connection con = dataSource.getConnection();
                        PreparedStatement ps = con.prepareStatement("DELETE FROM " + tableShops + " WHERE id = ?")) {
                    ps.setInt(1, shop.getID());
                    ps.executeUpdate();

                    plugin.debug("Removing shop from database (#" + shop.getID() + ")");

                    if (callback != null) {
                        callback.callSyncResult(null);
                    }
                } catch (SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to remove shop from database");
                    plugin.debug("Failed to remove shop from database (#" + shop.getID() + ")");
                    plugin.debug(ex);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Get shop amounts for each player
     * 
     * @param callback Callback that returns a map of each player's shop amount
     */
    public void getShopAmounts(final Callback<Map<UUID, Integer>> callback) {
        new BukkitRunnable(){
            @Override
            public void run() {
                try (Connection con = dataSource.getConnection();
                        Statement s = con.createStatement()) {
                    ResultSet rs = s.executeQuery("SELECT vendor, COUNT(*) AS count FROM " + tableShops + " WHERE shoptype = 'NORMAL' GROUP BY vendor");

                    plugin.debug("Getting shop amounts from database");

                    Map<UUID, Integer> result = new HashMap<>();
                    while (rs.next()) {
                        UUID uuid = UUID.fromString(rs.getString("vendor"));
                        result.put(uuid, rs.getInt("count"));
                    }

                    if (callback != null) {
                        callback.callSyncResult(result);
                    }
                } catch (SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to get shop amounts from database");
                    plugin.debug("Failed to get shop amounts from database");
                    plugin.debug(ex);
                }        
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Get all shops of a player, including admin shops
     * 
     * @param callback Callback that returns a set of shops of the given player
     */
    public void getShops(UUID playerUuid, final Callback<Collection<Shop>> callback) {
        new BukkitRunnable(){
            @Override
            public void run() {
                try (Connection con = dataSource.getConnection();
                        PreparedStatement ps = con.prepareStatement("SELECT * FROM " + tableShops + " WHERE vendor = ?")) {
                    ps.setString(1, playerUuid.toString());
                    ResultSet rs = ps.executeQuery();

                    plugin.debug("Getting a player's shops from database");

                    Set<Shop> result = new HashSet<>();
                    while (rs.next()) {
                        int id = rs.getInt("id");

                        plugin.debug("Getting Shop... (#" + id + ")");

                        int x = rs.getInt("x");
                        int y = rs.getInt("y");
                        int z = rs.getInt("z");

                        World world = plugin.getServer().getWorld(rs.getString("world"));
                        Location location = new Location(world, x, y, z);
                        OfflinePlayer vendor = Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor")));
                        ItemStack itemStack = Utils.decode(rs.getString("product"));
                        int amount = rs.getInt("amount");
                        ShopProduct product = new ShopProduct(itemStack, amount);
                        double buyPrice = rs.getDouble("buyprice");
                        double sellPrice = rs.getDouble("sellprice");
                        ShopType shopType = ShopType.valueOf(rs.getString("shoptype"));

                        plugin.debug("Initializing new shop... (#" + id + ")");

                        result.add(new Shop(id, plugin, vendor, product, location, buyPrice, sellPrice, shopType));
                    }

                    if (callback != null) {
                        callback.callSyncResult(result);
                    }
                } catch (SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to get player's shops from database");
                    plugin.debug("Failed to get player's shops from database");
                    plugin.debug(ex);
                }        
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Get all shops from the database that are located in the given chunks
     * 
     * @param chunks Shops in these chunks are retrieved
     * @param callback Callback that returns an immutable collection of shops if succeeded
     */
    public void getShopsInChunks(final Chunk[] chunks, final Callback<Collection<Shop>> callback) {
        // Split chunks into packages containing each {splitSize} chunks at max
        int splitSize = 80;
        int parts = (int) Math.ceil(chunks.length / (double) splitSize);
        Chunk[][] splitChunks = new Chunk[parts][];
        for (int i = 0; i < parts; i++) {
            int size = i < parts - 1 ? splitSize : chunks.length % splitSize;
            Chunk[] tmp = new Chunk[size];
            System.arraycopy(chunks, i * splitSize, tmp, 0, size);
            splitChunks[i] = tmp;
        }

        new BukkitRunnable(){
            @Override
            public void run() {
                List<Shop> shops = new ArrayList<>();

                // Send a request for each chunk package
                for (Chunk[] newChunks : splitChunks) {

                    // Map chunks by world
                    Map<String, Set<Chunk>> chunksByWorld = new HashMap<>();
                    for (Chunk chunk : newChunks) {
                        String world = chunk.getWorld().getName();
                        Set<Chunk> chunksForWorld = chunksByWorld.getOrDefault(world, new HashSet<>());
                        chunksForWorld.add(chunk);
                        chunksByWorld.put(world, chunksForWorld);
                    }
    
                    // Create query dynamically
                    String query = "SELECT * FROM " + tableShops + " WHERE ";
                    for (String world : chunksByWorld.keySet()) {
                        query += "(world = ? AND (";
                        int chunkNum = chunksByWorld.get(world).size();
                        for (int i = 0; i < chunkNum; i++) {
                            query += "((x BETWEEN ? AND ?) AND (z BETWEEN ? AND ?)) OR ";
                        }
                        query += "1=0)) OR ";
                    }
                    query += "1=0";
    
                    try (Connection con = dataSource.getConnection();
                            PreparedStatement ps = con.prepareStatement(query)) {
                        int index = 0;
                        for (String world : chunksByWorld.keySet()) {
                            ps.setString(++index, world);
                            for (Chunk chunk : chunksByWorld.get(world)) {
                                int minX = chunk.getX() * 16;
                                int minZ = chunk.getZ() * 16;
                                ps.setInt(++index, minX);
                                ps.setInt(++index, minX + 15);
                                ps.setInt(++index, minZ);
                                ps.setInt(++index, minZ + 15);
                            }
                        }
    
                        ResultSet rs = ps.executeQuery();
                        while (rs.next()) {
                            int id = rs.getInt("id");
    
                            plugin.debug("Getting Shop... (#" + id + ")");
    
                            int x = rs.getInt("x");
                            int y = rs.getInt("y");
                            int z = rs.getInt("z");
    
                            World world = plugin.getServer().getWorld(rs.getString("world"));
                            Location location = new Location(world, x, y, z);
                            OfflinePlayer vendor = Bukkit.getOfflinePlayer(UUID.fromString(rs.getString("vendor")));
                            ItemStack itemStack = Utils.decode(rs.getString("product"));
                            int amount = rs.getInt("amount");
                            ShopProduct product = new ShopProduct(itemStack, amount);
                            double buyPrice = rs.getDouble("buyprice");
                            double sellPrice = rs.getDouble("sellprice");
                            ShopType shopType = ShopType.valueOf(rs.getString("shoptype"));
    
                            plugin.debug("Initializing new shop... (#" + id + ")");
    
                            shops.add(new Shop(id, plugin, vendor, product, location, buyPrice, sellPrice, shopType));
                        }
                    } catch (SQLException ex) {
                        if (callback != null) {
                            callback.callSyncError(ex);
                        }
    
                        plugin.getLogger().severe("Failed to get shops from database");
                        plugin.debug("Failed to get shops");
                        plugin.debug(ex);

                        return;
                    }
                }
    
                if (callback != null) {
                    callback.callSyncResult(Collections.unmodifiableCollection(shops));
                }
            };
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Adds a shop to the database
     * 
     * @param shop     Shop to add
     * @param callback Callback that - if succeeded - returns the ID the shop was
     *                 given (as {@code int})
     */
    public void addShop(final Shop shop, final Callback<Integer> callback) {
        final String queryNoId = "REPLACE INTO " + tableShops + " (vendor,product,amount,world,x,y,z,buyprice,sellprice,shoptype) VALUES(?,?,?,?,?,?,?,?,?,?)";
        final String queryWithId = "REPLACE INTO " + tableShops + " (id,vendor,product,amount,world,x,y,z,buyprice,sellprice,shoptype) VALUES(?,?,?,?,?,?,?,?,?,?,?)";

        new BukkitRunnable() {
            @Override
            public void run() {
                String query = shop.hasId() ? queryWithId : queryNoId;

                try (Connection con = dataSource.getConnection();
                        PreparedStatement ps = con.prepareStatement(query, Statement.RETURN_GENERATED_KEYS)) {
                    int i = 0;
                    if (shop.hasId()) {
                        i = 1;
                        ps.setInt(1, shop.getID());
                    }

                    ps.setString(i+1, shop.getVendor().getUniqueId().toString());
                    ps.setString(i+2, Utils.encode(shop.getProduct().getItemStack()));
                    ps.setInt(i+3, shop.getProduct().getAmount());
                    ps.setString(i+4, shop.getLocation().getWorld().getName());
                    ps.setInt(i+5, shop.getLocation().getBlockX());
                    ps.setInt(i+6, shop.getLocation().getBlockY());
                    ps.setInt(i+7, shop.getLocation().getBlockZ());
                    ps.setDouble(i+8, shop.getBuyPrice());
                    ps.setDouble(i+9, shop.getSellPrice());
                    ps.setString(i+10, shop.getShopType().toString());
                    ps.executeUpdate();

                    if (!shop.hasId()) {
                        int shopId = -1;
                        ResultSet rs = ps.getGeneratedKeys();
                        if (rs.next()) {
                            shopId = rs.getInt(1);
                        }

                        shop.setId(shopId);
                    }

                    if (callback != null) {
                        callback.callSyncResult(shop.getID());
                    }

                    plugin.debug("Adding shop to database (#" + shop.getID() + ")");
                } catch (SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to add shop to database");
                    plugin.debug("Failed to add shop to database (#" + shop.getID() + ")");
                    plugin.debug(ex);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Log an economy transaction to the database
     * 
     * @param executor Player who bought/sold something
     * @param shop The {@link Shop} the player bought from or sold to
     * @param product The {@link ItemStack} that was bought/sold
     * @param price The price the product was bought or sold for
     * @param type Whether the executor bought or sold
     * @param callback Callback that - if succeeded - returns {@code null}
     */
    public void logEconomy(final Player executor, Shop shop, ShopProduct product, double price, Type type, final Callback<Void> callback) {
        final String query = "INSERT INTO " + tableLogs + " (shop_id,timestamp,time,player_name,player_uuid,product_name,product,amount,"
                + "vendor_name,vendor_uuid,admin,world,x,y,z,price,type) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";

        if (Config.enableEconomyLog) {
            new BukkitRunnable() {
                @Override
                public void run() {
                    try (Connection con = dataSource.getConnection();
                            PreparedStatement ps = con.prepareStatement(query)) {

                        long millis = System.currentTimeMillis();

                        ps.setInt(1, shop.getID());
                        ps.setString(2, dateFormat.format(millis));
                        ps.setLong(3, millis);
                        ps.setString(4, executor.getName());
                        ps.setString(5, executor.getUniqueId().toString());
                        ps.setString(6, product.getLocalizedName());
                        ps.setString(7, Utils.encode(product.getItemStack()));
                        ps.setInt(8, product.getAmount());
                        ps.setString(9, shop.getVendor().getName());
                        ps.setString(10, shop.getVendor().getUniqueId().toString());
                        ps.setBoolean(11, shop.getShopType() == ShopType.ADMIN);
                        ps.setString(12, shop.getLocation().getWorld().getName());
                        ps.setInt(13, shop.getLocation().getBlockX());
                        ps.setInt(14, shop.getLocation().getBlockY());
                        ps.setInt(15, shop.getLocation().getBlockZ());
                        ps.setDouble(16, price);
                        ps.setString(17, type.toString());
                        ps.executeUpdate();

                        if (callback != null) {
                            callback.callSyncResult(null);
                        }

                        plugin.debug("Logged economy transaction to database");
                    } catch (SQLException ex) {
                        if (callback != null) {
                            callback.callSyncError(ex);
                        }

                        plugin.getLogger().severe("Failed to log economy transaction to database");
                        plugin.debug("Failed to log economy transaction to database");
                        plugin.debug(ex);
                    }
                }
            }.runTaskAsynchronously(plugin);
        } else {
            if (callback != null) {
                callback.callSyncResult(null);
            }
        }
    }

    /**
     * Cleans up the economy log to reduce file size
     * 
     * @param async Whether the call should be executed asynchronously
     */
    public void cleanUpEconomy(boolean async) {
        BukkitRunnable runnable = new BukkitRunnable() {
            @Override
            public void run() {
                long time = System.currentTimeMillis() - Config.cleanupEconomyLogDays * 86400000L;
                String queryCleanUpLog = "DELETE FROM " + tableLogs + " WHERE time < " + time;
                String queryCleanUpPlayers = "DELETE FROM " + tableLogouts + " WHERE time < " + time;

                try (Connection con = dataSource.getConnection();
                        Statement s = con.createStatement();
                        Statement s2 = con.createStatement()) {
                    s.executeUpdate(queryCleanUpLog);
                    s2.executeUpdate(queryCleanUpPlayers);

                    plugin.getLogger().info("Cleaned up economy log");
                    plugin.debug("Cleaned up economy log");
                } catch (SQLException ex) {
                    plugin.getLogger().severe("Failed to clean up economy log");
                    plugin.debug("Failed to clean up economy log");
                    plugin.debug(ex);
                }
            }
        };

        if (async) {
            runnable.runTaskAsynchronously(plugin);
        } else {
            runnable.run();
        }
    }

    /**
     * Get the revenue a player got while he was offline
     * 
     * @param player     Player whose revenue to get
     * @param logoutTime Time in milliseconds when he logged out the last time
     * @param callback   Callback that - if succeeded - returns the revenue the
     *                   player made while offline (as {@code double})
     */
    public void getRevenue(final Player player, final long logoutTime, final Callback<Double> callback) {
        new BukkitRunnable() {
            @Override
            public void run() {
                double revenue = 0;

                try (Connection con = dataSource.getConnection();
                        PreparedStatement ps = con.prepareStatement("SELECT * FROM " + tableLogs + " WHERE vendor_uuid = ?")) {
                    ps.setString(1, player.getUniqueId().toString());
                    ResultSet rs = ps.executeQuery();

                    while (rs.next()) {
                        long timestamp = rs.getLong("time");
                        double singleRevenue = rs.getDouble("price");
                        ShopBuySellEvent.Type type = ShopBuySellEvent.Type.valueOf(rs.getString("type"));

                        if (type == ShopBuySellEvent.Type.SELL) {
                            singleRevenue = -singleRevenue;
                        }

                        if (timestamp > logoutTime) {
                            revenue += singleRevenue;
                        }
                    }

                    if (callback != null) {
                        callback.callSyncResult(revenue);
                    }
                } catch (SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to get revenue from database");
                    plugin.debug("Failed to get revenue from player \"" + player.getUniqueId().toString() + "\"");
                    plugin.debug(ex);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Log a logout to the database
     * 
     * @param player    Player who logged out
     * @param callback  Callback that - if succeeded - returns {@code null}
     */
    public void logLogout(final Player player, final Callback<Void> callback) {
        new BukkitRunnable() {
            @Override
            public void run() {
                try (Connection con = dataSource.getConnection();
                        PreparedStatement ps = con.prepareStatement("REPLACE INTO " + tableLogouts + " (player,time) VALUES(?,?)")) {
                    ps.setString(1, player.getUniqueId().toString());
                    ps.setLong(2, System.currentTimeMillis());
                    ps.executeUpdate();

                    if (callback != null) {
                        callback.callSyncResult(null);
                    }

                    plugin.debug("Logged logout to database");
                } catch (final SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to log last logout to database");
                    plugin.debug("Failed to log logout to database");
                    plugin.debug(ex);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Get the last logout of a player
     * 
     * @param player   Player who logged out
     * @param callback Callback that - if succeeded - returns the time in
     *                 milliseconds the player logged out (as {@code long})
     *                 or {@code -1} if the player has not logged out yet.
     */
    public void getLastLogout(final Player player, final Callback<Long> callback) {
        new BukkitRunnable() {
            @Override
            public void run() {
                try (Connection con = dataSource.getConnection();
                        PreparedStatement ps = con.prepareStatement("SELECT * FROM " + tableLogouts + " WHERE player = ?")) {
                    ps.setString(1, player.getUniqueId().toString());
                    ResultSet rs = ps.executeQuery();

                    if (rs.next()) {
                        if (callback != null) {
                            callback.callSyncResult(rs.getLong("time"));
                        }
                    }

                    if (callback != null) {
                        callback.callSyncResult(-1L);
                    }
                } catch (SQLException ex) {
                    if (callback != null) {
                        callback.callSyncError(ex);
                    }

                    plugin.getLogger().severe("Failed to get last logout from database");
                    plugin.debug("Failed to get last logout from player \"" + player.getName() + "\"");
                    plugin.debug(ex);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    /**
     * Closes the data source
     */
    public void disconnect() {
        if (dataSource != null) {
            dataSource.close();
            dataSource = null;
        }
    }

    /**
     * Returns whether a connection to the database has been established
     */
    public boolean isInitialized() {
        return initialized;
    }

    public enum DatabaseType {
        SQLite, MySQL
    }
} public class MySQL extends Database {

    public MySQL(ShopChest plugin) {
        super(plugin);
    }

    @Override
    HikariDataSource getDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(String.format("jdbc:mysql://%s:%d/%s?autoReconnect=true&useSSL=false&serverTimezone=UTC",
                Config.databaseMySqlHost, Config.databaseMySqlPort, Config.databaseMySqlDatabase));
        config.setUsername(Config.databaseMySqlUsername);
        config.setPassword(Config.databaseMySqlPassword);
        config.setConnectionTestQuery("SELECT 1");

        return new HikariDataSource(config);
    }

    /**
     * Sends an asynchronous ping to the database
     */
    public void ping() {
        new BukkitRunnable() {
            @Override
            public void run() {
                try (Connection con = dataSource.getConnection();
                        Statement s = con.createStatement()) {
                    plugin.debug("Pinging to MySQL server...");
                    s.execute("/* ping */ SELECT 1");
                } catch (SQLException ex) {
                    plugin.getLogger().severe("Failed to ping to MySQL server. Trying to reconnect...");
                    plugin.debug("Failed to ping to MySQL server. Trying to reconnect...");
                    connect(null);
                }
            }
        }.runTaskAsynchronously(plugin);
    }

    @Override
    String getQueryCreateTableShops() {
        return "CREATE TABLE IF NOT EXISTS " + tableShops + " ("
            + "id INTEGER PRIMARY KEY AUTO_INCREMENT,"
            + "vendor TINYTEXT NOT NULL,"
            + "product TEXT NOT NULL,"
            + "amount INTEGER NOT NULL,"
            + "world TINYTEXT NOT NULL,"
            + "x INTEGER NOT NULL,"
            + "y INTEGER NOT NULL,"
            + "z INTEGER NOT NULL,"
            + "buyprice FLOAT NOT NULL,"
            + "sellprice FLOAT NOT NULL,"
            + "shoptype TINYTEXT NOT NULL)";
    }

    @Override
    String getQueryCreateTableLog() {
        return "CREATE TABLE IF NOT EXISTS " + tableLogs + " ("
            + "id INTEGER PRIMARY KEY AUTO_INCREMENT,"
            + "shop_id INTEGER NOT NULL,"
            + "timestamp TINYTEXT NOT NULL,"
            + "time LONG NOT NULL,"
            + "player_name TINYTEXT NOT NULL,"
            + "player_uuid TINYTEXT NOT NULL,"
            + "product_name TINYTEXT NOT NULL,"
            + "product TEXT NOT NULL,"
            + "amount INTEGER NOT NULL,"
            + "vendor_name TINYTEXT NOT NULL,"
            + "vendor_uuid TINYTEXT NOT NULL,"
            + "admin BIT NOT NULL,"
            + "world TINYTEXT NOT NULL,"
            + "x INTEGER NOT NULL,"
            + "y INTEGER NOT NULL,"
            + "z INTEGER NOT NULL,"
            + "price FLOAT NOT NULL,"
            + "type TINYTEXT NOT NULL)";
    }

    @Override
    String getQueryCreateTableLogout() {
        return "CREATE TABLE IF NOT EXISTS " + tableLogouts + " ("
            + "player VARCHAR(36) PRIMARY KEY NOT NULL,"
            + "time LONG NOT NULL)";
    }

    @Override
    String getQueryCreateTableFields() {
        return "CREATE TABLE IF NOT EXISTS " + tableFields + " ("
            + "field VARCHAR(32) PRIMARY KEY NOT NULL,"
            + "value INTEGER NOT NULL)";
    }

    @Override
    String getQueryGetTable() {
        return "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?";
    }
} public class SQLite extends Database {

    public SQLite(ShopChest plugin) {
        super(plugin);
    }

    @Override
    HikariDataSource getDataSource() {
        try {
            // Initialize driver class so HikariCP can find it
            Class.forName("org.sqlite.JDBC");
        } catch (ClassNotFoundException e) {
            plugin.getLogger().severe("Failed to initialize SQLite driver");
            plugin.debug("Failed to initialize SQLite driver");
            plugin.debug(e);
            return null;
        }

        File folder = plugin.getDataFolder();
        File dbFile = new File(folder, "shops.db");

        if (!dbFile.exists()) {
            try {
                dbFile.createNewFile();
            } catch (IOException ex) {
                plugin.getLogger().severe("Failed to create database file");
                plugin.debug("Failed to create database file");
                plugin.debug(ex);
                return null;
            }
        }
        
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(String.format("jdbc:sqlite:" + dbFile));
        config.setConnectionTestQuery("SELECT 1");

        return new HikariDataSource(config);
    }

    /**
     * Vacuums the database synchronously to reduce file size
     */
    public void vacuum() {
        try (Connection con = dataSource.getConnection();
                Statement s = con.createStatement()) {
            s.executeUpdate("VACUUM");

            plugin.debug("Vacuumed SQLite database");
        } catch (final SQLException ex) {
            plugin.getLogger().warning("Failed to vacuum database");
            plugin.debug("Failed to vacuum database");
            plugin.debug(ex);
        }
    }

    @Override
    String getQueryCreateTableShops() {
        return "CREATE TABLE IF NOT EXISTS " + tableShops + " ("
            + "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            + "vendor TINYTEXT NOT NULL,"
            + "product TEXT NOT NULL,"
            + "amount INTEGER NOT NULL,"
            + "world TINYTEXT NOT NULL,"
            + "x INTEGER NOT NULL,"
            + "y INTEGER NOT NULL,"
            + "z INTEGER NOT NULL,"
            + "buyprice FLOAT NOT NULL,"
            + "sellprice FLOAT NOT NULL,"
            + "shoptype TINYTEXT NOT NULL)";
    }

    @Override
    String getQueryCreateTableLog() {
        return "CREATE TABLE IF NOT EXISTS " + tableLogs + " ("
            + "id INTEGER PRIMARY KEY AUTOINCREMENT,"
            + "shop_id INTEGER NOT NULL,"
            + "timestamp TINYTEXT NOT NULL,"
            + "time LONG NOT NULL,"
            + "player_name TINYTEXT NOT NULL,"
            + "player_uuid TINYTEXT NOT NULL,"
            + "product_name TINYTEXT NOT NULL,"
            + "product TEXT NOT NULL,"
            + "amount INTEGER NOT NULL,"
            + "vendor_name TINYTEXT NOT NULL,"
            + "vendor_uuid TINYTEXT NOT NULL,"
            + "admin BIT NOT NULL,"
            + "world TINYTEXT NOT NULL,"
            + "x INTEGER NOT NULL,"
            + "y INTEGER NOT NULL,"
            + "z INTEGER NOT NULL,"
            + "price FLOAT NOT NULL,"
            + "type TINYTEXT NOT NULL)";
    }

    @Override
    String getQueryCreateTableLogout() {
        return "CREATE TABLE IF NOT EXISTS " + tableLogouts + " ("
            + "player VARCHAR(36) PRIMARY KEY NOT NULL,"
            + "time LONG NOT NULL)";
    }

    @Override
    String getQueryCreateTableFields() {
        return "CREATE TABLE IF NOT EXISTS " + tableFields + " ("
            + "field VARCHAR(32) PRIMARY KEY NOT NULL,"
            + "value INTEGER NOT NULL)";
    }

    @Override
    String getQueryGetTable() {
        return "SELECT name FROM sqlite_master WHERE type='table' AND name=?";
    }
} public abstract class Callback<T> {
    private ShopChest plugin;

    public Callback(ShopChest plugin) {
        this.plugin = plugin;
    }

    public void onResult(T result) {}

    public void onError(Throwable throwable) {}

    public final void callSyncResult(final T result) {
        new BukkitRunnable() {
            @Override
            public void run() {
                onResult(result);
            }
        }.runTask(plugin);
    }

    public final void callSyncError(final Throwable throwable) {
        new BukkitRunnable() {
            @Override
            public void run() {
                onError(throwable);
            }
        }.runTask(plugin);
    }
} public class ClickType {
    private static Map<UUID, ClickType> playerClickType = new HashMap<>();
    private static Map<UUID, BukkitTask> playerTimers = new HashMap<>();

    private EnumClickType enumClickType;

    public ClickType(EnumClickType enumClickType) {
        this.enumClickType = enumClickType;
    }

    /**
     * Clear click types, cancel timers, and reset game modes
     */
    public static void clear() {
        playerClickType.forEach((uuid, ct) -> {
            if (ct instanceof SelectClickType) {
                Player p = Bukkit.getPlayer(uuid);
                if (p != null)
                    p.setGameMode(((SelectClickType) ct).getGameMode());
            }
        });
        playerTimers.forEach((uuid, timer) -> timer.cancel());
    }

    /**
     * Gets the click type of a player
     *
     * @param player Player whose click type should be gotten
     * @return The Player's click type or <b>null</b> if he doesn't have one
     */
    public static ClickType getPlayerClickType(OfflinePlayer player) {
        return playerClickType.get(player.getUniqueId());
    }

    /**
     * Removes the click type from a player and cancels the 15 second timer
     * 
     * @param player Player to remove the click type from
     */
    public static void removePlayerClickType(OfflinePlayer player) {
        UUID uuid = player.getUniqueId();
        if (playerClickType.get(uuid) instanceof SelectClickType && player instanceof Player) {
            // Reset gamemode player has select click type
            ((Player) player).setGameMode(((SelectClickType) playerClickType.get(uuid)).gameMode);
        }
        playerClickType.remove(uuid);

        // If a timer is still running, cancel it
        Optional.ofNullable(playerTimers.get(uuid)).ifPresent(task -> task.cancel());
        playerTimers.remove(uuid);
    }

    /**
     * Sets the click type of a player and removes it after 15 seconds
     *
     * @param player    Player whose click type should be set
     * @param clickType Click type to set
     */
    public static void setPlayerClickType(OfflinePlayer player, ClickType clickType) {
        UUID uuid = player.getUniqueId();
        if (playerClickType.get(uuid) instanceof SelectClickType && player instanceof Player) {
            // Reset gamemode player has select click type
            ((Player) player).setGameMode(((SelectClickType) playerClickType.get(uuid)).gameMode);
        }
        playerClickType.put(uuid, clickType);

        // If a timer is already running, cancel it
        Optional.ofNullable(playerTimers.get(uuid)).ifPresent(task -> task.cancel());

        if (clickType.getClickType() != EnumClickType.SELECT_ITEM) {
            // Remove ClickType after 15 seconds if player has not clicked a chest
            playerTimers.put(uuid, new BukkitRunnable() {
                @Override
                public void run() {
                    playerClickType.remove(uuid);
                }
            }.runTaskLater(ShopChest.getInstance(), 300));
        }
    }

    /**
     * @return Type of the click type
     */
    public EnumClickType getClickType() {
        return enumClickType;
    }

    public enum EnumClickType {
        CREATE, REMOVE, INFO, OPEN, SELECT_ITEM
    }

    public static class CreateClickType extends ClickType {
        private ShopProduct product;
        private double buyPrice;
        private double sellPrice;
        private ShopType shopType;

        public CreateClickType(ShopProduct product, double buyPrice, double sellPrice, ShopType shopType) {
            super(EnumClickType.CREATE);
            this.product = product;
            this.sellPrice = sellPrice;
            this.buyPrice = buyPrice;
            this.shopType = shopType;
        }

        /**
         * Returns the item, the player has hold in his hands
         */
        public ShopProduct getProduct() {
            return product;
        }

        /**
         * Returns the buy price, the player has entered
         */
        public double getBuyPrice() {
            return buyPrice;
        }

        /**
         * Returns the sell price, the player has entered
         */
        public double getSellPrice() {
            return sellPrice;
        }

        /**
         * Returns the shop type, the player has entered
         */
        public ShopType getShopType() {
            return shopType;
        }
    }

    public static class SelectClickType extends ClickType {
        private ItemStack itemStack;
        private GameMode gameMode;
        private int amount;
        private double buyPrice;
        private double sellPrice;
        private ShopType shopType;

        public SelectClickType(GameMode gameMode, int amount, double buyPrice, double sellPrice, ShopType shopType) {
            super(EnumClickType.SELECT_ITEM);
            this.gameMode = gameMode;
            this.amount = amount;
            this.sellPrice = sellPrice;
            this.buyPrice = buyPrice;
            this.shopType = shopType;
        }

        /**
         * Returns the selected item (or {@code null} if no item has been selected)
         */
        public ItemStack getItem() {
            return itemStack;
        }

        /**
         * Sets the selected item
         * @param itemStack The item to set as selected
         */
        public void setItem(ItemStack itemStack) {
            this.itemStack = itemStack;
        }

        /**
         * Returns the gamemode, the player was in before entering creative mode
         */
        public GameMode getGameMode() {
            return gameMode;
        }

        /**
         * Returns the amount, the player has entered
         */
        public int getAmount() {
            return amount;
        }

        /**
         * Returns the buy price, the player has entered
         */
        public double getBuyPrice() {
            return buyPrice;
        }

        /**
         * Returns the sell price, the player has entered
         */
        public double getSellPrice() {
            return sellPrice;
        }

        /**
         * Returns the shop type, the player has entered
         */
        public ShopType getShopType() {
            return shopType;
        }
    }

} public class Permissions {

    public static final String CREATE = "shopchest.create";
    public static final String CREATE_BUY = "shopchest.create.buy";
    public static final String CREATE_SELL = "shopchest.create.sell";
    public static final String CREATE_ADMIN = "shopchest.create.admin";
    public static final String CREATE_PROTECTED = "shopchest.create.protected";
    public static final String REMOVE_OTHER = "shopchest.remove.other";
    public static final String REMOVE_ADMIN = "shopchest.remove.admin";
    public static final String BUY = "shopchest.buy";
    public static final String SELL = "shopchest.sell";
    public static final String OPEN_OTHER = "shopchest.openOther";
    public static final String UPDATE_NOTIFICATION = "shopchest.notification.update";
    public static final String RELOAD = "shopchest.reload";
    public static final String UPDATE = "shopchest.update";
    public static final String NO_LIMIT = "shopchest.limit.*";
    public static final String CONFIG = "shopchest.config";
    public static final String EXTEND_OTHER = "shopchest.extend.other";
    public static final String EXTEND_PROTECTED = "shopchest.extend.protected";
    public static final String BYPASS_EXTERNAL_PLUGIN = "shopchest.external.bypass";

} public class ShopUpdater {
    
    private final ShopChest plugin;
    private final BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();

    private volatile Thread thread;

    public ShopUpdater(ShopChest plugin) {
        this.plugin = plugin;
    }

    /**
     * Start task, except if it is already
     */
    public void start() {
        if (!isRunning()) {
            thread = new Thread(() -> {
                while (!Thread.interrupted()) {
                    try {
                        queue.take().run();
                    } catch (InterruptedException e) {
                        break;
                    }
                }
            }, "Shop Updater");
            thread.start();
        }
    }

    /**
     * Stop any running task then start it again
     */
    public void restart() {
        stop();
        start();
    }

    /**
     * Stop task properly
     */
    public void stop() {
        if (thread != null) {
            thread.interrupt();
            thread = null;
        }
    }

    /**
     * @return whether task is running or not
     */
    public boolean isRunning() {
        return thread != null;
    }

    /**
     * Queue a task to update shops for the given player
     * 
     * @param player Player to show updates
     */
    public void updateShops(Player player) {
        queue(() -> plugin.getShopUtils().updateShops(player));
    }

    /**
     * Queue a task to update shops for players in the given world
     * 
     * @param world World in whose players to show updates
     */
    public void updateShops(World world) {
        queue(() -> {
            for (Player player : world.getPlayers()) {
                plugin.getShopUtils().updateShops(player);
            }
        });
    }

    /**
     * Queue a task to update shops for all players
     */
    public void updateShops() {
        queue(() -> {
            for (Player player : Bukkit.getOnlinePlayers()) {
                plugin.getShopUtils().updateShops(player);
            }
        });
    }

    /**
     * Register a task to run before next loop
     *
     * @param runnable task to run
     */
    public void queue(Runnable runnable) {
        queue.add(runnable);
    }
} public class ShopUtils {

    private final Map<UUID, Counter> playerShopAmount = new HashMap<>();

    // concurrent since it is updated in async task
    private final Map<UUID, Location> playerLocation = new ConcurrentHashMap<>();
    private final Map<Location, Shop> shopLocation = new ConcurrentHashMap<>();
    private final Collection<Shop> shopLocationValues = Collections.unmodifiableCollection(shopLocation.values());
    private final ShopChest plugin;

    public ShopUtils(ShopChest plugin) {
        this.plugin = plugin;
    }

    /**
     * Get the shop at a given location
     *
     * @param location Location of the shop
     * @return Shop at the given location or <b>null</b> if no shop is found there
     */
    public Shop getShop(Location location) {
        Location newLocation = new Location(location.getWorld(), location.getBlockX(),
                location.getBlockY(), location.getBlockZ());

        return shopLocation.get(newLocation);
    }

    /**
     * Checks whether there is a shop at a given location
     * @param location Location to check
     * @return Whether there is a shop at the given location
     */
    public boolean isShop(Location location) {
        return getShop(location) != null;
    }

    /**
     * Get a collection of all loaded shops
     * <p>
     * This collection is safe to use for looping over and removing shops.
     *
     * @return Read-only collection of all shops, may contain duplicates for double chests
     */
    public Collection<Shop> getShops() {
        return Collections.unmodifiableCollection(new ArrayList<>(shopLocationValues));
    }

    /**
     * Get all shops
     *
     * @see #getShops()
     * @return Copy of collection of all shops, may contain duplicates
     * @deprecated Use {@link #getShops()} instead
     */
    @Deprecated
    public Collection<Shop> getShopsCopy() {
        return new ArrayList<>(getShops());
    }

    /**
     * Add a shop
     * @param shop Shop to add
     * @param addToDatabase Whether the shop should also be added to the database
     * @param callback Callback that - if succeeded - returns the ID the shop had or was given (as {@code int})
     */
    public void addShop(Shop shop, boolean addToDatabase, Callback<Integer> callback) {
        InventoryHolder ih = shop.getInventoryHolder();
        plugin.debug("Adding shop... (#" + shop.getID() + ")");

        if (ih instanceof DoubleChest) {
            DoubleChest dc = (DoubleChest) ih;
            Chest r = (Chest) dc.getRightSide();
            Chest l = (Chest) dc.getLeftSide();

            plugin.debug("Added shop as double chest. (#" + shop.getID() + ")");

            shopLocation.put(r.getLocation(), shop);
            shopLocation.put(l.getLocation(), shop);
        } else {
            plugin.debug("Added shop as single chest. (#" + shop.getID() + ")");

            shopLocation.put(shop.getLocation(), shop);
        }

        if (addToDatabase) {
            if (shop.getShopType() != ShopType.ADMIN) {
                playerShopAmount.compute(shop.getVendor().getUniqueId(), (uuid, amount) -> amount == null ? new Counter(1) : amount.increment());
            }
            plugin.getShopDatabase().addShop(shop, callback);
        } else {
            if (callback != null) callback.callSyncResult(shop.getID());
        }

    }

    /**
     * Add a shop
     * @param shop Shop to add
     * @param addToDatabase Whether the shop should also be added to the database
     */
    public void addShop(Shop shop, boolean addToDatabase) {
        addShop(shop, addToDatabase, null);
    }

    /**
     * Removes (i.e. unloads) all currently loaded shops
     */
    public void removeShops() {
        shopLocation.forEach((location, shop) -> {
            if (!shop.isCreated()) return;

            plugin.debug("Removing shop " + shop.getID());
            shop.removeItem();
            shop.removeHologram();
        });
        shopLocation.clear();
    }

    /** Remove a shop. May not work properly if double chest doesn't exist!
     * @param shop Shop to remove
     * @param removeFromDatabase Whether the shop should also be removed from the database
     * @param callback Callback that - if succeeded - returns null
     * @see ShopUtils#removeShopById(int, boolean, Callback)
     */
    public void removeShop(Shop shop, boolean removeFromDatabase, Callback<Void> callback) {
        plugin.debug("Removing shop (#" + shop.getID() + ")");

        if (shop.isCreated()) {
            InventoryHolder ih = shop.getInventoryHolder();

            if (ih instanceof DoubleChest) {
                DoubleChest dc = (DoubleChest) ih;
                Chest r = (Chest) dc.getRightSide();
                Chest l = (Chest) dc.getLeftSide();

                shopLocation.remove(r.getLocation());
                shopLocation.remove(l.getLocation());
            } else {
                shopLocation.remove(shop.getLocation());
            }

            shop.removeItem();
            shop.removeHologram();
        }

        if (removeFromDatabase) {
            if (shop.getShopType() != ShopType.ADMIN) {
                playerShopAmount.compute(shop.getVendor().getUniqueId(), (uuid, amount) -> amount == null ? new Counter() : amount.decrement());
            }
            plugin.getShopDatabase().removeShop(shop, callback);
        } else {
            if (callback != null) callback.callSyncResult(null);
        }
    }

    /**
     * Remove a shop. May not work properly if double chest doesn't exist!
     * @param shop Shop to remove
     * @param removeFromDatabase Whether the shop should also be removed from the database
     * @see ShopUtils#removeShopById(int, boolean)
     */
    public void removeShop(Shop shop, boolean removeFromDatabase) {
        removeShop(shop, removeFromDatabase, null);
    }

    /**
     * Remove a shop by its ID
     * @param shopId ID of the shop to remove
     * @param removeFromDatabase Whether the shop should also be removed from the database
     * @param callback Callback that - if succeeded - returns null
     */
    public void removeShopById(int shopId, boolean removeFromDatabase, Callback<Void> callback) {
        Map<Location, Shop> toRemove = shopLocation.entrySet().stream()
                .filter(e -> e.getValue().getID() == shopId)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        plugin.debug(String.format("Removing %d shop(s) with ID %d", toRemove.size(), shopId));

        if (toRemove.isEmpty()) {
            if (callback != null) callback.callSyncResult(null);
            return;
        }

        toRemove.forEach((loc, shop) -> {
            shopLocation.remove(loc);

            shop.removeItem();
            shop.removeHologram();
        });

        Shop first = toRemove.values().iterator().next();
        boolean isAdmin = first.getShopType() == ShopType.ADMIN;
        UUID vendorUuid = first.getVendor().getUniqueId();

        // Database#removeShop removes shop by ID so this only needs to be called once
        if (removeFromDatabase) {
            if (!isAdmin) {
                playerShopAmount.compute(vendorUuid, (uuid, amount) -> amount == null ? new Counter() : amount.decrement());
            }
            plugin.getShopDatabase().removeShop(toRemove.values().iterator().next(), callback);
        } else {
            if (callback != null) callback.callSyncResult(null);
        }
    }

    /**
     * Remove a shop by its ID
     * @param shopId ID of the shop to remove
     * @param removeFromDatabase Whether the shop should also be removed from the database
     */
    public void removeShopById(int shopId, boolean removeFromDatabase) {
        removeShopById(shopId, removeFromDatabase, null);
    }

    /**
     * Get the shop limits of a player
     * @param p Player, whose shop limits should be returned
     * @return The shop limits of the given player
     */
    public int getShopLimit(Player p) {
        int limit = 0;
        boolean useDefault = true;

        for (PermissionAttachmentInfo permInfo : p.getEffectivePermissions()) {
            if (permInfo.getPermission().startsWith("shopchest.limit.") && p.hasPermission(permInfo.getPermission())) {
                if (permInfo.getPermission().equalsIgnoreCase(Permissions.NO_LIMIT)) {
                    limit = -1;
                    useDefault = false;
                    break;
                } else {
                    String[] spl = permInfo.getPermission().split("shopchest.limit.");

                    if (spl.length > 1) {
                        try {
                            int newLimit = Integer.valueOf(spl[1]);

                            if (newLimit < 0) {
                                limit = -1;
                                break;
                            }

                            limit = Math.max(limit, newLimit);
                            useDefault = false;
                        } catch (NumberFormatException ignored) {
                            /* Ignore and continue */
                        }
                    }
                }
            }
        }

        if (limit < -1) limit = -1;
        return (useDefault ?Config.defaultLimit : limit);
    }

    /**
     * Get the amount of shops of a player
     * @param p Player, whose shops should be counted
     * @return The amount of a shops a player has (if {@link Config#excludeAdminShops} is true, admin shops won't be counted)
     */
    public int getShopAmount(OfflinePlayer p) {
        return playerShopAmount.getOrDefault(p.getUniqueId(), new Counter()).get();
    }

    /**
     * Get all shops of a player from the database without loading them
     * @param p Player, whose shops should be get
     * @param callback Callback that returns a collection of the given player's shops
     */
    public void getShops(OfflinePlayer p, Callback<Collection<Shop>> callback) {
        plugin.getShopDatabase().getShops(p.getUniqueId(), new Callback<Collection<Shop>>(plugin) {
            @Override
            public void onResult(Collection<Shop> result) {
                Set<Shop> shops = new HashSet<>();
                for (Shop playerShop : result) {
                    Shop loadedShop = getShop(playerShop.getLocation());
                    if (loadedShop != null && loadedShop.equals(playerShop)) {
                        shops.add(loadedShop);
                    } else {
                        shops.add(playerShop);
                    }
                }
                if (callback != null) callback.onResult(shops);
            }

            @Override
            public void onError(Throwable throwable) {
                if (callback != null) callback.onError(throwable);
            }
        });
    }

    /**
     * Loads the amount of shops for each player
     * @param callback Callback that returns the amount of shops for each player
     */
    public void loadShopAmounts(final Callback<Map<UUID, Integer>> callback) {
        plugin.getShopDatabase().getShopAmounts(new Callback<Map<UUID,Integer>>(plugin) {
            @Override
            public void onResult(Map<UUID, Integer> result) {
                playerShopAmount.clear();
                result.forEach((uuid, amount) -> playerShopAmount.put(uuid, new Counter(amount)));
                if (callback != null) callback.onResult(result);
            }

            @Override
            public void onError(Throwable throwable) {
                if (callback != null) callback.onError(throwable);
            }
        });
    }

    /**
     * Gets all shops in the given chunk from the database and adds them to the server
     * @param chunk The chunk to load shops from
     * @param callback Callback that returns the amount of shops added if succeeded
     * @see ShopUtils#loadShops(Chunk[], Callback)
     */
    public void loadShops(final Chunk chunk, final Callback<Integer> callback) {
        loadShops(new Chunk[] {chunk}, callback);
    }

    /**
     * Gets all shops in the given chunks from the database and adds them to the server
     * @param chunk The chunks to load shops from
     * @param callback Callback that returns the amount of shops added if succeeded
     * @see ShopUtils#loadShops(Chunk Callback)
     */
    public void loadShops(final Chunk[] chunks, final Callback<Integer> callback) {
        plugin.getShopDatabase().getShopsInChunks(chunks, new Callback<Collection<Shop>>(plugin) {
            @Override
            public void onResult(Collection<Shop> result) {
                Collection<Shop> loadedShops = new HashSet<>();

                for (Shop shop : result) {
                    Location loc = shop.getLocation();

                    // Don't add shop if shop is already loaded
                    if (shopLocation.containsKey(loc)) {
                        continue;
                    }

                    int x = loc.getBlockX() / 16;
                    int z = loc.getBlockZ() / 16;
                    
                    // Don't add shop if chunk is no longer loaded
                    if (!loc.getWorld().isChunkLoaded(x, z)) {
                        continue;
                    }

                    if (shop.create(true)) {
                        addShop(shop, false);
                        loadedShops.add(shop);
                    }
                }

                if (callback != null) callback.onResult(loadedShops.size());

                Bukkit.getPluginManager().callEvent(new ShopsLoadedEvent(Collections.unmodifiableCollection(loadedShops)));
            }

            @Override
            public void onError(Throwable throwable) {
                if (callback != null) callback.onError(throwable);
            }
        });
    }

    /**
     * Update hologram and item of all shops for a player
     * @param player Player to show the updates
     */
    public void updateShops(Player player) {
        updateShops(player, false);
    }

    /**
     * Update hologram and item of all shops for a player
     * @param player Player to show the updates
     * @param force Whether update should be forced even if player has not moved
     */
    public void updateShops(Player player, boolean force) {
        if (!force && player.getLocation().equals(playerLocation.get(player.getUniqueId()))) {
            // Player has not moved, so don't calculate shops again.
            return;
        }

        if (Config.onlyShowShopsInSight) {
            updateVisibleShops(player);
        } else {
            updateNearestShops(player);
        }

        playerLocation.put(player.getUniqueId(), player.getLocation());
    }

    /**
     * Remove a saved location of a player to force a recalculation
     * of whether the hologram should be visible.
     * This should only be called when really needed
     * @param player Player whose saved location will be reset
     */
    public void resetPlayerLocation(Player player) {
        playerLocation.remove(player.getUniqueId());
    }

    private void updateVisibleShops(Player player) {
        double itemDistSquared = Math.pow(Config.maximalItemDistance, 2);
        double maxDist = Config.maximalDistance;

        double nearestDistSquared = Double.MAX_VALUE;
        Shop nearestShop = null;

        Location pLoc = player.getEyeLocation();
        Vector pDir = pLoc.getDirection();

        // Display holograms based on sight
        for (double i = 0; i <= maxDist; i++) {
            Location loc = pLoc.clone();
            Vector dir = pDir.clone();
            double factor = Math.min(i, maxDist);
            
            loc.add(dir.multiply(factor));
            Location locBelow = loc.clone().subtract(0, 1, 0);

            // Check block below as player may look at hologram
            Shop shop = getShop(loc);
            if (shop == null) {
                shop = getShop(locBelow);
            }

            if (shop != null && shop.hasHologram()) {
                double distSquared = pLoc.distanceSquared(loc);
                if (distSquared < nearestDistSquared) {
                    nearestDistSquared = distSquared;
                    nearestShop = shop;
                }
            }
        }

        for (Shop shop : getShops()) {
            if (!shop.equals(nearestShop) && shop.hasHologram()) {
                shop.getHologram().hidePlayer(player);
            }

            // Display item based on distance
            Location shopLocation = shop.getLocation();
            if (shopLocation.getWorld().getName().equals(player.getWorld().getName())) {
                double distSquared = shop.getLocation().distanceSquared(player.getLocation());

                if (shop.hasItem()) {
                    if (distSquared <= itemDistSquared) {
                        shop.getItem().showPlayer(player);
                    } else {
                        shop.getItem().hidePlayer(player);
                    }
                }
            }
        }

        if (nearestShop != null) {
            nearestShop.getHologram().showPlayer(player);
        }
    }

    private void updateNearestShops(Player p) {
        double holoDistSqr = Math.pow(Config.maximalDistance, 2);
        double itemDistSqr = Math.pow(Config.maximalItemDistance, 2);

        Location playerLocation = p.getLocation();

        for (Shop shop : getShops()) {
            if (playerLocation.getWorld().getName().equals(shop.getLocation().getWorld().getName())) {
                double distSqr = shop.getLocation().distanceSquared(playerLocation);

                if (shop.hasHologram()) {
                    if (distSqr <= holoDistSqr) {
                        shop.getHologram().showPlayer(p);
                    } else {
                        shop.getHologram().hidePlayer(p);
                    }
                }

                if (shop.hasItem()) {
                    if (distSqr <= itemDistSqr) {
                        shop.getItem().showPlayer(p);
                    } else {
                        shop.getItem().hidePlayer(p);
                    }
                }
            }
        }
    }
} public class UpdateChecker {

    private ShopChest plugin;
    private String version;
    private String link;

    public UpdateChecker(ShopChest plugin) {
        this.plugin = plugin;
    }

    /**
     * Check if an update is needed
     *
     * @return {@link UpdateCheckerResult#TRUE} if an update is available,
     *         {@link UpdateCheckerResult#FALSE} if no update is needed or
     *         {@link UpdateCheckerResult#ERROR} if an error occurred
     */
    public UpdateCheckerResult check() {
        try {
            plugin.debug("Checking for updates...");

            URL url = new URL("https://api.spiget.org/v2/resources/11431/versions?size=1&page=1&sort=-releaseDate");
            URLConnection conn = url.openConnection();
            conn.setRequestProperty("User-Agent", "ShopChest/UpdateChecker");

            InputStreamReader reader = new InputStreamReader(conn.getInputStream());
            JsonElement element = new JsonParser().parse(reader);

            if (element.isJsonArray()) {
                JsonObject result = element.getAsJsonArray().get(0).getAsJsonObject();
                String id = result.get("id").getAsString();
                version = result.get("name").getAsString();
                link = "https://www.spigotmc.org/resources/shopchest.11431/download?version=" + id;
            } else {
                plugin.debug("Failed to check for updates");
                plugin.debug("Result: " + element.toString());
                return UpdateCheckerResult.ERROR;
            }

            if (plugin.getDescription().getVersion().equals(version)) {
                plugin.debug("No update found");
                return UpdateCheckerResult.FALSE;
            } else {
                plugin.debug("Update found: " + version);
                return UpdateCheckerResult.TRUE;
            }

        } catch (Exception e) {
            plugin.debug("Failed to check for updates");
            plugin.debug(e);
            return UpdateCheckerResult.ERROR;
        }
    }

    /**
     * @return Latest Version or <b>null</b> if no update is available
     */
    public String getVersion() {
        return version;
    }

    /**
     * @return Download Link of the latest version of <b>null</b> if no update is available
     */
    public String getLink() {
        return link;
    }

    public enum UpdateCheckerResult {
        TRUE,
        FALSE,
        ERROR
    }


} public enum UpdateCheckerResult {
    TRUE,
    FALSE,
    ERROR
} public class Utils {
    static NMSClassResolver nmsClassResolver = new NMSClassResolver();
    static Class<?> entityClass = nmsClassResolver.resolveSilent("world.entity.Entity");
    static Class<?> entityArmorStandClass = nmsClassResolver.resolveSilent("world.entity.decoration.EntityArmorStand");
    static Class<?> entityItemClass = nmsClassResolver.resolveSilent("world.entity.item.EntityItem");
    static Class<?> dataWatcherClass = nmsClassResolver.resolveSilent("network.syncher.DataWatcher");
    static Class<?> dataWatcherObjectClass = nmsClassResolver.resolveSilent("network.syncher.DataWatcherObject");
    static Class<?> chatSerializerClass = nmsClassResolver.resolveSilent("ChatSerializer", "network.chat.IChatBaseComponent$ChatSerializer");

    private Utils() {}

    /**
     * Check if two items are similar to each other
     * @param itemStack1 The first item
     * @param itemStack2 The second item
     * @return {@code true} if the given items are similar or {@code false} if not
     */
    public static boolean isItemSimilar(ItemStack itemStack1, ItemStack itemStack2) {
        if (itemStack1 == null || itemStack2 == null) {
            return false;
        }

        ItemMeta itemMeta1 = itemStack1.getItemMeta();
        ItemMeta itemMeta2 = itemStack2.getItemMeta();

        if (itemMeta1 instanceof BookMeta && itemMeta2 instanceof BookMeta) {
            BookMeta bookMeta1 = (BookMeta) itemStack1.getItemMeta();
            BookMeta bookMeta2 = (BookMeta) itemStack2.getItemMeta();

            if ((getMajorVersion() == 9 && getRevision() == 1) || getMajorVersion() == 8) {
                CustomBookMeta.Generation generation1 = CustomBookMeta.getGeneration(itemStack1);
                CustomBookMeta.Generation generation2 = CustomBookMeta.getGeneration(itemStack2);

                if (generation1 == null) CustomBookMeta.setGeneration(itemStack1, CustomBookMeta.Generation.ORIGINAL);
                if (generation2 == null) CustomBookMeta.setGeneration(itemStack2, CustomBookMeta.Generation.ORIGINAL);
            } else {
                if (bookMeta1.getGeneration() == null) bookMeta1.setGeneration(BookMeta.Generation.ORIGINAL);
                if (bookMeta2.getGeneration() == null) bookMeta2.setGeneration(BookMeta.Generation.ORIGINAL);
            }

            itemStack1.setItemMeta(bookMeta1);
            itemStack2.setItemMeta(bookMeta2);

            itemStack1 = decode(encode(itemStack1));
            itemStack2 = decode(encode(itemStack2));
        }

        return itemStack1.isSimilar(itemStack2);
    }

    /**
     * Gets the amount of items in an inventory
     *
     * @param inventory The inventory, in which the items are counted
     * @param itemStack The items to count
     * @return Amount of given items in the given inventory
     */
    public static int getAmount(Inventory inventory, ItemStack itemStack) {
        int amount = 0;

        ArrayList<ItemStack> inventoryItems = new ArrayList<>();

        if (inventory instanceof PlayerInventory) {
            for (int i = 0; i < 37; i++) {
                if (i == 36) {
                    if (getMajorVersion() < 9) {
                        break;
                    }
                    i = 40;
                }
                inventoryItems.add(inventory.getItem(i));
            }
        } else {
            for (int i = 0; i < inventory.getSize(); i++) {
                inventoryItems.add(inventory.getItem(i));
            }
        }

        for (ItemStack item : inventoryItems) {
            if (isItemSimilar(item, itemStack)) {
                amount += item.getAmount();
            }
        }

        return amount;
    }

    /**
     * Get the amount of the given item, that fits in the given inventory
     *
     * @param inventory Inventory, where to search for free space
     * @param itemStack Item, of which the amount that fits in the inventory should be returned
     * @return Amount of the given item, that fits in the given inventory
     */
    public static int getFreeSpaceForItem(Inventory inventory, ItemStack itemStack) {
        HashMap<Integer, Integer> slotFree = new HashMap<>();

        if (inventory instanceof PlayerInventory) {
            for (int i = 0; i < 37; i++) {
                if (i == 36) {
                    if (getMajorVersion() < 9) {
                        break;
                    }
                    i = 40;
                }

                ItemStack item = inventory.getItem(i);
                if (item == null || item.getType() == Material.AIR) {
                    slotFree.put(i, itemStack.getMaxStackSize());
                } else {
                    if (isItemSimilar(item, itemStack)) {
                        int amountInSlot = item.getAmount();
                        int amountToFullStack = itemStack.getMaxStackSize() - amountInSlot;
                        slotFree.put(i, amountToFullStack);
                    }
                }
            }
        } else {
            for (int i = 0; i < inventory.getSize(); i++) {
                ItemStack item = inventory.getItem(i);
                if (item == null || item.getType() == Material.AIR) {
                    slotFree.put(i, itemStack.getMaxStackSize());
                } else {
                    if (isItemSimilar(item, itemStack)) {
                        int amountInSlot = item.getAmount();
                        int amountToFullStack = itemStack.getMaxStackSize() - amountInSlot;
                        slotFree.put(i, amountToFullStack);
                    }
                }
            }
        }

        int freeAmount = 0;
        for (int value : slotFree.values()) {
            freeAmount += value;
        }

        return freeAmount;
    }

    /**
     * @param p Player whose item in his main hand should be returned
     * @return {@link ItemStack} in his main hand, or {@code null} if he doesn't hold one
     */
    public static ItemStack getItemInMainHand(Player p) {
        if (getMajorVersion() < 9) {
            if (p.getItemInHand().getType() == Material.AIR)
                return null;
            else
                return p.getItemInHand();
        }

        if (p.getInventory().getItemInMainHand().getType() == Material.AIR)
            return null;
        else
            return p.getInventory().getItemInMainHand();
    }

    /**
     * @param p Player whose item in his off hand should be returned
     * @return {@link ItemStack} in his off hand, or {@code null} if he doesn't hold one or the server version is below 1.9
     */
    public static ItemStack getItemInOffHand(Player p) {
        if (getMajorVersion() < 9)
            return null;
        else if (p.getInventory().getItemInOffHand().getType() == Material.AIR)
            return null;
        else
            return p.getInventory().getItemInOffHand();
    }

    /**
     * @param p Player whose item in his hand should be returned
     * @return Item in his main hand, or the item in his off if he doesn't have one in this main hand, or {@code null}
     *         if he doesn't have one in both hands
     */
    public static ItemStack getPreferredItemInHand(Player p) {
        if (getMajorVersion() < 9)
            return getItemInMainHand(p);
        else if (getItemInMainHand(p) != null)
            return getItemInMainHand(p);
        else
            return getItemInOffHand(p);
    }

    /**
     * @param p Player to check if he has an axe in one of his hands
     * @return Whether a player has an axe in one of his hands
     */
    public static boolean hasAxeInHand(Player p) {
        List<String> axes;
        if (Utils.getMajorVersion() < 13)
            axes = Arrays.asList("WOOD_AXE", "STONE_AXE", "IRON_AXE", "GOLD_AXE", "DIAMOND_AXE");
        else 
            axes = Arrays.asList("WOODEN_AXE", "STONE_AXE", "IRON_AXE", "GOLDEN_AXE", "DIAMOND_AXE");

        ItemStack item = getItemInMainHand(p);
        if (item == null || !axes.contains(item.getType().toString())) {
            item = getItemInOffHand(p);
        }

        return item != null && axes.contains(item.getType().toString());
    }

    /**
     * <p>Check if a player is allowed to create a shop that sells or buys the given item.</p>
     * @param player Player to check
     * @param item Item to be sold or bought
     * @param buy Whether buying should be enabled
     * @param sell Whether selling should be enabled
     * @return Whether the player is allowed
     */
    public static boolean hasPermissionToCreateShop(Player player, ItemStack item, boolean buy, boolean sell) {
        if (hasPermissionToCreateShop(player, item, Permissions.CREATE)) {
            return true;
        } else if (!sell && buy && hasPermissionToCreateShop(player, item,Permissions.CREATE_BUY)) {
            return true;
        } else if (!buy && sell && hasPermissionToCreateShop(player, item, Permissions.CREATE_SELL)) {
            return true;
        } else if (buy && sell && hasPermissionToCreateShop(player, item, Permissions.CREATE_BUY, Permissions.CREATE_SELL)) {
            return true;
        }

        return false;
    }

    private static boolean hasPermissionToCreateShop(Player player, ItemStack item, String... permissions) {
        for (String permission : permissions) {
            boolean b1 = false;
            boolean b2 = false;
            boolean b3 = false;

            if (player.hasPermission(permission)) {
                b1 = true;
            }

            if (item != null) {
                if (item.getDurability() == 0) {
                    String perm1 = permission + "." + item.getType().toString();
                    String perm2 = permission + "." + item.getType().toString() + ".0";

                    if (player.hasPermission(perm1) || player.hasPermission(perm2)) {
                        b2 = true;
                    }
                }

                if (player.hasPermission(permission + "." + item.getType().toString() + "." + item.getDurability())) {
                    b3 = true;
                }
            }

            if (!(b1 || b2 || b3)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Get a set for the location(s) of the shop's chest(s)
     * @param shop The shop
     * @return A set of 1 or 2 locations
     */
    public static Set<Location> getChestLocations(Shop shop) {
        Set<Location> chestLocations = new HashSet<>();
        InventoryHolder ih = shop.getInventoryHolder();
        if (ih instanceof DoubleChest) {
            DoubleChest dc = (DoubleChest) ih;
            chestLocations.add(((Chest) dc.getLeftSide()).getLocation());
            chestLocations.add(((Chest) dc.getRightSide()).getLocation());
        } else {
            chestLocations.add(shop.getLocation());
        }
        return chestLocations;
    }

    /**
     * Send a clickable update notification to the given player.
     * @param plugin An instance of the {@link ShopChest} plugin
     * @param p The player to receive the notification
     */
    public static void sendUpdateMessage(ShopChest plugin, Player p) {
        JsonBuilder jb = new JsonBuilder(plugin);
        Map<String, JsonBuilder.Part> hoverEvent = new HashMap<>();
        hoverEvent.put("action", new JsonBuilder.Part("show_text"));
        hoverEvent.put("value", new JsonBuilder.Part(LanguageUtils.getMessage(Message.UPDATE_CLICK_TO_DOWNLOAD)));

        Map<String, JsonBuilder.Part> clickEvent = new HashMap<>();
        clickEvent.put("action", new JsonBuilder.Part("open_url"));
        clickEvent.put("value", new JsonBuilder.Part(plugin.getDownloadLink()));

        JsonBuilder.PartMap rootPart = JsonBuilder.parse(LanguageUtils.getMessage(Message.UPDATE_AVAILABLE,
                new Replacement(Placeholder.VERSION, plugin.getLatestVersion()))).toMap();
                
        rootPart.setValue("hoverEvent", new JsonBuilder.PartMap(hoverEvent));
        rootPart.setValue("clickEvent", new JsonBuilder.PartMap(clickEvent));
        
        jb.setRootPart(rootPart);
        jb.sendJson(p);
    }

    /**
     * Create a NMS data watcher object to send via a {@code PacketPlayOutEntityMetadata} packet.
     * Gravity will be disabled and the custom name will be displayed if available.
     * @param customName Custom Name of the entity or {@code null}
     * @param nmsItemStack NMS ItemStack or {@code null} if armor stand
     */
    public static Object createDataWatcher(String customName, Object nmsItemStack) {
        String version = getServerVersion();
        int majorVersion = getMajorVersion();

        try {
            byte entityFlags = nmsItemStack == null ? (byte) 0b100000 : 0; // invisible if armor stand
            byte armorStandFlags = nmsItemStack == null ? (byte) 0b10000 : 0; // marker (since 1.8_R2)

            Object dataWatcher = dataWatcherClass.getConstructor(entityClass).newInstance((Object) null);
            if (majorVersion < 9) {
                if (getRevision() == 1) armorStandFlags = 0; // Marker not supported on 1.8_R1

                Method a = dataWatcherClass.getMethod("a", int.class, Object.class);
                a.invoke(dataWatcher, 0, entityFlags); // flags
                a.invoke(dataWatcher, 1, (short) 300); // air ticks (?)
                a.invoke(dataWatcher, 3, (byte) (customName != null ? 1 : 0)); // custom name visible
                a.invoke(dataWatcher, 2, customName != null ? customName : ""); // custom name
                a.invoke(dataWatcher, 4, (byte) 1); // silent
                a.invoke(dataWatcher, 10, nmsItemStack == null ? armorStandFlags : nmsItemStack); // item / armor stand flags
            } else {
                Method register = dataWatcherClass.getMethod("register", dataWatcherObjectClass, Object.class);
                String[] dataWatcherObjectFieldNames;

                if ("v1_9_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"ax", "ay", "aA", "az", "aB", null, "c", "a"};
                } else if ("v1_9_R2".equals(version)){
                    dataWatcherObjectFieldNames = new String[] {"ay", "az", "aB", "aA", "aC", null, "c", "a"};
                } else if ("v1_10_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"aa", "az", "aB", "aA", "aC", "aD", "c", "a"};
                } else if ("v1_11_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"Z", "az", "aB", "aA", "aC", "aD", "c", "a"};
                } else if ("v1_12_R1".equals(version) || "v1_12_R2".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"Z", "aA", "aC", "aB", "aD", "aE", "c", "a"};
                } else if ("v1_13_R1".equals(version) || "v1_13_R2".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"ac", "aD", "aF", "aE", "aG", "aH", "b", "a"};
                } else if ("v1_14_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"W", "AIR_TICKS", "aA", "az", "aB", "aC", "ITEM", "b"};
                } else if ("v1_15_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"T", "AIR_TICKS", "aA", "az", "aB", "aC", "ITEM", "b"};
                } else if ("v1_16_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"T", "AIR_TICKS", "ay", "ax", "az", "aA", "ITEM", "b"};
                } else if ("v1_16_R2".equals(version) || "v1_16_R3".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"S", "AIR_TICKS", "ar", "aq", "as", "at", "ITEM", "b"};
                } else if ("v1_17_R1".equals(version)) {
                    dataWatcherObjectFieldNames = new String[] {"Z", "aI", "aK", "aJ", "aL", "aM", "c", "bG"};
                } else {
                    return null;
                }

                Field fEntityFlags = entityClass.getDeclaredField(dataWatcherObjectFieldNames[0]);
                Field fAirTicks = entityClass.getDeclaredField(dataWatcherObjectFieldNames[1]);
                Field fNameVisible = entityClass.getDeclaredField(dataWatcherObjectFieldNames[2]);
                Field fCustomName = entityClass.getDeclaredField(dataWatcherObjectFieldNames[3]);
                Field fSilent = entityClass.getDeclaredField(dataWatcherObjectFieldNames[4]);
                Field fNoGravity = majorVersion >= 10 ? entityClass.getDeclaredField(dataWatcherObjectFieldNames[5]) : null;
                Field fItem = entityItemClass.getDeclaredField(dataWatcherObjectFieldNames[6]);
                Field fArmorStandFlags = entityArmorStandClass.getDeclaredField(dataWatcherObjectFieldNames[7]);

                fEntityFlags.setAccessible(true);
                fAirTicks.setAccessible(true);
                fNameVisible.setAccessible(true);
                fCustomName.setAccessible(true);
                fSilent.setAccessible(true);
                if (majorVersion >= 10) fNoGravity.setAccessible(true);
                fItem.setAccessible(true);
                fArmorStandFlags.setAccessible(true);
                
                register.invoke(dataWatcher, fEntityFlags.get(null), entityFlags);
                register.invoke(dataWatcher, fAirTicks.get(null), 300);
                register.invoke(dataWatcher, fNameVisible.get(null), customName != null);
                register.invoke(dataWatcher, fSilent.get(null), true);
                if (majorVersion < 13) register.invoke(dataWatcher, fCustomName.get(null), customName != null ? customName : "");
                
                if (nmsItemStack != null) {
                    register.invoke(dataWatcher, fItem.get(null), majorVersion < 11 ? com.google.common.base.Optional.of(nmsItemStack) : nmsItemStack);
                } else {
                    register.invoke(dataWatcher, fArmorStandFlags.get(null), armorStandFlags);
                }

                if (majorVersion >= 10) {
                    register.invoke(dataWatcher, fNoGravity.get(null), true);
                    if (majorVersion >= 13) {
                        if (customName != null) {
                            Object iChatBaseComponent = chatSerializerClass.getMethod("a", String.class).invoke(null, JsonBuilder.parse(customName).toString());
                            register.invoke(dataWatcher, fCustomName.get(null), Optional.of(iChatBaseComponent));
                        } else {
                            register.invoke(dataWatcher, fCustomName.get(null), Optional.empty());
                        }
                    }
                }
            }
            return dataWatcher;
        } catch (InstantiationException | InvocationTargetException | NoSuchFieldException | IllegalAccessException | NoSuchMethodException e) {
            ShopChest.getInstance().getLogger().severe("Failed to create data watcher!");
            ShopChest.getInstance().debug("Failed to create data watcher");
            ShopChest.getInstance().debug(e);
        }
        return null;
    }

    /**
     * Get a free entity ID for use in {@link #createPacketSpawnEntity(ShopChest, int, UUID, Location, Vector, EntityType)}
     * 
     * @return The id or {@code -1} if a free entity ID could not be retrieved.
     */
    public static int getFreeEntityId() {
        try {
            Field entityCountField = new FieldResolver(entityClass).resolve("entityCount", "b");
            entityCountField.setAccessible(true);
            if (entityCountField.getType() == int.class) {
                int id = entityCountField.getInt(null);
                entityCountField.setInt(null, id+1);
                return id;
            } else if (entityCountField.getType() == AtomicInteger.class) {
                return ((AtomicInteger) entityCountField.get(null)).incrementAndGet();
            }

            return -1;
        } catch (Exception e) {
            return -1;
        }
    }

    /**
     * Create a {@code PacketPlayOutSpawnEntity} object.
     * Only {@link EntityType#ARMOR_STAND} and {@link EntityType#DROPPED_ITEM} are supported! 
     */
    public static Object createPacketSpawnEntity(ShopChest plugin, int id, UUID uuid, Location loc, EntityType type) {
        try {
            Class<?> packetPlayOutSpawnEntityClass = nmsClassResolver.resolveSilent("network.protocol.game.PacketPlayOutSpawnEntity");
            Class<?> entityTypesClass = nmsClassResolver.resolveSilent("world.entity.EntityTypes");
            Class<?> vec3dClass = nmsClassResolver.resolveSilent("world.phys.Vec3D");

            boolean isPre9 = getMajorVersion() < 9;
            boolean isPre14 = getMajorVersion() < 14;

            double y = loc.getY();
            if (type == EntityType.ARMOR_STAND && !getServerVersion().equals("v1_8_R1")) {
                // Marker armor stand => lift by normal armor stand height
                y += 1.975;
            }

            if (getMajorVersion() >= 17) {
                // Empty packet constructor does not exist anymore in 1.17+
                Constructor<?> c = packetPlayOutSpawnEntityClass.getConstructor(int.class, UUID.class, double.class, double.class, double.class,
                        float.class, float.class, entityTypesClass, int.class, vec3dClass);

                Object vec3d = vec3dClass.getField("a").get(null);
                Object entityType = entityTypesClass.getField(type == EntityType.ARMOR_STAND ? "c" : "Q").get(null);

                return c.newInstance(id, uuid, loc.getX(), y, loc.getZ(), 0f, 0f, entityType, 0, vec3d);
            }
            
            Object packet = packetPlayOutSpawnEntityClass.getConstructor().newInstance();

            Field[] fields = new Field[12];
            fields[0] = packetPlayOutSpawnEntityClass.getDeclaredField("a"); // ID
            fields[1] = packetPlayOutSpawnEntityClass.getDeclaredField("b"); // UUID (Only 1.9+)
            fields[2] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "b" : "c"); // Loc X
            fields[3] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "c" : "d"); // Loc Y
            fields[4] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "d" : "e"); // Loc Z
            fields[5] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "e" : "f"); // Mot X
            fields[6] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "f" : "g"); // Mot Y
            fields[7] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "g" : "h"); // Mot Z
            fields[8] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "h" : "i"); // Pitch
            fields[9] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "i" : "j"); // Yaw
            fields[10] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "j" : "k"); // Type
            fields[11] = packetPlayOutSpawnEntityClass.getDeclaredField(isPre9 ? "k" : "l"); // Data

            for (Field field : fields) {
                field.setAccessible(true);
            }

            Object entityType = null;
            if (!isPre14) {
                entityType = entityTypesClass.getField(type == EntityType.ARMOR_STAND ? "ARMOR_STAND" : "ITEM").get(null);
            }

            fields[0].set(packet, id);
            if (!isPre9) fields[1].set(packet, uuid);
            if (isPre9) {
                fields[2].set(packet, (int)(loc.getX() * 32));
                fields[3].set(packet, (int)(y * 32));
                fields[4].set(packet, (int)(loc.getZ() * 32));
            } else {
                fields[2].set(packet, loc.getX());
                fields[3].set(packet, y);
                fields[4].set(packet, loc.getZ());
            }
            fields[5].set(packet, 0);
            fields[6].set(packet, 0);
            fields[7].set(packet, 0);
            fields[8].set(packet, 0);
            fields[9].set(packet, 0);
            if (isPre14) fields[10].set(packet, type == EntityType.ARMOR_STAND ? 78 : 2);
            else fields[10].set(packet, entityType);
            fields[11].set(packet, 0);

            return packet;
        } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
            plugin.getLogger().severe("Failed to create packet to spawn entity!");
            plugin.debug("Failed to create packet to spawn entity!");
            plugin.debug(e);
            return null;
        }
    }

    /**
     * Send a packet to a player
     * @param plugin An instance of the {@link ShopChest} plugin
     * @param packet Packet to send
     * @param player Player to which the packet should be sent
     * @return {@code true} if the packet was sent, or {@code false} if an exception was thrown
     */
    public static boolean sendPacket(ShopChest plugin, Object packet, Player player) {
        try {
            if (packet == null) {
                plugin.debug("Failed to send packet: Packet is null");
                return false;
            }

            Class<?> packetClass = nmsClassResolver.resolveSilent("network.protocol.Packet");
            if (packetClass == null) {
                plugin.debug("Failed to send packet: Could not find Packet class");
                return false;
            }

            Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player);
            Field fConnection = (new FieldResolver(nmsPlayer.getClass())).resolve("playerConnection", "b");
            Object playerConnection = fConnection.get(nmsPlayer);

            playerConnection.getClass().getMethod("sendPacket", packetClass).invoke(playerConnection, packet);

            return true;
        } catch (NoSuchMethodException | NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
            plugin.getLogger().severe("Failed to send packet " + packet.getClass().getName());
            plugin.debug("Failed to send packet " + packet.getClass().getName());
            plugin.debug(e);
            return false;
        }
    }

    /**
     * @return The current server version with revision number (e.g. v1_9_R2, v1_10_R1)
     */
    public static String getServerVersion() {
        String packageName = Bukkit.getServer().getClass().getPackage().getName();

        return packageName.substring(packageName.lastIndexOf('.') + 1);
    }

    /**
     * @return The revision of the current server version (e.g. <i>2</i> for v1_9_R2, <i>1</i> for v1_10_R1)
     */
    public static int getRevision() {
        return Integer.parseInt(getServerVersion().substring(getServerVersion().length() - 1));
    }

    /**
     * @return The major version of the server (e.g. <i>9</i> for 1.9.2, <i>10</i> for 1.10)
     */
    public static int getMajorVersion() {
        return Integer.parseInt(getServerVersion().split("_")[1]);
    }

    /**
     * Encodes an {@link ItemStack} in a Base64 String
     * @param itemStack {@link ItemStack} to encode
     * @return Base64 encoded String
     */
    public static String encode(ItemStack itemStack) {
        YamlConfiguration config = new YamlConfiguration();
        config.set("i", itemStack);
        return Base64.getEncoder().encodeToString(config.saveToString().getBytes(StandardCharsets.UTF_8));
    }

    /**
     * Decodes an {@link ItemStack} from a Base64 String
     * @param string Base64 encoded String to decode
     * @return Decoded {@link ItemStack}
     */
    public static ItemStack decode(String string) {
        YamlConfiguration config = new YamlConfiguration();
        try {
            config.loadFromString(new String(Base64.getDecoder().decode(string), StandardCharsets.UTF_8));
        } catch (IllegalArgumentException | InvalidConfigurationException e) {
            e.printStackTrace();
            return null;
        }
        return config.getItemStack("i", null);
    }


}
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import com.palmergames.bukkit.towny.Towny;
import com.wasteofplastic.askyblock.ASkyBlock;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.AdvancedPie;
import org.bstats.charts.SimplePie;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitRunnable;
import org.codemc.worldguardwrapper.WorldGuardWrapper;
import de.epiceric.shopchest.command.ShopCommand;
import de.epiceric.shopchest.config.Config;
import de.epiceric.shopchest.config.HologramFormat;
import de.epiceric.shopchest.event.ShopInitializedEvent;
import de.epiceric.shopchest.external.BentoBoxShopFlag;
import de.epiceric.shopchest.external.PlotSquaredOldShopFlag;
import de.epiceric.shopchest.external.PlotSquaredShopFlag;
import de.epiceric.shopchest.external.WorldGuardShopFlag;
import de.epiceric.shopchest.external.listeners.ASkyBlockListener;
import de.epiceric.shopchest.external.listeners.GriefPreventionListener;
import de.epiceric.shopchest.external.listeners.IslandWorldListener;
import de.epiceric.shopchest.external.listeners.PlotSquaredListener;
import de.epiceric.shopchest.external.listeners.TownyListener;
import de.epiceric.shopchest.external.listeners.USkyBlockListener;
import de.epiceric.shopchest.language.LanguageUtils;
import de.epiceric.shopchest.listeners.AreaShopListener;
import de.epiceric.shopchest.listeners.BentoBoxListener;
import de.epiceric.shopchest.listeners.BlockExplodeListener;
import de.epiceric.shopchest.listeners.ChestProtectListener;
import de.epiceric.shopchest.listeners.CreativeModeListener;
import de.epiceric.shopchest.listeners.NotifyPlayerOnJoinListener;
import de.epiceric.shopchest.listeners.ShopInteractListener;
import de.epiceric.shopchest.listeners.ShopItemListener;
import de.epiceric.shopchest.listeners.ShopUpdateListener;
import de.epiceric.shopchest.listeners.WorldGuardListener;
import de.epiceric.shopchest.shop.Shop;
import de.epiceric.shopchest.shop.Shop.ShopType;
import de.epiceric.shopchest.sql.Database;
import de.epiceric.shopchest.sql.MySQL;
import de.epiceric.shopchest.sql.SQLite;
import de.epiceric.shopchest.utils.Callback;
import de.epiceric.shopchest.utils.ClickType;
import de.epiceric.shopchest.utils.Permissions;
import de.epiceric.shopchest.utils.ShopUpdater;
import de.epiceric.shopchest.utils.ShopUtils;
import de.epiceric.shopchest.utils.UpdateChecker;
import de.epiceric.shopchest.utils.UpdateChecker.UpdateCheckerResult;
import de.epiceric.shopchest.utils.Utils;
import fr.xephi.authme.AuthMe;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
import me.wiefferink.areashop.AreaShop;
import net.milkbowl.vault.economy.Economy;
import pl.islandworld.IslandWorld;
import us.talabrek.ultimateskyblock.api.uSkyBlockAPI;
import world.bentobox.bentobox.BentoBox;
package de.epiceric.shopchest;





public class ShopChest extends JavaPlugin {

    private static ShopChest instance;

    private Config config;
    private HologramFormat hologramFormat;
    private ShopCommand shopCommand;
    private Economy econ = null;
    private Database database;
    private boolean isUpdateNeeded = false;
    private String latestVersion = "";
    private String downloadLink = "";
    private ShopUtils shopUtils;
    private FileWriter fw;
    private Plugin worldGuard;
    private Towny towny;
    private AuthMe authMe;
    private uSkyBlockAPI uSkyBlock;
    private ASkyBlock aSkyBlock;
    private IslandWorld islandWorld;
    private GriefPrevention griefPrevention;
    private AreaShop areaShop;
    private BentoBox bentoBox;
    private ShopUpdater updater;
    private ExecutorService shopCreationThreadPool;

    /**
     * @return An instance of ShopChest
     */
    public static ShopChest getInstance() {
        return instance;
    }

    /**
     * Sets up the economy of Vault
     * @return Whether an economy plugin has been registered
     */
    private boolean setupEconomy() {
        RegisteredServiceProvider<Economy> rsp = getServer().getServicesManager().getRegistration(Economy.class);
        if (rsp == null) {
            return false;
        }
        econ = rsp.getProvider();
        return econ != null;
    }

    @Override
    public void onLoad() {
        instance = this;

        config = new Config(this);

        if (Config.enableDebugLog) {
            File debugLogFile = new File(getDataFolder(), "debug.txt");

            try {
                if (!debugLogFile.exists()) {
                    debugLogFile.createNewFile();
                }

                new PrintWriter(debugLogFile).close();

                fw = new FileWriter(debugLogFile, true);
            } catch (IOException e) {
                getLogger().info("Failed to instantiate FileWriter");
                e.printStackTrace();
            }
        }

        debug("Loading ShopChest version " + getDescription().getVersion());

        worldGuard = Bukkit.getServer().getPluginManager().getPlugin("WorldGuard");
        if (worldGuard != null) {
            WorldGuardShopFlag.register(this);