diff --git a/pom.xml b/pom.xml index 9564b24..b84f3c5 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.pablo67340.GUIShop GUIShop - 8.0 + 8.1 GUIShop https://www.spigotmc.org/resources/guishop.2451/ This plugin is the ultimate solution to all the signs, the chests, the glitches. @@ -58,16 +58,10 @@ org.spigotmc spigot-api - 1.14.4-R0.1-SNAPSHOT + 1.16.3-R0.1-SNAPSHOT provided - - org.bukkit - bukkit - 1.14.4-R0.1-SNAPSHOT - provided - com.github.MilkBowl VaultAPI @@ -87,7 +81,7 @@ org.projectlombok lombok - 1.18.8 + 1.18.12 provided @@ -114,10 +108,10 @@ org.apache.maven.plugins maven-compiler-plugin - 2.0.2 + 3.8.1 1.8 - 1.8 + 1.8 diff --git a/src/com/pablo67340/guishop/Main.java b/src/com/pablo67340/guishop/Main.java index 7eee452..e47ea8b 100644 --- a/src/com/pablo67340/guishop/Main.java +++ b/src/com/pablo67340/guishop/Main.java @@ -44,506 +44,501 @@ public final class Main extends JavaPlugin { - /** - * The overridden config file objects. - */ - @Getter - private File configf, specialf; - - /** - * The loaded shops read from the config. - */ - @Getter - private Map shops; - - /** - * The configs FileConfiguration object. - */ - @Getter - private FileConfiguration mainConfig, customConfig; - - /** - * An instance Vault's Economy. - */ - @Getter - private static Economy ECONOMY; - - /** - * the instance of the dynamic price provider, if dynamic pricing is used - */ - @Getter - private static DynamicPriceProvider DYNAMICPRICING; - - /** - * An instance of this class. - */ - @Getter - public static Main INSTANCE; - - /** - * A {@link Set} that will store every command that can be used by a - * {@link Player} to open the {@link Menu}. - */ - @Getter - public static final Set BUY_COMMANDS = new HashSet<>(); - - /** - * A {@link Set} that will store every command that can be used by a - * {@link Player} to open the {@link Sell} GUI. - */ - @Getter - public static final Set SELL_COMMANDS = new HashSet<>(); - - @Getter - public Map> loadedShops = new HashMap<>(); - - @Getter - private final Map ITEMTABLE = new HashMap<>(); - - /** - * A {@link Map} that will store our {@link Creator}s when the server first - * starts. - */ - @Getter - public static final List CREATOR = new ArrayList<>(); - - @Getter - private final MatLib matLib = new MatLib(); - - @Getter - @Setter - private Boolean creatorRefresh = false; - - @Getter - private final Map openShopInstances = new HashMap<>(); - - /** - * The current buy command - */ - private BuyCommand buyCommand = null; - - /** - * The current sell command - */ - private SellCommand sellCommand = null; - - @Override - public void onEnable() { - INSTANCE = this; - shops = new LinkedHashMap<>(); - createFiles(); - - if (!setupEconomy()) { - getLogger().log(Level.INFO, "Vault could not detect an economy plugin!"); - getServer().getPluginManager().disablePlugin(this); - return; - } - - getServer().getPluginManager().registerEvents(PlayerListener.INSTANCE, this); - getServer().getPluginCommand("guishop").setExecutor(new GuishopCommand()); - getServer().getPluginCommand("guishopuser").setExecutor(new GuishopUserCommand()); - loadDefaults(); - if (Config.isDynamicPricing() && !setupDynamicPricing()) { - getLogger().log(Level.INFO, "Could not find a DynamicPriceProvider! Disabling dynamic pricing..."); - Config.setDynamicPricing(false); - } - - loadShopDefs(); - - switch (Config.getCommandsMode()) { - case INTERCEPT: - CommandsInterceptor.register(); - break; - case REGISTER: - registerCommands(false); - break; - default: - break; - } - } - - public void loadShopDefs() { - - ConfigurationSection menuItems = Main.getINSTANCE().getConfig().getConfigurationSection("menu-items"); - - for (String key : menuItems.getKeys(false)) { - - String name = menuItems.getString(key + ".Name") != null ? ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(menuItems.getString(key + ".Name"))) : " "; - - String description = menuItems.getString(key + ".Desc") != null ? ChatColor.translateAlternateColorCodes( - '&', Objects.requireNonNull(menuItems.getString(key + ".Desc"))) : " "; - - ItemType itemType = menuItems.getString(key + ".Type") != null - ? ItemType.valueOf(menuItems.getString(key + ".Type")) - : ItemType.SHOP; - - if (!menuItems.getBoolean(key + ".Enabled") && itemType == ItemType.SHOP) { - continue; - - } - - String itemID = itemType != ItemType.BLANK ? menuItems.getString(key + ".Item") : "AIR"; - - List lore = new ArrayList<>(); - - if (description.length() > 0) { - lore.add(description); - } - - shops.put(key.toLowerCase(), new ShopDef(key, name, description, lore, itemType, itemID)); - } - - new Menu().itemWarmup(); - loadPRICETABLE(); - } - - /** - * Register/unregister the GUIShop commands with the bukkit server.
- * Accesses the command map via reflection - * - * @param onlyUnregister if true, new commands will not be registered, only, existing ones will be unregistered - */ - private void registerCommands(boolean onlyUnregister) { - if (onlyUnregister && buyCommand == null && sellCommand == null) { - // Nothing is registered, no need to do anything - return; - } - getLogger().info("Registering/unregistering commands " + StringUtils.join(Main.BUY_COMMANDS, "|") + " and " + StringUtils.join(Main.SELL_COMMANDS, "|")); - - try { - final Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap"); - - bukkitCommandMap.setAccessible(true); - CommandMap commandMap = (CommandMap) bukkitCommandMap.get(Bukkit.getServer()); - - // Unregister old commands - if (buyCommand != null) { - buyCommand.unregister(commandMap); - } - - if (sellCommand != null) { - sellCommand.unregister(commandMap); - } - - if (onlyUnregister) { - return; - } - // Register new commands - buyCommand = new BuyCommand(new ArrayList<>(Main.BUY_COMMANDS)); - commandMap.register(buyCommand.getName(), buyCommand); - - sellCommand = new SellCommand(new ArrayList<>(Main.SELL_COMMANDS)); - commandMap.register(sellCommand.getName(), sellCommand); - - } catch (IllegalAccessException | NoSuchFieldException e) { - e.printStackTrace(); - } - } - - public GuishopUserCommand getUserCommands() { - return (GuishopUserCommand) getServer().getPluginCommand("guishopuser").getExecutor(); - } - - /** - * Check if Vault is present, Check if an Economy plugin is present, if so Hook. - */ - private Boolean setupEconomy() { - if (getServer().getPluginManager().getPlugin("Vault") == null) { - return false; - } - - RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); - - if (rsp == null || rsp.getProvider() == null) { - return false; - } - - ECONOMY = rsp.getProvider(); - - return true; - } - - /** - * Find the dynamic price provider if present - */ - private boolean setupDynamicPricing() { - RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(DynamicPriceProvider.class); - - if (rsp == null || rsp.getProvider() == null) { - return false; - } - DYNAMICPRICING = rsp.getProvider(); - - return true; - } - - /** - * Load all deault config values, translate colors, store. - */ - public void loadDefaults() { - BUY_COMMANDS.addAll(getMainConfig().getStringList("buy-commands")); - SELL_COMMANDS.addAll(getMainConfig().getStringList("sell-commands")); - Config.setCommandsMode(CommandsMode.parseFromConfig(getMainConfig().getString("commands-mode"))); - Config.setPrefix(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("prefix")))); - Config.setSignsOnly(getMainConfig().getBoolean("signs-only")); - Config.setSignTitle(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("sign-title")))); - Config.setNotEnoughPre(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("not-enough-pre")))); - Config.setNotEnoughPost(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("not-enough-post")))); - Config.setPurchased(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("purchased")))); - Config.setTaken(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("taken")))); - Config.setSold( - ChatColor.translateAlternateColorCodes('&', Objects.requireNonNull(getMainConfig().getString("sold")))); - Config.setAdded(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("added")))); - Config.setCantSell(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("cant-sell")))); - Config.setEscapeOnly(getMainConfig().getBoolean("escape-only")); - Config.setAlternateSellEnabled(getMainConfig().getBoolean("alternate-sell-enable", false)); - Config.setSound(getMainConfig().getString("purchase-sound")); - Config.setSoundEnabled(getMainConfig().getBoolean("enable-sound")); - Config.setEnableCreator(getMainConfig().getBoolean("ingame-config")); - Config.setCantBuy(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("cant-buy")))); - Config.setMenuRows(getMainConfig().getInt("menu-rows")); - Config.setFull(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("full-inventory")))); - Config.setNoPermission(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("no-permission")))); - Config.setCurrency(getMainConfig().getString("currency")); - Config.setCurrencySuffix(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("currency-suffix")))); - Config.setMenuTitle(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("menu-title", "Menu"))); - Config.setShopTitle(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("shop-title", "Menu &f> &r{shopname}"))); - Config.setSellTitle(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("sell-title", "Menu &f> &rSell"))); - Config.setAltSellTitle(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("alt-sell-title", "Menu &f> &rSell"))); - Config.setQtyTitle(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("qty-title")))); - Config.setBackButtonItem(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("back-button-item")))); - Config.setBackButtonText( - ChatColor.translateAlternateColorCodes('&', Objects.requireNonNull(getMainConfig().getString("back")))); - Config.setBuyLore(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("buy-lore")))); - Config.setSellLore(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("sell-lore")))); - Config.setFreeLore(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("free-lore")))); - - Config.setCannotBuy(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("cannot-buy")))); - Config.setCannotSell(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(getMainConfig().getString("cannot-sell")))); - Config.setForwardPageButtonName( - ChatColor.translateAlternateColorCodes('&', getMainConfig().getString("forward-page-button-name", ""))); - Config.setBackwardPageButtonName( - ChatColor.translateAlternateColorCodes('&', getMainConfig().getString("backward-page-button-name", ""))); - Config.setAltSellIndicatorMaterial(getMainConfig().getString("alt-sell-indicator-material", "EMERALD")); - Config.setAltSellAddMaterial(getMainConfig().getString("alt-sell-add-material", "GREEN_STAINED_GLASS_PANE")); - Config.setAltSellRemoveMaterial(getMainConfig().getString("alt-sell-remove-material", "RED_STAINED_GLASS_PANE")); - Config.setAltSellQuantity1(getMainConfig().getInt("alt-sell-quantity-1", 1)); - Config.setAltSellQuantity2(getMainConfig().getInt("alt-sell-quantity-2", 10)); - Config.setAltSellQuantity3(getMainConfig().getInt("alt-sell-quantity-3", 64)); - Config.setAltSellConfirmMaterial(getMainConfig().getString("alt-sell-confirm-material", "EMERALD_BLOCK")); - Config.setAltSellCancelMaterial(getMainConfig().getString("alt-sell-cancel-material", "REDSTONE_BLOCK")); - Config.setAltSellConfirmName(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("alt-sell-confirm-name", "&a&lConfirm"))); - Config.setAltSellCancelName(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("alt-sell-cancel-name", "&c&lCancel"))); - Config.setAltSellNotEnough(ChatColor.translateAlternateColorCodes('&', - getMainConfig().getString("alt-sell-not-enough", "&cYou do not have enough items to sell."))); - Config.getDisabledQty().addAll(getMainConfig().getStringList("disabled-qty-items")); - Config.setDynamicPricing(getMainConfig().getBoolean("dynamic-pricing", false)); - Config.setDebugMode(getMainConfig().getBoolean("debug-mode")); - } - - private void loadPRICETABLE() { - - for (String shop : Main.getINSTANCE().getCustomConfig().getKeys(false)) { - - ConfigurationSection config = Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop); - if (config == null) { - log("Check the section for shop " + shop + " in the shops.yml. It was not found."); - continue; - } - - assert config != null; - for (String str : config.getKeys(false)) { - - Item item = new Item(); - - ConfigurationSection section = config.getConfigurationSection(str); - if (section == null) { - log("Check the config section for item " + str + " in shop " + shop + " the shops.yml. It is not a valid section."); - continue; - } - - item.setMaterial((section.contains("id") ? (String) section.get("id") : "AIR")); - if (item.isAnyPotion()) { - ConfigurationSection potionSection = section.getConfigurationSection("potion-info"); - if (potionSection != null) { - item.parsePotionType(potionSection.getString("type"), - potionSection.getBoolean("splash", false), - potionSection.getBoolean("extended", false), potionSection.getInt("amplifier", -1)); - } - } - item.setMobType((section.contains("mobType") ? (String) section.get("mobType") : "PIG")); - - item.setBuyPrice(section.get("buy-price")); - - item.setSellPrice(section.get("sell-price")); - - item.setItemType( - section.contains("type") ? ItemType.valueOf((String) section.get("type")) : ItemType.SHOP); - - item.setUseDynamicPricing(section.getBoolean("use-dynamic-price", true)); - - ITEMTABLE.put(item.getItemString(), item); - } - } - } - - /** - * Force create all YML files. - */ - public void createFiles() { - - configf = new File(getDataFolder(), "config.yml"); - specialf = new File(getDataFolder(), "shops.yml"); - - if (!configf.exists()) { - configf.getParentFile().mkdirs(); - saveResource("config.yml", false); - } - - if (!specialf.exists()) { - specialf.getParentFile().mkdirs(); - saveResource("shops.yml", false); - } - - mainConfig = new YamlConfiguration(); - customConfig = new YamlConfiguration(); - - try { - mainConfig.load(configf); - customConfig.load(specialf); - } catch (InvalidConfigurationException | IOException e) { - e.printStackTrace(); - } - - } - - public void reload(Player player, Boolean ignoreCreator) { - createFiles(); - shops.clear(); - ITEMTABLE.clear(); - BUY_COMMANDS.clear(); - SELL_COMMANDS.clear(); - loadedShops.clear(); - if (!ignoreCreator) { - CREATOR.clear(); - } - reloadConfig(); - reloadCustomConfig(); - loadDefaults(); - loadShopDefs(); - - // If the CommandsMode is REGISTER, register/re-register the commands - // Otherwise, unregister the commands - CommandsMode cmdsMode = Config.getCommandsMode(); - registerCommands(cmdsMode != CommandsMode.REGISTER); - - // Intercept commands using the listener, if configured - if (cmdsMode == CommandsMode.INTERCEPT) { - CommandsInterceptor.register(); - - } else { - // Unregisters previous command listener - CommandsInterceptor.unregister(); - } - sendMessage(player, "&aGUIShop Reloaded"); - - } - - public void reloadCustomConfig() { - try { - customConfig.load(specialf); - } catch (IOException | InvalidConfigurationException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Formats money using the economy plugin's significant digits.
- * Does not add currency prefixes or suffixes.
- *
- * Example: 2.4193 -> 2.42
- * Prevents scientific notation being displayed on items. - * - * @param value what to format - * @return the formatted result - */ - public static String economyFormat(double value) { - int digits = ECONOMY.fractionalDigits(); - return (digits == -1) ? Double.toString(value) : String.format("%." + digits + "f", value); - } - - public static String placeholderIfy(String input, Player player, Item item) { - String str = input; - - str = str.replace("{PLAYER_NAME}", player.getName()); - str = str.replace("{PLAYER_UUID}", player.getUniqueId().toString()); - if (item.hasShopName()) { - str = str.replace("{ITEM_SHOP_NAME}", item.getShopName()); - } else { - str = str.replace("{ITEM_SHOP_NAME}", XMaterial.matchXMaterial(item.getMaterial()).get().name()); - } - if (item.hasBuyName()) { - str = str.replace("{ITEM_BUY_NAME}", item.getBuyName()); - } else { - str = str.replace("{ITEM_BUY_NAME}", XMaterial.matchXMaterial(item.getMaterial()).get().name()); - } - if (item.hasBuyPrice()) { - str = str.replace("{BUY_PRICE}", Double.toString(item.calculateBuyPrice(1))); - } - if (item.hasSellPrice()) { - str = str.replace("{SELL_PRICE}", Double.toString(item.calculateSellPrice(1))); - } - str = str.replace("{CURRENCY_SYMBOL}", Config.getCurrency()); - str = str.replace("{CURRENCY_SUFFIX}", Config.getCurrencySuffix()); - - return str; - } - - public static void log(String input) { - Main.getINSTANCE().getLogger().log(Level.WARNING, "[GUISHOP]: " + input); - } - - public static void debugLog(String input) { - if (Config.isDebugMode()) { - Main.getINSTANCE().getLogger().log(Level.WARNING, "[GUISHOP][DEBUG]: " + input); - } - } - - /** - * Sends a message using '{@literal &}' colour codes instead of '§' codes. - * - * @param commandSender the recipient - * @param message the message, which uses {@literal &} colour codes - */ - public static void sendMessage(CommandSender commandSender, String message) { - commandSender.sendMessage(ChatColor.translateAlternateColorCodes('&', message)); - } + /** + * The overridden config file objects. + */ + @Getter + private File configf, specialf; + + /** + * The loaded shops read from the config. + */ + @Getter + private Map shops; + + /** + * The configs FileConfiguration object. + */ + @Getter + private FileConfiguration mainConfig, customConfig; + + /** + * An instance Vault's Economy. + */ + @Getter + private static Economy ECONOMY; + + /** + * the instance of the dynamic price provider, if dynamic pricing is used + */ + @Getter + private static DynamicPriceProvider DYNAMICPRICING; + + /** + * An instance of this class. + */ + @Getter + public static Main INSTANCE; + + /** + * A {@link Set} that will store every command that can be used by a + * {@link Player} to open the {@link Menu}. + */ + @Getter + public static final Set BUY_COMMANDS = new HashSet<>(); + + /** + * A {@link Set} that will store every command that can be used by a + * {@link Player} to open the {@link Sell} GUI. + */ + @Getter + public static final Set SELL_COMMANDS = new HashSet<>(); + + @Getter + public Map> loadedShops = new HashMap<>(); + + @Getter + private final Map ITEMTABLE = new HashMap<>(); + + /** + * A {@link Map} that will store our {@link Creator}s when the server first + * starts. + */ + @Getter + public static final List CREATOR = new ArrayList<>(); + + @Getter + private final MatLib matLib = new MatLib(); + + @Getter + @Setter + private Boolean creatorRefresh = false; + + @Getter + private final Map openShopInstances = new HashMap<>(); + + /** + * The current buy command + */ + private BuyCommand buyCommand = null; + + /** + * The current sell command + */ + private SellCommand sellCommand = null; + + @Override + public void onEnable() { + INSTANCE = this; + shops = new LinkedHashMap<>(); + createFiles(); + + if (!setupEconomy()) { + getLogger().log(Level.INFO, "Vault could not detect an economy plugin!"); + getServer().getPluginManager().disablePlugin(this); + return; + } + + getServer().getPluginManager().registerEvents(PlayerListener.INSTANCE, this); + getServer().getPluginCommand("guishop").setExecutor(new GuishopCommand()); + getServer().getPluginCommand("guishopuser").setExecutor(new GuishopUserCommand()); + loadDefaults(); + if (Config.isDynamicPricing() && !setupDynamicPricing()) { + getLogger().log(Level.INFO, "Could not find a DynamicPriceProvider! Disabling dynamic pricing..."); + Config.setDynamicPricing(false); + } + + loadShopDefs(); + + switch (Config.getCommandsMode()) { + case INTERCEPT: + CommandsInterceptor.register(); + break; + case REGISTER: + registerCommands(false); + break; + default: + break; + } + } + + public void loadShopDefs() { + + ConfigurationSection menuItems = Main.getINSTANCE().getConfig().getConfigurationSection("menu-items"); + + menuItems.getKeys(false).forEach(key -> { + String name = menuItems.getString(key + ".Name") != null ? ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(menuItems.getString(key + ".Name"))) : " "; + String description = menuItems.getString(key + ".Desc") != null ? ChatColor.translateAlternateColorCodes( + '&', Objects.requireNonNull(menuItems.getString(key + ".Desc"))) : " "; + ItemType itemType = menuItems.getString(key + ".Type") != null + ? ItemType.valueOf(menuItems.getString(key + ".Type")) + : ItemType.SHOP; + if (!(!menuItems.getBoolean(key + ".Enabled") && itemType == ItemType.SHOP)) { + String itemID = itemType != ItemType.BLANK ? menuItems.getString(key + ".Item") : "AIR"; + + List lore = new ArrayList<>(); + + if (description.length() > 0) { + lore.add(description); + } + + shops.put(key.toLowerCase(), new ShopDef(key, name, description, lore, itemType, itemID)); + } + }); + + new Menu().itemWarmup(); + loadPRICETABLE(); + } + + /** + * Register/unregister the GUIShop commands with the bukkit server.
+ * Accesses the command map via reflection + * + * @param onlyUnregister if true, new commands will not be registered, only, + * existing ones will be unregistered + */ + private void registerCommands(boolean onlyUnregister) { + if (onlyUnregister && buyCommand == null && sellCommand == null) { + // Nothing is registered, no need to do anything + return; + } + getLogger().log(Level.INFO, "Registering/unregistering commands {0} and {1}", new Object[]{StringUtils.join(Main.BUY_COMMANDS, "|"), StringUtils.join(Main.SELL_COMMANDS, "|")}); + + try { + final Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap"); + + bukkitCommandMap.setAccessible(true); + CommandMap commandMap = (CommandMap) bukkitCommandMap.get(Bukkit.getServer()); + + // Unregister old commands + if (buyCommand != null) { + buyCommand.unregister(commandMap); + } + + if (sellCommand != null) { + sellCommand.unregister(commandMap); + } + + if (onlyUnregister) { + return; + } + // Register new commands + buyCommand = new BuyCommand(new ArrayList<>(Main.BUY_COMMANDS)); + commandMap.register(buyCommand.getName(), buyCommand); + + sellCommand = new SellCommand(new ArrayList<>(Main.SELL_COMMANDS)); + commandMap.register(sellCommand.getName(), sellCommand); + + } catch (IllegalAccessException | NoSuchFieldException e) { + debugLog("Error registering commands: " + e.getMessage()); + } + } + + public GuishopUserCommand getUserCommands() { + return (GuishopUserCommand) getServer().getPluginCommand("guishopuser").getExecutor(); + } + + /** + * Check if Vault is present, Check if an Economy plugin is present, if so + * Hook. + */ + private Boolean setupEconomy() { + if (getServer().getPluginManager().getPlugin("Vault") == null) { + return false; + } + + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); + + if (rsp == null || rsp.getProvider() == null) { + return false; + } + + ECONOMY = rsp.getProvider(); + + return true; + } + + /** + * Find the dynamic price provider if present + */ + private boolean setupDynamicPricing() { + RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(DynamicPriceProvider.class); + + if (rsp == null || rsp.getProvider() == null) { + return false; + } + DYNAMICPRICING = rsp.getProvider(); + + return true; + } + + /** + * Load all deault config values, translate colors, store. + */ + public void loadDefaults() { + BUY_COMMANDS.addAll(getMainConfig().getStringList("buy-commands")); + SELL_COMMANDS.addAll(getMainConfig().getStringList("sell-commands")); + Config.setCommandsMode(CommandsMode.parseFromConfig(getMainConfig().getString("commands-mode"))); + Config.setPrefix(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("prefix")))); + Config.setSignsOnly(getMainConfig().getBoolean("signs-only")); + Config.setSignTitle(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("sign-title")))); + Config.setNotEnoughPre(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("not-enough-pre")))); + Config.setNotEnoughPost(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("not-enough-post")))); + Config.setPurchased(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("purchased")))); + Config.setTaken(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("taken")))); + Config.setSold( + ChatColor.translateAlternateColorCodes('&', Objects.requireNonNull(getMainConfig().getString("sold")))); + Config.setAdded(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("added")))); + Config.setCantSell(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("cant-sell")))); + Config.setEscapeOnly(getMainConfig().getBoolean("escape-only")); + Config.setAlternateSellEnabled(getMainConfig().getBoolean("alternate-sell-enable", false)); + Config.setSound(getMainConfig().getString("purchase-sound")); + Config.setSoundEnabled(getMainConfig().getBoolean("enable-sound")); + Config.setEnableCreator(getMainConfig().getBoolean("ingame-config")); + Config.setCantBuy(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("cant-buy")))); + Config.setMenuRows(getMainConfig().getInt("menu-rows")); + Config.setFull(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("full-inventory")))); + Config.setNoPermission(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("no-permission")))); + Config.setCurrency(getMainConfig().getString("currency")); + Config.setCurrencySuffix(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("currency-suffix")))); + Config.setMenuTitle(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("menu-title", "Menu"))); + Config.setShopTitle(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("shop-title", "Menu &f> &r{shopname}"))); + Config.setSellTitle(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("sell-title", "Menu &f> &rSell"))); + Config.setAltSellTitle(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("alt-sell-title", "Menu &f> &rSell"))); + Config.setQtyTitle(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("qty-title")))); + Config.setBackButtonItem(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("back-button-item")))); + Config.setBackButtonText( + ChatColor.translateAlternateColorCodes('&', Objects.requireNonNull(getMainConfig().getString("back")))); + Config.setBuyLore(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("buy-lore")))); + Config.setSellLore(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("sell-lore")))); + Config.setFreeLore(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("free-lore")))); + + Config.setCannotBuy(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("cannot-buy")))); + Config.setCannotSell(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(getMainConfig().getString("cannot-sell")))); + Config.setForwardPageButtonName( + ChatColor.translateAlternateColorCodes('&', getMainConfig().getString("forward-page-button-name", ""))); + Config.setBackwardPageButtonName( + ChatColor.translateAlternateColorCodes('&', getMainConfig().getString("backward-page-button-name", ""))); + Config.setAltSellIndicatorMaterial(getMainConfig().getString("alt-sell-indicator-material", "EMERALD")); + Config.setAltSellAddMaterial(getMainConfig().getString("alt-sell-add-material", "GREEN_STAINED_GLASS_PANE")); + Config.setAltSellRemoveMaterial(getMainConfig().getString("alt-sell-remove-material", "RED_STAINED_GLASS_PANE")); + Config.setAltSellQuantity1(getMainConfig().getInt("alt-sell-quantity-1", 1)); + Config.setAltSellQuantity2(getMainConfig().getInt("alt-sell-quantity-2", 10)); + Config.setAltSellQuantity3(getMainConfig().getInt("alt-sell-quantity-3", 64)); + Config.setAltSellConfirmMaterial(getMainConfig().getString("alt-sell-confirm-material", "EMERALD_BLOCK")); + Config.setAltSellCancelMaterial(getMainConfig().getString("alt-sell-cancel-material", "REDSTONE_BLOCK")); + Config.setAltSellConfirmName(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("alt-sell-confirm-name", "&a&lConfirm"))); + Config.setAltSellCancelName(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("alt-sell-cancel-name", "&c&lCancel"))); + Config.setAltSellNotEnough(ChatColor.translateAlternateColorCodes('&', + getMainConfig().getString("alt-sell-not-enough", "&cYou do not have enough items to sell."))); + Config.getDisabledQty().addAll(getMainConfig().getStringList("disabled-qty-items")); + Config.setDynamicPricing(getMainConfig().getBoolean("dynamic-pricing", false)); + Config.setDebugMode(getMainConfig().getBoolean("debug-mode")); + } + + private void loadPRICETABLE() { + + for (String shop : Main.getINSTANCE().getCustomConfig().getKeys(false)) { + + ConfigurationSection config = Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop); + if (config == null) { + log("Check the section for shop " + shop + " in the shops.yml. It was not found."); + continue; + } + + assert config != null; + for (String str : config.getKeys(false)) { + + Item item = new Item(); + + ConfigurationSection section = config.getConfigurationSection(str); + if (section == null) { + log("Check the config section for item " + str + " in shop " + shop + " the shops.yml. It is not a valid section."); + continue; + } + + item.setMaterial((section.contains("id") ? (String) section.get("id") : "AIR")); + if (item.isAnyPotion()) { + ConfigurationSection potionSection = section.getConfigurationSection("potion-info"); + if (potionSection != null) { + item.parsePotionType(potionSection.getString("type"), + potionSection.getBoolean("splash", false), + potionSection.getBoolean("extended", false), potionSection.getInt("amplifier", -1)); + } + } + item.setMobType((section.contains("mobType") ? (String) section.get("mobType") : "PIG")); + + item.setBuyPrice(section.get("buy-price")); + + item.setSellPrice(section.get("sell-price")); + + item.setItemType( + section.contains("type") ? ItemType.valueOf((String) section.get("type")) : ItemType.SHOP); + + item.setUseDynamicPricing(section.getBoolean("use-dynamic-price", true)); + + ITEMTABLE.put(item.getItemString(), item); + } + } + } + + /** + * Force create all YML files. + */ + public void createFiles() { + + configf = new File(getDataFolder(), "config.yml"); + specialf = new File(getDataFolder(), "shops.yml"); + + if (!configf.exists()) { + configf.getParentFile().mkdirs(); + saveResource("config.yml", false); + } + + if (!specialf.exists()) { + specialf.getParentFile().mkdirs(); + saveResource("shops.yml", false); + } + + mainConfig = new YamlConfiguration(); + customConfig = new YamlConfiguration(); + + try { + mainConfig.load(configf); + customConfig.load(specialf); + } catch (InvalidConfigurationException | IOException e) { + debugLog("Error creating configs: " + e.getMessage()); + } + + } + + public void reload(Player player, Boolean ignoreCreator) { + createFiles(); + shops.clear(); + ITEMTABLE.clear(); + BUY_COMMANDS.clear(); + SELL_COMMANDS.clear(); + loadedShops.clear(); + if (!ignoreCreator) { + CREATOR.clear(); + } + reloadConfig(); + reloadCustomConfig(); + loadDefaults(); + loadShopDefs(); + + // If the CommandsMode is REGISTER, register/re-register the commands + // Otherwise, unregister the commands + CommandsMode cmdsMode = Config.getCommandsMode(); + registerCommands(cmdsMode != CommandsMode.REGISTER); + + // Intercept commands using the listener, if configured + if (cmdsMode == CommandsMode.INTERCEPT) { + CommandsInterceptor.register(); + + } else { + // Unregisters previous command listener + CommandsInterceptor.unregister(); + } + sendMessage(player, "&aGUIShop Reloaded"); + + } + + public void reloadCustomConfig() { + try { + customConfig.load(specialf); + } catch (IOException | InvalidConfigurationException e) { + // TODO Auto-generated catch block + debugLog("Error loading custom config: " + e.getMessage()); + } + } + + /** + * Formats money using the economy plugin's significant digits.
+ * Does not add currency prefixes or suffixes.
+ *
+ * Example: 2.4193 -> 2.42
+ * Prevents scientific notation being displayed on items. + * + * @param value what to format + * @return the formatted result + */ + public static String economyFormat(double value) { + int digits = ECONOMY.fractionalDigits(); + return (digits == -1) ? Double.toString(value) : String.format("%." + digits + "f", value); + } + + public static String placeholderIfy(String input, Player player, Item item) { + String str = input; + + str = str.replace("{PLAYER_NAME}", player.getName()); + str = str.replace("{PLAYER_UUID}", player.getUniqueId().toString()); + if (item.hasShopName()) { + str = str.replace("{ITEM_SHOP_NAME}", item.getShopName()); + } else { + str = str.replace("{ITEM_SHOP_NAME}", XMaterial.matchXMaterial(item.getMaterial()).get().name()); + } + if (item.hasBuyName()) { + str = str.replace("{ITEM_BUY_NAME}", item.getBuyName()); + } else { + str = str.replace("{ITEM_BUY_NAME}", XMaterial.matchXMaterial(item.getMaterial()).get().name()); + } + if (item.hasBuyPrice()) { + str = str.replace("{BUY_PRICE}", Double.toString(item.calculateBuyPrice(1))); + } + if (item.hasSellPrice()) { + str = str.replace("{SELL_PRICE}", Double.toString(item.calculateSellPrice(1))); + } + str = str.replace("{CURRENCY_SYMBOL}", Config.getCurrency()); + str = str.replace("{CURRENCY_SUFFIX}", Config.getCurrencySuffix()); + + return str; + } + + public static void log(String input) { + Main.getINSTANCE().getLogger().log(Level.WARNING, "[GUISHOP]: {0}", input); + } + + public static void debugLog(String input) { + if (Config.isDebugMode()) { + Main.getINSTANCE().getLogger().log(Level.WARNING, "[GUISHOP][DEBUG]: {0}", input); + } + } + + /** + * Sends a message using '{@literal &}' colour codes instead of '§' codes. + * + * @param commandSender the recipient + * @param message the message, which uses {@literal &} colour codes + */ + public static void sendMessage(CommandSender commandSender, String message) { + commandSender.sendMessage(ChatColor.translateAlternateColorCodes('&', message)); + } } diff --git a/src/com/pablo67340/guishop/api/DynamicPriceProvider.java b/src/com/pablo67340/guishop/api/DynamicPriceProvider.java index 8bde1a0..220bea2 100644 --- a/src/com/pablo67340/guishop/api/DynamicPriceProvider.java +++ b/src/com/pablo67340/guishop/api/DynamicPriceProvider.java @@ -3,60 +3,60 @@ /** * Used to hook into GUIShop and provide dynamic pricing.
*
- * Implementations must be registered with the Bukkit registration system - * in order for GUIShop to detect and use them. + * Implementations must be registered with the Bukkit registration system in + * order for GUIShop to detect and use them. * */ public interface DynamicPriceProvider { - - /** - * Calculates the buy price of a certain quantity of a specific item.
- * The item is provided as a unique string based key.
- *
- * The fixed, configured buy and sell prices of the item, as defined in the - * shops.yml, are provided in order to parameterise the price equation this - * DynamicPriceProvider uses. - * - * @param item a unique string based representation of the item - * @param quantity the amount of the item which would be bought - * @param staticBuyPrice the configured buy price in the shops.yml - * @param staticSellPrice the configured sell price in the shops.yml - * @return the calculated buy price - */ - double calculateBuyPrice(String item, int quantity, double staticBuyPrice, double staticSellPrice); - - /** - * Calculates the sell price of a certain quantity of a specific item.
- * The item is provided as a qunie string based key.
- *
- * The fixed, configured buy and sell prices of the item, as defined in the - * shops.yml, are provided in order to parameterise the price equation this - * DynamicPriceProvider uses. - * - * @param item a unique string based representation of the item - * @param quantity the amount of the item which would be sold - * @param staticBuyPrice the configured buy price in the shops.yml - * @param staticSellPrice the configured sell price in the shops.yml - * @return the calculated buy price - */ - double calculateSellPrice(String item, int quantity, double staticBuyPrice, double staticSellPrice); - - /** - * Indicates to this DynamicPriceProvider that a certain quantity of a - * specific item has been bought. - * - * @param item a unique string based representation of the item - * @param quantity the amount of the item which was bought - */ - void buyItem(String item, int quantity); - - /** - * Indicates to this DynamicPriceProvider that a certain quantity of a - * specific item has been sold. - * - * @param item a unique string based representation of the item - * @param quantity the amount of the item which was sold - */ - void sellItem(String item, int quantity); - + + /** + * Calculates the buy price of a certain quantity of a specific item.
+ * The item is provided as a unique string based key.
+ *
+ * The fixed, configured buy and sell prices of the item, as defined in the + * shops.yml, are provided in order to parameterise the price equation this + * DynamicPriceProvider uses. + * + * @param item a unique string based representation of the item + * @param quantity the amount of the item which would be bought + * @param staticBuyPrice the configured buy price in the shops.yml + * @param staticSellPrice the configured sell price in the shops.yml + * @return the calculated buy price + */ + double calculateBuyPrice(String item, int quantity, double staticBuyPrice, double staticSellPrice); + + /** + * Calculates the sell price of a certain quantity of a specific item.
+ * The item is provided as a qunie string based key.
+ *
+ * The fixed, configured buy and sell prices of the item, as defined in the + * shops.yml, are provided in order to parameterise the price equation this + * DynamicPriceProvider uses. + * + * @param item a unique string based representation of the item + * @param quantity the amount of the item which would be sold + * @param staticBuyPrice the configured buy price in the shops.yml + * @param staticSellPrice the configured sell price in the shops.yml + * @return the calculated buy price + */ + double calculateSellPrice(String item, int quantity, double staticBuyPrice, double staticSellPrice); + + /** + * Indicates to this DynamicPriceProvider that a certain quantity of a + * specific item has been bought. + * + * @param item a unique string based representation of the item + * @param quantity the amount of the item which was bought + */ + void buyItem(String item, int quantity); + + /** + * Indicates to this DynamicPriceProvider that a certain quantity of a + * specific item has been sold. + * + * @param item a unique string based representation of the item + * @param quantity the amount of the item which was sold + */ + void sellItem(String item, int quantity); + } diff --git a/src/com/pablo67340/guishop/api/GuiShopAPI.java b/src/com/pablo67340/guishop/api/GuiShopAPI.java index 2e21d7c..2b4bb84 100644 --- a/src/com/pablo67340/guishop/api/GuiShopAPI.java +++ b/src/com/pablo67340/guishop/api/GuiShopAPI.java @@ -11,130 +11,142 @@ /** * Officially supported API for interacting with GuiShop.
*
- * Accessing GuiShop internals is not supported and liable to change at any time. + * Accessing GuiShop internals is not supported and liable to change at any + * time. * */ public class GuiShopAPI { - private GuiShopAPI() {} - - /** - * Sells the specified items for the player as if the player - * had used the sell GUI and inserted the items there.
- *
- * The items' total sale price is summed and the reward is given to the player. - * If an item cannot be sold, the items are added back to the player's inventory.
- * Use check {@link #canBeSold(ItemStack} to check if an item cannot be sold. - * No items are removed from the players' inventory; the caller is trusted with such.
- *
- * This may be useful if, for example, you want to make an - * autosell feature which uses the same prices from GuiShop, - * so you do not have to create a separate config. - * - * @param player the player for whom to sell - * @param items the items which are sold - */ - public static void sellItems(Player player, ItemStack...items) { - Sell.sellItems(player, items); - } - - /** - * Determines whether the specified item could be sold - * through the sell GUI.
- *
- * Formally, if an item is listed in the shops.yml with - * a nonzero sell price, it can be sold. - * - * @param item the itemstack which would be sold - * @return whether it can be sold - */ - public static boolean canBeSold(ItemStack item) { - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); - return shopItem != null && shopItem.hasSellPrice(); - } - - /** - * Determines whether the specified item could be bought - * (has a buy price). An item is considered to be able - * to be purchased even if it is not displayed in the GUI.
- *
- * Formally, if an item is listed in the shops.yml with a - * defined buy price, it can be bought. - * - * @param item the itemstack which would be bought - * @return whether it can be bought - */ - public static boolean canBeBought(ItemStack item) { - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); - return shopItem != null && shopItem.hasBuyPrice(); - } - - /** - * Gets the buy price for an item with specified quantity.
- * If the item does not exist or does not have a buy price, -1 is returned. - * - * @param item the itemstack - * @param quantity the quantity which would be purchased - * @return the buy price or minus 1 if not set - */ - public static double getBuyPrice(ItemStack item, int quantity) { - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); - return (shopItem != null && shopItem.hasBuyPrice()) ? shopItem.calculateBuyPrice(quantity) : -1; - } - - /** - * Gets the sell price for an item with specified quantity.
- * If the item does not exist or does not have a sell price, -1 is returned. - * - * @param item the itemstack - * @param quantity the quantity which would be sold - * @return the sell price or minus 1 if not set - */ - public static double getSellPrice(ItemStack item, int quantity) { - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); - return (shopItem != null && shopItem.hasSellPrice()) ? shopItem.calculateSellPrice(quantity) : -1; - } - - /** - * Indicates to GUIShop that the item has been purchased with the specified quantity.
- * If dynamic pricing is enabled, GUIShop will then inform the dynamic pricing provider - * that the purchase has occurred. (If disabled, nothing happens)
- *
- * Note that even if you are not using dynamic pricing, calling this method is recommended - * because it automatically ensures compatibility with dynamic pricing. - * - * @param item the itemstack - * @param quantity the quantity which was purchased - */ - public static void indicateBoughtItems(ItemStack item, int quantity) { - String itemString = Item.getItemStringForItemStack(item); - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(itemString); + private GuiShopAPI() { + } - if (shopItem != null && Config.isDynamicPricing() && shopItem.isUseDynamicPricing() && shopItem.hasBuyPrice() - && shopItem.hasSellPrice()) { - Main.getDYNAMICPRICING().buyItem(itemString, quantity); - } - } - - /** - * Indicates to GUIShop that the item has been sold with the specified quantity.
- * If dynamic pricing is enabled, GUIShop will then inform the dynamic pricing provider - * that the purchase has occurred. (If disabled, nothing happens)
- *
- * Note that even if you are not using dynamic pricing, calling this method is recommended - * because it automatically ensures compatibility with dynamic pricing. - * - * @param item the itemstack - * @param quantity the quantity which was purchased - */ - public static void indicateSoldItems(ItemStack item, int quantity) { - String itemString = Item.getItemStringForItemStack(item); - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(itemString); + /** + * Sells the specified items for the player as if the player had used the + * sell GUI and inserted the items there.
+ *
+ * The items' total sale price is summed and the reward is given to the + * player. If an item cannot be sold, the items are added back to the + * player's inventory.
+ * Use check {@link #canBeSold(ItemStack} to check if an item cannot be + * sold. No items are removed from the players' inventory; the caller + * is trusted with such.
+ *
+ * This may be useful if, for example, you want to make an autosell feature + * which uses the same prices from GuiShop, so you do not have to create a + * separate config. + * + * @param player the player for whom to sell + * @param items the items which are sold + */ + public static void sellItems(Player player, ItemStack... items) { + Sell.sellItems(player, items); + } + + /** + * Determines whether the specified item could be sold through the sell GUI. + *
+ *
+ * Formally, if an item is listed in the shops.yml with a nonzero sell + * price, it can be sold. + * + * @param item the itemstack which would be sold + * @return whether it can be sold + */ + public static boolean canBeSold(ItemStack item) { + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); + return shopItem != null && shopItem.hasSellPrice(); + } + + /** + * Determines whether the specified item could be bought (has a buy price). + * An item is considered to be able to be purchased even if it is not + * displayed in the GUI.
+ *
+ * Formally, if an item is listed in the shops.yml with a defined buy price, + * it can be bought. + * + * @param item the itemstack which would be bought + * @return whether it can be bought + */ + public static boolean canBeBought(ItemStack item) { + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); + return shopItem != null && shopItem.hasBuyPrice(); + } + + /** + * Gets the buy price for an item with specified quantity.
+ * If the item does not exist or does not have a buy price, -1 + * is returned. + * + * @param item the itemstack + * @param quantity the quantity which would be purchased + * @return the buy price or minus 1 if not set + */ + public static double getBuyPrice(ItemStack item, int quantity) { + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); + return (shopItem != null && shopItem.hasBuyPrice()) ? shopItem.calculateBuyPrice(quantity) : -1; + } + + /** + * Gets the sell price for an item with specified quantity.
+ * If the item does not exist or does not have a sell price, -1 + * is returned. + * + * @param item the itemstack + * @param quantity the quantity which would be sold + * @return the sell price or minus 1 if not set + */ + public static double getSellPrice(ItemStack item, int quantity) { + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(Item.getItemStringForItemStack(item)); + return (shopItem != null && shopItem.hasSellPrice()) ? shopItem.calculateSellPrice(quantity) : -1; + } + + /** + * Indicates to GUIShop that the item has been purchased with the specified + * quantity.
+ * If dynamic pricing is enabled, GUIShop will then inform the dynamic + * pricing provider that the purchase has occurred. (If disabled, nothing + * happens)
+ *
+ * Note that even if you are not using dynamic pricing, calling this method + * is recommended because it automatically ensures compatibility with + * dynamic pricing. + * + * @param item the itemstack + * @param quantity the quantity which was purchased + */ + public static void indicateBoughtItems(ItemStack item, int quantity) { + String itemString = Item.getItemStringForItemStack(item); + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(itemString); + + if (shopItem != null && Config.isDynamicPricing() && shopItem.isUseDynamicPricing() && shopItem.hasBuyPrice() + && shopItem.hasSellPrice()) { + Main.getDYNAMICPRICING().buyItem(itemString, quantity); + } + } + + /** + * Indicates to GUIShop that the item has been sold with the specified + * quantity.
+ * If dynamic pricing is enabled, GUIShop will then inform the dynamic + * pricing provider that the purchase has occurred. (If disabled, nothing + * happens)
+ *
+ * Note that even if you are not using dynamic pricing, calling this method + * is recommended because it automatically ensures compatibility with + * dynamic pricing. + * + * @param item the itemstack + * @param quantity the quantity which was purchased + */ + public static void indicateSoldItems(ItemStack item, int quantity) { + String itemString = Item.getItemStringForItemStack(item); + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(itemString); + + if (shopItem != null && Config.isDynamicPricing() && shopItem.isUseDynamicPricing() && shopItem.hasBuyPrice() + && shopItem.hasSellPrice()) { + Main.getDYNAMICPRICING().sellItem(itemString, quantity); + } + } - if (shopItem != null && Config.isDynamicPricing() && shopItem.isUseDynamicPricing() && shopItem.hasBuyPrice() - && shopItem.hasSellPrice()) { - Main.getDYNAMICPRICING().sellItem(itemString, quantity); - } - } - } diff --git a/src/com/pablo67340/guishop/commands/BuyCommand.java b/src/com/pablo67340/guishop/commands/BuyCommand.java index d54fa58..67045c8 100644 --- a/src/com/pablo67340/guishop/commands/BuyCommand.java +++ b/src/com/pablo67340/guishop/commands/BuyCommand.java @@ -9,6 +9,7 @@ import java.util.ArrayList; public class BuyCommand extends BukkitCommand { + public BuyCommand(ArrayList aliases) { super(aliases.remove(0)); this.description = "Opens the shops menu."; diff --git a/src/com/pablo67340/guishop/commands/CommandsInterceptor.java b/src/com/pablo67340/guishop/commands/CommandsInterceptor.java index 472e3b2..9609d34 100644 --- a/src/com/pablo67340/guishop/commands/CommandsInterceptor.java +++ b/src/com/pablo67340/guishop/commands/CommandsInterceptor.java @@ -10,53 +10,54 @@ import com.pablo67340.guishop.Main; /** - * Listener when the commands mode is {@link com.pablo67340.guishop.definition.CommandsMode#INTERCEPT CommandsMode.INTERCEPT}. + * Listener when the commands mode is + * {@link com.pablo67340.guishop.definition.CommandsMode#INTERCEPT CommandsMode.INTERCEPT}. * */ public class CommandsInterceptor implements Listener { - private static CommandsInterceptor inst; - - /** - * Registers the listener if not yet registered - * - */ - public static void register() { - if (inst == null) { - inst = new CommandsInterceptor(); - Bukkit.getPluginManager().registerEvents(inst, Main.getINSTANCE()); - } - } - - /** - * Unregisters the listener if already registered - * - */ - public static void unregister() { - if (inst != null) { - HandlerList.unregisterAll(inst); - inst = null; - } - } - - /* + private static CommandsInterceptor inst; + + /** + * Registers the listener if not yet registered + * + */ + public static void register() { + if (inst == null) { + inst = new CommandsInterceptor(); + Bukkit.getPluginManager().registerEvents(inst, Main.getINSTANCE()); + } + } + + /** + * Unregisters the listener if already registered + * + */ + public static void unregister() { + if (inst != null) { + HandlerList.unregisterAll(inst); + inst = null; + } + } + + /* * By ignoring cancelled events we can avoid incompatibilities with some plugins, * e.g. anti-combat logging plugins, which block commands selectively. - */ - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public void onCommand(PlayerCommandPreprocessEvent evt) { - - String[] cut = evt.getMessage().substring(1).split(" "); - GuishopUserCommand userCmds = Main.getINSTANCE().getUserCommands(); - - if (Main.BUY_COMMANDS.contains(cut[0])) { - userCmds.buyCommand(evt.getPlayer(), (cut.length >= 2) ? cut[1] : null); - evt.setCancelled(true); - - } else if (Main.SELL_COMMANDS.contains(cut[0])) { - userCmds.sellCommand(evt.getPlayer()); - evt.setCancelled(true); - } - } - + */ + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onCommand(PlayerCommandPreprocessEvent evt) { + + String[] cut = evt.getMessage().substring(1).split(" "); + GuishopUserCommand userCmds = Main.getINSTANCE().getUserCommands(); + + if (Main.BUY_COMMANDS.contains(cut[0])) { + userCmds.buyCommand(evt.getPlayer(), (cut.length >= 2) ? cut[1] : null); + evt.setCancelled(true); + + } else if (Main.SELL_COMMANDS.contains(cut[0])) { + userCmds.sellCommand(evt.getPlayer()); + evt.setCancelled(true); + } + } + } diff --git a/src/com/pablo67340/guishop/commands/GuishopCommand.java b/src/com/pablo67340/guishop/commands/GuishopCommand.java index c578362..715588b 100644 --- a/src/com/pablo67340/guishop/commands/GuishopCommand.java +++ b/src/com/pablo67340/guishop/commands/GuishopCommand.java @@ -15,69 +15,70 @@ public class GuishopCommand implements CommandExecutor { - /** - * Gets the permission corresponding to a subcommand of /guishop - * - * @param subCommand the subcommand, null for the base command - * @return the permission - */ - private String getRequiredPermission(String subCommand) { - if (subCommand == null) { - return "guishop.admin"; - } - switch (subCommand.toLowerCase()) { - case "reload": - return "guishop.reload"; - default: - return "guishop.admin"; - } - } - - /** - * Whether the command sender has the permission for a subcommand of /guishop - * - * @param sender the command sender - * @param subCommand the sub command, null for the base command - * @return true if permitted, false otherwise - */ - private boolean hasRequiredPermission(CommandSender sender, String subCommand) { - return sender.hasPermission(getRequiredPermission(subCommand)) || sender.isOp(); - } - + /** + * Gets the permission corresponding to a subcommand of /guishop + * + * @param subCommand the subcommand, null for the base command + * @return the permission + */ + private String getRequiredPermission(String subCommand) { + if (subCommand == null) { + return "guishop.admin"; + } + switch (subCommand.toLowerCase()) { + case "reload": + return "guishop.reload"; + default: + return "guishop.admin"; + } + } + + /** + * Whether the command sender has the permission for a subcommand of + * /guishop + * + * @param sender the command sender + * @param subCommand the sub command, null for the base command + * @return true if permitted, false otherwise + */ + private boolean hasRequiredPermission(CommandSender sender, String subCommand) { + return sender.hasPermission(getRequiredPermission(subCommand)) || sender.isOp(); + } + @Override public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] args) { - if (!hasRequiredPermission(commandSender, (args.length >= 1) ? args[0] : null)) { - Main.sendMessage(commandSender, Config.getNoPermission()); - return true; - } + if (!hasRequiredPermission(commandSender, (args.length >= 1) ? args[0] : null)) { + Main.sendMessage(commandSender, Config.getNoPermission()); + return true; + } - Player player = (Player) commandSender; + Player player = (Player) commandSender; if (args.length >= 1) { - if (args[0].equalsIgnoreCase("parsematerial")) { - if (args.length >= 2) { - Item tempItem = new Item(); - tempItem.setMaterial(args[1]); - player.sendMessage(args[1] + " is " + ((tempItem.parseMaterial() == null) ? "NOT " : "") + "a valid material."); - } else { - player.sendMessage("Please specify a material."); - } + if (args[0].equalsIgnoreCase("parsematerial")) { + if (args.length >= 2) { + Item tempItem = new Item(); + tempItem.setMaterial(args[1]); + player.sendMessage(args[1] + " is " + ((tempItem.parseMaterial() == null) ? "NOT " : "") + "a valid material."); + } else { + player.sendMessage("Please specify a material."); + } - } else if (args[0].equalsIgnoreCase("parsemob")) { - if (args.length >= 2) { - Item tempItem = new Item(); - tempItem.setMobType(args[1]); - player.sendMessage(args[1] + " is " + ((tempItem.parseMobSpawnerType() == null) ? "NOT " : "") + "a valid mob type."); - } else { - player.sendMessage("Please specify a mob."); - } + } else if (args[0].equalsIgnoreCase("parsemob")) { + if (args.length >= 2) { + Item tempItem = new Item(); + tempItem.setMobType(args[1]); + player.sendMessage(args[1] + " is " + ((tempItem.parseMobSpawnerType() == null) ? "NOT " : "") + "a valid mob type."); + } else { + player.sendMessage("Please specify a mob."); + } - } else if (args[0].equalsIgnoreCase("edit") || args[0].equalsIgnoreCase("e")) { + } else if (args[0].equalsIgnoreCase("edit") || args[0].equalsIgnoreCase("e")) { - Main.getCREATOR().add(player.getName()); - Main.debugLog("Added player to creator mode"); - PlayerListener.INSTANCE.openShop(player); + Main.getCREATOR().add(player.getName()); + Main.debugLog("Added player to creator mode"); + PlayerListener.INSTANCE.openShop(player); } else if (args[0].equalsIgnoreCase("p") || args[0].equalsIgnoreCase("price")) { Object result = null; @@ -86,10 +87,10 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command } else { try { result = Double.parseDouble(args[1]); - } catch (Exception ex) { + } catch (NumberFormatException ex) { try { result = Integer.parseInt(args[1]); - } catch (Exception ex2) { + } catch (NumberFormatException ex2) { player.sendMessage("Please use a valid value"); } } @@ -98,25 +99,25 @@ public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command } else if (args[0].equalsIgnoreCase("s") || args[0].equalsIgnoreCase("sell")) { - if (args.length >= 2) { + if (args.length >= 2) { Object result = null; if (args[1].equalsIgnoreCase("false")) { result = false; } else { try { result = Double.parseDouble(args[1]); - } catch (Exception ex) { + } catch (NumberFormatException ex) { try { result = Integer.parseInt(args[1]); - } catch (Exception ex2) { + } catch (NumberFormatException ex2) { player.sendMessage("Please use a valid value"); } } } ItemUtil.setSell(result, player); - } else { - player.sendMessage("Please specify a value."); - } + } else { + player.sendMessage("Please specify a value."); + } } else if (args[0].equalsIgnoreCase("sn") || args[0].equalsIgnoreCase("shopname")) { if (args.length >= 2) { diff --git a/src/com/pablo67340/guishop/commands/GuishopUserCommand.java b/src/com/pablo67340/guishop/commands/GuishopUserCommand.java index e8d8e6a..cae0a4a 100644 --- a/src/com/pablo67340/guishop/commands/GuishopUserCommand.java +++ b/src/com/pablo67340/guishop/commands/GuishopUserCommand.java @@ -14,75 +14,75 @@ public class GuishopUserCommand implements CommandExecutor { - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (!(sender instanceof Player)) { - Main.sendMessage(sender, "&cPlayers only."); - return true; - } - Player player = (Player) sender; - - if (args.length >= 1) { - if (Main.BUY_COMMANDS.contains(args[0].toLowerCase())) { - - buyCommand(player, (args.length >= 2) ? args[1] : null); - return true; - - } else if (Main.SELL_COMMANDS.contains(args[0].toLowerCase())) { - - sellCommand(player); - return true; - } - } - Main.sendMessage(player, "&cUnknown command."); - return true; - } - - /** - * Whether a player uses a buy command.
- * Includes permission checks - * - * @param player the player - * @param shop the command argument for a specific shop, can be null - */ - void buyCommand(Player player, String shop) { - if (player.hasPermission("guishop.use") || player.isOp()) { - - if (shop == null) { - PlayerListener.INSTANCE.openShop(player); - - } else if (Main.getINSTANCE().getShops().containsKey(shop.toLowerCase())) { - - ShopDef shopDef = Main.getINSTANCE().getShops().get(shop.toLowerCase()); - - if (player.hasPermission("guishop.shop." + shopDef.getShop()) - || player.hasPermission("guishop.shop.*") || player.isOp()) { - new Menu().openShop(player, shopDef); - } else { - player.sendMessage(Config.getNoPermission()); - } - - } else { - Main.sendMessage(player, "&cShop not found"); - } - - } else { - player.sendMessage(Config.getNoPermission()); + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + Main.sendMessage(sender, "&cPlayers only."); + return true; } - } - - /** - * When a player uses a sell command.
- * Includes permission checks - * - * @param player the player - */ - void sellCommand(Player player) { - if (player.hasPermission("guishop.sell") || player.isOp()) { - new Sell().open(player); - } else { - player.sendMessage(Config.getNoPermission()); - } - } + Player player = (Player) sender; + + if (args.length >= 1) { + if (Main.BUY_COMMANDS.contains(args[0].toLowerCase())) { + + buyCommand(player, (args.length >= 2) ? args[1] : null); + return true; + + } else if (Main.SELL_COMMANDS.contains(args[0].toLowerCase())) { + + sellCommand(player); + return true; + } + } + Main.sendMessage(player, "&cUnknown command."); + return true; + } + + /** + * Whether a player uses a buy command.
+ * Includes permission checks + * + * @param player the player + * @param shop the command argument for a specific shop, can be null + */ + void buyCommand(Player player, String shop) { + if (player.hasPermission("guishop.use") || player.isOp()) { + + if (shop == null) { + PlayerListener.INSTANCE.openShop(player); + + } else if (Main.getINSTANCE().getShops().containsKey(shop.toLowerCase())) { + + ShopDef shopDef = Main.getINSTANCE().getShops().get(shop.toLowerCase()); + + if (player.hasPermission("guishop.shop." + shopDef.getShop()) + || player.hasPermission("guishop.shop.*") || player.isOp()) { + new Menu().openShop(player, shopDef); + } else { + player.sendMessage(Config.getNoPermission()); + } + + } else { + Main.sendMessage(player, "&cShop not found"); + } + + } else { + player.sendMessage(Config.getNoPermission()); + } + } + + /** + * When a player uses a sell command.
+ * Includes permission checks + * + * @param player the player + */ + void sellCommand(Player player) { + if (player.hasPermission("guishop.sell") || player.isOp()) { + new Sell().open(player); + } else { + player.sendMessage(Config.getNoPermission()); + } + } } diff --git a/src/com/pablo67340/guishop/commands/SellCommand.java b/src/com/pablo67340/guishop/commands/SellCommand.java index fc526b8..ba9dd4c 100644 --- a/src/com/pablo67340/guishop/commands/SellCommand.java +++ b/src/com/pablo67340/guishop/commands/SellCommand.java @@ -9,6 +9,7 @@ import java.util.ArrayList; public class SellCommand extends BukkitCommand { + public SellCommand(ArrayList aliases) { super(aliases.remove(0)); this.description = "Opens the sell menu."; @@ -19,7 +20,7 @@ public SellCommand(ArrayList aliases) { @Override public boolean execute(@NotNull CommandSender commandSender, @NotNull String label, @NotNull String[] args) { - Player player = (Player) commandSender; + Player player = (Player) commandSender; Main.getINSTANCE().getUserCommands().sellCommand(player); diff --git a/src/com/pablo67340/guishop/definition/AltSellPane.java b/src/com/pablo67340/guishop/definition/AltSellPane.java index 8c38277..8a5cddb 100644 --- a/src/com/pablo67340/guishop/definition/AltSellPane.java +++ b/src/com/pablo67340/guishop/definition/AltSellPane.java @@ -18,71 +18,71 @@ public class AltSellPane extends Pane { - private List items = new ArrayList<>(); - - @Getter - private int subjectQuantity; - - public AltSellPane(GuiItem subjectItem, GuiItem[] addRemoveItems, GuiItem indicatorItem, GuiItem confirmItem, GuiItem cancelItem) { - super(9, 6); - items.add(subjectItem); - for (int n = 0; n < 6; n++) { - items.add(addRemoveItems[n]); - } - items.add(indicatorItem); - items.add(confirmItem); - items.add(cancelItem); - } - - public int setSubjectQuantity(int subjectQuantity) { - ItemStack subjectItem = items.get(0).getItem().clone(); - if (subjectQuantity > subjectItem.getMaxStackSize()) { - subjectQuantity = subjectItem.getMaxStackSize(); - } - subjectItem.setAmount(subjectQuantity); - items.set(0, new GuiItem(subjectItem)); - this.subjectQuantity = subjectQuantity; - return subjectQuantity; - } - - public void setIndicatorName(String name) { - items.set(7, Item.renameGuiItem(items.get(7), name)); - } - - @Override - public void display(Gui gui, Inventory inventory, PlayerInventory playerInventory, int paneOffsetX, int paneOffsetY, - int maxLength, int maxHeight) { - inventory.setItem(13, items.get(0).getItem()); - inventory.setItem(18, items.get(1).getItem()); - inventory.setItem(19, items.get(2).getItem()); - inventory.setItem(20, items.get(3).getItem()); - inventory.setItem(24, items.get(4).getItem()); - inventory.setItem(25, items.get(5).getItem()); - inventory.setItem(26, items.get(6).getItem()); - inventory.setItem(31, items.get(7).getItem()); - inventory.setItem(48, items.get(8).getItem()); - inventory.setItem(50, items.get(9).getItem()); - } - - @Override - public boolean click(Gui gui, InventoryClickEvent event, int paneOffsetX, int paneOffsetY, int maxLength, - int maxHeight) { - return false; - } - - @Override - public Collection getItems() { - return new ArrayList<>(items); - } - - @Override - public Collection getPanes() { - return new HashSet<>(); - } - - @Override - public void clear() { - items.clear(); - } + private final List items = new ArrayList<>(); + + @Getter + private int subjectQuantity; + + public AltSellPane(GuiItem subjectItem, GuiItem[] addRemoveItems, GuiItem indicatorItem, GuiItem confirmItem, GuiItem cancelItem) { + super(9, 6); + items.add(subjectItem); + for (int n = 0; n < 6; n++) { + items.add(addRemoveItems[n]); + } + items.add(indicatorItem); + items.add(confirmItem); + items.add(cancelItem); + } + + public int setSubjectQuantity(int subjectQuantity) { + ItemStack subjectItem = items.get(0).getItem().clone(); + if (subjectQuantity > subjectItem.getMaxStackSize()) { + subjectQuantity = subjectItem.getMaxStackSize(); + } + subjectItem.setAmount(subjectQuantity); + items.set(0, new GuiItem(subjectItem)); + this.subjectQuantity = subjectQuantity; + return subjectQuantity; + } + + public void setIndicatorName(String name) { + items.set(7, Item.renameGuiItem(items.get(7), name)); + } + + @Override + public void display(Gui gui, Inventory inventory, PlayerInventory playerInventory, int paneOffsetX, int paneOffsetY, + int maxLength, int maxHeight) { + inventory.setItem(13, items.get(0).getItem()); + inventory.setItem(18, items.get(1).getItem()); + inventory.setItem(19, items.get(2).getItem()); + inventory.setItem(20, items.get(3).getItem()); + inventory.setItem(24, items.get(4).getItem()); + inventory.setItem(25, items.get(5).getItem()); + inventory.setItem(26, items.get(6).getItem()); + inventory.setItem(31, items.get(7).getItem()); + inventory.setItem(48, items.get(8).getItem()); + inventory.setItem(50, items.get(9).getItem()); + } + + @Override + public boolean click(Gui gui, InventoryClickEvent event, int paneOffsetX, int paneOffsetY, int maxLength, + int maxHeight) { + return false; + } + + @Override + public Collection getItems() { + return new ArrayList<>(items); + } + + @Override + public Collection getPanes() { + return new HashSet<>(); + } + + @Override + public void clear() { + items.clear(); + } } diff --git a/src/com/pablo67340/guishop/definition/CommandsMode.java b/src/com/pablo67340/guishop/definition/CommandsMode.java index 48ef7cf..d49d62b 100644 --- a/src/com/pablo67340/guishop/definition/CommandsMode.java +++ b/src/com/pablo67340/guishop/definition/CommandsMode.java @@ -1,45 +1,47 @@ package com.pablo67340.guishop.definition; import com.pablo67340.guishop.Main; +import java.util.logging.Level; public enum CommandsMode { - /** - * Intercepts all commands using the PlayerCommandPreprocessEvent.
- * Useful for server owners with plugin conflicts. Does not support tab complete. - * - */ - INTERCEPT, - /** - * Registers the commands using reflection. - * - */ - REGISTER, - NONE; - - /** - * Parses the commands mode configuration option from the config - * - * @param cmdsModeStr the config option string, null if not set - * @return the parsed commands mode, never null - */ - public static CommandsMode parseFromConfig(String cmdsModeStr) { - if (cmdsModeStr == null) { - // Fallback to legacy option register-commands - return (Main.getINSTANCE().getMainConfig().getBoolean("register-commands", true)) ? REGISTER : NONE; - } - switch (cmdsModeStr.toLowerCase()) { - case "INTERCEPT": - return INTERCEPT; - case "REGISTER": - return REGISTER; - case "NONE": - return NONE; - default: - // User specified unknown mode, warn in console and use default option - Main.getINSTANCE().getLogger().warning("Unknown commands-mode " + cmdsModeStr); - return REGISTER; - } - } - + /** + * Intercepts all commands using the PlayerCommandPreprocessEvent.
+ * Useful for server owners with plugin conflicts. Does not support tab + * complete. + * + */ + INTERCEPT, + /** + * Registers the commands using reflection. + * + */ + REGISTER, + NONE; + + /** + * Parses the commands mode configuration option from the config + * + * @param cmdsModeStr the config option string, null if not set + * @return the parsed commands mode, never null + */ + public static CommandsMode parseFromConfig(String cmdsModeStr) { + if (cmdsModeStr == null) { + // Fallback to legacy option register-commands + return (Main.getINSTANCE().getMainConfig().getBoolean("register-commands", true)) ? REGISTER : NONE; + } + switch (cmdsModeStr.toLowerCase()) { + case "INTERCEPT": + return INTERCEPT; + case "REGISTER": + return REGISTER; + case "NONE": + return NONE; + default: + // User specified unknown mode, warn in console and use default option + Main.getINSTANCE().getLogger().log(Level.WARNING, "Unknown commands-mode {0}", cmdsModeStr); + return REGISTER; + } + } + } diff --git a/src/com/pablo67340/guishop/definition/Item.java b/src/com/pablo67340/guishop/definition/Item.java index d76ad83..58b2bf3 100644 --- a/src/com/pablo67340/guishop/definition/Item.java +++ b/src/com/pablo67340/guishop/definition/Item.java @@ -27,531 +27,534 @@ public final class Item { - /** - * The name of this {@link Item} when presented on the GUI. - */ - @Getter - @Setter - private String shopName, buyName; - - @Getter - @Setter - private int slot; - - @Getter - @Setter - private int configSlot; - - /** - * The Material of this {@link Item}. - */ - @Getter - @Setter - private String material; - - /** - * The price to buy this {@link Item}. - */ - @Getter - @Setter - private Object buyPrice; - - /** - * The mob ID of this item if it's a spawner {@link Item}. - */ - @Getter - @Setter - private String mobType; - - /** - * The amount of money given when selling this {@link Item}. - */ - @Getter - @Setter - private Object sellPrice; - - /** - * Whether this item, specifically, uses dynamic pricing - */ - @Getter - @Setter - private boolean useDynamicPricing; - - /** - * The slot of this {@link Item} when presented on the GUI. - */ - @Getter - @Setter - private ItemType itemType; - - @Getter - @Setter - private List buyLore, shopLore; - - @Getter - @Setter - private List commands; - - /** - * The enchantsments on this {@link Item}. - */ - @Getter - @Setter - private String[] enchantments; - - /** - * The preparsed potion if this item is a potion - * - */ - @Getter - private Potion potion; - - private static final String SPAWNER_MATERIAL = XMaterial.SPAWNER.parseMaterial().name(); - - /** - * Materials to which a potion type may be applied.
- * This always has length 3, for normal potions, splash potions, - * and lingering potions.
- *
- * None of the elements are null but the last can be empty. - * - */ - private static final String[] POTION_MATERIALS; - - static { - String potionName = XMaterial.POTION.parseMaterial().name(); - - // splash potion is not separate on all versions - Material splashPotionMaterial = XMaterial.SPLASH_POTION.parseMaterial(); - String splashPotionName = (splashPotionMaterial != null) ? splashPotionMaterial.name() : ""; - // lingering potion does not exist on all versions - Material lingerPotionMaterial = XMaterial.LINGERING_POTION.parseMaterial(); - String lingerPotionName = (lingerPotionMaterial != null) ? lingerPotionMaterial.name() : ""; - - POTION_MATERIALS = new String[] {potionName, splashPotionName, lingerPotionName}; - } - - public boolean hasShopName() { - return (shopName != null) && !shopName.isEmpty(); - } - - public boolean hasBuyName() { - return buyName != null; - } - - public boolean hasShopLore() { - return (shopLore != null) && !shopLore.isEmpty(); - } - - public boolean hasBuyLore() { - return (buyLore != null) && !buyLore.isEmpty(); - } - - public boolean hasEnchantments() { - return (enchantments != null) && (enchantments.length != 0) && !enchantments[0].isEmpty(); - } - - public boolean hasCommands() { - return (commands != null) && !commands.isEmpty(); - } - - /** - * If this item has a potion.
- * If is not a potion, this will always return false - * - * @return true if the item has a potion, false otherwise - */ - public boolean hasPotion() { - return potion != null; - } - - /** - * If the specified material is a potion, either a normal potion, - * splash potion, or lingering potion. - * - * @param material the material - * @return true if a potion, false otherwise - */ - private static boolean isPotionMaterial(String material) { - return (POTION_MATERIALS[0].equalsIgnoreCase(material) || POTION_MATERIALS[1].equalsIgnoreCase(material) - || POTION_MATERIALS[2].equalsIgnoreCase(material)); - } - - /** - * Whether this item's material is a potion, splash potion, or - * lingering potion - * - * @return true if the material is some kind of potion, false otherwise - */ - public boolean isAnyPotion() { - return isPotionMaterial(material); - } - - /** - * Sets and parses the potion type of the item.
- * Remember to call {@link #isAnyPotion()} first - * - * @param type the potion type for the item from the shops.yml - * @param splash whether the potion is a splash potion - * @param extended whether the potion has extended duration - * @param level the tier/amplifier of the potion - */ - @SuppressWarnings("deprecation") - public void parsePotionType(String type, boolean splash, boolean extended, int level) { - if (type != null) { - XPotion xpotion = XPotion.matchXPotion(type).orElse(null); - if (xpotion != null) { - PotionEffectType effectType = xpotion.parsePotionEffectType(); - if (effectType != null) { - for (PotionType vanillaType : PotionType.values()) { - if (vanillaType.getEffectType() != null && vanillaType.getEffectType().equals(effectType)) { - potion = new Potion(vanillaType); - potion.setSplash(splash); - if (!vanillaType.isInstant()) { - potion.setHasExtendedDuration(extended); - } - if (level > 0 && level <= vanillaType.getMaxLevel()) { - potion.setLevel(level); - } - return; - } - } - } - } - Main.log("Invalid potion info: {type=" + type + ",splash=" + splash + ",extended=" + extended + ",level=" + level + "}"); - } - } - - /** - * Whether the item is a mob spawner - * - * @return if the item - */ - public boolean isMobSpawner() { - if (material.equalsIgnoreCase(SPAWNER_MATERIAL)) { - return true; - } - XMaterial spawnerXMaterial = XMaterial.SPAWNER; - return material.equalsIgnoreCase(spawnerXMaterial.name()) || spawnerXMaterial.anyMatchLegacy(material); - } - - /** - * Checks whether the item has a defined AND nonzero sell price.
- * For the sell price to be defined it must be an integer or double. - * - * @return true if the sell price is valid, false otherwise - */ - public boolean hasSellPrice() { - // instanceof does the null-check for us - return (sellPrice instanceof Double && ((Double) sellPrice) != 0D) - || (sellPrice instanceof Integer && ((Integer) sellPrice) != 0); - } - - /** - * Checks whether the item has a defined buy price.
- * For the buy price to be defined it must be an integer or double. - * - * @return true if the buy price is valid, false otherwise - */ - public boolean hasBuyPrice() { - // instanceof does the null-check for us - return (buyPrice instanceof Double) || (buyPrice instanceof Integer); - } - - /** - * Checks whether the mob type is defined - * - * @return true if defined, false otherwise - */ - public boolean hasMobType() { - return (mobType != null) && !mobType.isEmpty(); - } - - /** - * Assuming the buy price is an integer or a double, get it as a double. - * Remember to check {@link #hasBuyPrice()} first - * - * @return the buy price as a double - */ - public double getBuyPriceAsDouble() { - return (buyPrice instanceof Double) ? (Double) buyPrice : ((Integer) buyPrice).doubleValue(); - } - - /** - * Assuming the sell price is an integer or a double, get it as a double. - * Remember to check {@link #hasSellPrice()} first - * - * @return the sell price as a double - */ - public double getSellPriceAsDouble() { - return (sellPrice instanceof Double) ? (Double) sellPrice : ((Integer) sellPrice).doubleValue(); - } - - /** - * Assumming {@link #hasBuyPrice()} = true, - * calculate the buy price taking based on the given quantity.
- * If dynamic pricing is enabled, the DynamicPriceProvider is used for calculations. - * Otherwise, the buy price and the quantity are simply multiplied. - * - * @param quantity the quantity of the item - * @return the calculated buy price - */ - public double calculateBuyPrice(int quantity) { - // sell price must be defined and nonzero for dynamic pricing to work - if (Config.isDynamicPricing() && isUseDynamicPricing() && hasSellPrice()) { - - return Main.getDYNAMICPRICING().calculateBuyPrice(getItemString(), quantity, getBuyPriceAsDouble(), - getSellPriceAsDouble()); - } - // default to fixed pricing - return getBuyPriceAsDouble() * quantity; - } - - /** - * Assumming {@link #hasSellPrice()} = true, - * calculate the sell price taking based on the given quantity.
- * If dynamic pricing is enabled, the DynamicPriceProvider is used for calculations. - * Otherwise, the sell price and the quantity are simply mmultiplied. - * - * @param quantity the quantity of the item - * @return the calculated sell price - */ - public double calculateSellPrice(int quantity) { - // buy price must be defined for dynamic pricing to work - if (Config.isDynamicPricing() && isUseDynamicPricing() && hasBuyPrice()) { - - return Main.getDYNAMICPRICING().calculateSellPrice(getItemString(), quantity, getBuyPriceAsDouble(), - getSellPriceAsDouble()); - } - // default to fixed pricing - return getSellPriceAsDouble() * quantity; - } - - /** - * Gets the lore display for this item's buy price.
- * If there is no buy price, Config.getCannotBuy() is returned. - * If free, Config.getFreeLore is returned. - * Otherwise, the buy price is calculated based on the quantity, and the - * lore displaying the calculated buy price is returned. Takes into - * account dynamic pricing, if enabled. - * - * @param quantity the quantity of the item - * @return the buy price lore - */ - public String getBuyLore(int quantity) { - if (hasBuyPrice()) { - - double buyPriceAsDouble = getBuyPriceAsDouble(); - if (buyPriceAsDouble != 0) { - - return Config.getBuyLore().replace("{amount}", - Config.getCurrency() + Main.economyFormat(calculateBuyPrice(quantity)) + Config.getCurrencySuffix()); - } - return Config.getFreeLore(); - } - return Config.getCannotBuy(); - } - - /** - * Gets the lore display for this item's sell price.
- * If there is no sell price, Config.getCannotSell() is returned. - * Otherwise, the sell price is calculated based on the quantity, and the - * lore displaying the calculated sell price is returned. Takes into - * account dynamic pricing, if enabled. - * - * @param quantity the quantity of the item - * @return the sell price lore - */ - public String getSellLore(int quantity) { - if (hasSellPrice()) { - return Config.getSellLore().replace("{amount}", - Config.getCurrency() + Main.economyFormat(calculateSellPrice(quantity)) + Config.getCurrencySuffix()); - } - return Config.getCannotSell(); - } - - /** - * If the item is a mob spawner, getMaterial().toUpperCase - * + ":" + getMobType().toLowerCase() is returned. - * Otherwise, getMaterial().toUpperCase is simply returned. - * - * @return the item string representation - */ - public String getItemString() { - if (isMobSpawner()) { - return material.toUpperCase() + ":spawner:" + getMobType().toLowerCase(); - } - return material.toUpperCase(); - } - - /** - * Checks if the item is a mob spawner, accounting for - * differences in server versions. - * - * @param item the itemstack - * @return whether the item is a mob spawner - */ - public static boolean isSpawnerItem(ItemStack item) { - return item.getType().name().equals(SPAWNER_MATERIAL); - } - - /** - * Equivalent of {@link Item#getItemString()} for an ItemStack, - * i.e., any minecraft item, not just a shop item.
- *
- * If the item is a mob spawner, item.getType().toString().toUpperCase - * + ":" + mobType.toString().toLowerCase() is returned where - * mobtype is the mob type of the mob spawner. - * Otherwise, getType().toString().toUpperCase is simply returned. - * - * @param item the itemstack - * @return the item string representation of the itemstack - */ - public static String getItemStringForItemStack(ItemStack item) { - if (isSpawnerItem(item)) { - - String mobType; - NBTTagCompound cmp = ItemNBTUtil.getTag(item); - if (cmp.hasKey("GUIShopSpawner")) { - mobType = cmp.getString("GUIShopSpawner"); - - } else if (cmp.hasKey("BlockEntityTag")) { - NBTTagCompound subCmp = (NBTTagCompound) cmp.get("BlockEntityTag"); - mobType = subCmp.getString("EntityId").toUpperCase(); - - } else { - // default to pig - mobType = "PIG"; - } - - return item.getType().toString().toUpperCase() + ":spawner:" + mobType.toString().toLowerCase(); - - } - return item.getType().toString().toUpperCase(); - } - - /** - * Parses the material of this Item.
- * If the material cannot be resolved, null should be returned.
- *
- * This operation is somewhat resource intensive. Consider running asynchronously. - * (Keep in mind thread safety of course) - * - * @return a gui item using the appropriate itemstack - */ - public GuiItem parseMaterial() { - - GuiItem gItem = null; - - /* - * First attempt - * Use XMaterial - */ - XMaterial xmaterial = XMaterial.matchXMaterial(getMaterial()).orElse(null); - ItemStack itemStack = (xmaterial != null) ? xmaterial.parseItem() : null; - - if (itemStack != null && itemStack.getItemMeta() != null) { // If underlying itemstack cannot be resolved (is null or null meta), fail immediately - try { - gItem = new GuiItem(itemStack); - return gItem; // if itemStack is nonnull and no exception thrown, attempt has succeeded - } catch (Exception ex2) { - if (Config.isDebugMode()) { - ex2.printStackTrace(); - } - } - } - - Main.debugLog("Failed to find item by Material: " + getMaterial() + ". Attempting workarounds..."); - /* - * Second attempt - * "OFF"/"ON" fix - */ - if (getMaterial().endsWith("_ON")) { // Only use OFF fix if _ON is detected - - - try { - // remove the "_ON" and add "_OFF" - itemStack = new ItemStack(Material.valueOf(getMaterial().substring(0, getMaterial().length() - 2) + "OFF")); - gItem = new GuiItem(itemStack); - return gItem; // if no exception thrown, attempt has succeeded - } catch (Exception ex3) { - if (Config.isDebugMode()) { - ex3.printStackTrace(); - } - } - - Main.debugLog("OFF Fix for: " + getMaterial() + " Failed. Attempting ItemID Lookup..."); - } - - /* - * Third attempt - * Using MatLib - */ - // Final Stand, lets try to find this user's item - MatLibEntry itemInfo = MatLib.getMAP().get(getMaterial()); - if (itemInfo != null) { - - int id = itemInfo.getId(); - short data = itemInfo.getData(); - - try { - - itemStack = LegacyItemConstructor.invoke(id, 1, data); // can never be null - - gItem = new GuiItem(itemStack); - return gItem; - } catch (Exception ex4) { - if (Config.isDebugMode()) { - ex4.printStackTrace(); - } - } catch (NoSuchMethodError nsme) { - // For servers missing the legacy constructor https://pastebin.com/GDy2ih9s - } - } - - Main.debugLog("ItemID Fix for: " + getMaterial() + " Failed. Falling back to air."); - - setItemType(ItemType.BLANK); - setEnchantments(null); - // null indicates failure - return null; - } - - /** - * Parses the mob type of this item if it is a spawner item.
- * Remember to check {@link #isMobSpawner()} - * - * @return the entity type, or null if invalid - */ - public EntityType parseMobSpawnerType() { - @SuppressWarnings("deprecation") - EntityType type = EntityType.fromName(getMobType()); - if (type != null) { - return type; - } - - Main.debugLog("Failed to find entity type using EntityType#fromName"); - try { - return EntityType.valueOf(getMobType()); - } catch (IllegalArgumentException ignored) {} - - Main.debugLog("Failed to find entity type using EntityType#valueOf"); - return null; - } - - /** - * Renames a GuiItem - * - * @param gItem the gui item - * @param name the new name - * @return an updated gui item - */ - public static GuiItem renameGuiItem(GuiItem gItem, String name) { - ItemStack item = gItem.getItem().clone(); - ItemMeta itemMeta = item.getItemMeta(); - itemMeta.setDisplayName(name); - item.setItemMeta(itemMeta); - return new GuiItem(item); - } + /** + * The name of this {@link Item} when presented on the GUI. + */ + @Getter + @Setter + private String shopName, buyName; + + @Getter + @Setter + private int slot; + + @Getter + @Setter + private int configSlot; + + /** + * The Material of this {@link Item}. + */ + @Getter + @Setter + private String material; + + /** + * The price to buy this {@link Item}. + */ + @Getter + @Setter + private Object buyPrice; + + /** + * The mob ID of this item if it's a spawner {@link Item}. + */ + @Getter + @Setter + private String mobType; + + /** + * The amount of money given when selling this {@link Item}. + */ + @Getter + @Setter + private Object sellPrice; + + /** + * Whether this item, specifically, uses dynamic pricing + */ + @Getter + @Setter + private boolean useDynamicPricing; + + /** + * The slot of this {@link Item} when presented on the GUI. + */ + @Getter + @Setter + private ItemType itemType; + + @Getter + @Setter + private List buyLore, shopLore; + + @Getter + @Setter + private List commands; + + /** + * The enchantsments on this {@link Item}. + */ + @Getter + @Setter + private String[] enchantments; + + /** + * The preparsed potion if this item is a potion + * + */ + @Getter + private Potion potion; + + private static final String SPAWNER_MATERIAL = XMaterial.SPAWNER.parseMaterial().name(); + + /** + * Materials to which a potion type may be applied.
+ * This always has length 3, for normal potions, splash potions, and + * lingering potions.
+ *
+ * None of the elements are null but the last can be empty. + * + */ + private static final String[] POTION_MATERIALS; + + static { + String potionName = XMaterial.POTION.parseMaterial().name(); + + // splash potion is not separate on all versions + Material splashPotionMaterial = XMaterial.SPLASH_POTION.parseMaterial(); + String splashPotionName = (splashPotionMaterial != null) ? splashPotionMaterial.name() : ""; + // lingering potion does not exist on all versions + Material lingerPotionMaterial = XMaterial.LINGERING_POTION.parseMaterial(); + String lingerPotionName = (lingerPotionMaterial != null) ? lingerPotionMaterial.name() : ""; + + POTION_MATERIALS = new String[]{potionName, splashPotionName, lingerPotionName}; + } + + public boolean hasShopName() { + return (shopName != null) && !shopName.isEmpty(); + } + + public boolean hasBuyName() { + return buyName != null; + } + + public boolean hasShopLore() { + return (shopLore != null) && !shopLore.isEmpty(); + } + + public boolean hasBuyLore() { + return (buyLore != null) && !buyLore.isEmpty(); + } + + public boolean hasEnchantments() { + return (enchantments != null) && (enchantments.length != 0) && !enchantments[0].isEmpty(); + } + + public boolean hasCommands() { + return (commands != null) && !commands.isEmpty(); + } + + /** + * If this item has a potion.
+ * If is not a potion, this will always return false + * + * @return true if the item has a potion, false otherwise + */ + public boolean hasPotion() { + return potion != null; + } + + /** + * If the specified material is a potion, either a normal potion, splash + * potion, or lingering potion. + * + * @param material the material + * @return true if a potion, false otherwise + */ + private static boolean isPotionMaterial(String material) { + return (POTION_MATERIALS[0].equalsIgnoreCase(material) || POTION_MATERIALS[1].equalsIgnoreCase(material) + || POTION_MATERIALS[2].equalsIgnoreCase(material)); + } + + /** + * Whether this item's material is a potion, splash potion, or lingering + * potion + * + * @return true if the material is some kind of potion, false otherwise + */ + public boolean isAnyPotion() { + return isPotionMaterial(material); + } + + /** + * Sets and parses the potion type of the item.
+ * Remember to call {@link #isAnyPotion()} first + * + * @param type the potion type for the item from the shops.yml + * @param splash whether the potion is a splash potion + * @param extended whether the potion has extended duration + * @param level the tier/amplifier of the potion + */ + @SuppressWarnings("deprecation") + public void parsePotionType(String type, boolean splash, boolean extended, int level) { + if (type != null) { + XPotion xpotion = XPotion.matchXPotion(type).orElse(null); + if (xpotion != null) { + PotionEffectType effectType = xpotion.parsePotionEffectType(); + if (effectType != null) { + for (PotionType vanillaType : PotionType.values()) { + if (vanillaType.getEffectType() != null && vanillaType.getEffectType().equals(effectType)) { + potion = new Potion(vanillaType); + potion.setSplash(splash); + if (!vanillaType.isInstant()) { + potion.setHasExtendedDuration(extended); + } + if (level > 0 && level <= vanillaType.getMaxLevel()) { + potion.setLevel(level); + } + return; + } + } + } + } + Main.log("Invalid potion info: {type=" + type + ",splash=" + splash + ",extended=" + extended + ",level=" + level + "}"); + } + } + + /** + * Whether the item is a mob spawner + * + * @return if the item + */ + public boolean isMobSpawner() { + if (material.equalsIgnoreCase(SPAWNER_MATERIAL)) { + return true; + } + XMaterial spawnerXMaterial = XMaterial.SPAWNER; + return material.equalsIgnoreCase(spawnerXMaterial.name()) || spawnerXMaterial.anyMatchLegacy(material); + } + + /** + * Checks whether the item has a defined AND nonzero sell price.
+ * For the sell price to be defined it must be an integer or double. + * + * @return true if the sell price is valid, false otherwise + */ + public boolean hasSellPrice() { + // instanceof does the null-check for us + return (sellPrice instanceof Double && ((Double) sellPrice) != 0D) + || (sellPrice instanceof Integer && ((Integer) sellPrice) != 0); + } + + /** + * Checks whether the item has a defined buy price.
+ * For the buy price to be defined it must be an integer or double. + * + * @return true if the buy price is valid, false otherwise + */ + public boolean hasBuyPrice() { + // instanceof does the null-check for us + return (buyPrice instanceof Double) || (buyPrice instanceof Integer); + } + + /** + * Checks whether the mob type is defined + * + * @return true if defined, false otherwise + */ + public boolean hasMobType() { + return (mobType != null) && !mobType.isEmpty(); + } + + /** + * Assuming the buy price is an integer or a double, get it as a double. + * Remember to check {@link #hasBuyPrice()} first + * + * @return the buy price as a double + */ + public double getBuyPriceAsDouble() { + return (buyPrice instanceof Double) ? (Double) buyPrice : ((Integer) buyPrice).doubleValue(); + } + + /** + * Assuming the sell price is an integer or a double, get it as a double. + * Remember to check {@link #hasSellPrice()} first + * + * @return the sell price as a double + */ + public double getSellPriceAsDouble() { + return (sellPrice instanceof Double) ? (Double) sellPrice : ((Integer) sellPrice).doubleValue(); + } + + /** + * Assumming {@link #hasBuyPrice()} = true, calculate the buy + * price taking based on the given quantity.
+ * If dynamic pricing is enabled, the DynamicPriceProvider is used for + * calculations. Otherwise, the buy price and the quantity are simply + * multiplied. + * + * @param quantity the quantity of the item + * @return the calculated buy price + */ + public double calculateBuyPrice(int quantity) { + // sell price must be defined and nonzero for dynamic pricing to work + if (Config.isDynamicPricing() && isUseDynamicPricing() && hasSellPrice()) { + + return Main.getDYNAMICPRICING().calculateBuyPrice(getItemString(), quantity, getBuyPriceAsDouble(), + getSellPriceAsDouble()); + } + // default to fixed pricing + return getBuyPriceAsDouble() * quantity; + } + + /** + * Assumming {@link #hasSellPrice()} = true, calculate the sell + * price taking based on the given quantity.
+ * If dynamic pricing is enabled, the DynamicPriceProvider is used for + * calculations. Otherwise, the sell price and the quantity are simply + * mmultiplied. + * + * @param quantity the quantity of the item + * @return the calculated sell price + */ + public double calculateSellPrice(int quantity) { + // buy price must be defined for dynamic pricing to work + if (Config.isDynamicPricing() && isUseDynamicPricing() && hasBuyPrice()) { + + return Main.getDYNAMICPRICING().calculateSellPrice(getItemString(), quantity, getBuyPriceAsDouble(), + getSellPriceAsDouble()); + } + // default to fixed pricing + return getSellPriceAsDouble() * quantity; + } + + /** + * Gets the lore display for this item's buy price.
+ * If there is no buy price, Config.getCannotBuy() is returned. + * If free, Config.getFreeLore is returned. Otherwise, the buy + * price is calculated based on the quantity, and the lore displaying the + * calculated buy price is returned. Takes into account dynamic pricing, if + * enabled. + * + * @param quantity the quantity of the item + * @return the buy price lore + */ + public String getBuyLore(int quantity) { + if (hasBuyPrice()) { + + double buyPriceAsDouble = getBuyPriceAsDouble(); + if (buyPriceAsDouble != 0) { + + return Config.getBuyLore().replace("{amount}", + Config.getCurrency() + Main.economyFormat(calculateBuyPrice(quantity)) + Config.getCurrencySuffix()); + } + return Config.getFreeLore(); + } + return Config.getCannotBuy(); + } + + /** + * Gets the lore display for this item's sell price.
+ * If there is no sell price, Config.getCannotSell() is + * returned. Otherwise, the sell price is calculated based on the quantity, + * and the lore displaying the calculated sell price is returned. Takes into + * account dynamic pricing, if enabled. + * + * @param quantity the quantity of the item + * @return the sell price lore + */ + public String getSellLore(int quantity) { + if (hasSellPrice()) { + return Config.getSellLore().replace("{amount}", + Config.getCurrency() + Main.economyFormat(calculateSellPrice(quantity)) + Config.getCurrencySuffix()); + } + return Config.getCannotSell(); + } + + /** + * If the item is a mob spawner, getMaterial().toUpperCase + * + ":" + getMobType().toLowerCase() is returned. Otherwise, + * getMaterial().toUpperCase is simply returned. + * + * @return the item string representation + */ + public String getItemString() { + if (isMobSpawner()) { + return material.toUpperCase() + ":spawner:" + getMobType().toLowerCase(); + } + return material.toUpperCase(); + } + + /** + * Checks if the item is a mob spawner, accounting for differences in server + * versions. + * + * @param item the itemstack + * @return whether the item is a mob spawner + */ + public static boolean isSpawnerItem(ItemStack item) { + return item.getType().name().equals(SPAWNER_MATERIAL); + } + + /** + * Equivalent of {@link Item#getItemString()} for an ItemStack, i.e., + * any minecraft item, not just a shop item.
+ *
+ * If the item is a mob spawner, item.getType().toString().toUpperCase + * + ":" + mobType.toString().toLowerCase() is returned where + * mobtype is the mob type of the mob spawner. Otherwise, + * getType().toString().toUpperCase is simply returned. + * + * @param item the itemstack + * @return the item string representation of the itemstack + */ + public static String getItemStringForItemStack(ItemStack item) { + if (isSpawnerItem(item)) { + + String mobType; + NBTTagCompound cmp = ItemNBTUtil.getTag(item); + if (cmp.hasKey("GUIShopSpawner")) { + mobType = cmp.getString("GUIShopSpawner"); + + } else if (cmp.hasKey("BlockEntityTag")) { + NBTTagCompound subCmp = (NBTTagCompound) cmp.get("BlockEntityTag"); + mobType = subCmp.getString("EntityId").toUpperCase(); + + } else { + // default to pig + mobType = "PIG"; + } + + return item.getType().toString().toUpperCase() + ":spawner:" + mobType.toLowerCase(); + + } + return item.getType().toString().toUpperCase(); + } + + /** + * Parses the material of this Item.
+ * If the material cannot be resolved, null should be returned. + *
+ *
+ * This operation is somewhat resource intensive. Consider running + * asynchronously. (Keep in mind thread safety of course) + * + * @return a gui item using the appropriate itemstack + */ + public GuiItem parseMaterial() { + + GuiItem gItem; + + /* + * First attempt + * Use XMaterial + */ + XMaterial xmaterial = XMaterial.matchXMaterial(getMaterial()).orElse(null); + ItemStack itemStack = (xmaterial != null) ? xmaterial.parseItem() : null; + + if (itemStack != null && itemStack.getItemMeta() != null) { // If underlying itemstack cannot be resolved (is null or null meta), fail immediately + try { + gItem = new GuiItem(itemStack); + return gItem; // if itemStack is nonnull and no exception thrown, attempt has succeeded + } catch (Exception ex2) { + if (Config.isDebugMode()) { + Main.debugLog("Error parsing material: "+ex2.getMessage()); + } + } + } + + Main.debugLog("Failed to find item by Material: " + getMaterial() + ". Attempting workarounds..."); + /* + * Second attempt + * "OFF"/"ON" fix + */ + if (getMaterial().endsWith("_ON")) { // Only use OFF fix if _ON is detected + + try { + // remove the "_ON" and add "_OFF" + itemStack = new ItemStack(Material.valueOf(getMaterial().substring(0, getMaterial().length() - 2) + "OFF")); + gItem = new GuiItem(itemStack); + return gItem; // if no exception thrown, attempt has succeeded + } catch (Exception ex3) { + if (Config.isDebugMode()) { + Main.debugLog("Error parsing item attempt 3: "+ex3.getMessage()); + } + } + + Main.debugLog("OFF Fix for: " + getMaterial() + " Failed. Attempting ItemID Lookup..."); + } + + /* + * Third attempt + * Using MatLib + */ + // Final Stand, lets try to find this user's item + MatLibEntry itemInfo = MatLib.getMAP().get(getMaterial()); + if (itemInfo != null) { + + int id = itemInfo.getId(); + short data = itemInfo.getData(); + + try { + + itemStack = LegacyItemConstructor.invoke(id, 1, data); // can never be null + + gItem = new GuiItem(itemStack); + return gItem; + } catch (Exception ex4) { + if (Config.isDebugMode()) { + Main.debugLog("Error parsing item attemp 4: "+ex4.getMessage()); + } + } catch (NoSuchMethodError nsme) { + // For servers missing the legacy constructor https://pastebin.com/GDy2ih9s + } + } + + Main.debugLog("ItemID Fix for: " + getMaterial() + " Failed. Falling back to air."); + + setItemType(ItemType.BLANK); + setEnchantments(null); + // null indicates failure + return null; + } + + /** + * Parses the mob type of this item if it is a spawner item.
+ * Remember to check {@link #isMobSpawner()} + * + * @return the entity type, or null if invalid + */ + public EntityType parseMobSpawnerType() { + @SuppressWarnings("deprecation") + EntityType type = EntityType.fromName(getMobType()); + if (type != null) { + return type; + } + + Main.debugLog("Failed to find entity type using EntityType#fromName"); + try { + return EntityType.valueOf(getMobType()); + } catch (IllegalArgumentException ignored) { + } + + Main.debugLog("Failed to find entity type using EntityType#valueOf"); + return null; + } + + /** + * Renames a GuiItem + * + * @param gItem the gui item + * @param name the new name + * @return an updated gui item + */ + public static GuiItem renameGuiItem(GuiItem gItem, String name) { + ItemStack item = gItem.getItem().clone(); + ItemMeta itemMeta = item.getItemMeta(); + itemMeta.setDisplayName(name); + item.setItemMeta(itemMeta); + return new GuiItem(item); + } } diff --git a/src/com/pablo67340/guishop/definition/ItemType.java b/src/com/pablo67340/guishop/definition/ItemType.java index 3805085..03f473c 100644 --- a/src/com/pablo67340/guishop/definition/ItemType.java +++ b/src/com/pablo67340/guishop/definition/ItemType.java @@ -1,5 +1,5 @@ package com.pablo67340.guishop.definition; public enum ItemType { - ITEM, COMMAND, DUMMY, SHOP, BLANK + ITEM, COMMAND, DUMMY, SHOP, BLANK } diff --git a/src/com/pablo67340/guishop/definition/ShopDef.java b/src/com/pablo67340/guishop/definition/ShopDef.java index b01d022..9bb5460 100644 --- a/src/com/pablo67340/guishop/definition/ShopDef.java +++ b/src/com/pablo67340/guishop/definition/ShopDef.java @@ -11,7 +11,7 @@ public class ShopDef { @Getter public List lore; - + @Getter public ItemType itemType; @@ -24,5 +24,4 @@ public ShopDef(String shop, String name, String description, List lore, this.itemID = itemID; } - } diff --git a/src/com/pablo67340/guishop/definition/ShopPane.java b/src/com/pablo67340/guishop/definition/ShopPane.java index 35693cd..1455fed 100644 --- a/src/com/pablo67340/guishop/definition/ShopPane.java +++ b/src/com/pablo67340/guishop/definition/ShopPane.java @@ -5,7 +5,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; -import java.util.Map.Entry; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.Inventory; @@ -22,76 +21,78 @@ public class ShopPane extends Pane { - private Map items; - @Getter - private Map dummies; - public static ShopPane INSTANCE; - private int increment; - - public ShopPane(int length, int height) { - super(length, height); - items = new HashMap<>(); - dummies = new HashMap<>(); - INSTANCE = this; - } - - public void addBlankItem() { - increment++; - } - - public void addItem(GuiItem item) { - items.put(items.size() + increment, item); - } - - public void setItem(GuiItem item, Integer slot) { - items.put(slot, item); - } - - @Override - public void clear() { - items.clear(); - } - - @Override - public boolean click(@NotNull Gui arg0, @NotNull InventoryClickEvent event, int arg2, int arg3, int arg4, - int arg5) { - return false; - } - - public void setDummy(Integer slot, ItemStack item) { - dummies.put(slot, item); - } - - @Override - public void display(@NotNull Gui gui, @NotNull Inventory inventory, @NotNull PlayerInventory playerInventory, - int paneOffsetX, int paneOffsetY, int maxLength, int maxHeight) { - for (Entry entry : items.entrySet()) { - inventory.setItem(entry.getKey(), entry.getValue().getItem()); - } - for (Entry entry : dummies.entrySet()) { - System.out.println("Entry: "+entry.getKey()+":"+entry.getValue()); - inventory.setItem(entry.getKey(), entry.getValue()); - } - } - - @NotNull - @Override - public Collection getItems() { - return new ArrayList<>(items.values()); - } - - @NotNull - @Override - public Collection getPanes() { - return new HashSet<>(); - } - - public Map getItemsMap() { - return this.items; - } - - public ShopPane getINSTANCE() { - return INSTANCE; - } + private final Map items; + @Getter + private final Map dummies; + public static ShopPane INSTANCE; + private int increment; + + public ShopPane(int length, int height) { + super(length, height); + items = new HashMap<>(); + dummies = new HashMap<>(); + INSTANCE = this; + } + + public void addBlankItem() { + increment++; + } + + public void addItem(GuiItem item) { + items.put(items.size() + increment, item); + } + + public void setItem(GuiItem item, Integer slot) { + items.put(slot, item); + } + + @Override + public void clear() { + items.clear(); + } + + @Override + public boolean click(@NotNull Gui arg0, @NotNull InventoryClickEvent event, int arg2, int arg3, int arg4, + int arg5) { + return false; + } + + public void setDummy(Integer slot, ItemStack item) { + dummies.put(slot, item); + } + + @Override + public void display(@NotNull Gui gui, @NotNull Inventory inventory, @NotNull PlayerInventory playerInventory, + int paneOffsetX, int paneOffsetY, int maxLength, int maxHeight) { + items.entrySet().forEach(entry -> { + inventory.setItem(entry.getKey(), entry.getValue().getItem()); + }); + dummies.entrySet().stream().map(entry -> { + System.out.println("Entry: " + entry.getKey() + ":" + entry.getValue()); + return entry; + }).forEachOrdered(entry -> { + inventory.setItem(entry.getKey(), entry.getValue()); + }); + } + + @NotNull + @Override + public Collection getItems() { + return new ArrayList<>(items.values()); + } + + @NotNull + @Override + public Collection getPanes() { + return new HashSet<>(); + } + + public Map getItemsMap() { + return this.items; + } + + public ShopPane getINSTANCE() { + return INSTANCE; + } } diff --git a/src/com/pablo67340/guishop/listenable/AltSell.java b/src/com/pablo67340/guishop/listenable/AltSell.java index 7e45175..23ab241 100644 --- a/src/com/pablo67340/guishop/listenable/AltSell.java +++ b/src/com/pablo67340/guishop/listenable/AltSell.java @@ -18,134 +18,134 @@ public class AltSell { - private final Item subjectItem; - private final Gui gui; - - private AltSellPane pane; - - private final Item indicatorItem; - private final Item addItem; - private final Item removeItem; - private final Item confirmItem; - private final Item cancelItem; - - public AltSell(Item subjectItem) { - this.subjectItem = subjectItem; - gui = new Gui(Main.getINSTANCE(), 6, ChatColor.translateAlternateColorCodes('&', Config.getAltSellTitle())); - indicatorItem = new Item(); - indicatorItem.setMaterial(Config.getAltSellIndicatorMaterial()); - addItem = new Item(); - addItem.setMaterial(Config.getAltSellAddMaterial()); - removeItem = new Item(); - removeItem.setMaterial(Config.getAltSellRemoveMaterial()); - confirmItem = new Item(); - confirmItem.setMaterial(Config.getAltSellConfirmMaterial()); - cancelItem = new Item(); - cancelItem.setMaterial(Config.getAltSellCancelMaterial()); - } - - private GuiItem setQuantityAndGet(ItemStack item, int quantity) { - item.setAmount(quantity); - return new GuiItem(item); - } - - public void open(Player player) { - if (!player.hasPermission("guishop.sell")) { - player.sendMessage(Config.getNoPermission()); - return; - } - GuiItem gItem = subjectItem.parseMaterial(); - GuiItem gIndicator = indicatorItem.parseMaterial(); - GuiItem gAddItem = addItem.parseMaterial(); - GuiItem gRemoveItem = removeItem.parseMaterial(); - GuiItem gConfirmItem = confirmItem.parseMaterial(); - GuiItem gCancelItem = cancelItem.parseMaterial(); - if (gItem != null && gIndicator != null && gAddItem != null && gRemoveItem != null && gConfirmItem != null - && gCancelItem != null) { - GuiItem[] addRemoveItems = new GuiItem[6]; - ItemStack addItem = gAddItem.getItem(); - addRemoveItems[0] = setQuantityAndGet(addItem.clone(), Config.getAltSellQuantity1()); - addRemoveItems[1] = setQuantityAndGet(addItem.clone(), Config.getAltSellQuantity2()); - addRemoveItems[2] = setQuantityAndGet(addItem.clone(), Config.getAltSellQuantity3()); - ItemStack removeItem = gRemoveItem.getItem(); - addRemoveItems[3] = setQuantityAndGet(removeItem.clone(), Config.getAltSellQuantity1()); - addRemoveItems[4] = setQuantityAndGet(removeItem.clone(), Config.getAltSellQuantity2()); - addRemoveItems[5] = setQuantityAndGet(removeItem.clone(), Config.getAltSellQuantity3()); - pane = new AltSellPane(gItem, addRemoveItems, gIndicator, - Item.renameGuiItem(gConfirmItem, Config.getAltSellConfirmName()), Item.renameGuiItem(gCancelItem, Config.getAltSellCancelName())); - pane.setSubjectQuantity(1); - pane.setIndicatorName(subjectItem.getSellLore(1)); - gui.addPane(pane); - gui.setOnTopClick(this::onClick); - gui.setOnBottomClick(event -> event.setCancelled(true)); - gui.show(player); - } else { - Main.log("One or more of the materials you defined in the alt sell GUI are not valid."); - } - } - - private void changeQuantity(int delta) { - int previous = pane.getSubjectQuantity(); - int update = previous + delta; - if (update < 1) { - update = 1; - } - update = pane.setSubjectQuantity(update); - if (update != previous) { - pane.setIndicatorName(subjectItem.getSellLore(update)); - gui.update(); - } - } - - private void sell(Player player, ItemStack itemStack) { - // remove IF's IF-uuid NBT tag - NBTTagCompound comp = ItemNBTUtil.getTag(itemStack); - comp.remove("IF-uuid"); - itemStack = ItemNBTUtil.setNBTTag(comp, itemStack); - - Main.debugLog(itemStack.toString()); - - int amount = itemStack.getAmount(); - Map result = player.getInventory().removeItem(itemStack); - if (result.isEmpty()) { - - Sell.roundAndGiveMoney(player, subjectItem.calculateSellPrice(amount)); - // buy price must be defined for dynamic pricing to work - if (subjectItem.hasBuyPrice() && Config.isDynamicPricing()) { - Main.getDYNAMICPRICING().sellItem(subjectItem.getItemString(), amount); - } - } else { - ItemStack addBack = result.get(0).clone(); - addBack.setAmount(amount - addBack.getAmount()); - if (addBack.getAmount() > 0) { - player.getInventory().addItem(addBack); - } - player.sendMessage(Config.getAltSellNotEnough().replace("{amount}", Integer.toString(amount))); - } - } - - private void onClick(InventoryClickEvent evt) { - evt.setCancelled(true); - switch (evt.getSlot()) { - case 18: - case 19: - case 20: - changeQuantity(evt.getCurrentItem().getAmount()); - break; - case 24: - case 25: - case 26: - changeQuantity(-evt.getCurrentItem().getAmount()); - break; - case 48: - sell((Player) evt.getWhoClicked(), evt.getInventory().getItem(13)); - break; - case 50: - evt.getWhoClicked().closeInventory(); - break; - default: - break; - } - } - + private final Item subjectItem; + private final Gui gui; + + private AltSellPane pane; + + private final Item indicatorItem; + private final Item addItem; + private final Item removeItem; + private final Item confirmItem; + private final Item cancelItem; + + public AltSell(Item subjectItem) { + this.subjectItem = subjectItem; + gui = new Gui(Main.getINSTANCE(), 6, ChatColor.translateAlternateColorCodes('&', Config.getAltSellTitle())); + indicatorItem = new Item(); + indicatorItem.setMaterial(Config.getAltSellIndicatorMaterial()); + addItem = new Item(); + addItem.setMaterial(Config.getAltSellAddMaterial()); + removeItem = new Item(); + removeItem.setMaterial(Config.getAltSellRemoveMaterial()); + confirmItem = new Item(); + confirmItem.setMaterial(Config.getAltSellConfirmMaterial()); + cancelItem = new Item(); + cancelItem.setMaterial(Config.getAltSellCancelMaterial()); + } + + private GuiItem setQuantityAndGet(ItemStack item, int quantity) { + item.setAmount(quantity); + return new GuiItem(item); + } + + public void open(Player player) { + if (!player.hasPermission("guishop.sell")) { + player.sendMessage(Config.getNoPermission()); + return; + } + GuiItem gItem = subjectItem.parseMaterial(); + GuiItem gIndicator = indicatorItem.parseMaterial(); + GuiItem gAddItem = addItem.parseMaterial(); + GuiItem gRemoveItem = removeItem.parseMaterial(); + GuiItem gConfirmItem = confirmItem.parseMaterial(); + GuiItem gCancelItem = cancelItem.parseMaterial(); + if (gItem != null && gIndicator != null && gAddItem != null && gRemoveItem != null && gConfirmItem != null + && gCancelItem != null) { + GuiItem[] addRemoveItems = new GuiItem[6]; + ItemStack addItemstack = gAddItem.getItem(); + addRemoveItems[0] = setQuantityAndGet(addItemstack.clone(), Config.getAltSellQuantity1()); + addRemoveItems[1] = setQuantityAndGet(addItemstack.clone(), Config.getAltSellQuantity2()); + addRemoveItems[2] = setQuantityAndGet(addItemstack.clone(), Config.getAltSellQuantity3()); + ItemStack removeItemstack = gRemoveItem.getItem(); + addRemoveItems[3] = setQuantityAndGet(removeItemstack.clone(), Config.getAltSellQuantity1()); + addRemoveItems[4] = setQuantityAndGet(removeItemstack.clone(), Config.getAltSellQuantity2()); + addRemoveItems[5] = setQuantityAndGet(removeItemstack.clone(), Config.getAltSellQuantity3()); + pane = new AltSellPane(gItem, addRemoveItems, gIndicator, + Item.renameGuiItem(gConfirmItem, Config.getAltSellConfirmName()), Item.renameGuiItem(gCancelItem, Config.getAltSellCancelName())); + pane.setSubjectQuantity(1); + pane.setIndicatorName(subjectItem.getSellLore(1)); + gui.addPane(pane); + gui.setOnTopClick(this::onClick); + gui.setOnBottomClick(event -> event.setCancelled(true)); + gui.show(player); + } else { + Main.log("One or more of the materials you defined in the alt sell GUI are not valid."); + } + } + + private void changeQuantity(int delta) { + int previous = pane.getSubjectQuantity(); + int update = previous + delta; + if (update < 1) { + update = 1; + } + update = pane.setSubjectQuantity(update); + if (update != previous) { + pane.setIndicatorName(subjectItem.getSellLore(update)); + gui.update(); + } + } + + private void sell(Player player, ItemStack itemStack) { + // remove IF's IF-uuid NBT tag + NBTTagCompound comp = ItemNBTUtil.getTag(itemStack); + comp.remove("IF-uuid"); + itemStack = ItemNBTUtil.setNBTTag(comp, itemStack); + + Main.debugLog(itemStack.toString()); + + int amount = itemStack.getAmount(); + Map result = player.getInventory().removeItem(itemStack); + if (result.isEmpty()) { + + Sell.roundAndGiveMoney(player, subjectItem.calculateSellPrice(amount)); + // buy price must be defined for dynamic pricing to work + if (subjectItem.hasBuyPrice() && Config.isDynamicPricing()) { + Main.getDYNAMICPRICING().sellItem(subjectItem.getItemString(), amount); + } + } else { + ItemStack addBack = result.get(0).clone(); + addBack.setAmount(amount - addBack.getAmount()); + if (addBack.getAmount() > 0) { + player.getInventory().addItem(addBack); + } + player.sendMessage(Config.getAltSellNotEnough().replace("{amount}", Integer.toString(amount))); + } + } + + private void onClick(InventoryClickEvent evt) { + evt.setCancelled(true); + switch (evt.getSlot()) { + case 18: + case 19: + case 20: + changeQuantity(evt.getCurrentItem().getAmount()); + break; + case 24: + case 25: + case 26: + changeQuantity(-evt.getCurrentItem().getAmount()); + break; + case 48: + sell((Player) evt.getWhoClicked(), evt.getInventory().getItem(13)); + break; + case 50: + evt.getWhoClicked().closeInventory(); + break; + default: + break; + } + } + } diff --git a/src/com/pablo67340/guishop/listenable/Menu.java b/src/com/pablo67340/guishop/listenable/Menu.java index bb16772..5cf0a9e 100644 --- a/src/com/pablo67340/guishop/listenable/Menu.java +++ b/src/com/pablo67340/guishop/listenable/Menu.java @@ -21,172 +21,173 @@ public final class Menu { - /** - * The GUI that is projected onto the screen when a {@link Player} opens the - * {@link Menu}. - */ - private Gui GUI; - - private Boolean hasClicked = false; - - /** - * A {@link Map} that will store our {@link Shop}s when the server first starts. - * - * @key The index on the {@link Menu} that this shop is located at. - * @value The shop. - */ - - public Menu() { - this.GUI = new Gui(Main.getINSTANCE(), Config.getMenuRows(), "" + Config.getMenuTitle()); - } - - public void itemWarmup() { - Main.getINSTANCE().getLogger().log(Level.INFO, "Warming Items..."); - long startTime = System.currentTimeMillis(); - for (ShopDef shopDef : Main.getINSTANCE().getShops().values()) { - if (shopDef.getItemType() == ItemType.SHOP) { - new Shop(shopDef.getShop(), shopDef.getName(), shopDef.getDescription(), shopDef.getLore(), this) - .loadItems(); - } - } - long estimatedTime = System.currentTimeMillis() - startTime; - Main.getINSTANCE().getLogger().log(Level.INFO, "Item warming completed in: " + estimatedTime + "ms"); - } - - /** - * Preloads the configs into their corresponding objects. - */ - public void preLoad(Player player) { - - ShopPane page = new ShopPane(9, 1); - - for (ShopDef shopDef : Main.getINSTANCE().getShops().values()) { - - if (shopDef.getItemType() != ItemType.SHOP || player.hasPermission("guishop.shop." + shopDef.getShop()) - || player.hasPermission("guishop.shop.*") || player.isOp()) { - page.addItem(buildMenuItem(shopDef.getItemID(), shopDef)); - } else { - page.addBlankItem(); - } - } - - GUI.addPane(page); - - } - - public GuiItem buildMenuItem(String itemID, ShopDef shopDef) { - - ItemStack itemStack = XMaterial.matchXMaterial(itemID).get().parseItem(); - - if (shopDef.getItemType() != ItemType.BLANK) { - setName(itemStack, shopDef.getName(), shopDef.getLore(), shopDef); - } - return new GuiItem(itemStack); - } - - /** - * Opens the GUI in this {@link Menu}. - */ - public void open(Player player) { - - if (!player.hasPermission("guishop.use") && !player.isOp()) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(Main.getINSTANCE().getMainConfig().getString("no-permission")))); - return; - } - - if (Main.getINSTANCE().getMainConfig().getStringList("disabled-worlds").contains(player.getWorld().getName())) { - player.sendMessage(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(Main.getINSTANCE().getMainConfig().getString("disabled-world")))); - return; - } - - preLoad(player); - - GUI.setOnTopClick(this::onShopClick); - GUI.setOnBottomClick(event -> { - event.setCancelled(true); - }); - if (Main.getCREATOR().contains(player.getName())) { - GUI.setOnClose(event -> onClose(event)); - } - GUI.show(player); - - } - - /** - * Sets the item's display name. - */ - private ItemStack setName(ItemStack item, String name, List lore, ShopDef shopDef) { - ItemMeta IM = item.getItemMeta(); - - if (name != null) { - assert IM != null; - IM.setDisplayName(name); - } - - if (lore != null && !lore.isEmpty() && shopDef.getItemType() == ItemType.SHOP) { - assert IM != null; - IM.setLore(lore); - } - - item.setItemMeta(IM); - - return item; - - } + /** + * The GUI that is projected onto the screen when a {@link Player} opens the + * {@link Menu}. + */ + private final Gui GUI; + + private Boolean hasClicked = false; + + /** + * A {@link Map} that will store our {@link Shop}s when the server first + * starts. + * + * @key The index on the {@link Menu} that this shop is located at. + * @value The shop. + */ + public Menu() { + this.GUI = new Gui(Main.getINSTANCE(), Config.getMenuRows(), "" + Config.getMenuTitle()); + } + + public void itemWarmup() { + Main.getINSTANCE().getLogger().log(Level.INFO, "Warming Items..."); + long startTime = System.currentTimeMillis(); + Main.getINSTANCE().getShops().values().stream().filter(shopDef -> (shopDef.getItemType() == ItemType.SHOP)).forEachOrdered(shopDef -> { + new Shop(shopDef.getShop(), shopDef.getName(), shopDef.getDescription(), shopDef.getLore(), this) + .loadItems(); + }); + long estimatedTime = System.currentTimeMillis() - startTime; + Main.getINSTANCE().getLogger().log(Level.INFO, "Item warming completed in: {0}ms", estimatedTime); + } + + /** + * Preloads the configs into their corresponding objects. + * + * @param player - The player warming up the GUI + */ + public void preLoad(Player player) { + + ShopPane page = new ShopPane(9, 1); + + Main.getINSTANCE().getShops().values().forEach(shopDef -> { + if (shopDef.getItemType() != ItemType.SHOP || player.hasPermission("guishop.shop." + shopDef.getShop()) + || player.hasPermission("guishop.shop.*") || player.isOp()) { + page.addItem(buildMenuItem(shopDef.getItemID(), shopDef)); + } else { + page.addBlankItem(); + } + }); + + GUI.addPane(page); + + } + + public GuiItem buildMenuItem(String itemID, ShopDef shopDef) { + + ItemStack itemStack = XMaterial.matchXMaterial(itemID).get().parseItem(); + + if (shopDef.getItemType() != ItemType.BLANK) { + setName(itemStack, shopDef.getName(), shopDef.getLore(), shopDef); + } + return new GuiItem(itemStack); + } + + /** + * Opens the GUI in this {@link Menu}. + * + * @param player - The player the GUI will display to + */ + public void open(Player player) { + + if (!player.hasPermission("guishop.use") && !player.isOp()) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(Main.getINSTANCE().getMainConfig().getString("no-permission")))); + return; + } + + if (Main.getINSTANCE().getMainConfig().getStringList("disabled-worlds").contains(player.getWorld().getName())) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(Main.getINSTANCE().getMainConfig().getString("disabled-world")))); + return; + } + + preLoad(player); + + GUI.setOnTopClick(this::onShopClick); + GUI.setOnBottomClick(event -> { + event.setCancelled(true); + }); + if (Main.getCREATOR().contains(player.getName())) { + GUI.setOnClose(event -> onClose(event)); + } + GUI.show(player); + + } + + /** + * Sets the item's display name. + */ + private ItemStack setName(ItemStack item, String name, List lore, ShopDef shopDef) { + ItemMeta IM = item.getItemMeta(); + + if (name != null) { + assert IM != null; + IM.setDisplayName(name); + } + + if (lore != null && !lore.isEmpty() && shopDef.getItemType() == ItemType.SHOP) { + assert IM != null; + IM.setLore(lore); + } + + item.setItemMeta(IM); + + return item; + + } + + /** + * Handle global inventory click events, check if inventory is for GUIShop, + * if so, run logic. + */ + private void onShopClick(InventoryClickEvent e) { + Player player = (Player) e.getWhoClicked(); + e.setCancelled(true); + + if (e.getCurrentItem() == null || e.getCurrentItem().getType() == Material.AIR) { + return; + } - /** - * Handle global inventory click events, check if inventory is for GUIShop, if - * so, run logic. - */ - private void onShopClick(InventoryClickEvent e) { - Player player = (Player) e.getWhoClicked(); - e.setCancelled(true); + hasClicked = true; - if (e.getCurrentItem() == null || e.getCurrentItem().getType() == Material.AIR) { - return; - } + ShopDef shopDef = new ArrayList<>(Main.getINSTANCE().getShops().values()).get(e.getSlot()); - hasClicked = true; + if (shopDef.getItemType() == ItemType.SHOP) { + openShop(player, shopDef); + } - ShopDef shopDef = new ArrayList<>(Main.getINSTANCE().getShops().values()).get(e.getSlot()); + } - if (shopDef.getItemType() == ItemType.SHOP) { - openShop(player, shopDef); - } + public Shop openShop(Player player, ShopDef shopDef) { - } - - public Shop openShop(Player player, ShopDef shopDef) { - - if (shopDef.getItemType() == ItemType.SHOP) { - /* + if (shopDef.getItemType() == ItemType.SHOP) { + /* * The currently open shop associated with this Menu instance. - */ - Shop openShop; - if (!Main.getINSTANCE().getLoadedShops().containsKey(shopDef.getName())) { - openShop = new Shop(shopDef.getShop(), shopDef.getName(), shopDef.getDescription(), shopDef.getLore(), - this); - } else { - openShop = new Shop(shopDef.getShop(), shopDef.getName(), shopDef.getDescription(), shopDef.getLore(), - this, Main.getINSTANCE().getLoadedShops().get(shopDef.getName())); - } - - openShop.loadItems(); - openShop.open(player); - return Main.getINSTANCE().getOpenShopInstances().put(player.getUniqueId(), openShop); - } - return null; - } - - private void onClose(InventoryCloseEvent e) { - if (!hasClicked) { - Player p = (Player) e.getPlayer(); - if (Main.getCREATOR().contains(p.getName())) { - Main.getCREATOR().remove(p.getName()); - } - } - } + */ + Shop openShop; + if (!Main.getINSTANCE().getLoadedShops().containsKey(shopDef.getName())) { + openShop = new Shop(shopDef.getShop(), shopDef.getName(), shopDef.getDescription(), shopDef.getLore(), + this); + } else { + openShop = new Shop(shopDef.getShop(), shopDef.getName(), shopDef.getDescription(), shopDef.getLore(), + this, Main.getINSTANCE().getLoadedShops().get(shopDef.getName())); + } + + openShop.loadItems(); + openShop.open(player); + return Main.getINSTANCE().getOpenShopInstances().put(player.getUniqueId(), openShop); + } + return null; + } + + private void onClose(InventoryCloseEvent e) { + if (!hasClicked) { + Player p = (Player) e.getPlayer(); + if (Main.getCREATOR().contains(p.getName())) { + Main.getCREATOR().remove(p.getName()); + } + } + } } diff --git a/src/com/pablo67340/guishop/listenable/PlayerListener.java b/src/com/pablo67340/guishop/listenable/PlayerListener.java index 0b784ae..4292c28 100644 --- a/src/com/pablo67340/guishop/listenable/PlayerListener.java +++ b/src/com/pablo67340/guishop/listenable/PlayerListener.java @@ -21,125 +21,125 @@ import com.pablo67340.guishop.Main; import com.pablo67340.guishop.definition.Item; -import com.pablo67340.guishop.definition.ItemType; -import com.pablo67340.guishop.definition.ShopDef; import com.pablo67340.guishop.util.Config; -import com.pablo67340.guishop.util.ItemUtil; -import com.pablo67340.guishop.util.XMaterial; public final class PlayerListener implements Listener { - /** - * An instance of a {@link PlayerListener} that will be used to handle this - * specific object reference from other classes, even though methods here will - * be static. - */ - public static final PlayerListener INSTANCE = new PlayerListener(); - - public void openShop(Player player) { - if (Main.getINSTANCE().getCreatorRefresh()) { - Main.sendMessage(player, "&aGUIShop config was recently edited in creator mode. Reloading before opening..."); - Main.getINSTANCE().reload(player, true); - Main.getINSTANCE().setCreatorRefresh(false); - } - Menu menu = new Menu(); - menu.open(player); - } - - /** - * Print the usage of the plugin to the player. - */ - public void printUsage(Player player) { - Main.sendMessage(player, "&dG&9U&8I&3S&dh&9o&8p &3C&do&9m&8m&3a&dn&8d&3s&d:"); - Main.sendMessage(player, "&7/guishop &eedit/e &0- &aOpens in Editor Mode"); - Main.sendMessage(player, "&7/guishop &eprice/p {price} &0- &aSet item in hand's buy price"); - Main.sendMessage(player, "&7/guishop &esell/s {price} &0- &aSet item in hand's sell price"); - Main.sendMessage(player, "&7/guishop &eshopname/sn {name} &0- &aSet item in hand's Shop-Name"); - Main.sendMessage(player, "&7/guishop &ebuyname/bn {name} &0- &aSet item in hand's Buy-Name"); - Main.sendMessage(player, "&7/guishop &eenchant/e {enchants} &0- &aSet item in hand's Enchantments"); - Main.sendMessage(player, "&7/guishop &easll {line} &0- &aAdd Shop Lore Line"); - Main.sendMessage(player, "&7/guishop &edsll {lineNumber} &0- &aDelete Shop Lore Line. Starts at 0"); - Main.sendMessage(player, "&7/guishop &eesll {lineNumber} {line} &0- &aEdit Shop Lore Line. Starts at 0"); - Main.sendMessage(player, "&7/guishop &eabll {line} &0- &aAdd Buy Lore Line"); - Main.sendMessage(player, "&7/guishop &edbll {lineNumber} &0- &aDelete Buy Lore Line. Starts at 0"); - Main.sendMessage(player, "&7/guishop &eebll {lineNumber} {line} &0- &aEdit Buy Lore Line. Starts at 0"); - Main.sendMessage(player, "&7/guishop &eac {command} &0- &aAdd Command to item"); - Main.sendMessage(player, "&7/guishop &edc {lineNumber} &0- &aDelete Command by line. Starts at 0"); - Main.sendMessage(player, "&7/guishop &eec {lineNumber} {cmd} &0- &aEdit Command by line. Starts at 0"); - Main.sendMessage(player, "&7/guishop &emt {type} &0- &aSet an item's mob type. Used for Spawners/Eggs."); - Main.sendMessage(player, "&7/guishop &et {type} &0- &aSet an item's type. BLANK, SHOP, COMMAND, DUMMY"); - } - - // When the inventory closes - - // When the player clicks a sign - @EventHandler - public void onInteract(PlayerInteractEvent e) { - Player player = e.getPlayer(); - Block block = e.getClickedBlock(); - - // If the block exists - if (block != null) { - // If the block has a state - block.getState(); - // If the block state is a Sign - if (block.getState() instanceof Sign) { - Sign sign = (Sign) block.getState(); - String line1 = ChatColor.translateAlternateColorCodes('&', sign.getLine(0)); - // Check if the sign is a GUIShop sign - if (line1.equalsIgnoreCase(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(Main.INSTANCE.getMainConfig().getString("sign-title"))))) { - // If the player has Permission to use sign - if (player.hasPermission("guishop.use") && player.hasPermission("guishop.sign.use") - || player.isOp()) { - e.setCancelled(true); - Menu menu = new Menu(); - menu.open(player); - } else { - e.setCancelled(true); - player.sendMessage(Config.getPrefix() + " " + Config.getNoPermission()); - } - - } - } - } - } - - /** - * Custom MobSpawner placement method. - */ - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent event) { - ItemStack item = event.getItemInHand(); - if (Item.isSpawnerItem(item)) { - - NBTTagCompound cmp = ItemNBTUtil.getTag(item); - if (cmp.hasKey("GUIShopSpawner")) { - - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> { - - String mobId = cmp.getString("GUIShopSpawner"); - Block block = event.getBlockPlaced(); - CreatureSpawner cs = (CreatureSpawner) block.getState(); - - Main.debugLog("Applying mob type " + mobId); - /* - * Although valueOf is almost always safe here because - * we used EntityType.name() when setting the NBT tag, - * it's possible the user might change server versions, - * in which case the EntityType enum may have changed. - */ - try { - cs.setSpawnedType(EntityType.valueOf(mobId)); - cs.update(); - } catch (IllegalArgumentException veryRareException) { - Main.log("Detected outdated mob spawner ID: " + mobId + " placed by " + event.getPlayer()); - } - - }, 1L); - } - } - } + /** + * An instance of a {@link PlayerListener} that will be used to handle this + * specific object reference from other classes, even though methods here + * will be static. + */ + public static final PlayerListener INSTANCE = new PlayerListener(); + + public void openShop(Player player) { + if (Main.getINSTANCE().getCreatorRefresh()) { + Main.sendMessage(player, "&aGUIShop config was recently edited in creator mode. Reloading before opening..."); + Main.getINSTANCE().reload(player, true); + Main.getINSTANCE().setCreatorRefresh(false); + } + Menu menu = new Menu(); + menu.open(player); + } + + /** + * Print the usage of the plugin to the player. + * + * @param player - The player the help text will be sent to + */ + public void printUsage(Player player) { + Main.sendMessage(player, "&dG&9U&8I&3S&dh&9o&8p &3C&do&9m&8m&3a&dn&8d&3s&d:"); + Main.sendMessage(player, "&7/guishop &eedit/e &0- &aOpens in Editor Mode"); + Main.sendMessage(player, "&7/guishop &eprice/p {price} &0- &aSet item in hand's buy price"); + Main.sendMessage(player, "&7/guishop &esell/s {price} &0- &aSet item in hand's sell price"); + Main.sendMessage(player, "&7/guishop &eshopname/sn {name} &0- &aSet item in hand's Shop-Name"); + Main.sendMessage(player, "&7/guishop &ebuyname/bn {name} &0- &aSet item in hand's Buy-Name"); + Main.sendMessage(player, "&7/guishop &eenchant/e {enchants} &0- &aSet item in hand's Enchantments"); + Main.sendMessage(player, "&7/guishop &easll {line} &0- &aAdd Shop Lore Line"); + Main.sendMessage(player, "&7/guishop &edsll {lineNumber} &0- &aDelete Shop Lore Line. Starts at 0"); + Main.sendMessage(player, "&7/guishop &eesll {lineNumber} {line} &0- &aEdit Shop Lore Line. Starts at 0"); + Main.sendMessage(player, "&7/guishop &eabll {line} &0- &aAdd Buy Lore Line"); + Main.sendMessage(player, "&7/guishop &edbll {lineNumber} &0- &aDelete Buy Lore Line. Starts at 0"); + Main.sendMessage(player, "&7/guishop &eebll {lineNumber} {line} &0- &aEdit Buy Lore Line. Starts at 0"); + Main.sendMessage(player, "&7/guishop &eac {command} &0- &aAdd Command to item"); + Main.sendMessage(player, "&7/guishop &edc {lineNumber} &0- &aDelete Command by line. Starts at 0"); + Main.sendMessage(player, "&7/guishop &eec {lineNumber} {cmd} &0- &aEdit Command by line. Starts at 0"); + Main.sendMessage(player, "&7/guishop &emt {type} &0- &aSet an item's mob type. Used for Spawners/Eggs."); + Main.sendMessage(player, "&7/guishop &et {type} &0- &aSet an item's type. BLANK, SHOP, COMMAND, DUMMY"); + } + + // When the inventory closes + // When the player clicks a sign + @EventHandler + public void onInteract(PlayerInteractEvent e) { + Player player = e.getPlayer(); + Block block = e.getClickedBlock(); + + // If the block exists + if (block != null) { + // If the block has a state + block.getState(); + // If the block state is a Sign + if (block.getState() instanceof Sign) { + Sign sign = (Sign) block.getState(); + String line1 = ChatColor.translateAlternateColorCodes('&', sign.getLine(0)); + // Check if the sign is a GUIShop sign + if (line1.equalsIgnoreCase(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(Main.INSTANCE.getMainConfig().getString("sign-title"))))) { + // If the player has Permission to use sign + if (player.hasPermission("guishop.use") && player.hasPermission("guishop.sign.use") + || player.isOp()) { + e.setCancelled(true); + Menu menu = new Menu(); + menu.open(player); + } else { + e.setCancelled(true); + player.sendMessage(Config.getPrefix() + " " + Config.getNoPermission()); + } + + } + } + } + } + + /** + * Custom MobSpawner placement method. + * + * @param event - The event type we're listening to + */ + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent event) { + ItemStack item = event.getItemInHand(); + if (Item.isSpawnerItem(item)) { + + NBTTagCompound cmp = ItemNBTUtil.getTag(item); + if (cmp.hasKey("GUIShopSpawner")) { + + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> { + + String mobId = cmp.getString("GUIShopSpawner"); + Block block = event.getBlockPlaced(); + CreatureSpawner cs = (CreatureSpawner) block.getState(); + + Main.debugLog("Applying mob type " + mobId); + + /* + * Although valueOf is almost always safe here because + * we used EntityType.name() when setting the NBT tag, + * it's possible the user might change server versions, + * in which case the EntityType enum may have changed. + */ + try { + cs.setSpawnedType(EntityType.valueOf(mobId)); + cs.update(); + } catch (IllegalArgumentException veryRareException) { + Main.log("Detected outdated mob spawner ID: " + mobId + " placed by " + event.getPlayer()); + } + + }, 1L); + } + } + } } diff --git a/src/com/pablo67340/guishop/listenable/Quantity.java b/src/com/pablo67340/guishop/listenable/Quantity.java index f35baca..69f8887 100644 --- a/src/com/pablo67340/guishop/listenable/Quantity.java +++ b/src/com/pablo67340/guishop/listenable/Quantity.java @@ -33,321 +33,314 @@ class Quantity { - /** - * The item currently being targetted. - */ - private Item item; - - /** - * The GUI that will be displayed. - */ - private Gui GUI; - - /** - * The map containing the sell increments. - */ - private Map qty = new HashMap<>(); - - /** - * The instance of the {@link Shop} that spawned this Quantity. - */ - private Shop currentShop; - - @Getter - private Player player; - - Quantity(Item item, Shop shop, Player input) { - this.item = item; - this.currentShop = shop; - this.player = input; - } - - /** - * Opens the GUI to sell the items in. - */ - void open() { - GUI.setOnClose(this::onClose); - GUI.setOnTopClick(this::onQuantityClick); - GUI.setOnBottomClick(event -> { - event.setCancelled(true); - }); - GUI.show(player); - } - - /** - * Preloads the inventory to display items. - */ - public Quantity loadInventory() { - GUI = new Gui(Main.getINSTANCE(), 6, Config.getQtyTitle()); - int multiplier = 1; - ShopPane page = new ShopPane(9, 6); - for (int x = 19; x <= 25; x++) { - - GuiItem gItem = item.parseMaterial(); - - ItemStack itemStack = gItem.getItem(); - - itemStack.setAmount(multiplier); - ItemMeta itemMeta = itemStack.getItemMeta(); - List lore = new ArrayList<>(); - - lore.add(item.getBuyLore(multiplier)); - - item.getShopLore().forEach(str -> { - lore.add(ChatColor.translateAlternateColorCodes('&', str)); - }); - - assert itemMeta != null; - itemMeta.setLore(lore); - - String type = itemStack.getType().toString(); - - boolean isInList = Config.getDisabledQty().stream().anyMatch(t -> spellCheck(type, t)); - - if (isInList && x >= 20) { - break; - } - - if (item.hasShopName()) { - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', item.getShopName())); - } else if (Item.isSpawnerItem(itemStack)) { - String mobName = item.getMobType(); - mobName = mobName.toLowerCase(); - mobName = mobName.substring(0, 1).toUpperCase() + mobName.substring(1).replace("_", " "); - itemMeta.setDisplayName(mobName + " Spawner"); - } - - if (item.hasEnchantments()) { - if (item.getEnchantments().length > 1) { - for (String enc : item.getEnchantments()) { - String enchantment = StringUtils.substringBefore(enc, ":"); - String level = StringUtils.substringAfter(enc, ":"); - itemStack.addUnsafeEnchantment( - XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), - Integer.parseInt(level)); - } - } - } - - itemStack.setItemMeta(itemMeta); - - if (item.hasPotion()) { - item.getPotion().apply(itemStack); - } - - page.setItem(gItem, x); - qty.put(x, multiplier); - multiplier *= 2; - } - - if (!Config.isEscapeOnly()) { - - ItemStack backButtonItem = XMaterial.matchXMaterial(Config.getBackButtonItem()).get().parseItem(); - - ItemMeta backButtonMeta = backButtonItem.getItemMeta(); - - assert backButtonMeta != null; - backButtonMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', - Objects.requireNonNull(Main.INSTANCE.getConfig().getString("back")))); - - backButtonItem.setItemMeta(backButtonMeta); - - GuiItem gItem = new GuiItem(backButtonItem, this::onQuantityClick); - page.setItem(gItem, 53); - - } - GUI.addPane(page); - - return this; - } - - private Boolean spellCheck(String type, String t) { - return type.contains(t); - } - - /** - * Executes when an item is clicked inside the Quantity Inventory. - */ - private void onQuantityClick(InventoryClickEvent e) { - Player player = (Player) e.getWhoClicked(); - e.setCancelled(true); - if (!Config.isEscapeOnly()) { - if (e.getSlot() == 53) { - currentShop.open(player); - return; - } - } - - if (e.getClickedInventory() == null) { - return; - } - - if (e.getCurrentItem() == null || e.getCurrentItem().getType() == Material.AIR) { - return; - } - - if (player.getInventory().firstEmpty() == -1) { - player.sendMessage(Config.getFull()); - return; - } - - if (!item.hasBuyPrice()) { - player.sendMessage(Config.getCantBuy()); - return; - } - - // Does the quantity work out? - int quantity = qty.get(e.getSlot()); - - // If the quantity is 0 - if (quantity == 0) { - player.sendMessage(Config.getPrefix() + " " + Config.getNotEnoughPre() + item.calculateBuyPrice(1) - + Config.getNotEnoughPost()); - player.setItemOnCursor(new ItemStack(Material.AIR)); - return; - } - - ItemStack itemStack = e.getCurrentItem().clone(); - - // remove IF's IF-uuid NBT tag - NBTTagCompound comp = ItemNBTUtil.getTag(itemStack); - comp.remove("IF-uuid"); - itemStack = ItemNBTUtil.setNBTTag(comp, itemStack); - - // If the item is not a mob spawner - if (!item.isMobSpawner()) { - // If the item has enchantments - if (item.hasEnchantments()) { - if (itemStack.getType() == Material.ENCHANTED_BOOK) { - EnchantmentStorageMeta meta = (EnchantmentStorageMeta) itemStack.getItemMeta(); - for (String enc : item.getEnchantments()) { - String enchantment = StringUtils.substringBefore(enc, ":"); - String level = StringUtils.substringAfter(enc, ":"); - assert meta != null; - meta.addStoredEnchant(XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), - Integer.parseInt(level), true); - - } - } else { - for (String enc : item.getEnchantments()) { - String enchantment = StringUtils.substringBefore(enc, ":"); - String level = StringUtils.substringAfter(enc, ":"); - itemStack.addUnsafeEnchantment( - XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), - Integer.parseInt(level)); - } - - } - } - } - - List lore = new ArrayList<>(); - - if (item.hasBuyLore()) { - item.getBuyLore().forEach(str -> { - lore.add(ChatColor.translateAlternateColorCodes('&', Main.placeholderIfy(str, player, item))); - }); - } - - ItemMeta itemMeta = itemStack.getItemMeta(); - - itemMeta.setLore(lore); - - if (item.hasBuyName()) { - assert itemMeta != null; - itemMeta.setDisplayName( - ChatColor.translateAlternateColorCodes('&', Main.placeholderIfy(item.getBuyName(), player, item))); - } else if (Item.isSpawnerItem(itemStack)) { - String mobName = item.getMobType(); - mobName = mobName.toLowerCase(); - mobName = mobName.substring(0, 1).toUpperCase() + mobName.substring(1).replace("_", " "); - assert itemMeta != null; - itemMeta.setDisplayName(mobName + " Spawner"); - } - - itemStack.setItemMeta(itemMeta); - - double priceToPay; - - /* - * If the map is empty, then the items purchased don't overflow the player's - * inventory. Otherwise, we need to reimburse the player (subtract it from - * priceToPay). - */ - - double priceToReimburse = 0D; - - // if the item is not a shift click - - int amount = itemStack.getAmount(); - - Runnable dynamicPricingUpdate = null; - - // sell price must be defined and nonzero for dynamic pricing to work - if (Config.isDynamicPricing() && item.isUseDynamicPricing() && item.hasSellPrice()) { - - String itemString = item.getItemString(); - dynamicPricingUpdate = () -> Main.getDYNAMICPRICING().buyItem(itemString, amount); - - priceToPay = Main.getDYNAMICPRICING().calculateBuyPrice(itemString, amount, item.getBuyPriceAsDouble(), item.getSellPriceAsDouble()); - } else { - priceToPay = item.getBuyPriceAsDouble() * amount; - } - - priceToPay -= priceToReimburse; - - // Check if the transition was successful - - if (Main.getECONOMY().withdrawPlayer(player, priceToPay).transactionSuccess()) { - // If the player has the sound enabled, play - // it! - if (Config.isSoundEnabled()) { - - player.playSound(player.getLocation(), XSound.matchXSound(Config.getSound()).get().parseSound(), 1, 1); - - } - player.sendMessage(Config.getPrefix() + Config.getPurchased() + priceToPay + Config.getTaken() - + Config.getCurrencySuffix()); - - if (item.isMobSpawner()) { - - EntityType type = item.parseMobSpawnerType(); - if (type == null) { - Main.log("Invalid EntityType in shops.yml: " + item.getMobType()); - - } else { - String entityValue = type.name(); - Main.debugLog("Attaching " + entityValue + " to purchased spawner"); - - NBTTagCompound tag = ItemNBTUtil.getTag(itemStack); - tag.setString("GUIShopSpawner", entityValue); - itemStack = ItemNBTUtil.setNBTTag(tag, itemStack); - } - } - - if (dynamicPricingUpdate != null) { - dynamicPricingUpdate.run(); - } + /** + * The item currently being targetted. + */ + private final Item item; + + /** + * The GUI that will be displayed. + */ + private Gui GUI; + + /** + * The map containing the sell increments. + */ + private final Map qty = new HashMap<>(); + + /** + * The instance of the {@link Shop} that spawned this Quantity. + */ + private final Shop currentShop; + + @Getter + private final Player player; + + Quantity(Item item, Shop shop, Player input) { + this.item = item; + this.currentShop = shop; + this.player = input; + } + + /** + * Opens the GUI to sell the items in. + */ + void open() { + GUI.setOnClose(this::onClose); + GUI.setOnTopClick(this::onQuantityClick); + GUI.setOnBottomClick(event -> { + event.setCancelled(true); + }); + GUI.show(player); + } + + /** + * Preloads the inventory to display items. + */ + public Quantity loadInventory() { + GUI = new Gui(Main.getINSTANCE(), 6, Config.getQtyTitle()); + int multiplier = 1; + ShopPane page = new ShopPane(9, 6); + for (int x = 19; x <= 25; x++) { + + GuiItem gItem = item.parseMaterial(); + + ItemStack itemStack = gItem.getItem(); + + itemStack.setAmount(multiplier); + ItemMeta itemMeta = itemStack.getItemMeta(); + List lore = new ArrayList<>(); + + lore.add(item.getBuyLore(multiplier)); + + item.getShopLore().forEach(str -> { + lore.add(ChatColor.translateAlternateColorCodes('&', str)); + }); + + assert itemMeta != null; + itemMeta.setLore(lore); + + String type = itemStack.getType().toString(); + + boolean isInList = Config.getDisabledQty().stream().anyMatch(t -> spellCheck(type, t)); + + if (isInList && x >= 20) { + break; + } + + if (item.hasShopName()) { + itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', item.getShopName())); + } else if (Item.isSpawnerItem(itemStack)) { + String mobName = item.getMobType(); + mobName = mobName.toLowerCase(); + mobName = mobName.substring(0, 1).toUpperCase() + mobName.substring(1).replace("_", " "); + itemMeta.setDisplayName(mobName + " Spawner"); + } + + if (item.hasEnchantments()) { + if (item.getEnchantments().length > 1) { + for (String enc : item.getEnchantments()) { + String enchantment = StringUtils.substringBefore(enc, ":"); + String level = StringUtils.substringAfter(enc, ":"); + itemStack.addUnsafeEnchantment( + XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), + Integer.parseInt(level)); + } + } + } + + itemStack.setItemMeta(itemMeta); + + if (item.hasPotion()) { + item.getPotion().apply(itemStack); + } + + page.setItem(gItem, x); + qty.put(x, multiplier); + multiplier *= 2; + } + + if (!Config.isEscapeOnly()) { + + ItemStack backButtonItem = XMaterial.matchXMaterial(Config.getBackButtonItem()).get().parseItem(); + + ItemMeta backButtonMeta = backButtonItem.getItemMeta(); + + assert backButtonMeta != null; + backButtonMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', + Objects.requireNonNull(Main.INSTANCE.getConfig().getString("back")))); + + backButtonItem.setItemMeta(backButtonMeta); + + GuiItem gItem = new GuiItem(backButtonItem, this::onQuantityClick); + page.setItem(gItem, 53); + + } + GUI.addPane(page); + + return this; + } + + private Boolean spellCheck(String type, String t) { + return type.contains(t); + } + + /** + * Executes when an item is clicked inside the Quantity Inventory. + */ + private void onQuantityClick(InventoryClickEvent e) { + e.setCancelled(true); + if (!Config.isEscapeOnly()) { + if (e.getSlot() == 53) { + currentShop.open(player); + return; + } + } + + if (e.getClickedInventory() == null) { + return; + } + + if (e.getCurrentItem() == null || e.getCurrentItem().getType() == Material.AIR) { + return; + } + + if (player.getInventory().firstEmpty() == -1) { + player.sendMessage(Config.getFull()); + return; + } + + if (!item.hasBuyPrice()) { + player.sendMessage(Config.getCantBuy()); + return; + } + + // Does the quantity work out? + int quantity = qty.get(e.getSlot()); + + // If the quantity is 0 + if (quantity == 0) { + player.sendMessage(Config.getPrefix() + " " + Config.getNotEnoughPre() + item.calculateBuyPrice(1) + + Config.getNotEnoughPost()); + player.setItemOnCursor(new ItemStack(Material.AIR)); + return; + } + + ItemStack itemStack = e.getCurrentItem().clone(); + + // remove IF's IF-uuid NBT tag + NBTTagCompound comp = ItemNBTUtil.getTag(itemStack); + comp.remove("IF-uuid"); + itemStack = ItemNBTUtil.setNBTTag(comp, itemStack); + + // If the item is not a mob spawner + if (!item.isMobSpawner()) { + // If the item has enchantments + if (item.hasEnchantments()) { + if (itemStack.getType() == Material.ENCHANTED_BOOK) { + EnchantmentStorageMeta meta = (EnchantmentStorageMeta) itemStack.getItemMeta(); + for (String enc : item.getEnchantments()) { + String enchantment = StringUtils.substringBefore(enc, ":"); + String level = StringUtils.substringAfter(enc, ":"); + assert meta != null; + meta.addStoredEnchant(XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), + Integer.parseInt(level), true); + + } + } else { + for (String enc : item.getEnchantments()) { + String enchantment = StringUtils.substringBefore(enc, ":"); + String level = StringUtils.substringAfter(enc, ":"); + itemStack.addUnsafeEnchantment( + XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), + Integer.parseInt(level)); + } + + } + } + } + + List lore = new ArrayList<>(); + + if (item.hasBuyLore()) { + item.getBuyLore().forEach(str -> { + lore.add(ChatColor.translateAlternateColorCodes('&', Main.placeholderIfy(str, player, item))); + }); + } + + ItemMeta itemMeta = itemStack.getItemMeta(); + + itemMeta.setLore(lore); + + if (item.hasBuyName()) { + assert itemMeta != null; + itemMeta.setDisplayName( + ChatColor.translateAlternateColorCodes('&', Main.placeholderIfy(item.getBuyName(), player, item))); + } else if (Item.isSpawnerItem(itemStack)) { + String mobName = item.getMobType(); + mobName = mobName.toLowerCase(); + mobName = mobName.substring(0, 1).toUpperCase() + mobName.substring(1).replace("_", " "); + assert itemMeta != null; + itemMeta.setDisplayName(mobName + " Spawner"); + } + + itemStack.setItemMeta(itemMeta); + + double priceToPay; + + /* + * If the map is empty, then the items purchased don't overflow the player's + * inventory. Otherwise, we need to reimburse the player (subtract it from + * priceToPay). + */ + double priceToReimburse = 0D; + + // if the item is not a shift click + int amount = itemStack.getAmount(); + + Runnable dynamicPricingUpdate = null; + + // sell price must be defined and nonzero for dynamic pricing to work + if (Config.isDynamicPricing() && item.isUseDynamicPricing() && item.hasSellPrice()) { + + String itemString = item.getItemString(); + dynamicPricingUpdate = () -> Main.getDYNAMICPRICING().buyItem(itemString, amount); + + priceToPay = Main.getDYNAMICPRICING().calculateBuyPrice(itemString, amount, item.getBuyPriceAsDouble(), item.getSellPriceAsDouble()); + } else { + priceToPay = item.getBuyPriceAsDouble() * amount; + } + + priceToPay -= priceToReimburse; + + // Check if the transition was successful + if (Main.getECONOMY().withdrawPlayer(player, priceToPay).transactionSuccess()) { + // If the player has the sound enabled, play + // it! + if (Config.isSoundEnabled()) { + + player.playSound(player.getLocation(), XSound.matchXSound(Config.getSound()).get().parseSound(), 1, 1); + + } + player.sendMessage(Config.getPrefix() + Config.getPurchased() + priceToPay + Config.getTaken() + + Config.getCurrencySuffix()); + + if (item.isMobSpawner()) { + + EntityType type = item.parseMobSpawnerType(); + if (type == null) { + Main.log("Invalid EntityType in shops.yml: " + item.getMobType()); + + } else { + String entityValue = type.name(); + Main.debugLog("Attaching " + entityValue + " to purchased spawner"); + + NBTTagCompound tag = ItemNBTUtil.getTag(itemStack); + tag.setString("GUIShopSpawner", entityValue); + itemStack = ItemNBTUtil.setNBTTag(tag, itemStack); + } + } + + if (dynamicPricingUpdate != null) { + dynamicPricingUpdate.run(); + } - player.getInventory().addItem(itemStack); + player.getInventory().addItem(itemStack); + + } else { + player.sendMessage(Config.getPrefix() + Config.getNotEnoughPre() + priceToPay + Config.getNotEnoughPost()); + } - } else { - player.sendMessage(Config.getPrefix() + Config.getNotEnoughPre() + priceToPay + Config.getNotEnoughPost()); - } + } - } - - /** - * The inventory closeEvent handling for the Menu. - */ - private void onClose(InventoryCloseEvent e) { - Player player = (Player) e.getPlayer(); - if (Config.isEscapeOnly()) { - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> currentShop.open(player), 1L); - - } - - } + /** + * The inventory closeEvent handling for the Menu. + */ + private void onClose(InventoryCloseEvent e) { + if (Config.isEscapeOnly()) { + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> currentShop.open(player), 1L); + } + } } diff --git a/src/com/pablo67340/guishop/listenable/Sell.java b/src/com/pablo67340/guishop/listenable/Sell.java index c75de6c..aa1a193 100644 --- a/src/com/pablo67340/guishop/listenable/Sell.java +++ b/src/com/pablo67340/guishop/listenable/Sell.java @@ -14,91 +14,95 @@ public final class Sell { - private Gui GUI; - - /** - * Open the {@link Sell} GUI. - */ - public void open(Player player) { - GUI = new Gui(Main.getINSTANCE(), 6, Config.getSellTitle()); - GUI.setOnClose(this::onSellClose); - StaticPane pane = new StaticPane(0, 0, 9, 6); - GUI.addPane(pane); - GUI.show(player); - } - - /** - * Sell items inside the {@link Sell} GUI. - */ - public void sell(Player player) { - sellItems(player, GUI.getInventory().getContents()); - GUI.getInventory().clear(); - } - - /** - * Sells the specified items on the behalf of a player - * - * @param player the player - * @param items the items - */ - public static void sellItems(Player player, ItemStack[] items) { - double moneyToGive = 0; - boolean couldntSell = false; - int countSell = 0; - for (ItemStack item : items) { - - if (item == null) { - continue; - } - - String itemString = Item.getItemStringForItemStack(item); - - Item shopItem = Main.getINSTANCE().getITEMTABLE().get(itemString); - if (shopItem == null || !shopItem.hasSellPrice()) { - countSell += 1; - couldntSell = true; - player.getInventory().addItem(item); - continue; - } - - int quantity = item.getAmount(); - - // buy price must be defined for dynamic pricing to work - if (Config.isDynamicPricing() && shopItem.isUseDynamicPricing() && shopItem.hasBuyPrice()) { - moneyToGive += Main.getDYNAMICPRICING().calculateSellPrice(itemString, quantity, - shopItem.getBuyPriceAsDouble(), shopItem.getSellPriceAsDouble()); - Main.getDYNAMICPRICING().sellItem(itemString, quantity); - } else { - moneyToGive += quantity * shopItem.getSellPriceAsDouble(); - } - - } - - if (couldntSell) { - player.sendMessage(Config.getPrefix() + " " + Config.getCantSell().replace("{count}", countSell + "")); - } - roundAndGiveMoney(player, moneyToGive); - } - - /** - * Rounds the amount and deposits it on behalf of the player. - * - * @param player the player - * @param moneyToGive the amount to give - */ - public static void roundAndGiveMoney(Player player, double moneyToGive) { - Double moneyToGiveRounded = (double) Math.round(moneyToGive * 100) / 100; - - if (moneyToGiveRounded > 0) { - Main.getECONOMY().depositPlayer(player, moneyToGiveRounded); - - player.sendMessage(Config.getSold() + moneyToGiveRounded + Config.getAdded()); - } - } - - private void onSellClose(InventoryCloseEvent event) { - Player player = (Player) event.getPlayer(); - sell(player); - } + private Gui GUI; + + /** + * Open the {@link Sell} GUI. + * + * @param player - The player the GUI will display to + */ + public void open(Player player) { + GUI = new Gui(Main.getINSTANCE(), 6, Config.getSellTitle()); + GUI.setOnClose(this::onSellClose); + StaticPane pane = new StaticPane(0, 0, 9, 6); + GUI.addPane(pane); + GUI.show(player); + } + + /** + * Sell items inside the {@link Sell} GUI. + * + * @param player - The player selling items + */ + public void sell(Player player) { + sellItems(player, GUI.getInventory().getContents()); + GUI.getInventory().clear(); + } + + /** + * Sells the specified items on the behalf of a player + * + * @param player the player + * @param items the items + */ + public static void sellItems(Player player, ItemStack[] items) { + double moneyToGive = 0; + boolean couldntSell = false; + int countSell = 0; + for (ItemStack item : items) { + + if (item == null) { + continue; + } + + String itemString = Item.getItemStringForItemStack(item); + + Item shopItem = Main.getINSTANCE().getITEMTABLE().get(itemString); + if (shopItem == null || !shopItem.hasSellPrice()) { + countSell += 1; + couldntSell = true; + player.getInventory().addItem(item); + continue; + } + + int quantity = item.getAmount(); + + // buy price must be defined for dynamic pricing to work + if (Config.isDynamicPricing() && shopItem.isUseDynamicPricing() && shopItem.hasBuyPrice()) { + moneyToGive += Main.getDYNAMICPRICING().calculateSellPrice(itemString, quantity, + shopItem.getBuyPriceAsDouble(), shopItem.getSellPriceAsDouble()); + Main.getDYNAMICPRICING().sellItem(itemString, quantity); + } else { + moneyToGive += quantity * shopItem.getSellPriceAsDouble(); + } + + } + + if (couldntSell) { + player.sendMessage(Config.getPrefix() + " " + Config.getCantSell().replace("{count}", countSell + "")); + } + roundAndGiveMoney(player, moneyToGive); + } + + /** + * Rounds the amount and deposits it on behalf of the player. + * + * @param player the player + * @param moneyToGive the amount to give + */ + public static void roundAndGiveMoney(Player player, double moneyToGive) { + Double moneyToGiveRounded = (double) Math.round(moneyToGive * 100) / 100; + + if (moneyToGiveRounded > 0) { + Main.getECONOMY().depositPlayer(player, moneyToGiveRounded); + + player.sendMessage(Config.getSold() + moneyToGiveRounded + Config.getAdded()); + } + } + + private void onSellClose(InventoryCloseEvent event) { + Player player = (Player) event.getPlayer(); + sell(player); + } } diff --git a/src/com/pablo67340/guishop/listenable/Shop.java b/src/com/pablo67340/guishop/listenable/Shop.java index 1f4c59c..e88d473 100644 --- a/src/com/pablo67340/guishop/listenable/Shop.java +++ b/src/com/pablo67340/guishop/listenable/Shop.java @@ -28,755 +28,747 @@ import com.pablo67340.guishop.util.Config; import com.pablo67340.guishop.util.XEnchantment; import com.pablo67340.guishop.util.XMaterial; +import java.io.IOException; import lombok.Getter; public class Shop { - /** - * The name of this {@link Shop}. - */ - @Getter - private final String name; - - /** - * The shop name of this {@link Shop}. - */ - @Getter - private final String shop; - - /** - * The description of this {@link Shop}. - */ - @Getter - private final String description; - - /** - * The lore of this {@link Shop}. - */ - @Getter - private final List lore; - - /** - * The list of {@link Item}s in this {@link Shop}. - */ - @Getter - private Map items; - - private Map editedItems; - - /** - * The list of {@link Page}'s in this {@link Shop}. - */ - private Gui GUI; - - private Menu menuInstance; - - private Boolean hasClicked = false; - - private int pageC = 0; - - private PaginatedPane currentPane; - - int oldPage = 0; - - private Integer lastIndex = 0; - - /** - * The constructor for a {@link Shop}. - * - * @param name The name of the shop. - * @param description The description of the shop. - * @param lore The lore of the shop. - */ - Shop(String shop, String name, String description, List lore, Menu menuInstance) { - this.name = name; - this.shop = shop; - this.description = description; - this.lore = lore; - this.menuInstance = menuInstance; - } - - /** - * The constructor for a {@link Shop}. - * - * @param name The name of the shop. - * @param description The description of the shop. - * @param lore The lore of the shop. - */ - public Shop(String shop, String name, String description, List lore) { - this.name = name; - this.shop = shop; - this.description = description; - this.lore = lore; - this.menuInstance = null; - } - - /** - * The constructor for a {@link Shop}. - * - * @param name The name of the shop. - * @param description The description of the shop. - * @param lore The lore of the shop. - */ - Shop(String shop, String name, String description, List lore, Menu menuInstance, Map items) { - this.name = name; - this.shop = shop; - this.description = description; - this.lore = lore; - this.menuInstance = menuInstance; - this.items = items; - } - - /** - * Load the specified shop - */ - public void loadItems() { - - if (items == null) { - - items = new HashMap<>(); - - ConfigurationSection config = Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop); - - if (config == null) { - Main.log("Check the section for shop " + shop + " in the shops.yml. It was not found."); - - } else { - for (String str : config.getKeys(false)) { - - Item item = new Item(); - - ConfigurationSection section = config.getConfigurationSection(str); - if (section == null) { - Main.log("Check the config section for item " + str + " in shop " + shop + " in the shops.yml. It is not a valid section."); - continue; - } - - item.setSlot((Integer.parseInt(str))); - - item.setMaterial((section.contains("id") ? (String) section.get("id") : "AIR")); - if (item.isAnyPotion()) { - ConfigurationSection potionSection = section.getConfigurationSection("potion-info"); - if (potionSection != null) { - item.parsePotionType(potionSection.getString("type"), - potionSection.getBoolean("splash", false), - potionSection.getBoolean("extended", false), potionSection.getInt("amplifier", -1)); - } - } - item.setMobType((section.contains("mobType") ? (String) section.get("mobType") : null)); - item.setShopName((section.contains("shop-name") ? (String) section.get("shop-name") : null)); - item.setBuyName((section.contains("buy-name") ? (String) section.get("buy-name") : null)); - if (section.contains("enchantments")) { - String enchantments = section.getString("enchantments"); - if (!enchantments.equalsIgnoreCase(" ")) { - item.setEnchantments(enchantments.split(" ")); - } - } - - item.setBuyPrice(section.get("buy-price")); - - item.setSellPrice(section.get("sell-price")); - - item.setItemType( - section.contains("type") ? ItemType.valueOf((String) section.get("type")) : ItemType.SHOP); - - item.setUseDynamicPricing(section.getBoolean("use-dynamic-price", true)); - - item.setShopLore( - (section.contains("shop-lore") ? section.getStringList("shop-lore") : new ArrayList<>())); - item.setBuyLore( - (section.contains("buy-lore") ? section.getStringList("buy-lore") : new ArrayList<>())); - item.setCommands( - (section.contains("commands") ? section.getStringList("commands") : new ArrayList<>())); - - Main.getINSTANCE().getITEMTABLE().put(item.getItemString(), item); - if (section.getBoolean("show-in-gui", true)) { - items.put(item.getSlot(), item); - } - - } - loadShop(); - } - } else { - loadShop(); - } - - } - - @SuppressWarnings("deprecation") - private void loadShop() { - Integer index = 0; - ShopPane page = new ShopPane(9, 6); - - this.GUI = new Gui(Main.getINSTANCE(), 6, - ChatColor.translateAlternateColorCodes('&', Config.getShopTitle().replace("{shopname}", getName()))); - PaginatedPane pane = new PaginatedPane(0, 0, 9, 6); - - for (Item item : items.values()) { - - GuiItem gItem = item.parseMaterial(); - - if (gItem == null) { - Main.debugLog("Item " + item.getMaterial() + " could not be resolved (invalid material)"); - continue; - } - - // Checks if an item is either a shop item or command item. This also handles - // Null items as there is a item type switch in the lines above. - if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { - - ItemStack itemStack = gItem.getItem(); - ItemMeta itemMeta = itemStack.getItemMeta(); - - if (itemMeta == null) { - Main.debugLog("Item + " + item.getMaterial() + " could not be resolved (null meta)"); - continue; - } - - List lore = new ArrayList<>(); - - lore.add(item.getBuyLore(1)); - - lore.add(item.getSellLore(1)); - - if (item.hasShopLore()) { - item.getShopLore().forEach(str -> { - if (!lore.contains(str) && !lore.contains( - Config.getBuyLore().replace("{AMOUNT}", Double.toString(item.calculateBuyPrice(1))))) { - lore.add(ChatColor.translateAlternateColorCodes('&', str)); - } - }); - } - - if (!lore.isEmpty()) { - assert itemMeta != null; - itemMeta.setLore(lore); - } - - if (item.hasShopName()) { - assert itemMeta != null; - itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', item.getShopName())); - } else if (item.isMobSpawner()) { - String mobName = item.getMobType(); - mobName = mobName.toLowerCase(); - mobName = mobName.substring(0, 1).toUpperCase() + mobName.substring(1).replace("_", " "); - assert itemMeta != null; - itemMeta.setDisplayName(mobName + " Spawner"); - } - - if (item.getEnchantments() != null) { - if (item.getEnchantments().length > 1) { - for (String enc : item.getEnchantments()) { - String enchantment = StringUtils.substringBefore(enc, ":"); - String level = StringUtils.substringAfter(enc, ":"); - itemStack.addUnsafeEnchantment( - XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), - Integer.parseInt(level)); - } - } - } - - itemStack.setItemMeta(itemMeta); - - if (item.hasPotion()) { - item.getPotion().apply(itemStack); - } - - } - - // Create Page - if (index == items.size() || ((index) - lastIndex) == 44) { - if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { - page.setItem(gItem, item.getSlot()); - } - - if (items.size() > 45) { - applyButtons(page); - } - lastIndex = index; - pane.addPane(pageC, page); - pageC += 1; - page = new ShopPane(9, 6); - } else { - if (pageC == 0) { - if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { - page.setItem(gItem, item.getSlot()); - } else { - page.setDummy(item.getSlot(), new ItemStack(Material.AIR)); - } - } else { - - if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { - page.setItem(gItem, item.getSlot() - lastIndex - 1); - } else { - page.setDummy(item.getSlot() - lastIndex - 1, new ItemStack(Material.AIR)); - } - } - } - - if (index + 1 == items.size()) { - pane.addPane(pageC, page); - applyButtons(page); - GUI.addPane(pane); - Main.getINSTANCE().getLoadedShops().put(name, items); - } - index += 1; - - } - - this.currentPane = pane; - - } - - /** - * Creates a named itemstack from a material and name. - * - * @param material the material - * @param name the name with colour codes already applied - * @return a named item - */ - private ItemStack makeNamedItem(Material material, String name) { - ItemStack is = new ItemStack(material); - if (!name.isEmpty()) { - ItemMeta meta = is.getItemMeta(); - meta.setDisplayName(name); - is.setItemMeta(meta); - } - return is; - } - - private void applyButtons(ShopPane page) { - if (page.getINSTANCE().getItemsMap().containsKey(44)) { - page.setItem(new GuiItem(makeNamedItem(Material.ARROW, Config.getBackwardPageButtonName())), 51); - } - if (pageC > 0) { - page.setItem(new GuiItem(makeNamedItem(Material.ARROW, Config.getForwardPageButtonName())), 47); - } - if (!Config.isEscapeOnly()) { - - ItemStack backButtonItem = new ItemStack( - Objects.requireNonNull(XMaterial.matchXMaterial(Config.getBackButtonItem()).get().parseMaterial())); - - ItemMeta backButtonMeta = backButtonItem.getItemMeta(); - - assert backButtonMeta != null; - backButtonMeta.setDisplayName(Config.getBackButtonText()); - - backButtonItem.setItemMeta(backButtonMeta); - - GuiItem item = new GuiItem(backButtonItem); - - page.setItem(item, 53); - } - } - - /** - * Open the player's shop - */ - public void open(Player input) { - // currentPane.setPage(0); - GUI.show(input); - if (!Main.getCREATOR().contains(input.getName())) { - GUI.setOnBottomClick(event -> { - event.setCancelled(true); - }); - } - GUI.setOnClose(this::onClose); - GUI.setOnGlobalClick(this::onShopClick); - - if (Main.CREATOR.contains(input.getName())) { - editedItems = new HashMap<>(); - } - - } - - private void onShopClick(InventoryClickEvent e) { - Player player = (Player) e.getWhoClicked(); - Main.debugLog("Click"); - if (!Main.getCREATOR().contains(player.getName())) { - e.setCancelled(true); - hasClicked = true; - } - - if (e.getClickedInventory() == null) { - return; - } - - // Forward Button - Main.debugLog("Clicked: " + e.getSlot()); - if (e.getSlot() == 51) { - hasClicked = true; - if (items.size() > 44) { - if (Main.getCREATOR().contains(player.getName())) { - ItemStack[] items = GUI.getInventory().getContents(); - - int slot = 0; - for (ItemStack item : items) { - ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setItem(new GuiItem(item), - slot); - slot += 1; - } - - saveItems(player); - } - ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(false); - currentPane.setPage(currentPane.getPage() + 1); - - ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(true); - GUI.update(); - } - return; - // Backward Button - } else if (e.getSlot() == 47) { - if (items.size() > 44) { - hasClicked = true; - - if (Main.getCREATOR().contains(player.getName())) { - ItemStack[] items = GUI.getInventory().getContents(); - - int slot = 0; - for (ItemStack item : items) { - ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setItem(new GuiItem(item), - slot); - slot += 1; - } - saveItems(player); - } - ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(false); - currentPane.setPage(currentPane.getPage() - 1); - - ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(true); - GUI.update(); - } - return; - // Back Button - } else if (e.getSlot() == 53 && !Config.isEscapeOnly()) { - if (menuInstance != null && !Main.getCREATOR().contains(player.getName())) { - menuInstance.open(player); - } - return; - } - - /* + /** + * The name of this {@link Shop}. + */ + @Getter + private final String name; + + /** + * The shop name of this {@link Shop}. + */ + @Getter + private final String shop; + + /** + * The description of this {@link Shop}. + */ + @Getter + private final String description; + + /** + * The lore of this {@link Shop}. + */ + @Getter + private final List lore; + + /** + * The list of {@link Item}s in this {@link Shop}. + */ + @Getter + private Map items; + + private Map editedItems; + + /** + * The list of {@link Page}'s in this {@link Shop}. + */ + private Gui GUI; + + private final Menu menuInstance; + + private Boolean hasClicked = false; + + private int pageC = 0; + + private PaginatedPane currentPane; + + int oldPage = 0; + + private Integer lastIndex = 0; + + /** + * The constructor for a {@link Shop}. + * + * @param name The name of the shop. + * @param description The description of the shop. + * @param lore The lore of the shop. + */ + Shop(String shop, String name, String description, List lore, Menu menuInstance) { + this.name = name; + this.shop = shop; + this.description = description; + this.lore = lore; + this.menuInstance = menuInstance; + } + + /** + * The constructor for a {@link Shop}. + * + * @param shop The Shop ID. + * @param name The name of the shop. + * @param description The description of the shop. + * @param lore The lore of the shop. + */ + public Shop(String shop, String name, String description, List lore) { + this.name = name; + this.shop = shop; + this.description = description; + this.lore = lore; + this.menuInstance = null; + } + + /** + * The constructor for a {@link Shop}. + * + * @param name The name of the shop. + * @param description The description of the shop. + * @param lore The lore of the shop. + */ + Shop(String shop, String name, String description, List lore, Menu menuInstance, Map items) { + this.name = name; + this.shop = shop; + this.description = description; + this.lore = lore; + this.menuInstance = menuInstance; + this.items = items; + } + + /** + * Load the specified shop + */ + public void loadItems() { + + if (items == null) { + + items = new HashMap<>(); + + ConfigurationSection config = Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop); + + if (config == null) { + Main.log("Check the section for shop " + shop + " in the shops.yml. It was not found."); + + } else { + for (String str : config.getKeys(false)) { + + Item item = new Item(); + + ConfigurationSection section = config.getConfigurationSection(str); + if (section == null) { + Main.log("Check the config section for item " + str + " in shop " + shop + " in the shops.yml. It is not a valid section."); + continue; + } + + item.setSlot((Integer.parseInt(str))); + + item.setMaterial((section.contains("id") ? (String) section.get("id") : "AIR")); + if (item.isAnyPotion()) { + ConfigurationSection potionSection = section.getConfigurationSection("potion-info"); + if (potionSection != null) { + item.parsePotionType(potionSection.getString("type"), + potionSection.getBoolean("splash", false), + potionSection.getBoolean("extended", false), potionSection.getInt("amplifier", -1)); + } + } + item.setMobType((section.contains("mobType") ? (String) section.get("mobType") : null)); + item.setShopName((section.contains("shop-name") ? (String) section.get("shop-name") : null)); + item.setBuyName((section.contains("buy-name") ? (String) section.get("buy-name") : null)); + if (section.contains("enchantments")) { + String enchantments = section.getString("enchantments"); + if (!enchantments.equalsIgnoreCase(" ")) { + item.setEnchantments(enchantments.split(" ")); + } + } + + item.setBuyPrice(section.get("buy-price")); + + item.setSellPrice(section.get("sell-price")); + + item.setItemType( + section.contains("type") ? ItemType.valueOf((String) section.get("type")) : ItemType.SHOP); + + item.setUseDynamicPricing(section.getBoolean("use-dynamic-price", true)); + + item.setShopLore( + (section.contains("shop-lore") ? section.getStringList("shop-lore") : new ArrayList<>())); + item.setBuyLore( + (section.contains("buy-lore") ? section.getStringList("buy-lore") : new ArrayList<>())); + item.setCommands( + (section.contains("commands") ? section.getStringList("commands") : new ArrayList<>())); + + Main.getINSTANCE().getITEMTABLE().put(item.getItemString(), item); + if (section.getBoolean("show-in-gui", true)) { + items.put(item.getSlot(), item); + } + + } + loadShop(); + } + } else { + loadShop(); + } + + } + + @SuppressWarnings("deprecation") + private void loadShop() { + Integer index = 0; + ShopPane page = new ShopPane(9, 6); + + this.GUI = new Gui(Main.getINSTANCE(), 6, + ChatColor.translateAlternateColorCodes('&', Config.getShopTitle().replace("{shopname}", getName()))); + PaginatedPane pane = new PaginatedPane(0, 0, 9, 6); + + for (Item item : items.values()) { + + GuiItem gItem = item.parseMaterial(); + + if (gItem == null) { + Main.debugLog("Item " + item.getMaterial() + " could not be resolved (invalid material)"); + continue; + } + + // Checks if an item is either a shop item or command item. This also handles + // Null items as there is a item type switch in the lines above. + if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { + + ItemStack itemStack = gItem.getItem(); + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) { + Main.debugLog("Item + " + item.getMaterial() + " could not be resolved (null meta)"); + continue; + } + + List itemLore = new ArrayList<>(); + + itemLore.add(item.getBuyLore(1)); + + itemLore.add(item.getSellLore(1)); + + if (item.hasShopLore()) { + item.getShopLore().forEach(str -> { + if (!itemLore.contains(str) && !itemLore.contains( + Config.getBuyLore().replace("{AMOUNT}", Double.toString(item.calculateBuyPrice(1))))) { + itemLore.add(ChatColor.translateAlternateColorCodes('&', str)); + } + }); + } + + if (!itemLore.isEmpty()) { + assert itemMeta != null; + itemMeta.setLore(itemLore); + } + + if (item.hasShopName()) { + assert itemMeta != null; + itemMeta.setDisplayName(ChatColor.translateAlternateColorCodes('&', item.getShopName())); + } else if (item.isMobSpawner()) { + String mobName = item.getMobType(); + mobName = mobName.toLowerCase(); + mobName = mobName.substring(0, 1).toUpperCase() + mobName.substring(1).replace("_", " "); + assert itemMeta != null; + itemMeta.setDisplayName(mobName + " Spawner"); + } + + if (item.getEnchantments() != null) { + if (item.getEnchantments().length > 1) { + for (String enc : item.getEnchantments()) { + String enchantment = StringUtils.substringBefore(enc, ":"); + String level = StringUtils.substringAfter(enc, ":"); + itemStack.addUnsafeEnchantment(XEnchantment.matchXEnchantment(enchantment).get().parseEnchantment(), Integer.parseInt(level)); + } + } + } + + itemStack.setItemMeta(itemMeta); + + if (item.hasPotion()) { + item.getPotion().apply(itemStack); + } + + } + + // Create Page + if (index == items.size() || ((index) - lastIndex) == 44) { + if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { + page.setItem(gItem, item.getSlot()); + } + + if (items.size() > 45) { + applyButtons(page); + } + lastIndex = index; + pane.addPane(pageC, page); + pageC += 1; + page = new ShopPane(9, 6); + } else { + if (pageC == 0) { + if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { + page.setItem(gItem, item.getSlot()); + } else { + page.setDummy(item.getSlot(), new ItemStack(Material.AIR)); + } + } else { + + if (item.getItemType() == ItemType.SHOP || item.getItemType() == ItemType.COMMAND) { + page.setItem(gItem, item.getSlot() - lastIndex - 1); + } else { + page.setDummy(item.getSlot() - lastIndex - 1, new ItemStack(Material.AIR)); + } + } + } + + if (index + 1 == items.size()) { + pane.addPane(pageC, page); + applyButtons(page); + GUI.addPane(pane); + Main.getINSTANCE().getLoadedShops().put(name, items); + } + index += 1; + + } + + this.currentPane = pane; + + } + + /** + * Creates a named itemstack from a material and name. + * + * @param material the material + * @param name the name with colour codes already applied + * @return a named item + */ + private ItemStack makeNamedItem(Material material, String name) { + ItemStack is = new ItemStack(material); + if (!name.isEmpty()) { + ItemMeta meta = is.getItemMeta(); + meta.setDisplayName(name); + is.setItemMeta(meta); + } + return is; + } + + private void applyButtons(ShopPane page) { + if (page.getINSTANCE().getItemsMap().containsKey(44)) { + page.setItem(new GuiItem(makeNamedItem(Material.ARROW, Config.getBackwardPageButtonName())), 51); + } + if (pageC > 0) { + page.setItem(new GuiItem(makeNamedItem(Material.ARROW, Config.getForwardPageButtonName())), 47); + } + if (!Config.isEscapeOnly()) { + + ItemStack backButtonItem = new ItemStack( + Objects.requireNonNull(XMaterial.matchXMaterial(Config.getBackButtonItem()).get().parseMaterial())); + + ItemMeta backButtonMeta = backButtonItem.getItemMeta(); + + assert backButtonMeta != null; + backButtonMeta.setDisplayName(Config.getBackButtonText()); + + backButtonItem.setItemMeta(backButtonMeta); + + GuiItem item = new GuiItem(backButtonItem); + + page.setItem(item, 53); + } + } + + /** + * Open the player's shop + * + * @param input The player the shop will open for. + */ + public void open(Player input) { + // currentPane.setPage(0); + GUI.show(input); + if (!Main.getCREATOR().contains(input.getName())) { + GUI.setOnBottomClick(event -> { + event.setCancelled(true); + }); + } + GUI.setOnClose(this::onClose); + GUI.setOnGlobalClick(this::onShopClick); + + if (Main.CREATOR.contains(input.getName())) { + editedItems = new HashMap<>(); + } + + } + + private void onShopClick(InventoryClickEvent e) { + Player player = (Player) e.getWhoClicked(); + Main.debugLog("Click"); + if (!Main.getCREATOR().contains(player.getName())) { + e.setCancelled(true); + hasClicked = true; + } + + if (e.getClickedInventory() == null) { + return; + } + + // Forward Button + Main.debugLog("Clicked: " + e.getSlot()); + if (e.getSlot() == 51) { + hasClicked = true; + if (items.size() > 44) { + if (Main.getCREATOR().contains(player.getName())) { + ItemStack[] shopItems = GUI.getInventory().getContents(); + + int slot = 0; + for (ItemStack item : shopItems) { + ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setItem(new GuiItem(item), + slot); + slot += 1; + } + + saveItems(player); + } + ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(false); + currentPane.setPage(currentPane.getPage() + 1); + + ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(true); + GUI.update(); + } + return; + // Backward Button + } else if (e.getSlot() == 47) { + if (items.size() > 44) { + hasClicked = true; + + if (Main.getCREATOR().contains(player.getName())) { + ItemStack[] shopItems = GUI.getInventory().getContents(); + + int slot = 0; + for (ItemStack item : shopItems) { + ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setItem(new GuiItem(item), + slot); + slot += 1; + } + saveItems(player); + } + ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(false); + currentPane.setPage(currentPane.getPage() - 1); + + ((ShopPane) currentPane.getPanes().toArray()[currentPane.getPage()]).setVisible(true); + GUI.update(); + } + return; + // Back Button + } else if (e.getSlot() == 53 && !Config.isEscapeOnly()) { + if (menuInstance != null && !Main.getCREATOR().contains(player.getName())) { + menuInstance.open(player); + } + return; + } + + /* * If the player has enough money to purchase the item, then allow them to. - */ - Main.debugLog("Creator Status:" + Main.getCREATOR().contains(player.getName())); - if (!Main.getCREATOR().contains(player.getName())) { - Item item = getItems().get((currentPane.getPage() * 45) + e.getSlot()); - - if (item == null) { - return; - - } else if (!item.hasBuyPrice()) { - - if (Config.isAlternateSellEnabled() && item.hasSellPrice() && (e.getClick() == ClickType.RIGHT || e.getClick() == ClickType.SHIFT_RIGHT)) { - new AltSell(item).open(player); - } else { - player.sendMessage(Config.getPrefix() + " " + Config.getCannotBuy()); - } - return; - } - - if (item.getItemType() == ItemType.SHOP) { - if (Config.isAlternateSellEnabled() && item.hasSellPrice() && (e.getClick() == ClickType.RIGHT || e.getClick() == ClickType.SHIFT_RIGHT)) { - new AltSell(item).open(player); - } else { - new Quantity(item, this, player).loadInventory().open(); - } - } else if (item.getItemType() == ItemType.COMMAND) { - - double priceToPay; - - Runnable dynamicPricingUpdate = null; - - // sell price must be defined and nonzero for dynamic pricing to work - if (Config.isDynamicPricing() && item.isUseDynamicPricing() && item.hasSellPrice()) { - - String itemString = item.getItemString(); - dynamicPricingUpdate = () -> Main.getDYNAMICPRICING().buyItem(itemString, 1); - - priceToPay = Main.getDYNAMICPRICING().calculateBuyPrice(itemString, 1, item.getBuyPriceAsDouble(), item.getSellPriceAsDouble()); - } else { - priceToPay = item.getBuyPriceAsDouble(); - } - - if (Main.getECONOMY().withdrawPlayer(player, priceToPay).transactionSuccess()) { - item.getCommands().forEach(str -> { - Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), - Main.placeholderIfy(str, player, item)); - }); - if (dynamicPricingUpdate != null) { - dynamicPricingUpdate.run(); - } - } else { - player.sendMessage(Config.getPrefix() + Config.getNotEnoughPre() + priceToPay - + Config.getNotEnoughPost()); - } - } - } else { - // When players remove an item from the shop - if (e.getClickedInventory().getType() != InventoryType.PLAYER) { - - // If an item was removed from the shop, this is null - if (e.getCurrentItem() != null) { - Main.debugLog("Cursor: " + e.getCursor()); - if (e.getInventory().getItem(e.getSlot()) != null) { - deleteShopItem(e.getSlot()); - } - - // When an item is dropped into the slot, it's not null. This is a new item. - } else { - - // Run the scheduler after this event is complete. This will ensure the - // possible new item is in the slot in time. - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), new Runnable() { - @Override - public void run() { - ItemStack item = e.getInventory().getItem(e.getSlot()); - if (item != null) { - Main.debugLog("new Item: " + item.getType()); - editShopItem(item, e.getSlot()); - } - } - }, 5L); - - } - } else { - // When the player moves an item from their inventory to the shop via shift - // click - if (e.getClick() == ClickType.SHIFT_LEFT || e.getClick() == ClickType.SHIFT_RIGHT) { - - // Since shift clicking moves items to the first available slot, we can assume - // the item - // will end up in this slot. - int slot = e.getInventory().firstEmpty(); - - // Run the scheduler after this event is complete. This will ensure the - // possible new item is in the slot in time. - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), new Runnable() { - @Override - public void run() { - ItemStack item = e.getInventory().getItem(slot); - if (item != null) { - Main.debugLog("new Item: " + item.getType()); - editShopItem(item, slot); - } - } - }, 5L); - } - } - - } - - } - - private void deleteShopItem(Integer slot) { - Main.debugLog("Deleting Item: " + slot); - Main.getINSTANCE().setCreatorRefresh(true); - Item dedItem = new Item(); - dedItem.setMaterial("DED"); - dedItem.setSlot(slot); - editedItems.put(slot, dedItem); - } - - /** - * The inventory closeEvent handling for the Menu. - */ - private void onClose(InventoryCloseEvent e) { - Player player = (Player) e.getPlayer(); - if (!Main.CREATOR.contains(player.getName())) { - if (Config.isEscapeOnly() && !hasClicked) { - BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); - scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> menuInstance.open(player), 1L); - - } else { - hasClicked = false; - } - } else { - saveItems(player); - } - - } - - public void editShopItem(ItemStack itemStack, int slot) { - Item item = new Item(); - Integer mult = (44 * currentPane.getPage()); - Integer configSlot = slot + mult; - Main.getINSTANCE().setCreatorRefresh(true); - if (itemStack != null) { - NBTTagCompound comp = ItemNBTUtil.getTag(itemStack); - ItemMeta im = itemStack.getItemMeta(); - item.setItemType(ItemType.SHOP); - item.setMaterial(itemStack.getType().toString()); - item.setSlot(configSlot); - if (comp.hasKey("buyPrice")) { - - Object buyPrice = getBuyPrice(itemStack); - Main.debugLog("had buyPrice comp: " + buyPrice); - item.setBuyPrice(buyPrice); - } - if (comp.hasKey("sellPrice")) { - - Object sellPrice = getSellPrice(itemStack); - item.setSellPrice(sellPrice); - } - - if (im.hasDisplayName()) { - item.setShopName(im.getDisplayName()); - } - - if (comp.hasKey("buyName")) { - item.setBuyName(comp.getString("buyName")); - } - - if (comp.hasKey("enchantments")) { - item.setEnchantments(comp.getString("enchantments").split(" ")); - } - - if (comp.hasKey("itemType")) { - item.setItemType(ItemType.valueOf(comp.getString("itemType"))); - } - - if (comp.hasKey("commands")) { - item.setItemType(ItemType.COMMAND); - item.setCommands(Arrays.asList(comp.getString("commands").split("::"))); - } - - if (comp.hasKey("mobType")) { - item.setMobType(comp.getString("mobType")); - } - - if (im.hasLore()) { - List lore = im.getLore(); - List cleaned = new ArrayList<>(); - for (String str : lore) { - if (!(ChatColor.stripColor(str) - .contains(ChatColor.stripColor(Config.getBuyLore().replace("{amount}", "")))) - && !(ChatColor.stripColor(str) - .contains(ChatColor.stripColor(Config.getSellLore().replace("{amount}", "")))) - && !(ChatColor.stripColor(str).contains(ChatColor.stripColor(Config.getCannotBuy()))) - && !(ChatColor.stripColor(str).contains(ChatColor.stripColor(Config.getCannotSell())))) { - cleaned.add(str); - } - } - item.setShopLore(cleaned); - } - - if (comp.hasKey("loreLines")) { - String line = comp.getString("loreLines"); - String[] lore = line.split("::"); - item.setBuyLore(Arrays.asList(lore)); - } - } - editedItems.put(item.getSlot(), item); - - Main.debugLog("Player Edited Item: " + item.getMaterial() + " slot: " + configSlot); - - } - - /** - * Save the items for current shop instance - */ - public void saveItems(Player player) { - - Main.debugLog("Getting Section for: " + shop); - - ConfigurationSection config = Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop) != null - ? Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop) - : Main.getINSTANCE().getCustomConfig().createSection(shop); - - Main.debugLog("Config: " + config); - - for (Item item : editedItems.values()) { - if (!item.getMaterial().equalsIgnoreCase("DED")) { - config.set(item.getSlot() + "", null); - ConfigurationSection section = config.createSection(item.getSlot() + ""); - section.set("type", item.getItemType().toString()); - section.set("id", item.getMaterial()); - if (item.hasBuyPrice()) { - section.set("buy-price", item.getBuyPrice()); - } - if (item.hasSellPrice()) { - section.set("sell-price", item.getSellPrice()); - } - if (item.hasShopLore()) { - section.set("shop-lore", item.getShopLore()); - } - if (item.hasShopName()) { - section.set("shop-name", item.getShopName()); - } - if (item.hasBuyName()) { - section.set("buy-name", item.getBuyName()); - } - if (item.hasEnchantments()) { - String parsed = ""; - for (String str : item.getEnchantments()) { - parsed += str + " "; - } - section.set("enchantments", parsed.trim()); - } - if (item.hasShopLore()) { - section.set("shop-lore", item.getShopLore()); - } - if (item.hasBuyLore()) { - section.set("buy-lore", item.getBuyLore()); - } - if (item.hasCommands()) { - section.set("commands", item.getCommands()); - } - if (item.hasMobType()) { - section.set("mobType", item.getMobType()); - } - } else { - Main.debugLog("Item was ded: " + item.getSlot()); - config.set(item.getSlot() + "", null); - } - } - try { - Main.getINSTANCE().getCustomConfig().save(Main.getINSTANCE().getSpecialf()); - } catch (Exception ex) { - Main.getINSTANCE().getLogger().log(Level.WARNING, ex.getMessage()); - } - - if (!hasClicked) { - Main.debugLog("Removed from creator"); - Main.getCREATOR().remove(player.getName()); - } - Main.sendMessage(player, "&aShop Saved!"); - - } - - /** - * Gets the buyPrice of the item using NBT, - * or null if not defined - * - */ - private Object getBuyPrice(ItemStack item) { - NBTTagCompound comp = ItemNBTUtil.getTag(item); - - if (comp.hasKey("buyPrice")) { - Double vl = comp.getDouble("buyPrice"); - return vl; - } - return null; - } - - /** - * Gets the sellPrice of an item using NBT, - * or null if not defined - * - */ - private Object getSellPrice(ItemStack item) { - NBTTagCompound comp = ItemNBTUtil.getTag(item); - - if (comp.hasKey("sellPrice")) { - Double vl = comp.getDouble("sellPrice"); - return vl; - } - return null; - } + */ + Main.debugLog("Creator Status:" + Main.getCREATOR().contains(player.getName())); + if (!Main.getCREATOR().contains(player.getName())) { + Item item = getItems().get((currentPane.getPage() * 45) + e.getSlot()); + + if (item == null) { + return; + + } else if (!item.hasBuyPrice()) { + + if (Config.isAlternateSellEnabled() && item.hasSellPrice() && (e.getClick() == ClickType.RIGHT || e.getClick() == ClickType.SHIFT_RIGHT)) { + new AltSell(item).open(player); + } else { + player.sendMessage(Config.getPrefix() + " " + Config.getCannotBuy()); + } + return; + } + + if (item.getItemType() == ItemType.SHOP) { + if (Config.isAlternateSellEnabled() && item.hasSellPrice() && (e.getClick() == ClickType.RIGHT || e.getClick() == ClickType.SHIFT_RIGHT)) { + new AltSell(item).open(player); + } else { + new Quantity(item, this, player).loadInventory().open(); + } + } else if (item.getItemType() == ItemType.COMMAND) { + + double priceToPay; + + Runnable dynamicPricingUpdate = null; + + // sell price must be defined and nonzero for dynamic pricing to work + if (Config.isDynamicPricing() && item.isUseDynamicPricing() && item.hasSellPrice()) { + + String itemString = item.getItemString(); + dynamicPricingUpdate = () -> Main.getDYNAMICPRICING().buyItem(itemString, 1); + + priceToPay = Main.getDYNAMICPRICING().calculateBuyPrice(itemString, 1, item.getBuyPriceAsDouble(), item.getSellPriceAsDouble()); + } else { + priceToPay = item.getBuyPriceAsDouble(); + } + + if (Main.getECONOMY().withdrawPlayer(player, priceToPay).transactionSuccess()) { + item.getCommands().forEach(str -> { + Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), + Main.placeholderIfy(str, player, item)); + }); + if (dynamicPricingUpdate != null) { + dynamicPricingUpdate.run(); + } + } else { + player.sendMessage(Config.getPrefix() + Config.getNotEnoughPre() + priceToPay + + Config.getNotEnoughPost()); + } + } + } else { + // When players remove an item from the shop + if (e.getClickedInventory().getType() != InventoryType.PLAYER) { + + // If an item was removed from the shop, this is null + if (e.getCurrentItem() != null) { + Main.debugLog("Cursor: " + e.getCursor()); + if (e.getInventory().getItem(e.getSlot()) != null) { + deleteShopItem(e.getSlot()); + } + + // When an item is dropped into the slot, it's not null. This is a new item. + } else { + + // Run the scheduler after this event is complete. This will ensure the + // possible new item is in the slot in time. + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> { + ItemStack item = e.getInventory().getItem(e.getSlot()); + if (item != null) { + Main.debugLog("new Item: " + item.getType()); + editShopItem(item, e.getSlot()); + } + }, 5L); + } + } else { + // When the player moves an item from their inventory to the shop via shift + // click + if (e.getClick() == ClickType.SHIFT_LEFT || e.getClick() == ClickType.SHIFT_RIGHT) { + + // Since shift clicking moves items to the first available slot, we can assume + // the item + // will end up in this slot. + int slot = e.getInventory().firstEmpty(); + + // Run the scheduler after this event is complete. This will ensure the + // possible new item is in the slot in time. + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> { + ItemStack item = e.getInventory().getItem(slot); + if (item != null) { + Main.debugLog("new Item: " + item.getType()); + editShopItem(item, slot); + } + }, 5L); + } + } + } + } + + private void deleteShopItem(Integer slot) { + Main.debugLog("Deleting Item: " + slot); + Main.getINSTANCE().setCreatorRefresh(true); + Item dedItem = new Item(); + dedItem.setMaterial("DED"); + dedItem.setSlot(slot); + editedItems.put(slot, dedItem); + } + + /** + * The inventory closeEvent handling for the Menu. + */ + private void onClose(InventoryCloseEvent e) { + Player player = (Player) e.getPlayer(); + if (!Main.CREATOR.contains(player.getName())) { + if (Config.isEscapeOnly() && !hasClicked) { + BukkitScheduler scheduler = Bukkit.getServer().getScheduler(); + scheduler.scheduleSyncDelayedTask(Main.getINSTANCE(), () -> menuInstance.open(player), 1L); + + } else { + hasClicked = false; + } + } else { + saveItems(player); + } + + } + + public void editShopItem(ItemStack itemStack, int slot) { + Item item = new Item(); + Integer mult = (44 * currentPane.getPage()); + Integer configSlot = slot + mult; + Main.getINSTANCE().setCreatorRefresh(true); + if (itemStack != null) { + NBTTagCompound comp = ItemNBTUtil.getTag(itemStack); + ItemMeta im = itemStack.getItemMeta(); + item.setItemType(ItemType.SHOP); + item.setMaterial(itemStack.getType().toString()); + item.setSlot(configSlot); + if (comp.hasKey("buyPrice")) { + + Object buyPrice = getBuyPrice(itemStack); + Main.debugLog("had buyPrice comp: " + buyPrice); + item.setBuyPrice(buyPrice); + } + if (comp.hasKey("sellPrice")) { + + Object sellPrice = getSellPrice(itemStack); + item.setSellPrice(sellPrice); + } + + if (im.hasDisplayName()) { + item.setShopName(im.getDisplayName()); + } + + if (comp.hasKey("buyName")) { + item.setBuyName(comp.getString("buyName")); + } + + if (comp.hasKey("enchantments")) { + item.setEnchantments(comp.getString("enchantments").split(" ")); + } + + if (comp.hasKey("itemType")) { + item.setItemType(ItemType.valueOf(comp.getString("itemType"))); + } + + if (comp.hasKey("commands")) { + item.setItemType(ItemType.COMMAND); + item.setCommands(Arrays.asList(comp.getString("commands").split("::"))); + } + + if (comp.hasKey("mobType")) { + item.setMobType(comp.getString("mobType")); + } + + if (im.hasLore()) { + List itemLore = im.getLore(); + List cleaned = new ArrayList<>(); + itemLore.stream().filter(str -> (!(ChatColor.stripColor(str) + .contains(ChatColor.stripColor(Config.getBuyLore().replace("{amount}", "")))) + && !(ChatColor.stripColor(str) + .contains(ChatColor.stripColor(Config.getSellLore().replace("{amount}", "")))) + && !(ChatColor.stripColor(str).contains(ChatColor.stripColor(Config.getCannotBuy()))) + && !(ChatColor.stripColor(str).contains(ChatColor.stripColor(Config.getCannotSell()))))).forEachOrdered(str -> { + cleaned.add(str); + }); + item.setShopLore(cleaned); + } + + if (comp.hasKey("loreLines")) { + String line = comp.getString("loreLines"); + String[] parsedLore = line.split("::"); + item.setBuyLore(Arrays.asList(parsedLore)); + } + } + editedItems.put(item.getSlot(), item); + + Main.debugLog("Player Edited Item: " + item.getMaterial() + " slot: " + configSlot); + + } + + /** + * Save the items for current shop instance + * + * @param player - The player who is saving the items. + */ + public void saveItems(Player player) { + + Main.debugLog("Getting Section for: " + shop); + + ConfigurationSection config = Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop) != null + ? Main.getINSTANCE().getCustomConfig().getConfigurationSection(shop) + : Main.getINSTANCE().getCustomConfig().createSection(shop); + + Main.debugLog("Config: " + config); + + editedItems.values().forEach(item -> { + if (!item.getMaterial().equalsIgnoreCase("DED")) { + config.set(item.getSlot() + "", null); + ConfigurationSection section = config.createSection(item.getSlot() + ""); + section.set("type", item.getItemType().toString()); + section.set("id", item.getMaterial()); + if (item.hasBuyPrice()) { + section.set("buy-price", item.getBuyPrice()); + } + if (item.hasSellPrice()) { + section.set("sell-price", item.getSellPrice()); + } + if (item.hasShopLore()) { + section.set("shop-lore", item.getShopLore()); + } + if (item.hasShopName()) { + section.set("shop-name", item.getShopName()); + } + if (item.hasBuyName()) { + section.set("buy-name", item.getBuyName()); + } + if (item.hasEnchantments()) { + String parsed = ""; + for (String str : item.getEnchantments()) { + parsed += str + " "; + } + section.set("enchantments", parsed.trim()); + } + if (item.hasShopLore()) { + section.set("shop-lore", item.getShopLore()); + } + if (item.hasBuyLore()) { + section.set("buy-lore", item.getBuyLore()); + } + if (item.hasCommands()) { + section.set("commands", item.getCommands()); + } + if (item.hasMobType()) { + section.set("mobType", item.getMobType()); + } + } else { + Main.debugLog("Item was ded: " + item.getSlot()); + config.set(item.getSlot() + "", null); + } + }); + try { + Main.getINSTANCE().getCustomConfig().save(Main.getINSTANCE().getSpecialf()); + } catch (IOException ex) { + Main.getINSTANCE().getLogger().log(Level.WARNING, ex.getMessage()); + } + + if (!hasClicked) { + Main.debugLog("Removed from creator"); + Main.getCREATOR().remove(player.getName()); + } + Main.sendMessage(player, "&aShop Saved!"); + } + + /** + * Gets the buyPrice of the item using NBT, or null if not + * defined + * + */ + private Object getBuyPrice(ItemStack item) { + NBTTagCompound comp = ItemNBTUtil.getTag(item); + + if (comp.hasKey("buyPrice")) { + Double vl = comp.getDouble("buyPrice"); + return vl; + } + return null; + } + + /** + * Gets the sellPrice of an item using NBT, or null if not + * defined + * + */ + private Object getSellPrice(ItemStack item) { + NBTTagCompound comp = ItemNBTUtil.getTag(item); + + if (comp.hasKey("sellPrice")) { + Double vl = comp.getDouble("sellPrice"); + return vl; + } + return null; + } } diff --git a/src/com/pablo67340/guishop/util/Config.java b/src/com/pablo67340/guishop/util/Config.java index 6466ea4..3905e4f 100644 --- a/src/com/pablo67340/guishop/util/Config.java +++ b/src/com/pablo67340/guishop/util/Config.java @@ -11,53 +11,53 @@ public final class Config { - /** - * True/False if GUIShop should use signs only. - */ - @Getter - @Setter - private static boolean signsOnly, escapeOnly, alternateSellEnabled, soundEnabled, enableCreator, - dynamicPricing, debugMode; - - /** - * The commands mode, determines whether to intercept commands, register them, or neither - * - */ - @Getter - @Setter - private static CommandsMode commandsMode; - - @Getter - private static List disabledQty = new ArrayList<>(); - - /** - * Common Language strings set in configuration. - * - */ - @Getter - @Setter - private static String added, cantSell, cantBuy, prefix, purchased, menuName, notEnoughPre, notEnoughPost, signTitle, - sellCommand, menuTitle, shopTitle, sellTitle, altSellTitle, sold, taken, sound, full, currency, - noPermission, qtyTitle, currencySuffix, backButtonItem, backButtonText, cannotSell, cannotBuy, buyLore, - sellLore, freeLore, forwardPageButtonName, backwardPageButtonName, altSellAddMaterial, - altSellRemoveMaterial, altSellIndicatorMaterial, altSellConfirmMaterial, altSellCancelMaterial, - altSellConfirmName, altSellCancelName, altSellNotEnough; - - /** - * Integers from the config - * - */ - @Getter - @Setter - private static int altSellQuantity1, altSellQuantity2, altSellQuantity3; - - /** - * Number of rows for the {@link Menu} GUI. - * - */ - @Getter - @Setter - private static Integer menuRows; - + /** + * True/False if GUIShop should use signs only. + */ + @Getter + @Setter + private static boolean signsOnly, escapeOnly, alternateSellEnabled, soundEnabled, enableCreator, + dynamicPricing, debugMode; + + /** + * The commands mode, determines whether to intercept commands, register + * them, or neither + * + */ + @Getter + @Setter + private static CommandsMode commandsMode; + + @Getter + private static List disabledQty = new ArrayList<>(); + + /** + * Common Language strings set in configuration. + * + */ + @Getter + @Setter + private static String added, cantSell, cantBuy, prefix, purchased, menuName, notEnoughPre, notEnoughPost, signTitle, + sellCommand, menuTitle, shopTitle, sellTitle, altSellTitle, sold, taken, sound, full, currency, + noPermission, qtyTitle, currencySuffix, backButtonItem, backButtonText, cannotSell, cannotBuy, buyLore, + sellLore, freeLore, forwardPageButtonName, backwardPageButtonName, altSellAddMaterial, + altSellRemoveMaterial, altSellIndicatorMaterial, altSellConfirmMaterial, altSellCancelMaterial, + altSellConfirmName, altSellCancelName, altSellNotEnough; + + /** + * Integers from the config + * + */ + @Getter + @Setter + private static int altSellQuantity1, altSellQuantity2, altSellQuantity3; + + /** + * Number of rows for the {@link Menu} GUI. + * + */ + @Getter + @Setter + private static Integer menuRows; } diff --git a/src/com/pablo67340/guishop/util/ItemUtil.java b/src/com/pablo67340/guishop/util/ItemUtil.java index 9e5325c..3efd439 100644 --- a/src/com/pablo67340/guishop/util/ItemUtil.java +++ b/src/com/pablo67340/guishop/util/ItemUtil.java @@ -14,641 +14,632 @@ public final class ItemUtil { - /** - * @param price Price - *

- * Set an item's buy price - */ - @SuppressWarnings("deprecation") - public static void setPrice(Object price, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - List lore = new ArrayList<>(); - - ItemMeta im = item.getItemMeta(); - if (im.getLore() != null) { - - im.getLore().forEach((str) -> { - if (!str.contains(ChatColor.stripColor(Config.getBuyLore().replace("{amount}", "")))) { - lore.add(str); - }else { - lore.add(Config.getBuyLore().replace("{amount}", price + "")); - } - }); - } - - im.setLore(lore); - item.setItemMeta(im); - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - - if (price instanceof Double) { - comp.setDouble("buyPrice", (Double) price); - } else if (price instanceof Integer) { - comp.setDouble("buyPrice", ((Integer) price).doubleValue()); - } else if (price instanceof Boolean) { - comp.remove("buyPrice"); - } else { - player.sendMessage( - Config.getPrefix() + " Pleas enter valid data. Accepted Value Example: (0.0, 100.0, 100, false)"); - } - - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Price set: " + price); - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void setSell(Object price, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - List lore = new ArrayList<>(); - - ItemMeta im = item.getItemMeta(); - if (im.getLore() != null) { - lore.addAll(im.getLore()); - } - - lore.add(Config.getSellLore().replace("{amount}", price + "")); - - im.setLore(lore); - item.setItemMeta(im); - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - - if (price instanceof Double) { - comp.setDouble("sellPrice", (Double) price); - } else if (price instanceof Integer) { - comp.setDouble("sellPrice", ((Integer) price).doubleValue()); - } else if (price instanceof Boolean) { - comp.remove("sellPrice"); - } else { - player.sendMessage( - Config.getPrefix() + " Pleas enter valid data. Accepted Value Example: (0.0, 100.0, 100, false)"); - } - - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Sell set: " + price); - } - - /** - * @param name The Item Name - * @param player The player who clicked the item. - *

- * - * Set an item's shop-name - * - * TODO: Add support for spaces in name - */ - @SuppressWarnings("deprecation") - public static void setShopName(String name, Player player) { - ItemStack item; - name = ChatColor.translateAlternateColorCodes('&', name); - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - ItemMeta im = item.getItemMeta(); - - im.setDisplayName(name); - - item.setItemMeta(im); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Name set: " + name); - } - - /** - * @param name The Item Name - * @param player The player who clicked the item. - *

- * - * Set an item's buy-name - * - * TODO: Add support for spaces in name - */ - @SuppressWarnings("deprecation") - public static void setBuyName(String name, Player player) { - ItemStack item; - name = ChatColor.translateAlternateColorCodes('&', name); - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - comp.setString("buyName", name); - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Buy-Name set: " + name); - } - - /** - * @param name The Item Name - * @param player The player who clicked the item. - *

- * - * Set an item's buy-name - * - * TODO: Add support for spaces in name - */ - @SuppressWarnings("deprecation") - public static void setEnchantments(String enchantments, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - comp.setString("enchantments", enchantments); - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Enchantments set: " + enchantments.trim()); - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void addToShopLore(String line, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - List lore = new ArrayList<>(); - - ItemMeta im = item.getItemMeta(); - if (im.getLore() != null) { - lore.addAll(im.getLore()); - } - - lore.add(ChatColor.translateAlternateColorCodes('&', line)); - - im.setLore(lore); - item.setItemMeta(im); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Added line to lore: " + line); - player.sendMessage(Config.getPrefix() + " Current Lore:"); - for (String str : lore) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void editShopLore(Integer index, String line, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - List lore = new ArrayList<>(); - - ItemMeta im = item.getItemMeta(); - if (im.getLore() != null) { - lore.addAll(im.getLore()); - } - - lore.set(index, ChatColor.translateAlternateColorCodes('&', line)); - - im.setLore(lore); - item.setItemMeta(im); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Edited line in lore: " + line); - player.sendMessage(Config.getPrefix() + " Current Lore:"); - for (String str : lore) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void deleteShopLore(int index, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - List lore = new ArrayList<>(); - - ItemMeta im = item.getItemMeta(); - if (im.getLore() != null) { - lore.addAll(im.getLore()); - } - - String line = lore.get(index); - - lore.remove(index); - - im.setLore(lore); - item.setItemMeta(im); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Deleted line to lore: " + line); - player.sendMessage(Config.getPrefix() + " Current Lore:"); - for (String str : lore) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void addToBuyLore(String line, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - line = ChatColor.translateAlternateColorCodes('&', line); - String addedLine = line; - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - if (comp.hasKey("loreLines")) { - line = comp.getString("loreLines") + "::" + line; - } - String[] lines = line.split("::"); - comp.setString("loreLines", line); - ItemStack fnl = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(fnl); - } else { - player.setItemInHand(fnl); - } - - player.sendMessage(Config.getPrefix() + " Added line to lore: " + addedLine); - player.sendMessage(Config.getPrefix() + " Current Lore:"); - for (String str : lines) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void editBuyLore(Integer slot, String line, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - line = ChatColor.translateAlternateColorCodes('&', line); - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - String[] lines = null; - if (comp.hasKey("loreLines")) { - lines = comp.getString("loreLines").split("::"); - } - - List lines2 = Arrays.asList(lines); - lines2.set(slot, line); - - String fnl = ""; - for (String str : lines2) { - fnl += str + "::"; - } - - comp.setString("loreLines", fnl); - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Added line to lore: " + line); - player.sendMessage(Config.getPrefix() + " Current Lore:"); - for (String str : lines2) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void deleteBuyLore(int slot, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - String[] lines = null; - if (comp.hasKey("loreLines")) { - lines = comp.getString("loreLines").split("::"); - } - - List lines2 = Arrays.asList(lines); - String line = lines2.get(slot); - lines2.remove(slot); - - String fnl = ""; - for (String str : lines2) { - fnl += str + "::"; - } - - comp.setString("loreLines", fnl); - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Removed line to lore: " + line); - player.sendMessage(Config.getPrefix() + " Current Lore:"); - for (String str : lines2) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void setType(String type, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - - comp.setString("itemType", type); - - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Set Item Type: " + type); - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void addCommand(String line, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - line = ChatColor.translateAlternateColorCodes('&', line); - String addedLine = line; - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - if (comp.hasKey("loreLines")) { - line = comp.getString("commands") + "::" + line; - } - String[] lines = line.split("::"); - comp.setString("commands", line); - ItemStack fnl = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(fnl); - } else { - player.setItemInHand(fnl); - } - - player.sendMessage(Config.getPrefix() + " Added Command to item: " + addedLine); - player.sendMessage(Config.getPrefix() + " Current Commands:"); - for (String str : lines) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void editCommand(Integer slot, String line, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - line = ChatColor.translateAlternateColorCodes('&', line); - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - String[] lines = null; - if (comp.hasKey("commands")) { - lines = comp.getString("commands").split("::"); - } - - List lines2 = Arrays.asList(lines); - lines2.set(slot, line); - - String fnl = ""; - for (String str : lines2) { - fnl += str + "::"; - } - - comp.setString("commands", fnl); - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Added command to item: " + line); - player.sendMessage(Config.getPrefix() + " Current Commands:"); - for (String str : lines2) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void deleteCommand(int slot, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - String[] lines = null; - if (comp.hasKey("commands")) { - lines = comp.getString("commands").split("::"); - } - - List lines2 = Arrays.asList(lines); - String line = lines2.get(slot); - lines2.remove(slot); - - String fnl = ""; - for (String str : lines2) { - fnl += str + "::"; - } - - comp.setString("commands", fnl); - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Removed command from item: " + line); - player.sendMessage(Config.getPrefix() + " Current Commands:"); - for (String str : lines2) { - player.sendMessage(Config.getPrefix() + " - " + str); - } - } - - /** - * @param sell Sell value - *

- * Set an item's sell price - */ - @SuppressWarnings("deprecation") - public static void setMobType(String type, Player player) { - ItemStack item; - if (XMaterial.isNewVersion()) { - item = player.getInventory().getItemInMainHand(); - } else { - item = player.getItemInHand(); - } - - NBTTagCompound comp = ItemNBTUtil.getTag(item); - - comp.setString("mobType", type); - - item = ItemNBTUtil.setNBTTag(comp, item); - - if (XMaterial.isNewVersion()) { - player.getInventory().setItemInMainHand(item); - } else { - player.setItemInHand(item); - } - - player.sendMessage(Config.getPrefix() + " Set Item Mob Type: " + type); - } + /** + * @param price Price + * @param player - The player who is setting an item price + * + * Set an item's buy price + */ + @SuppressWarnings("deprecation") + public static void setPrice(Object price, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + List lore = new ArrayList<>(); + + ItemMeta im = item.getItemMeta(); + if (im.getLore() != null) { + + im.getLore().forEach((str) -> { + if (!str.contains(ChatColor.stripColor(Config.getBuyLore().replace("{amount}", "")))) { + lore.add(str); + } else { + lore.add(Config.getBuyLore().replace("{amount}", price + "")); + } + }); + } + + im.setLore(lore); + item.setItemMeta(im); + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + + if (price instanceof Double) { + comp.setDouble("buyPrice", (Double) price); + } else if (price instanceof Integer) { + comp.setDouble("buyPrice", ((Integer) price).doubleValue()); + } else if (price instanceof Boolean) { + comp.remove("buyPrice"); + } else { + player.sendMessage( + Config.getPrefix() + " Pleas enter valid data. Accepted Value Example: (0.0, 100.0, 100, false)"); + } + + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Price set: " + price); + } + + /** + * @param price Sell value + * @param player - The player who is setting an item price + * + * Set an item's sell price + */ + @SuppressWarnings("deprecation") + public static void setSell(Object price, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + List lore = new ArrayList<>(); + + ItemMeta im = item.getItemMeta(); + if (im.getLore() != null) { + lore.addAll(im.getLore()); + } + + lore.add(Config.getSellLore().replace("{amount}", price + "")); + + im.setLore(lore); + item.setItemMeta(im); + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + + if (price instanceof Double) { + comp.setDouble("sellPrice", (Double) price); + } else if (price instanceof Integer) { + comp.setDouble("sellPrice", ((Integer) price).doubleValue()); + } else if (price instanceof Boolean) { + comp.remove("sellPrice"); + } else { + player.sendMessage( + Config.getPrefix() + " Pleas enter valid data. Accepted Value Example: (0.0, 100.0, 100, false)"); + } + + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Sell set: " + price); + } + + /** + * @param name The Item Name + * @param player The player who clicked the item. + * + * Set an item's shop-name + */ + @SuppressWarnings("deprecation") + public static void setShopName(String name, Player player) { + ItemStack item; + name = ChatColor.translateAlternateColorCodes('&', name); + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + ItemMeta im = item.getItemMeta(); + + im.setDisplayName(name); + + item.setItemMeta(im); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Name set: " + name); + } + + /** + * @param name The Item Name + * @param player The player who clicked the item. + * + * Set an item's buy-name + * + */ + @SuppressWarnings("deprecation") + public static void setBuyName(String name, Player player) { + ItemStack item; + name = ChatColor.translateAlternateColorCodes('&', name); + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + comp.setString("buyName", name); + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Buy-Name set: " + name); + } + + /** + * @param enchantments The enchantments to add + * @param player The player who clicked the item. + * + * Set an item's enchantments + */ + @SuppressWarnings("deprecation") + public static void setEnchantments(String enchantments, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + comp.setString("enchantments", enchantments); + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Enchantments set: " + enchantments.trim()); + } + + /** + * @param line The line to add to the shop lore + * @param player - The player who is setting the shop lore + * + * Add a line to an item's Shop lore + */ + @SuppressWarnings("deprecation") + public static void addToShopLore(String line, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + List lore = new ArrayList<>(); + + ItemMeta im = item.getItemMeta(); + if (im.getLore() != null) { + lore.addAll(im.getLore()); + } + + lore.add(ChatColor.translateAlternateColorCodes('&', line)); + + im.setLore(lore); + item.setItemMeta(im); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Added line to lore: " + line); + player.sendMessage(Config.getPrefix() + " Current Lore:"); + lore.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param index - The line number the lore will be updated on + * @param line - The text that will be saved to the specified line + * @param player - The player who is setting a Shop Lore + * + * Edit an item's Shop lore + */ + @SuppressWarnings("deprecation") + public static void editShopLore(Integer index, String line, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + List lore = new ArrayList<>(); + + ItemMeta im = item.getItemMeta(); + if (im.getLore() != null) { + lore.addAll(im.getLore()); + } + + lore.set(index, ChatColor.translateAlternateColorCodes('&', line)); + + im.setLore(lore); + item.setItemMeta(im); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Edited line in lore: " + line); + player.sendMessage(Config.getPrefix() + " Current Lore:"); + lore.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param index - The index the lore line will be deleted + * @param player - The player who is deleting a shop lore line + * + * Delete an item's shop lore + */ + @SuppressWarnings("deprecation") + public static void deleteShopLore(int index, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + List lore = new ArrayList<>(); + + ItemMeta im = item.getItemMeta(); + if (im.getLore() != null) { + lore.addAll(im.getLore()); + } + + String line = lore.get(index); + + lore.remove(index); + + im.setLore(lore); + item.setItemMeta(im); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Deleted line to lore: " + line); + player.sendMessage(Config.getPrefix() + " Current Lore:"); + lore.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param line - The line to be added to the lore + * @param player - The player who is adding a line to the lore + * + * Add a line to an item's buy lore + */ + @SuppressWarnings("deprecation") + public static void addToBuyLore(String line, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + line = ChatColor.translateAlternateColorCodes('&', line); + String addedLine = line; + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + if (comp.hasKey("loreLines")) { + line = comp.getString("loreLines") + "::" + line; + } + String[] lines = line.split("::"); + comp.setString("loreLines", line); + ItemStack fnl = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(fnl); + } else { + player.setItemInHand(fnl); + } + + player.sendMessage(Config.getPrefix() + " Added line to lore: " + addedLine); + player.sendMessage(Config.getPrefix() + " Current Lore:"); + for (String str : lines) { + player.sendMessage(Config.getPrefix() + " - " + str); + } + } + + /** + * @param slot - The slot number of the item being edited + * @param line - The line that will be added to the lore + * @param player - The player who is setting an item lore + * + * Edit an item's lore line + */ + @SuppressWarnings("deprecation") + public static void editBuyLore(Integer slot, String line, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + line = ChatColor.translateAlternateColorCodes('&', line); + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + String[] lines = null; + if (comp.hasKey("loreLines")) { + lines = comp.getString("loreLines").split("::"); + } + + List lines2 = Arrays.asList(lines); + lines2.set(slot, line); + + String fnl = ""; + fnl = lines2.stream().map(str -> str + "::").reduce(fnl, String::concat); + + comp.setString("loreLines", fnl); + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Added line to lore: " + line); + player.sendMessage(Config.getPrefix() + " Current Lore:"); + lines2.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param slot - The slot containing the item the lore will be removed on. + * @param player - The player who is setting an item price + * + * Delete an Item's lore line + */ + @SuppressWarnings("deprecation") + public static void deleteBuyLore(int slot, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + String[] lines = null; + if (comp.hasKey("loreLines")) { + lines = comp.getString("loreLines").split("::"); + } + + List lines2 = Arrays.asList(lines); + String line = lines2.get(slot); + lines2.remove(slot); + + String fnl = ""; + fnl = lines2.stream().map(str -> str + "::").reduce(fnl, String::concat); + + comp.setString("loreLines", fnl); + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Removed line to lore: " + line); + player.sendMessage(Config.getPrefix() + " Current Lore:"); + lines2.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param type - The Material name to set the item to + * @param player - The player setting type of the item + */ + @SuppressWarnings("deprecation") + public static void setType(String type, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + + comp.setString("itemType", type); + + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Set Item Type: " + type); + } + + /** + * @param line - The line to be added to the item's runnable commands + * @param player - The player who is setting the commands + */ + @SuppressWarnings("deprecation") + public static void addCommand(String line, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + line = ChatColor.translateAlternateColorCodes('&', line); + String addedLine = line; + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + if (comp.hasKey("loreLines")) { + line = comp.getString("commands") + "::" + line; + } + String[] lines = line.split("::"); + comp.setString("commands", line); + ItemStack fnl = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(fnl); + } else { + player.setItemInHand(fnl); + } + + player.sendMessage(Config.getPrefix() + " Added Command to item: " + addedLine); + player.sendMessage(Config.getPrefix() + " Current Commands:"); + for (String str : lines) { + player.sendMessage(Config.getPrefix() + " - " + str); + } + } + + /** + * @param slot - The slot containing the item that commands will be edited + * in + * @param line - The command line that will be added to the item + * @param player - The player who is setting the command + */ + @SuppressWarnings("deprecation") + public static void editCommand(Integer slot, String line, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + line = ChatColor.translateAlternateColorCodes('&', line); + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + String[] lines = null; + if (comp.hasKey("commands")) { + lines = comp.getString("commands").split("::"); + } + + List lines2 = Arrays.asList(lines); + lines2.set(slot, line); + + String fnl = ""; + fnl = lines2.stream().map(str -> str + "::").reduce(fnl, String::concat); + + comp.setString("commands", fnl); + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Added command to item: " + line); + player.sendMessage(Config.getPrefix() + " Current Commands:"); + lines2.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param slot - The slot containing the item a command will be deleted from + * @param player - The player who is deleting a command + */ + @SuppressWarnings("deprecation") + public static void deleteCommand(int slot, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + String[] lines = null; + if (comp.hasKey("commands")) { + lines = comp.getString("commands").split("::"); + } + + List lines2 = Arrays.asList(lines); + String line = lines2.get(slot); + lines2.remove(slot); + + String fnl = ""; + fnl = lines2.stream().map(str -> str + "::").reduce(fnl, String::concat); + + comp.setString("commands", fnl); + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Removed command from item: " + line); + player.sendMessage(Config.getPrefix() + " Current Commands:"); + lines2.forEach(str -> { + player.sendMessage(Config.getPrefix() + " - " + str); + }); + } + + /** + * @param type - The entity name of a mob + * @param player - The player who is setting the mob entity type + */ + @SuppressWarnings("deprecation") + public static void setMobType(String type, Player player) { + ItemStack item; + if (XMaterial.isNewVersion()) { + item = player.getInventory().getItemInMainHand(); + } else { + item = player.getItemInHand(); + } + + NBTTagCompound comp = ItemNBTUtil.getTag(item); + + comp.setString("mobType", type); + + item = ItemNBTUtil.setNBTTag(comp, item); + + if (XMaterial.isNewVersion()) { + player.getInventory().setItemInMainHand(item); + } else { + player.setItemInHand(item); + } + + player.sendMessage(Config.getPrefix() + " Set Item Mob Type: " + type); + } } diff --git a/src/com/pablo67340/guishop/util/MatLib.java b/src/com/pablo67340/guishop/util/MatLib.java index b8a8b9d..089df1f 100644 --- a/src/com/pablo67340/guishop/util/MatLib.java +++ b/src/com/pablo67340/guishop/util/MatLib.java @@ -16,748 +16,748 @@ public final class MatLib { private static final Map MAP = new HashMap<>(); static { - putEntry("PURPLE_STAINED_GLASS", "95:10"); - putEntry("BLUE_STAINED_GLASS", "95:11"); - putEntry("BROWN_STAINED_GLASS", "95:12"); - putEntry("BROWN_MUSHROOM", "39:0"); - putEntry("CHAINMAIL_LEGGINGS", "304:0"); - putEntry("LAVA_BUCKET", "327:0"); - putEntry("COMPARATOR", "150:0"); - putEntry("ACACIA_DOOR", "196:0"); - putEntry("CAULDRON", "380:0"); - putEntry("COAL_ORE", "16:0"); - putEntry("COAL_BLOCK", "173:0"); - putEntry("CAKE", "92:0"); - putEntry("OBSERVER", "218:0"); - putEntry("WOODEN_AXE", "271:0"); - putEntry("GOLDEN_HOE", "294:0"); - putEntry("WHITE_BANNER", "425:0"); - putEntry("MUSIC_DISK_11", "2266:0"); - putEntry("DARK_OAK_BOAT", "448:0"); - putEntry("FIREWORK_STAR", "402:0"); - putEntry("BRICK_STAIRS", "108:0"); - putEntry("DARK_OAK_LEAVES", "161:1"); - putEntry("ACACIA_LEAVES", "161:0"); - putEntry("PAPER", "339:0"); - putEntry("GOLDEN_LEGGINGS", "316:0"); - putEntry("POTATO", "392:0"); - putEntry("POWERED_RAIL", "27:0"); - putEntry("BIRCH_FENCE_GATE", "184:0"); - putEntry("SNOW_BLOCK", "80:0"); - putEntry("PURPLE_SHULKER_BOX", "229:0"); - putEntry("MUSHROOM_STEW", "282:0"); - putEntry("END_STONE_BRICKS", "206:0"); - putEntry("DRAGON_BREATH", "437:0"); - putEntry("RABBIT_FOOT", "414:0"); - putEntry("POPPY", "38:0"); - putEntry("BLUE_ORCHID", "38:1"); - putEntry("ALLIUM", "38:2"); - putEntry("AZURE_BLUET", "38:3"); - putEntry("RED_TULIP", "38:4"); - putEntry("WHITE_SHULKER_BOX", "219:0"); - putEntry("DAYLIGHT_DETECTOR", "151:0"); - putEntry("PACKED_ICE", "174:0"); - putEntry("DARK_OAK_DOOR", "197:0"); - putEntry("MINECART", "328:0"); - putEntry("ENDER_EYE", "381:0"); - putEntry("CHAINMAIL_BOOTS", "305:0"); - putEntry("IRON_ORE", "15:0"); - putEntry("JACK_O_LANTERN", "91:0"); - putEntry("STONE_SWORD", "272:0"); - putEntry("MUSIC_DISK_WARD", "2265:0"); - putEntry("END_CRYSTAL", "426:0"); - putEntry("TOTEM_OF_UNDYING", "449:0"); - putEntry("ENCHANTED_BOOK", "403:0"); - putEntry("WHEAT_SEEDS", "295:0"); - putEntry("OBSIDIAN", "49:0"); - putEntry("ACACIA_WOOD", "162:0"); - putEntry("JUNGLE_FENCE_GATE", "185:0"); - putEntry("GOLDEN_BOOTS", "317:0"); - putEntry("GHAST_TEAR", "370:0"); - putEntry("BAKED_POTATO", "393:0"); - putEntry("BED", "26:0"); - putEntry("DARK_OAK_WOOD", "162:1"); - putEntry("ORANGE_TULIP", "38:5"); - putEntry("BEETROOT", "207:0"); - putEntry("WHITE_TULIP", "38:6"); - putEntry("STONE_BRICK_STAIRS", "109:0"); - putEntry("GOLDEN_SWORD", "283:0"); - putEntry("PINK_TULIP", "38:7"); - putEntry("OXEYE_DAISY", "38:8"); - putEntry("APPLE", "260:0"); - putEntry("SPLASH_POTION", "438:0"); - putEntry("GREEN_STAINED_GLASS", "95:13"); - putEntry("RED_STAINED_GLASS", "95:14"); - putEntry("RABBIT_HIDE", "415:0"); - putEntry("BLACK_STAINED_GLASS", "95:15"); - putEntry("DANDELION", "37:0"); - putEntry("LARGE_FERN", "175:3"); - putEntry("ROSE_BUSH", "175:4"); - putEntry("PEONY", "175:5"); - putEntry("SUNFLOWER", "175:0"); - putEntry("LILAC", "175:1"); - putEntry("IRON_HELMET", "306:0"); - putEntry("TALL_GRASS", "175:2"); - putEntry("END_ROD", "198:0"); - putEntry("GLISTERING_MELON_SLICE", "382:0"); - putEntry("GOLD_ORE", "14:0"); - putEntry("REDSTONE_BLOCK", "152:0"); - putEntry("SADDLE", "329:0"); - putEntry("NETHER_PORTAL", "90:0"); - putEntry("MUSIC_DISK_STRAD", "2264:0"); - putEntry("BLACK_GLAZED_TERRACOTTA", "250:0"); - putEntry("SPRUCE_DOOR", "427:0"); - putEntry("COMPARATOR", "404:0"); - putEntry("STONE_SHOVEL", "273:0"); - putEntry("WHEAT", "296:0"); - putEntry("MOSSY_COBBLESTONE", "48:0"); - putEntry("SPECTRAL_ARROW", "439:0"); - putEntry("GRASS_PATH", "208:0"); - putEntry("FLOWER_POT", "140:0"); - putEntry("DARK_OAK_FENCE_GATE", "186:0"); - putEntry("GOLD_NUGGET", "371:0"); - putEntry("POISONOUS_POTATO", "394:0"); - putEntry("NOTE_BLOCK", "25:0"); - putEntry("ACACIA_STAIRS", "163:0"); - putEntry("FLINT", "318:0"); - putEntry("BOW", "261:0"); - putEntry("ARMOR_STAND", "416:0"); - putEntry("GOLDEN_SHOVEL", "284:0"); - putEntry("ELDER_GUARDIAN_SPAWN_EGG", "383:4"); - putEntry("WITHER_SPAWN_EGG", "383:5"); - putEntry("WHEAT", "59:0"); - putEntry("STRAY_SPAWN_EGG", "383:6"); - putEntry("MELON", "360:0"); - putEntry("BIRCH_DOOR", "428:0"); - putEntry("WHITE_BANNER", "176:0"); - putEntry("CHORUS_PLANT", "199:0"); - putEntry("ENDER_CHEST", "130:0"); - putEntry("NETHER_QUARTZ_ORE", "153:0"); - putEntry("GRAVEL", "13:0"); - putEntry("PURPLE_WOOL", "35:10"); - putEntry("LIME_CONCRETE", "251:5"); - putEntry("YELLOW_CONCRETE", "251:4"); - putEntry("GRAY_CONCRETE", "251:7"); - putEntry("PINK_CONCRETE", "251:6"); - putEntry("CYAN_CONCRETE", "251:9"); - putEntry("LIGHT_GRAY_CONCRETE", "251:8"); - putEntry("IRON_CHESTPLATE", "307:0"); - putEntry("ENVOKER_SPAWN_EGG", "383:34"); - putEntry("VEX_SPAWN_EGG", "383:35"); - putEntry("BLACK_WOOL", "35:15"); - putEntry("VINDICATOR_SPAWN_EGG", "383:36"); - putEntry("RED_WOOL", "35:14"); - putEntry("ORANGE_CONCRETE", "251:1"); - putEntry("NETHER_BRICK", "405:0"); - putEntry("GREEN_WOOL", "35:13"); - putEntry("WHITE_CONCRETE", "251:0"); - putEntry("BREAD", "297:0"); - putEntry("BROWN_WOOL", "35:12"); - putEntry("LIGHT_BLUE_CONCRETE", "251:3"); - putEntry("DONKEY_SPAWN_EGG", "383:31"); - putEntry("BLUE_WOOL", "35:11"); - putEntry("MAGENTA_CONCRETE", "251:2"); - putEntry("STONE_PICKAXE", "274:0"); - putEntry("MULE_SPAWN_EGG", "383:32"); - putEntry("MUSIC_DISK_STAL", "2263:0"); - putEntry("BOOKSHELF", "47:0"); - putEntry("IRON_HORSE_ARMOR", "417:0"); - putEntry("ZOMBIE_VILLAGER_SPAWN_EGG", "383:27"); - putEntry("END_GATEWAY", "209:0"); - putEntry("SKELETON_HORSE_SPAWN_EGG", "383:28"); - putEntry("ZOMBIE_HORSE_SPAWN_EGG", "383:29"); - putEntry("ACACIA_FENCE_GATE", "187:0"); - putEntry("NETHER_WART", "372:0"); - putEntry("MAP", "395:0"); - putEntry("SMOOTH_SANDSTONE", "24:2"); - putEntry("CHISELED_SANDSTONE", "24:1"); - putEntry("CARROTS", "141:0"); - putEntry("DARK_OAK_STAIRS", "164:0"); - putEntry("SANDSTONE", "24:0"); - putEntry("PORKCHOP", "319:0"); - putEntry("HUSK_SPAWN_EGG", "383:23"); - putEntry("ARROW", "262:0"); - putEntry("GOLDEN_PICKAXE", "285:0"); - putEntry("SAND", "12:0"); - putEntry("CRAFTING_TABLE", "58:0"); - putEntry("MOSSY_COBBLESTONE_WALL", "139:1"); - putEntry("BLAZE_ROD", "369:0"); - putEntry("CAVE_SPIDER_SPAWN_EGG", "383:59"); - putEntry("ENCHANTING_TABLE", "116:0"); - putEntry("COBBLESTONE_WALL", "139:0"); - putEntry("GRAY_WOOL", "35:7"); - putEntry("PINK_WOOL", "35:6"); - putEntry("LIME_WOOL", "35:5"); - putEntry("YELLOW_WOOL", "35:4"); - putEntry("LIGHT_BLUE_WOOL", "35:3"); - putEntry("LEATHER_LEGGINGS", "300:0"); - putEntry("SIGN", "323:0"); - putEntry("FISHING_ROD", "346:0"); - putEntry("MAGENTA_WOOL", "35:2"); - putEntry("ACACIA_FENCE", "192:0"); - putEntry("ORANGE_WOOL", "35:1"); - putEntry("RED_SAND", "12:1"); - putEntry("WHITE_WOOL", "35:0"); - putEntry("RED_SANDSTONE_STAIRS", "180:0"); - putEntry("CREEPER_SPAWN_EGG", "383:50"); - putEntry("MAGENTA_GLAZED_TERRACOTTA", "237:0"); - putEntry("SLIME_SPAWN_EGG", "383:55"); - putEntry("GHAST_SPAWN_EGG", "383:56"); - putEntry("ZOMBIE_PIGMAN_SPAWN_EGG", "383:57"); - putEntry("ENDERMAN_SPAWN_EGG", "383:58"); - putEntry("NETHER_WART_BLOCK", "214:0"); - putEntry("SKELETON_SPAWN_EGG", "383:51"); - putEntry("SPIDER_SPAWN_EGG", "383:52"); - putEntry("NAME_TAG", "421:0"); - putEntry("MUSIC_DISK_MELLOHI", "2262:0"); - putEntry("ZOMBIE_SPAWN_EGG", "383:54"); - putEntry("SPRUCE_BOAT", "444:0"); - putEntry("DISPENSER", "23:0"); - putEntry("TNT", "46:0"); - putEntry("LEVER", "69:0"); - putEntry("PUMPKIN_STEM", "104:0"); - putEntry("COCOA", "127:0"); - putEntry("MAP", "358:0"); - putEntry("MILK_BUCKET", "335:0"); - putEntry("WATER", "9:0"); - putEntry("DIAMOND_LEGGINGS", "312:0"); - putEntry("DARK_OAK_FENCE", "191:0"); - putEntry("PINK_SHULKER_BOX", "225:0"); - putEntry("GREEN_GLAZED_TERRACOTTA", "248:0"); - putEntry("CYAN_WOOL", "35:9"); - putEntry("LIGHT_GRAY_WOOL", "35:8"); - putEntry("PRISMARINE_CRYSTALS", "410:0"); - putEntry("PURPUR_PILLAR", "202:0"); - putEntry("POPPED_CHORUS_FRUIT", "433:0"); - putEntry("PISTON_HEAD", "34:0"); - putEntry("DIAMOND_BLOCK", "57:0"); - putEntry("LAVA", "11:0"); - putEntry("BREWING_STAND", "117:0"); - putEntry("CLOCK", "347:0"); - putEntry("HAY_BLOCK", "170:0"); - putEntry("SPRUCE_DOOR", "193:0"); - putEntry("OAK_DOOR", "324:0"); - putEntry("LEATHER_BOOTS", "301:0"); - putEntry("LIGHT_BLUE_GLAZED_TERRACOTTA", "238:0"); - putEntry("RED_NETHER_BRICKS", "215:0"); - putEntry("STONE_HOE", "291:0"); - putEntry("MUSIC_DISK_MALL", "2261:0"); - putEntry("COMMAND_BLOCK_MINECART", "422:0"); - putEntry("BIRCH_BOAT", "445:0"); - putEntry("LAPIS_BLOCK", "22:0"); - putEntry("SIGN", "68:0"); - putEntry("DANDELION_YELLOW", "351:11"); - putEntry("LIME_DYE", "351:10"); - putEntry("WOODEN_HOE", "290:0"); - putEntry("MAGENTA_DYE", "351:13"); - putEntry("MELON_STEM", "105:0"); - putEntry("LIGHT_BLUE_DYE", "351:12"); - putEntry("BONE_MEAL", "351:15"); - putEntry("SANDSTONE_STAIRS", "128:0"); - putEntry("ORANGE_DYE", "351:14"); - putEntry("BRICK", "336:0"); - putEntry("SHEARS", "359:0"); - putEntry("RED_SANDSTONE_SLAB", "181:0"); - putEntry("WATER", "8:0"); - putEntry("DIAMOND_BOOTS", "313:0"); - putEntry("BRICKS", "45:0"); - putEntry("SILVERFISH_SPAWN_EGG", "383:60"); - putEntry("BLAZE_SPAWN_EGG", "383:61"); - putEntry("GRAY_SHULKER_BOX", "226:0"); - putEntry("RED_GLAZED_TERRACOTTA", "249:0"); - putEntry("WITCH_SPAWN_EGG", "383:66"); - putEntry("ENDERMITE_SPAWN_EGG", "383:67"); - putEntry("RABBIT", "411:0"); - putEntry("GUARDIAN_SPAWN_EGG", "383:68"); - putEntry("SHULKER_SPAWN_EGG", "383:69"); - putEntry("PURPUR_STAIRS", "203:0"); - putEntry("MAGMA_CUBE_SPAWN_EGG", "383:62"); - putEntry("BAT_SPAWN_EGG", "383:65"); - putEntry("BEETROOT", "434:0"); - putEntry("PISTON", "33:0"); - putEntry("ICE", "79:0"); - putEntry("LAVA", "10:0"); - putEntry("GRAY_CARPET", "171:7"); - putEntry("LIGHT_GRAY_CARPET", "171:8"); - putEntry("CYAN_CARPET", "171:9"); - putEntry("CAULDRON", "118:0"); - putEntry("LIGHT_BLUE_CARPET", "171:3"); - putEntry("YELLOW_CARPET", "171:4"); - putEntry("LIME_CARPET", "171:5"); - putEntry("BUCKET", "325:0"); - putEntry("GLOWSTONE_DUST", "348:0"); - putEntry("PINK_CARPET", "171:6"); - putEntry("WHITE_CARPET", "171:0"); - putEntry("ORANGE_CARPET", "171:1"); - putEntry("CHAINMAIL_HELMET", "302:0"); - putEntry("DIAMOND_ORE", "56:0"); - putEntry("MAGENTA_CARPET", "171:2"); - putEntry("BIRCH_DOOR", "194:0"); - putEntry("SHEEP_SPAWN_EGG", "383:91"); - putEntry("COW_SPAWN_EGG", "383:92"); - putEntry("CHICKEN_SPAWN_EGG", "383:93"); - putEntry("SQUID_SPAWN_EGG", "383:94"); - putEntry("YELLOW_GLAZED_TERRACOTTA", "239:0"); - putEntry("PIG_SPAWN_EGG", "383:90"); - putEntry("PUMPKIN_PIE", "400:0"); - putEntry("JUNGLE_BOAT", "446:0"); - putEntry("BONE_BLOCK", "216:0"); - putEntry("IRON_HOE", "292:0"); - putEntry("WOLF_SPAWN_EGG", "383:95"); - putEntry("MUSIC_DISK_FAR", "2260:0"); - putEntry("MOOSHROOM_SPAWN_EGG", "383:96"); - putEntry("OCELOT_SPAWN_EGG", "383:98"); - putEntry("MUTTON", "423:0"); - putEntry("OAK_STAIRS", "44:2"); - putEntry("COBBLESTONE_SLAB", "44:3"); - putEntry("LAPIS_ORE", "21:0"); - putEntry("BRICK_SLAB", "44:4"); - putEntry("STONE_BRICK_SLAB", "44:5"); - putEntry("NETHER_BRICK_SLAB", "44:6"); - putEntry("MELON", "106:0"); - putEntry("EMERALD_ORE", "129:0"); - putEntry("QUARTZ_SLAB", "44:7"); - putEntry("GOLDEN_HELMET", "314:0"); - putEntry("FLOWER_POT", "390:0"); - putEntry("CLAY", "337:0"); - putEntry("BEDROCK", "7:0"); - putEntry("RED_SANDSTONE_SLAB", "182:0"); - putEntry("STONE_SLAB", "44:0"); - putEntry("COBBLESTONE_STAIRS", "67:0"); - putEntry("SANDSTONE_SLAB", "44:1"); - putEntry("LIGHT_GRAY_SHULKER_BOX", "227:0"); - putEntry("COOKED_RABBIT", "412:0"); - putEntry("BEETROOT_SEEDS", "435:0"); - putEntry("STICK", "280:0"); - putEntry("PURPUR_SLAB", "204:0"); - putEntry("DEAD_BUSH", "32:0"); - putEntry("END_PORTAL", "119:0"); - putEntry("RAW_SALMON", "349:1"); - putEntry("CHAINMAIL_CHESTPLATE", "303:0"); - putEntry("RAW_FISH", "349:0"); - putEntry("WATER_BUCKET", "326:0"); - putEntry("REDSTONE_WIRE", "55:0"); - putEntry("SNOW", "78:0"); - putEntry("CONCRETE", "172:0"); - putEntry("JUNGLE_DOOR", "195:0"); - putEntry("PUFFERFISH", "349:3"); - putEntry("TROPICAL_FISH", "349:2"); - putEntry("FIREWORK_ROCKET", "401:0"); - putEntry("COOKED_MUTTON", "424:0"); - putEntry("ACACIA_BOAT", "447:0"); - putEntry("STRUCTURE_VOID", "217:0"); - putEntry("DIAMOND_HOE", "293:0"); - putEntry("WOODEN_PICKAXE", "270:0"); - putEntry("COBBLESTONE_STAIRS", "43:3"); - putEntry("BRICK_STAIRS", "43:4"); - putEntry("CYAN_STAINED_GLASS_PANE", "160:9"); - putEntry("STONE_BRICK_STAIRS", "43:5"); - putEntry("LIGHT_GRAY_STAINED_GLASS_PANE", "160:8"); - putEntry("GLASS", "20:0"); - putEntry("NETHER_BRICK_STAIRS", "43:6"); - putEntry("GRAY_STAINED_GLASS_PANE", "160:7"); - putEntry("QUARTZ_STAIRS", "43:7"); - putEntry("OAK_FENCE_GATE", "107:0"); - putEntry("MAGENTA_STAINED_GLASS_PANE", "160:2"); - putEntry("GOLDEN_CHESTPLATE", "315:0"); - putEntry("SUGAR_CANE", "338:0"); - putEntry("CARROT", "391:0"); - putEntry("ORANGE_STAINED_GLASS_PANE", "160:1"); - putEntry("WHITE_STAINED_GLASS_PANE", "160:0"); - putEntry("OAK_SAPLING", "6:0"); - putEntry("PINK_STAINED_GLASS_PANE", "160:6"); - putEntry("SPRUCE_SAPLING", "6:1"); - putEntry("STONE_STAIRS", "43:0"); - putEntry("GLOWSTONE", "89:0"); - putEntry("LIME_STAINED_GLASS_PANE", "160:5"); - putEntry("BIRCH_SAPLING", "6:2"); - putEntry("SANDSTONE_STAIRS", "43:1"); - putEntry("YELLOW_STAINED_GLASS_PANE", "160:4"); - putEntry("SPRUCE_FENCE_GATE", "183:0"); - putEntry("JUNGLE_SAPLING", "6:3"); - putEntry("OAK_STAIRS", "43:2"); - putEntry("RAIL", "66:0"); - putEntry("LIGHT_BLUE_STAINED_GLASS_PANE", "160:3"); - putEntry("ACACIA_SAPLING", "6:4"); - putEntry("DARK_OAK_SAPLING", "6:5"); - putEntry("CYAN_SHULKER_BOX", "228:0"); - putEntry("BEETROOT_SOUP", "436:0"); - putEntry("PURPUR_SLAB", "205:0"); - putEntry("BOWL", "281:0"); - putEntry("RABBIT_STEW", "413:0"); - putEntry("CHEST_MINECART", "342:0"); - putEntry("RAW_CHICKEN", "365:0"); - putEntry("FERN", "31:2"); - putEntry("NETHER_BRICK", "112:0"); - putEntry("DROPPER", "158:0"); - putEntry("EMERALD", "388:0"); - putEntry("GRASS", "31:1"); - putEntry("TALL_GRASS", "31:0"); - putEntry("BITCH_STAIRS", "135:0"); - putEntry("CHEST", "54:0"); - putEntry("STONE_BUTTON", "77:0"); - putEntry("REPEATING_COMMAND_BLOCK", "210:0"); - putEntry("RED_SHULKER_BOX", "233:0"); - putEntry("IRON_SHOVEL", "256:0"); - putEntry("DIAMOND_AXE", "279:0"); - putEntry("TIPPED_ARROW", "440:0"); - putEntry("SEA_LANTERN", "169:0"); - putEntry("REDSTONE", "331:0"); - putEntry("BLAZE_POWDER", "377:0"); - putEntry("ENCHANTING_TABLE", "123:0"); - putEntry("TRAPPED_CHEST", "146:0"); - putEntry("OAK_PLANKS", "5:0"); - putEntry("SPRUCE_PLANKS", "5:1"); - putEntry("IRON_BLOCK", "42:0"); - putEntry("LADDER", "65:0"); - putEntry("SOUL_SAND", "88:0"); - putEntry("BIRCH_PLANKS", "5:2"); - putEntry("JUNGLE_PLANKS", "5:3"); - putEntry("RED_MUSHROOM_BLOCK", "100:0"); - putEntry("ACACIA_PLANKS", "5:4"); - putEntry("CAKE", "354:0"); - putEntry("DARK_OAK_PLANKS", "5:5"); - putEntry("IRON_SWORD", "267:0"); - putEntry("CYAN_GLAZED_TERRACOTTA", "244:0"); - putEntry("IRON_NUGGET", "452:0"); - putEntry("MAGENTA_SHULKER_BOX", "221:0"); - putEntry("NETHER_BRICK_FENCE", "113:0"); - putEntry("JUNGLE_STAIRS", "136:0"); - putEntry("CONCRETE", "159:0"); - putEntry("COOKED_PORKCHOP", "320:0"); - putEntry("COOKED_CHICKEN", "366:0"); - putEntry("ITEM_FRAME", "389:0"); - putEntry("COBWEB", "30:0"); - putEntry("YELLOW_CONCRETE", "159:4"); - putEntry("LIGHT_BLUE_CONCRETE", "159:3"); - putEntry("MAGENTA_CONCRETE", "159:2"); - putEntry("ORANGE_CONCRETE", "159:1"); - putEntry("OAK_STAIRS", "53:0"); - putEntry("REDSTONE_TORCH", "76:0"); - putEntry("BROWN_MUSHROOM_BLOCK", "99:0"); - putEntry("FURNACE_MINECART", "343:0"); - putEntry("BLACK_SHULKER_BOX", "234:0"); - putEntry("LINGERING_POTION", "441:0"); - putEntry("IRON_PICKAXE", "257:0"); - putEntry("LIGHT_GRAY_CONCRETE", "159:8"); - putEntry("GRAY_CONCRETE", "159:7"); - putEntry("PINK_CONCRETE", "159:6"); - putEntry("LIME_CONCRETE", "159:5"); - putEntry("CYAN_CONCRETE", "159:9"); - putEntry("CHAIN_COMMAND_BLOCK", "211:0"); - putEntry("LIGHT_WEIGHTED_PRESSURE_PLATE", "147:0"); - putEntry("IRON_BARS", "101:0"); - putEntry("MAGMA_CREAM", "378:0"); - putEntry("REDSTONE_LAMP", "123:0"); - putEntry("COBBLESTONE", "4:0"); - putEntry("GOLD_BLOCK", "41:0"); - putEntry("OAK_DOOR", "64:0"); - putEntry("SNOWBALL", "332:0"); - putEntry("BED", "355:0"); - putEntry("NETHERRACK", "87:0"); - putEntry("LIGHT_BLUE_SHULKER_BOX", "222:0"); - putEntry("PURPLE_GLAZED_TERRACOTTA", "245:0"); - putEntry("WOODEN_SWORD", "268:0"); - putEntry("ACACIA_DOOR", "430:0"); - putEntry("KNOWLEDGE_BOOK", "453:0"); - putEntry("COMMAND_BLOCK", "137:0"); - putEntry("CHISELED_STONE_BRICKS", "98:3"); - putEntry("ROTTEN_FLESH", "367:0"); - putEntry("NETHER_BRICK_STAIRS", "114:0"); - putEntry("BLACK_CONCRETE", "251:15"); - putEntry("SPAWNER", "52:0"); - putEntry("MOSSY_STONE_BRICKS", "98:1"); - putEntry("REDSTONE_TORCH", "75:0"); - putEntry("CRACKED_STONE_BRICKS", "98:2"); - putEntry("PAINTING", "321:0"); - putEntry("EGG", "344:0"); - putEntry("STONE_BRICKS", "98:0"); - putEntry("WHITE_GLAZED_TERRACOTTA", "235:0"); - putEntry("IRON_AXE", "258:0"); - putEntry("BLUE_CONCRETE", "251:11"); - putEntry("BROWN_CONCRETE", "251:12"); - putEntry("GREEN_CONCRETE", "251:13"); - putEntry("RED_CONCRETE", "251:14"); - putEntry("SHIELD", "442:0"); - putEntry("FROSTED_ICE", "212:0"); - putEntry("PURPLE_CONCRETE", "251:10"); - putEntry("GLASS_PANE", "102:0"); - putEntry("OAK_SLAB", "125:0"); - putEntry("SPRUCE_SLAB", "125:1"); - putEntry("HEAVY_WEIGHTED_PRESSURE_PLATE", "148:0"); - putEntry("BREWING_STAND", "379:0"); - putEntry("ACACIA_SLAB", "125:4"); - putEntry("DARK_OAK_SLAB", "125:5"); - putEntry("BIRCH_SLAB", "125:2"); - putEntry("JUNGLE_SLAB", "125:3"); - putEntry("DIRT", "3:0"); - putEntry("COARSE_DIRT", "3:1"); - putEntry("RED_MUSHROOM", "40:0"); - putEntry("SIGN", "63:0"); - putEntry("PODZOL", "3:2"); - putEntry("DIAMOND_HELMET", "310:0"); - putEntry("REPEATER", "356:0"); - putEntry("PUMPKIN", "86:0"); - putEntry("OAK_BOAT", "333:0"); - putEntry("RABBIT_SPAWN_EGG", "383:101"); - putEntry("YELLOW_SHULKER_BOX", "223:0"); - putEntry("WOODEN_SHOVEL", "269:0"); - putEntry("POLAR_BEAR_SPAWN_EGG", "383:102"); - putEntry("BLUE_GLAZED_TERRACOTTA", "246:0"); - putEntry("HORSE_SPAWN_EGG", "383:100"); - putEntry("PARROT_SPAWN_EGG", "383:105"); - putEntry("DARK_OAK_DOOR", "431:0"); - putEntry("LLAMA_SPAWN_EGG", "383:103"); - putEntry("CHORUS_FLOWER", "200:0"); - putEntry("INFESTED_CRACKED_STONE_BRICKS", "97:4"); - putEntry("NETHER_WART", "115:0"); - putEntry("CHISELED_STONE_BRICKS", "97:5"); - putEntry("ENDER_PEARL", "368:0"); - putEntry("BEACON", "138:0"); - putEntry("FIRE", "51:0"); - putEntry("REDSTONE_ORE", "74:0"); - putEntry("INFESTED_STONE_BRICKS", "97:2"); - putEntry("ENCHANTED_GOLDEN_APPLE", "322:1"); - putEntry("INFESTED_MOSSY_STONE_BRICKS", "97:3"); - putEntry("COMPASS", "345:0"); - putEntry("INFESTED_STONE", "97:0"); - putEntry("INFESTED_COBBLESTONE", "97:1"); - putEntry("GOLDEN_APPLE", "322:0"); - putEntry("ORANGE_GLAZED_TERRACOTTA", "236:0"); - putEntry("FLINT_AND_STEEL", "259:0"); - putEntry("LEAD", "420:0"); - putEntry("ELYTRA", "443:0"); - putEntry("MAGMA_BLOCK", "213:0"); - putEntry("OAK_SLAB", "126:0"); - putEntry("MELON", "103:0"); - putEntry("JUNGLE_SLAB", "126:3"); - putEntry("ACACIA_SLAB", "126:4"); - putEntry("SPRUCE_SLAB", "126:1"); - putEntry("BIRCH_SLAB", "126:2"); - putEntry("COMPARATOR", "149:0"); - putEntry("GRASS", "2:0"); - putEntry("OAK_FENCE", "85:0"); - putEntry("FURNACE", "62:0"); - putEntry("DIAMOND_CHESTPLATE", "311:0"); - putEntry("LEATHER", "334:0"); - putEntry("COOKIE", "357:0"); - putEntry("LIME_SHULKER_BOX", "224:0"); - putEntry("BROWN_GLAZED_TERRACOTTA", "247:0"); - putEntry("JUNGLE_FENCE", "190:0"); - putEntry("DARK_OAK_SLAB", "126:5"); - putEntry("CHORUS_FRUIT", "432:0"); - putEntry("PURPUR_BLOCK", "201:0"); - putEntry("PUMPKIN_SEEDS", "361:0"); - putEntry("QUARTZ", "406:0"); - putEntry("JUNGLE_DOOR", "429:0"); - putEntry("TORCH", "50:0"); - putEntry("TRAP_DOOR", "96:0"); - putEntry("REDSTONE_ORE", "73:0"); - putEntry("WHITE_WALL_BANNER", "177:0"); - putEntry("HOPPER", "154:0"); - putEntry("EXPERIENCE_BOTTLE", "384:0"); - putEntry("TRIPWIRE_HOOK", "131:0"); - putEntry("YELLOW_CONCRETE_POWDER", "252:4"); - putEntry("LIGHT_BLUE_CONCRETE_POWDER", "252:3"); - putEntry("PINK_CONCRETE_POWDER", "252:6"); - putEntry("LIME_CONCRETE_POWDER", "252:5"); - putEntry("LIGHT_GRAY_CONCRETE_POWDER", "252:8"); - putEntry("IRON_LEGGINGS", "308:0"); - putEntry("GRAY_CONCRETE_POWDER", "252:7"); - putEntry("CYAN_CONCRETE_POWDER", "252:9"); - putEntry("WHITE_CONCRETE_POWDER", "252:0"); - putEntry("STONE_AXE", "275:0"); - putEntry("LEATHER_HELMET", "298:0"); - putEntry("MAGENTA_CONCRETE_POWDER", "252:2"); - putEntry("ORANGE_CONCRETE_POWDER", "252:1"); - putEntry("COOKED_SALMON", "350:1"); - putEntry("GOLDEN_HORSE_ARMOR", "418:0"); - putEntry("COOKED_FISH", "350:0"); - putEntry("STONE", "1:0"); - putEntry("GRANITE", "1:1"); - putEntry("FURNACE", "61:0"); - putEntry("JUKEBOX", "84:0"); - putEntry("POLISHED_GRANITE", "1:2"); - putEntry("DIORITE", "1:3"); - putEntry("POLISHED_DIORITE", "1:4"); - putEntry("SPRUCE_FENCE", "188:0"); - putEntry("ANDESITE", "1:5"); - putEntry("POLISHED_ANDESITE", "1:6"); - putEntry("SLIME_BLOCK", "165:0"); - putEntry("POTION", "373:0"); - putEntry("POTATOES", "142:0"); - putEntry("GOLDEN_CARROT", "396:0"); - putEntry("MUSIC_DISK_CHIRP", "2259:0"); - putEntry("LIME_GLAZED_TERRACOTTA", "240:0"); - putEntry("COAL", "263:0"); - putEntry("GOLDEN_AXE", "286:0"); - putEntry("CHARCOAL", "263:1"); - putEntry("LIGHT_GRAY_STAINED_GLASS", "95:8"); - putEntry("CYAN_STAINED_GLASS", "95:9"); - putEntry("PINK_STAINED_GLASS", "95:6"); - putEntry("QUARTZ_PILLAR", "155:2"); - putEntry("MELON_SEEDS", "362:0"); - putEntry("TNT_MINECART", "407:0"); - putEntry("GRAY_STAINED_GLASS", "95:7"); - putEntry("CHISELED_QUARTZ_BLOCK", "155:1"); - putEntry("DAYLIGHT_DETECTOR", "178:0"); - putEntry("WET_SPONGE", "19:1"); - putEntry("OAK_PRESSURE_PLATE", "72:0"); - putEntry("WHITE_STAINED_GLASS", "95:0"); - putEntry("SPONGE", "19:0"); - putEntry("ORANGE_STAINED_GLASS", "95:1"); - putEntry("YELLOW_STAINED_GLASS", "95:4"); - putEntry("TRIPWIRE", "132:0"); - putEntry("QUARTZ_BLOCK", "155:0"); - putEntry("LIME_STAINED_GLASS", "95:5"); - putEntry("MAGENTA_STAINED_GLASS", "95:2"); - putEntry("FIRE_CHARGE", "385:0"); - putEntry("LIGHT_BLUE_STAINED_GLASS", "95:3"); - putEntry("LEATHER_CHESTPLATE", "299:0"); - putEntry("IRON_BOOTS", "309:0"); - putEntry("BLUE_SHULKER_BOX", "230:0"); - putEntry("DIAMOND_SWORD", "276:0"); - putEntry("CACTUS_GREEN", "351:2"); - putEntry("ZOMBIE_HEAD", "397:2"); - putEntry("ROSE_RED", "351:1"); - putEntry("WITHER_HEAD", "397:1"); - putEntry("DIAMOND_HORSE_ARMOR", "419:0"); - putEntry("INK_SAC", "351:0"); - putEntry("CREEPER_HEAD", "397:4"); - putEntry("HUMAN_HEAD", "397:3"); - putEntry("BIRCH_FENCE", "189:0"); - putEntry("DRAGON_HEAD", "397:5"); - putEntry("AIR", "0:0"); - putEntry("FARMLAND", "60:0"); - putEntry("PINK_DYE", "351:9"); - putEntry("GRAY_DYE", "351:8"); - putEntry("SUGAR_CANE", "83:0"); - putEntry("LIGHT_GRAY_DYE", "351:7"); - putEntry("END_PORTAL_FRAME", "120:0"); - putEntry("OAK_BUTTON", "143:0"); - putEntry("BARRIER", "166:0"); - putEntry("CYAN_DYE", "351:6"); - putEntry("PURPLE_DYE", "351:5"); - putEntry("LAPIS_LAZULI", "351:4"); - putEntry("GLASS_BOTTLE", "374:0"); - putEntry("SKELETON_HEAD", "397:0"); - putEntry("COCOA_BEANS", "351:3"); - putEntry("MUSIC_DISK_BLOCKS", "2258:0"); - putEntry("VILLAGER_SPAWN_EGG", "383:120"); - putEntry("BROWN_CONCRETE_POWDER", "252:12"); - putEntry("GREEN_CONCRETE_POWDER", "252:13"); - putEntry("RED_CONCRETE_POWDER", "252:14"); - putEntry("BLACK_CONCRETE_POWDER", "252:15"); - putEntry("PINK_GLAZED_TERRACOTTA", "241:0"); - putEntry("STRING", "287:0"); - putEntry("PURPLE_CONCRETE_POWDER", "252:10"); - putEntry("BLUE_CONCRETE_POWDER", "252:11"); - putEntry("DIAMOND", "264:0"); - putEntry("HOPPER_MINECART", "408:0"); - putEntry("BOOK", "340:0"); - putEntry("QUARTZ_STAIRS", "156:0"); - putEntry("GREEN_CONCRETE", "159:13"); - putEntry("BROWN_CONCRETE", "159:12"); - putEntry("RED_SANDSTONE", "179:0"); - putEntry("BLUE_CONCRETE", "159:11"); - putEntry("CHISELED_RED_SANDSTONE", "179:1"); - putEntry("PURPLE_CONCRETE", "159:10"); - putEntry("SMOOTH_RED_SANDSTONE", "179:2"); - putEntry("BIRCH_LEAVES", "18:2"); - putEntry("BLACK_CARPET", "171:15"); - putEntry("SPRUCE_LEAVES", "18:1"); - putEntry("IRON_DOOR", "71:0"); - putEntry("RED_CARPET", "171:14"); - putEntry("OAK_LEAVES", "18:0"); - putEntry("BLACK_CONCRETE", "159:15"); - putEntry("GREEN_CARPET", "171:13"); - putEntry("REPEATER", "94:0"); - putEntry("RED_CONCRETE", "159:14"); - putEntry("BROWN_CARPET", "171:12"); - putEntry("EMERALD_BLOCK", "133:0"); - putEntry("BEEF", "363:0"); - putEntry("MYCELIUM", "110:0"); - putEntry("KNOWLEGE_BOOK", "386:0"); - putEntry("DIAMOND_SHOVEL", "277:0"); - putEntry("BLUE_CARPET", "171:11"); - putEntry("PURPLE_CARPET", "171:10"); - putEntry("BROWN_SHULKER_BOX", "231:0"); - putEntry("BONE", "352:0"); - putEntry("CARROT_ON_A_STICK", "398:0"); - putEntry("IRON_TRAPDOOR", "167:0"); - putEntry("STICKY_PISTON", "29:0"); - putEntry("CLAY", "82:0"); - putEntry("SKULL", "144:0"); - putEntry("END_STONE", "121:0"); - putEntry("SPIDER_EYE", "375:0"); - putEntry("SHULKER_SHELL", "450:0"); - putEntry("FEATHER", "288:0"); - putEntry("MUSIC_DISK_CAT", "2257:0"); - putEntry("JUNGLE_LEAVES", "18:3"); - putEntry("GRAY_GLAZED_TERRACOTTA", "242:0"); - putEntry("IRON_INGOT", "265:0"); - putEntry("WRITTEN_BOOK", "387:0"); - putEntry("PRISMARINE_SHARD", "409:0"); - putEntry("SLIME_BALL", "341:0"); - putEntry("SPRUCE_STAIRS", "134:0"); - putEntry("ACTIVATOR_RAIL", "157:0"); - putEntry("JUNGLE_WOOD", "17:3"); - putEntry("BIRCH_WOOD", "17:2"); - putEntry("SPRUCE_WOOD", "17:1"); - putEntry("REPEATER", "93:0"); - putEntry("OAK_WOOD", "17:0"); - putEntry("LILY_PAD", "111:0"); - putEntry("COOKED_BEEF", "364:0"); - putEntry("STRUCTURE_BLOCK", "255:0"); - putEntry("DIAMOND_PICKAXE", "278:0"); - putEntry("STONE_PRESSURE_PLATE", "70:0"); - putEntry("MUSIC_DISK_WAIT", "2267:0"); - putEntry("GREEN_SHULKER_BOX", "232:0"); - putEntry("DARK_PRISMARINE", "168:2"); - putEntry("IRON_DOOR", "330:0"); - putEntry("SUGAR", "353:0"); - putEntry("FERMENTED_SPIDER_EYE", "376:0"); - putEntry("NETHER_STAR", "399:0"); - putEntry("PRISMARINE_BRICKS", "168:1"); - putEntry("ANVIL", "145:0"); - putEntry("BLUE_STAINED_GLASS_PANE", "160:11"); - putEntry("PRISMARINE", "168:0"); - putEntry("PURPLE_STAINED_GLASS_PANE", "160:10"); - putEntry("DETECTOR_RAIL", "28:0"); - putEntry("DRAGON_EGG", "122:0"); - putEntry("GOLD_INGOT", "266:0"); - putEntry("GUNPOWDER", "289:0"); - putEntry("CACTUS", "81:0"); - putEntry("GREEN_STAINED_GLASS_PANE", "160:13"); - putEntry("MUSIC_DISK_13", "2256:0"); - putEntry("BROWN_STAINED_GLASS_PANE", "160:12"); - putEntry("BLACK_STAINED_GLASS_PANE", "160:15"); - putEntry("ORANGE_SHULKER_BOX", "220:0"); - putEntry("LIGHT_GRAY_GLAZED_TERRACOTTA", "243:0"); - putEntry("RED_STAINED_GLASS_PANE", "160:14"); + putEntry("PURPLE_STAINED_GLASS", "95:10"); + putEntry("BLUE_STAINED_GLASS", "95:11"); + putEntry("BROWN_STAINED_GLASS", "95:12"); + putEntry("BROWN_MUSHROOM", "39:0"); + putEntry("CHAINMAIL_LEGGINGS", "304:0"); + putEntry("LAVA_BUCKET", "327:0"); + putEntry("COMPARATOR", "150:0"); + putEntry("ACACIA_DOOR", "196:0"); + putEntry("CAULDRON", "380:0"); + putEntry("COAL_ORE", "16:0"); + putEntry("COAL_BLOCK", "173:0"); + putEntry("CAKE", "92:0"); + putEntry("OBSERVER", "218:0"); + putEntry("WOODEN_AXE", "271:0"); + putEntry("GOLDEN_HOE", "294:0"); + putEntry("WHITE_BANNER", "425:0"); + putEntry("MUSIC_DISK_11", "2266:0"); + putEntry("DARK_OAK_BOAT", "448:0"); + putEntry("FIREWORK_STAR", "402:0"); + putEntry("BRICK_STAIRS", "108:0"); + putEntry("DARK_OAK_LEAVES", "161:1"); + putEntry("ACACIA_LEAVES", "161:0"); + putEntry("PAPER", "339:0"); + putEntry("GOLDEN_LEGGINGS", "316:0"); + putEntry("POTATO", "392:0"); + putEntry("POWERED_RAIL", "27:0"); + putEntry("BIRCH_FENCE_GATE", "184:0"); + putEntry("SNOW_BLOCK", "80:0"); + putEntry("PURPLE_SHULKER_BOX", "229:0"); + putEntry("MUSHROOM_STEW", "282:0"); + putEntry("END_STONE_BRICKS", "206:0"); + putEntry("DRAGON_BREATH", "437:0"); + putEntry("RABBIT_FOOT", "414:0"); + putEntry("POPPY", "38:0"); + putEntry("BLUE_ORCHID", "38:1"); + putEntry("ALLIUM", "38:2"); + putEntry("AZURE_BLUET", "38:3"); + putEntry("RED_TULIP", "38:4"); + putEntry("WHITE_SHULKER_BOX", "219:0"); + putEntry("DAYLIGHT_DETECTOR", "151:0"); + putEntry("PACKED_ICE", "174:0"); + putEntry("DARK_OAK_DOOR", "197:0"); + putEntry("MINECART", "328:0"); + putEntry("ENDER_EYE", "381:0"); + putEntry("CHAINMAIL_BOOTS", "305:0"); + putEntry("IRON_ORE", "15:0"); + putEntry("JACK_O_LANTERN", "91:0"); + putEntry("STONE_SWORD", "272:0"); + putEntry("MUSIC_DISK_WARD", "2265:0"); + putEntry("END_CRYSTAL", "426:0"); + putEntry("TOTEM_OF_UNDYING", "449:0"); + putEntry("ENCHANTED_BOOK", "403:0"); + putEntry("WHEAT_SEEDS", "295:0"); + putEntry("OBSIDIAN", "49:0"); + putEntry("ACACIA_WOOD", "162:0"); + putEntry("JUNGLE_FENCE_GATE", "185:0"); + putEntry("GOLDEN_BOOTS", "317:0"); + putEntry("GHAST_TEAR", "370:0"); + putEntry("BAKED_POTATO", "393:0"); + putEntry("BED", "26:0"); + putEntry("DARK_OAK_WOOD", "162:1"); + putEntry("ORANGE_TULIP", "38:5"); + putEntry("BEETROOT", "207:0"); + putEntry("WHITE_TULIP", "38:6"); + putEntry("STONE_BRICK_STAIRS", "109:0"); + putEntry("GOLDEN_SWORD", "283:0"); + putEntry("PINK_TULIP", "38:7"); + putEntry("OXEYE_DAISY", "38:8"); + putEntry("APPLE", "260:0"); + putEntry("SPLASH_POTION", "438:0"); + putEntry("GREEN_STAINED_GLASS", "95:13"); + putEntry("RED_STAINED_GLASS", "95:14"); + putEntry("RABBIT_HIDE", "415:0"); + putEntry("BLACK_STAINED_GLASS", "95:15"); + putEntry("DANDELION", "37:0"); + putEntry("LARGE_FERN", "175:3"); + putEntry("ROSE_BUSH", "175:4"); + putEntry("PEONY", "175:5"); + putEntry("SUNFLOWER", "175:0"); + putEntry("LILAC", "175:1"); + putEntry("IRON_HELMET", "306:0"); + putEntry("TALL_GRASS", "175:2"); + putEntry("END_ROD", "198:0"); + putEntry("GLISTERING_MELON_SLICE", "382:0"); + putEntry("GOLD_ORE", "14:0"); + putEntry("REDSTONE_BLOCK", "152:0"); + putEntry("SADDLE", "329:0"); + putEntry("NETHER_PORTAL", "90:0"); + putEntry("MUSIC_DISK_STRAD", "2264:0"); + putEntry("BLACK_GLAZED_TERRACOTTA", "250:0"); + putEntry("SPRUCE_DOOR", "427:0"); + putEntry("COMPARATOR", "404:0"); + putEntry("STONE_SHOVEL", "273:0"); + putEntry("WHEAT", "296:0"); + putEntry("MOSSY_COBBLESTONE", "48:0"); + putEntry("SPECTRAL_ARROW", "439:0"); + putEntry("GRASS_PATH", "208:0"); + putEntry("FLOWER_POT", "140:0"); + putEntry("DARK_OAK_FENCE_GATE", "186:0"); + putEntry("GOLD_NUGGET", "371:0"); + putEntry("POISONOUS_POTATO", "394:0"); + putEntry("NOTE_BLOCK", "25:0"); + putEntry("ACACIA_STAIRS", "163:0"); + putEntry("FLINT", "318:0"); + putEntry("BOW", "261:0"); + putEntry("ARMOR_STAND", "416:0"); + putEntry("GOLDEN_SHOVEL", "284:0"); + putEntry("ELDER_GUARDIAN_SPAWN_EGG", "383:4"); + putEntry("WITHER_SPAWN_EGG", "383:5"); + putEntry("WHEAT", "59:0"); + putEntry("STRAY_SPAWN_EGG", "383:6"); + putEntry("MELON", "360:0"); + putEntry("BIRCH_DOOR", "428:0"); + putEntry("WHITE_BANNER", "176:0"); + putEntry("CHORUS_PLANT", "199:0"); + putEntry("ENDER_CHEST", "130:0"); + putEntry("NETHER_QUARTZ_ORE", "153:0"); + putEntry("GRAVEL", "13:0"); + putEntry("PURPLE_WOOL", "35:10"); + putEntry("LIME_CONCRETE", "251:5"); + putEntry("YELLOW_CONCRETE", "251:4"); + putEntry("GRAY_CONCRETE", "251:7"); + putEntry("PINK_CONCRETE", "251:6"); + putEntry("CYAN_CONCRETE", "251:9"); + putEntry("LIGHT_GRAY_CONCRETE", "251:8"); + putEntry("IRON_CHESTPLATE", "307:0"); + putEntry("ENVOKER_SPAWN_EGG", "383:34"); + putEntry("VEX_SPAWN_EGG", "383:35"); + putEntry("BLACK_WOOL", "35:15"); + putEntry("VINDICATOR_SPAWN_EGG", "383:36"); + putEntry("RED_WOOL", "35:14"); + putEntry("ORANGE_CONCRETE", "251:1"); + putEntry("NETHER_BRICK", "405:0"); + putEntry("GREEN_WOOL", "35:13"); + putEntry("WHITE_CONCRETE", "251:0"); + putEntry("BREAD", "297:0"); + putEntry("BROWN_WOOL", "35:12"); + putEntry("LIGHT_BLUE_CONCRETE", "251:3"); + putEntry("DONKEY_SPAWN_EGG", "383:31"); + putEntry("BLUE_WOOL", "35:11"); + putEntry("MAGENTA_CONCRETE", "251:2"); + putEntry("STONE_PICKAXE", "274:0"); + putEntry("MULE_SPAWN_EGG", "383:32"); + putEntry("MUSIC_DISK_STAL", "2263:0"); + putEntry("BOOKSHELF", "47:0"); + putEntry("IRON_HORSE_ARMOR", "417:0"); + putEntry("ZOMBIE_VILLAGER_SPAWN_EGG", "383:27"); + putEntry("END_GATEWAY", "209:0"); + putEntry("SKELETON_HORSE_SPAWN_EGG", "383:28"); + putEntry("ZOMBIE_HORSE_SPAWN_EGG", "383:29"); + putEntry("ACACIA_FENCE_GATE", "187:0"); + putEntry("NETHER_WART", "372:0"); + putEntry("MAP", "395:0"); + putEntry("SMOOTH_SANDSTONE", "24:2"); + putEntry("CHISELED_SANDSTONE", "24:1"); + putEntry("CARROTS", "141:0"); + putEntry("DARK_OAK_STAIRS", "164:0"); + putEntry("SANDSTONE", "24:0"); + putEntry("PORKCHOP", "319:0"); + putEntry("HUSK_SPAWN_EGG", "383:23"); + putEntry("ARROW", "262:0"); + putEntry("GOLDEN_PICKAXE", "285:0"); + putEntry("SAND", "12:0"); + putEntry("CRAFTING_TABLE", "58:0"); + putEntry("MOSSY_COBBLESTONE_WALL", "139:1"); + putEntry("BLAZE_ROD", "369:0"); + putEntry("CAVE_SPIDER_SPAWN_EGG", "383:59"); + putEntry("ENCHANTING_TABLE", "116:0"); + putEntry("COBBLESTONE_WALL", "139:0"); + putEntry("GRAY_WOOL", "35:7"); + putEntry("PINK_WOOL", "35:6"); + putEntry("LIME_WOOL", "35:5"); + putEntry("YELLOW_WOOL", "35:4"); + putEntry("LIGHT_BLUE_WOOL", "35:3"); + putEntry("LEATHER_LEGGINGS", "300:0"); + putEntry("SIGN", "323:0"); + putEntry("FISHING_ROD", "346:0"); + putEntry("MAGENTA_WOOL", "35:2"); + putEntry("ACACIA_FENCE", "192:0"); + putEntry("ORANGE_WOOL", "35:1"); + putEntry("RED_SAND", "12:1"); + putEntry("WHITE_WOOL", "35:0"); + putEntry("RED_SANDSTONE_STAIRS", "180:0"); + putEntry("CREEPER_SPAWN_EGG", "383:50"); + putEntry("MAGENTA_GLAZED_TERRACOTTA", "237:0"); + putEntry("SLIME_SPAWN_EGG", "383:55"); + putEntry("GHAST_SPAWN_EGG", "383:56"); + putEntry("ZOMBIE_PIGMAN_SPAWN_EGG", "383:57"); + putEntry("ENDERMAN_SPAWN_EGG", "383:58"); + putEntry("NETHER_WART_BLOCK", "214:0"); + putEntry("SKELETON_SPAWN_EGG", "383:51"); + putEntry("SPIDER_SPAWN_EGG", "383:52"); + putEntry("NAME_TAG", "421:0"); + putEntry("MUSIC_DISK_MELLOHI", "2262:0"); + putEntry("ZOMBIE_SPAWN_EGG", "383:54"); + putEntry("SPRUCE_BOAT", "444:0"); + putEntry("DISPENSER", "23:0"); + putEntry("TNT", "46:0"); + putEntry("LEVER", "69:0"); + putEntry("PUMPKIN_STEM", "104:0"); + putEntry("COCOA", "127:0"); + putEntry("MAP", "358:0"); + putEntry("MILK_BUCKET", "335:0"); + putEntry("WATER", "9:0"); + putEntry("DIAMOND_LEGGINGS", "312:0"); + putEntry("DARK_OAK_FENCE", "191:0"); + putEntry("PINK_SHULKER_BOX", "225:0"); + putEntry("GREEN_GLAZED_TERRACOTTA", "248:0"); + putEntry("CYAN_WOOL", "35:9"); + putEntry("LIGHT_GRAY_WOOL", "35:8"); + putEntry("PRISMARINE_CRYSTALS", "410:0"); + putEntry("PURPUR_PILLAR", "202:0"); + putEntry("POPPED_CHORUS_FRUIT", "433:0"); + putEntry("PISTON_HEAD", "34:0"); + putEntry("DIAMOND_BLOCK", "57:0"); + putEntry("LAVA", "11:0"); + putEntry("BREWING_STAND", "117:0"); + putEntry("CLOCK", "347:0"); + putEntry("HAY_BLOCK", "170:0"); + putEntry("SPRUCE_DOOR", "193:0"); + putEntry("OAK_DOOR", "324:0"); + putEntry("LEATHER_BOOTS", "301:0"); + putEntry("LIGHT_BLUE_GLAZED_TERRACOTTA", "238:0"); + putEntry("RED_NETHER_BRICKS", "215:0"); + putEntry("STONE_HOE", "291:0"); + putEntry("MUSIC_DISK_MALL", "2261:0"); + putEntry("COMMAND_BLOCK_MINECART", "422:0"); + putEntry("BIRCH_BOAT", "445:0"); + putEntry("LAPIS_BLOCK", "22:0"); + putEntry("SIGN", "68:0"); + putEntry("DANDELION_YELLOW", "351:11"); + putEntry("LIME_DYE", "351:10"); + putEntry("WOODEN_HOE", "290:0"); + putEntry("MAGENTA_DYE", "351:13"); + putEntry("MELON_STEM", "105:0"); + putEntry("LIGHT_BLUE_DYE", "351:12"); + putEntry("BONE_MEAL", "351:15"); + putEntry("SANDSTONE_STAIRS", "128:0"); + putEntry("ORANGE_DYE", "351:14"); + putEntry("BRICK", "336:0"); + putEntry("SHEARS", "359:0"); + putEntry("RED_SANDSTONE_SLAB", "181:0"); + putEntry("WATER", "8:0"); + putEntry("DIAMOND_BOOTS", "313:0"); + putEntry("BRICKS", "45:0"); + putEntry("SILVERFISH_SPAWN_EGG", "383:60"); + putEntry("BLAZE_SPAWN_EGG", "383:61"); + putEntry("GRAY_SHULKER_BOX", "226:0"); + putEntry("RED_GLAZED_TERRACOTTA", "249:0"); + putEntry("WITCH_SPAWN_EGG", "383:66"); + putEntry("ENDERMITE_SPAWN_EGG", "383:67"); + putEntry("RABBIT", "411:0"); + putEntry("GUARDIAN_SPAWN_EGG", "383:68"); + putEntry("SHULKER_SPAWN_EGG", "383:69"); + putEntry("PURPUR_STAIRS", "203:0"); + putEntry("MAGMA_CUBE_SPAWN_EGG", "383:62"); + putEntry("BAT_SPAWN_EGG", "383:65"); + putEntry("BEETROOT", "434:0"); + putEntry("PISTON", "33:0"); + putEntry("ICE", "79:0"); + putEntry("LAVA", "10:0"); + putEntry("GRAY_CARPET", "171:7"); + putEntry("LIGHT_GRAY_CARPET", "171:8"); + putEntry("CYAN_CARPET", "171:9"); + putEntry("CAULDRON", "118:0"); + putEntry("LIGHT_BLUE_CARPET", "171:3"); + putEntry("YELLOW_CARPET", "171:4"); + putEntry("LIME_CARPET", "171:5"); + putEntry("BUCKET", "325:0"); + putEntry("GLOWSTONE_DUST", "348:0"); + putEntry("PINK_CARPET", "171:6"); + putEntry("WHITE_CARPET", "171:0"); + putEntry("ORANGE_CARPET", "171:1"); + putEntry("CHAINMAIL_HELMET", "302:0"); + putEntry("DIAMOND_ORE", "56:0"); + putEntry("MAGENTA_CARPET", "171:2"); + putEntry("BIRCH_DOOR", "194:0"); + putEntry("SHEEP_SPAWN_EGG", "383:91"); + putEntry("COW_SPAWN_EGG", "383:92"); + putEntry("CHICKEN_SPAWN_EGG", "383:93"); + putEntry("SQUID_SPAWN_EGG", "383:94"); + putEntry("YELLOW_GLAZED_TERRACOTTA", "239:0"); + putEntry("PIG_SPAWN_EGG", "383:90"); + putEntry("PUMPKIN_PIE", "400:0"); + putEntry("JUNGLE_BOAT", "446:0"); + putEntry("BONE_BLOCK", "216:0"); + putEntry("IRON_HOE", "292:0"); + putEntry("WOLF_SPAWN_EGG", "383:95"); + putEntry("MUSIC_DISK_FAR", "2260:0"); + putEntry("MOOSHROOM_SPAWN_EGG", "383:96"); + putEntry("OCELOT_SPAWN_EGG", "383:98"); + putEntry("MUTTON", "423:0"); + putEntry("OAK_STAIRS", "44:2"); + putEntry("COBBLESTONE_SLAB", "44:3"); + putEntry("LAPIS_ORE", "21:0"); + putEntry("BRICK_SLAB", "44:4"); + putEntry("STONE_BRICK_SLAB", "44:5"); + putEntry("NETHER_BRICK_SLAB", "44:6"); + putEntry("MELON", "106:0"); + putEntry("EMERALD_ORE", "129:0"); + putEntry("QUARTZ_SLAB", "44:7"); + putEntry("GOLDEN_HELMET", "314:0"); + putEntry("FLOWER_POT", "390:0"); + putEntry("CLAY", "337:0"); + putEntry("BEDROCK", "7:0"); + putEntry("RED_SANDSTONE_SLAB", "182:0"); + putEntry("STONE_SLAB", "44:0"); + putEntry("COBBLESTONE_STAIRS", "67:0"); + putEntry("SANDSTONE_SLAB", "44:1"); + putEntry("LIGHT_GRAY_SHULKER_BOX", "227:0"); + putEntry("COOKED_RABBIT", "412:0"); + putEntry("BEETROOT_SEEDS", "435:0"); + putEntry("STICK", "280:0"); + putEntry("PURPUR_SLAB", "204:0"); + putEntry("DEAD_BUSH", "32:0"); + putEntry("END_PORTAL", "119:0"); + putEntry("RAW_SALMON", "349:1"); + putEntry("CHAINMAIL_CHESTPLATE", "303:0"); + putEntry("RAW_FISH", "349:0"); + putEntry("WATER_BUCKET", "326:0"); + putEntry("REDSTONE_WIRE", "55:0"); + putEntry("SNOW", "78:0"); + putEntry("CONCRETE", "172:0"); + putEntry("JUNGLE_DOOR", "195:0"); + putEntry("PUFFERFISH", "349:3"); + putEntry("TROPICAL_FISH", "349:2"); + putEntry("FIREWORK_ROCKET", "401:0"); + putEntry("COOKED_MUTTON", "424:0"); + putEntry("ACACIA_BOAT", "447:0"); + putEntry("STRUCTURE_VOID", "217:0"); + putEntry("DIAMOND_HOE", "293:0"); + putEntry("WOODEN_PICKAXE", "270:0"); + putEntry("COBBLESTONE_STAIRS", "43:3"); + putEntry("BRICK_STAIRS", "43:4"); + putEntry("CYAN_STAINED_GLASS_PANE", "160:9"); + putEntry("STONE_BRICK_STAIRS", "43:5"); + putEntry("LIGHT_GRAY_STAINED_GLASS_PANE", "160:8"); + putEntry("GLASS", "20:0"); + putEntry("NETHER_BRICK_STAIRS", "43:6"); + putEntry("GRAY_STAINED_GLASS_PANE", "160:7"); + putEntry("QUARTZ_STAIRS", "43:7"); + putEntry("OAK_FENCE_GATE", "107:0"); + putEntry("MAGENTA_STAINED_GLASS_PANE", "160:2"); + putEntry("GOLDEN_CHESTPLATE", "315:0"); + putEntry("SUGAR_CANE", "338:0"); + putEntry("CARROT", "391:0"); + putEntry("ORANGE_STAINED_GLASS_PANE", "160:1"); + putEntry("WHITE_STAINED_GLASS_PANE", "160:0"); + putEntry("OAK_SAPLING", "6:0"); + putEntry("PINK_STAINED_GLASS_PANE", "160:6"); + putEntry("SPRUCE_SAPLING", "6:1"); + putEntry("STONE_STAIRS", "43:0"); + putEntry("GLOWSTONE", "89:0"); + putEntry("LIME_STAINED_GLASS_PANE", "160:5"); + putEntry("BIRCH_SAPLING", "6:2"); + putEntry("SANDSTONE_STAIRS", "43:1"); + putEntry("YELLOW_STAINED_GLASS_PANE", "160:4"); + putEntry("SPRUCE_FENCE_GATE", "183:0"); + putEntry("JUNGLE_SAPLING", "6:3"); + putEntry("OAK_STAIRS", "43:2"); + putEntry("RAIL", "66:0"); + putEntry("LIGHT_BLUE_STAINED_GLASS_PANE", "160:3"); + putEntry("ACACIA_SAPLING", "6:4"); + putEntry("DARK_OAK_SAPLING", "6:5"); + putEntry("CYAN_SHULKER_BOX", "228:0"); + putEntry("BEETROOT_SOUP", "436:0"); + putEntry("PURPUR_SLAB", "205:0"); + putEntry("BOWL", "281:0"); + putEntry("RABBIT_STEW", "413:0"); + putEntry("CHEST_MINECART", "342:0"); + putEntry("RAW_CHICKEN", "365:0"); + putEntry("FERN", "31:2"); + putEntry("NETHER_BRICK", "112:0"); + putEntry("DROPPER", "158:0"); + putEntry("EMERALD", "388:0"); + putEntry("GRASS", "31:1"); + putEntry("TALL_GRASS", "31:0"); + putEntry("BITCH_STAIRS", "135:0"); + putEntry("CHEST", "54:0"); + putEntry("STONE_BUTTON", "77:0"); + putEntry("REPEATING_COMMAND_BLOCK", "210:0"); + putEntry("RED_SHULKER_BOX", "233:0"); + putEntry("IRON_SHOVEL", "256:0"); + putEntry("DIAMOND_AXE", "279:0"); + putEntry("TIPPED_ARROW", "440:0"); + putEntry("SEA_LANTERN", "169:0"); + putEntry("REDSTONE", "331:0"); + putEntry("BLAZE_POWDER", "377:0"); + putEntry("ENCHANTING_TABLE", "123:0"); + putEntry("TRAPPED_CHEST", "146:0"); + putEntry("OAK_PLANKS", "5:0"); + putEntry("SPRUCE_PLANKS", "5:1"); + putEntry("IRON_BLOCK", "42:0"); + putEntry("LADDER", "65:0"); + putEntry("SOUL_SAND", "88:0"); + putEntry("BIRCH_PLANKS", "5:2"); + putEntry("JUNGLE_PLANKS", "5:3"); + putEntry("RED_MUSHROOM_BLOCK", "100:0"); + putEntry("ACACIA_PLANKS", "5:4"); + putEntry("CAKE", "354:0"); + putEntry("DARK_OAK_PLANKS", "5:5"); + putEntry("IRON_SWORD", "267:0"); + putEntry("CYAN_GLAZED_TERRACOTTA", "244:0"); + putEntry("IRON_NUGGET", "452:0"); + putEntry("MAGENTA_SHULKER_BOX", "221:0"); + putEntry("NETHER_BRICK_FENCE", "113:0"); + putEntry("JUNGLE_STAIRS", "136:0"); + putEntry("CONCRETE", "159:0"); + putEntry("COOKED_PORKCHOP", "320:0"); + putEntry("COOKED_CHICKEN", "366:0"); + putEntry("ITEM_FRAME", "389:0"); + putEntry("COBWEB", "30:0"); + putEntry("YELLOW_CONCRETE", "159:4"); + putEntry("LIGHT_BLUE_CONCRETE", "159:3"); + putEntry("MAGENTA_CONCRETE", "159:2"); + putEntry("ORANGE_CONCRETE", "159:1"); + putEntry("OAK_STAIRS", "53:0"); + putEntry("REDSTONE_TORCH", "76:0"); + putEntry("BROWN_MUSHROOM_BLOCK", "99:0"); + putEntry("FURNACE_MINECART", "343:0"); + putEntry("BLACK_SHULKER_BOX", "234:0"); + putEntry("LINGERING_POTION", "441:0"); + putEntry("IRON_PICKAXE", "257:0"); + putEntry("LIGHT_GRAY_CONCRETE", "159:8"); + putEntry("GRAY_CONCRETE", "159:7"); + putEntry("PINK_CONCRETE", "159:6"); + putEntry("LIME_CONCRETE", "159:5"); + putEntry("CYAN_CONCRETE", "159:9"); + putEntry("CHAIN_COMMAND_BLOCK", "211:0"); + putEntry("LIGHT_WEIGHTED_PRESSURE_PLATE", "147:0"); + putEntry("IRON_BARS", "101:0"); + putEntry("MAGMA_CREAM", "378:0"); + putEntry("REDSTONE_LAMP", "123:0"); + putEntry("COBBLESTONE", "4:0"); + putEntry("GOLD_BLOCK", "41:0"); + putEntry("OAK_DOOR", "64:0"); + putEntry("SNOWBALL", "332:0"); + putEntry("BED", "355:0"); + putEntry("NETHERRACK", "87:0"); + putEntry("LIGHT_BLUE_SHULKER_BOX", "222:0"); + putEntry("PURPLE_GLAZED_TERRACOTTA", "245:0"); + putEntry("WOODEN_SWORD", "268:0"); + putEntry("ACACIA_DOOR", "430:0"); + putEntry("KNOWLEDGE_BOOK", "453:0"); + putEntry("COMMAND_BLOCK", "137:0"); + putEntry("CHISELED_STONE_BRICKS", "98:3"); + putEntry("ROTTEN_FLESH", "367:0"); + putEntry("NETHER_BRICK_STAIRS", "114:0"); + putEntry("BLACK_CONCRETE", "251:15"); + putEntry("SPAWNER", "52:0"); + putEntry("MOSSY_STONE_BRICKS", "98:1"); + putEntry("REDSTONE_TORCH", "75:0"); + putEntry("CRACKED_STONE_BRICKS", "98:2"); + putEntry("PAINTING", "321:0"); + putEntry("EGG", "344:0"); + putEntry("STONE_BRICKS", "98:0"); + putEntry("WHITE_GLAZED_TERRACOTTA", "235:0"); + putEntry("IRON_AXE", "258:0"); + putEntry("BLUE_CONCRETE", "251:11"); + putEntry("BROWN_CONCRETE", "251:12"); + putEntry("GREEN_CONCRETE", "251:13"); + putEntry("RED_CONCRETE", "251:14"); + putEntry("SHIELD", "442:0"); + putEntry("FROSTED_ICE", "212:0"); + putEntry("PURPLE_CONCRETE", "251:10"); + putEntry("GLASS_PANE", "102:0"); + putEntry("OAK_SLAB", "125:0"); + putEntry("SPRUCE_SLAB", "125:1"); + putEntry("HEAVY_WEIGHTED_PRESSURE_PLATE", "148:0"); + putEntry("BREWING_STAND", "379:0"); + putEntry("ACACIA_SLAB", "125:4"); + putEntry("DARK_OAK_SLAB", "125:5"); + putEntry("BIRCH_SLAB", "125:2"); + putEntry("JUNGLE_SLAB", "125:3"); + putEntry("DIRT", "3:0"); + putEntry("COARSE_DIRT", "3:1"); + putEntry("RED_MUSHROOM", "40:0"); + putEntry("SIGN", "63:0"); + putEntry("PODZOL", "3:2"); + putEntry("DIAMOND_HELMET", "310:0"); + putEntry("REPEATER", "356:0"); + putEntry("PUMPKIN", "86:0"); + putEntry("OAK_BOAT", "333:0"); + putEntry("RABBIT_SPAWN_EGG", "383:101"); + putEntry("YELLOW_SHULKER_BOX", "223:0"); + putEntry("WOODEN_SHOVEL", "269:0"); + putEntry("POLAR_BEAR_SPAWN_EGG", "383:102"); + putEntry("BLUE_GLAZED_TERRACOTTA", "246:0"); + putEntry("HORSE_SPAWN_EGG", "383:100"); + putEntry("PARROT_SPAWN_EGG", "383:105"); + putEntry("DARK_OAK_DOOR", "431:0"); + putEntry("LLAMA_SPAWN_EGG", "383:103"); + putEntry("CHORUS_FLOWER", "200:0"); + putEntry("INFESTED_CRACKED_STONE_BRICKS", "97:4"); + putEntry("NETHER_WART", "115:0"); + putEntry("CHISELED_STONE_BRICKS", "97:5"); + putEntry("ENDER_PEARL", "368:0"); + putEntry("BEACON", "138:0"); + putEntry("FIRE", "51:0"); + putEntry("REDSTONE_ORE", "74:0"); + putEntry("INFESTED_STONE_BRICKS", "97:2"); + putEntry("ENCHANTED_GOLDEN_APPLE", "322:1"); + putEntry("INFESTED_MOSSY_STONE_BRICKS", "97:3"); + putEntry("COMPASS", "345:0"); + putEntry("INFESTED_STONE", "97:0"); + putEntry("INFESTED_COBBLESTONE", "97:1"); + putEntry("GOLDEN_APPLE", "322:0"); + putEntry("ORANGE_GLAZED_TERRACOTTA", "236:0"); + putEntry("FLINT_AND_STEEL", "259:0"); + putEntry("LEAD", "420:0"); + putEntry("ELYTRA", "443:0"); + putEntry("MAGMA_BLOCK", "213:0"); + putEntry("OAK_SLAB", "126:0"); + putEntry("MELON", "103:0"); + putEntry("JUNGLE_SLAB", "126:3"); + putEntry("ACACIA_SLAB", "126:4"); + putEntry("SPRUCE_SLAB", "126:1"); + putEntry("BIRCH_SLAB", "126:2"); + putEntry("COMPARATOR", "149:0"); + putEntry("GRASS", "2:0"); + putEntry("OAK_FENCE", "85:0"); + putEntry("FURNACE", "62:0"); + putEntry("DIAMOND_CHESTPLATE", "311:0"); + putEntry("LEATHER", "334:0"); + putEntry("COOKIE", "357:0"); + putEntry("LIME_SHULKER_BOX", "224:0"); + putEntry("BROWN_GLAZED_TERRACOTTA", "247:0"); + putEntry("JUNGLE_FENCE", "190:0"); + putEntry("DARK_OAK_SLAB", "126:5"); + putEntry("CHORUS_FRUIT", "432:0"); + putEntry("PURPUR_BLOCK", "201:0"); + putEntry("PUMPKIN_SEEDS", "361:0"); + putEntry("QUARTZ", "406:0"); + putEntry("JUNGLE_DOOR", "429:0"); + putEntry("TORCH", "50:0"); + putEntry("TRAP_DOOR", "96:0"); + putEntry("REDSTONE_ORE", "73:0"); + putEntry("WHITE_WALL_BANNER", "177:0"); + putEntry("HOPPER", "154:0"); + putEntry("EXPERIENCE_BOTTLE", "384:0"); + putEntry("TRIPWIRE_HOOK", "131:0"); + putEntry("YELLOW_CONCRETE_POWDER", "252:4"); + putEntry("LIGHT_BLUE_CONCRETE_POWDER", "252:3"); + putEntry("PINK_CONCRETE_POWDER", "252:6"); + putEntry("LIME_CONCRETE_POWDER", "252:5"); + putEntry("LIGHT_GRAY_CONCRETE_POWDER", "252:8"); + putEntry("IRON_LEGGINGS", "308:0"); + putEntry("GRAY_CONCRETE_POWDER", "252:7"); + putEntry("CYAN_CONCRETE_POWDER", "252:9"); + putEntry("WHITE_CONCRETE_POWDER", "252:0"); + putEntry("STONE_AXE", "275:0"); + putEntry("LEATHER_HELMET", "298:0"); + putEntry("MAGENTA_CONCRETE_POWDER", "252:2"); + putEntry("ORANGE_CONCRETE_POWDER", "252:1"); + putEntry("COOKED_SALMON", "350:1"); + putEntry("GOLDEN_HORSE_ARMOR", "418:0"); + putEntry("COOKED_FISH", "350:0"); + putEntry("STONE", "1:0"); + putEntry("GRANITE", "1:1"); + putEntry("FURNACE", "61:0"); + putEntry("JUKEBOX", "84:0"); + putEntry("POLISHED_GRANITE", "1:2"); + putEntry("DIORITE", "1:3"); + putEntry("POLISHED_DIORITE", "1:4"); + putEntry("SPRUCE_FENCE", "188:0"); + putEntry("ANDESITE", "1:5"); + putEntry("POLISHED_ANDESITE", "1:6"); + putEntry("SLIME_BLOCK", "165:0"); + putEntry("POTION", "373:0"); + putEntry("POTATOES", "142:0"); + putEntry("GOLDEN_CARROT", "396:0"); + putEntry("MUSIC_DISK_CHIRP", "2259:0"); + putEntry("LIME_GLAZED_TERRACOTTA", "240:0"); + putEntry("COAL", "263:0"); + putEntry("GOLDEN_AXE", "286:0"); + putEntry("CHARCOAL", "263:1"); + putEntry("LIGHT_GRAY_STAINED_GLASS", "95:8"); + putEntry("CYAN_STAINED_GLASS", "95:9"); + putEntry("PINK_STAINED_GLASS", "95:6"); + putEntry("QUARTZ_PILLAR", "155:2"); + putEntry("MELON_SEEDS", "362:0"); + putEntry("TNT_MINECART", "407:0"); + putEntry("GRAY_STAINED_GLASS", "95:7"); + putEntry("CHISELED_QUARTZ_BLOCK", "155:1"); + putEntry("DAYLIGHT_DETECTOR", "178:0"); + putEntry("WET_SPONGE", "19:1"); + putEntry("OAK_PRESSURE_PLATE", "72:0"); + putEntry("WHITE_STAINED_GLASS", "95:0"); + putEntry("SPONGE", "19:0"); + putEntry("ORANGE_STAINED_GLASS", "95:1"); + putEntry("YELLOW_STAINED_GLASS", "95:4"); + putEntry("TRIPWIRE", "132:0"); + putEntry("QUARTZ_BLOCK", "155:0"); + putEntry("LIME_STAINED_GLASS", "95:5"); + putEntry("MAGENTA_STAINED_GLASS", "95:2"); + putEntry("FIRE_CHARGE", "385:0"); + putEntry("LIGHT_BLUE_STAINED_GLASS", "95:3"); + putEntry("LEATHER_CHESTPLATE", "299:0"); + putEntry("IRON_BOOTS", "309:0"); + putEntry("BLUE_SHULKER_BOX", "230:0"); + putEntry("DIAMOND_SWORD", "276:0"); + putEntry("CACTUS_GREEN", "351:2"); + putEntry("ZOMBIE_HEAD", "397:2"); + putEntry("ROSE_RED", "351:1"); + putEntry("WITHER_HEAD", "397:1"); + putEntry("DIAMOND_HORSE_ARMOR", "419:0"); + putEntry("INK_SAC", "351:0"); + putEntry("CREEPER_HEAD", "397:4"); + putEntry("HUMAN_HEAD", "397:3"); + putEntry("BIRCH_FENCE", "189:0"); + putEntry("DRAGON_HEAD", "397:5"); + putEntry("AIR", "0:0"); + putEntry("FARMLAND", "60:0"); + putEntry("PINK_DYE", "351:9"); + putEntry("GRAY_DYE", "351:8"); + putEntry("SUGAR_CANE", "83:0"); + putEntry("LIGHT_GRAY_DYE", "351:7"); + putEntry("END_PORTAL_FRAME", "120:0"); + putEntry("OAK_BUTTON", "143:0"); + putEntry("BARRIER", "166:0"); + putEntry("CYAN_DYE", "351:6"); + putEntry("PURPLE_DYE", "351:5"); + putEntry("LAPIS_LAZULI", "351:4"); + putEntry("GLASS_BOTTLE", "374:0"); + putEntry("SKELETON_HEAD", "397:0"); + putEntry("COCOA_BEANS", "351:3"); + putEntry("MUSIC_DISK_BLOCKS", "2258:0"); + putEntry("VILLAGER_SPAWN_EGG", "383:120"); + putEntry("BROWN_CONCRETE_POWDER", "252:12"); + putEntry("GREEN_CONCRETE_POWDER", "252:13"); + putEntry("RED_CONCRETE_POWDER", "252:14"); + putEntry("BLACK_CONCRETE_POWDER", "252:15"); + putEntry("PINK_GLAZED_TERRACOTTA", "241:0"); + putEntry("STRING", "287:0"); + putEntry("PURPLE_CONCRETE_POWDER", "252:10"); + putEntry("BLUE_CONCRETE_POWDER", "252:11"); + putEntry("DIAMOND", "264:0"); + putEntry("HOPPER_MINECART", "408:0"); + putEntry("BOOK", "340:0"); + putEntry("QUARTZ_STAIRS", "156:0"); + putEntry("GREEN_CONCRETE", "159:13"); + putEntry("BROWN_CONCRETE", "159:12"); + putEntry("RED_SANDSTONE", "179:0"); + putEntry("BLUE_CONCRETE", "159:11"); + putEntry("CHISELED_RED_SANDSTONE", "179:1"); + putEntry("PURPLE_CONCRETE", "159:10"); + putEntry("SMOOTH_RED_SANDSTONE", "179:2"); + putEntry("BIRCH_LEAVES", "18:2"); + putEntry("BLACK_CARPET", "171:15"); + putEntry("SPRUCE_LEAVES", "18:1"); + putEntry("IRON_DOOR", "71:0"); + putEntry("RED_CARPET", "171:14"); + putEntry("OAK_LEAVES", "18:0"); + putEntry("BLACK_CONCRETE", "159:15"); + putEntry("GREEN_CARPET", "171:13"); + putEntry("REPEATER", "94:0"); + putEntry("RED_CONCRETE", "159:14"); + putEntry("BROWN_CARPET", "171:12"); + putEntry("EMERALD_BLOCK", "133:0"); + putEntry("BEEF", "363:0"); + putEntry("MYCELIUM", "110:0"); + putEntry("KNOWLEGE_BOOK", "386:0"); + putEntry("DIAMOND_SHOVEL", "277:0"); + putEntry("BLUE_CARPET", "171:11"); + putEntry("PURPLE_CARPET", "171:10"); + putEntry("BROWN_SHULKER_BOX", "231:0"); + putEntry("BONE", "352:0"); + putEntry("CARROT_ON_A_STICK", "398:0"); + putEntry("IRON_TRAPDOOR", "167:0"); + putEntry("STICKY_PISTON", "29:0"); + putEntry("CLAY", "82:0"); + putEntry("SKULL", "144:0"); + putEntry("END_STONE", "121:0"); + putEntry("SPIDER_EYE", "375:0"); + putEntry("SHULKER_SHELL", "450:0"); + putEntry("FEATHER", "288:0"); + putEntry("MUSIC_DISK_CAT", "2257:0"); + putEntry("JUNGLE_LEAVES", "18:3"); + putEntry("GRAY_GLAZED_TERRACOTTA", "242:0"); + putEntry("IRON_INGOT", "265:0"); + putEntry("WRITTEN_BOOK", "387:0"); + putEntry("PRISMARINE_SHARD", "409:0"); + putEntry("SLIME_BALL", "341:0"); + putEntry("SPRUCE_STAIRS", "134:0"); + putEntry("ACTIVATOR_RAIL", "157:0"); + putEntry("JUNGLE_WOOD", "17:3"); + putEntry("BIRCH_WOOD", "17:2"); + putEntry("SPRUCE_WOOD", "17:1"); + putEntry("REPEATER", "93:0"); + putEntry("OAK_WOOD", "17:0"); + putEntry("LILY_PAD", "111:0"); + putEntry("COOKED_BEEF", "364:0"); + putEntry("STRUCTURE_BLOCK", "255:0"); + putEntry("DIAMOND_PICKAXE", "278:0"); + putEntry("STONE_PRESSURE_PLATE", "70:0"); + putEntry("MUSIC_DISK_WAIT", "2267:0"); + putEntry("GREEN_SHULKER_BOX", "232:0"); + putEntry("DARK_PRISMARINE", "168:2"); + putEntry("IRON_DOOR", "330:0"); + putEntry("SUGAR", "353:0"); + putEntry("FERMENTED_SPIDER_EYE", "376:0"); + putEntry("NETHER_STAR", "399:0"); + putEntry("PRISMARINE_BRICKS", "168:1"); + putEntry("ANVIL", "145:0"); + putEntry("BLUE_STAINED_GLASS_PANE", "160:11"); + putEntry("PRISMARINE", "168:0"); + putEntry("PURPLE_STAINED_GLASS_PANE", "160:10"); + putEntry("DETECTOR_RAIL", "28:0"); + putEntry("DRAGON_EGG", "122:0"); + putEntry("GOLD_INGOT", "266:0"); + putEntry("GUNPOWDER", "289:0"); + putEntry("CACTUS", "81:0"); + putEntry("GREEN_STAINED_GLASS_PANE", "160:13"); + putEntry("MUSIC_DISK_13", "2256:0"); + putEntry("BROWN_STAINED_GLASS_PANE", "160:12"); + putEntry("BLACK_STAINED_GLASS_PANE", "160:15"); + putEntry("ORANGE_SHULKER_BOX", "220:0"); + putEntry("LIGHT_GRAY_GLAZED_TERRACOTTA", "243:0"); + putEntry("RED_STAINED_GLASS_PANE", "160:14"); } - + private static void putEntry(String material, String idColonData) { - int colonIndex = idColonData.indexOf(':'); - int id = Integer.parseInt(idColonData.substring(0, colonIndex)); - short data = Short.parseShort(idColonData.substring(colonIndex + 1)); - MAP.put(material, new MatLibEntry(id, data)); + int colonIndex = idColonData.indexOf(':'); + int id = Integer.parseInt(idColonData.substring(0, colonIndex)); + short data = Short.parseShort(idColonData.substring(colonIndex + 1)); + MAP.put(material, new MatLibEntry(id, data)); } public void printRev() { - for (Entry entry : MAP.entrySet()) { - MatLibEntry itemInfo = entry.getValue(); - System.out.println("putEntry(\"" + entry.getKey() + "\", \"" + itemInfo.getId() + ":" + itemInfo.getData() + "\");"); - } + MAP.entrySet().forEach(entry -> { + MatLibEntry itemInfo = entry.getValue(); + System.out.println("putEntry(\"" + entry.getKey() + "\", \"" + itemInfo.getId() + ":" + itemInfo.getData() + "\");"); + }); } @AllArgsConstructor @Getter public static class MatLibEntry { - - private final int id; - private final short data; - + + private final int id; + private final short data; + } } diff --git a/src/com/pablo67340/guishop/util/XMaterial.java b/src/com/pablo67340/guishop/util/XMaterial.java index aadfabf..3bbd37a 100644 --- a/src/com/pablo67340/guishop/util/XMaterial.java +++ b/src/com/pablo67340/guishop/util/XMaterial.java @@ -1,10 +1,8 @@ -package com.pablo67340.guishop.util; - /* * The MIT License (MIT) * * Copyright (c) 2018 Hex_27 - * Copyright (c) 2019 Crypto Morin + * Copyright (c) 2020 Crypto Morin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -22,12 +20,13 @@ * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +package com.pablo67340.guishop.util; + import com.google.common.base.Enums; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang.WordUtils; @@ -40,35 +39,36 @@ import java.util.*; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; -import java.util.stream.Collectors; +import java.util.regex.PatternSyntaxException; -/* - * References - * - * * * GitHub: https://github.com/CryptoMorin/XSeries/blob/master/XMaterial.java - * * XSeries: https://www.spigotmc.org/threads/378136/ +/** + * XMaterial - Data Values/Pre-flattening
+ * 1.13 and above as priority. + *

+ * This class is mainly designed to support {@link ItemStack}. If you want to use it on blocks, you'll have to use + * XBlock + *

* Pre-flattening: https://minecraft.gamepedia.com/Java_Edition_data_values/Pre-flattening * Materials: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html - * Materials (1.8): https://helpch.at/docs/1.8/org/bukkit/Material.html + * Materials (1.12): https://helpch.at/docs/1.12.2/index.html?org/bukkit/Material.html * Material IDs: https://minecraft-ids.grahamedgecombe.com/ * Material Source Code: https://hub.spigotmc.org/stash/projects/SPIGOT/repos/bukkit/browse/src/main/java/org/bukkit/Material.java * XMaterial v1: https://www.spigotmc.org/threads/329630/ - */ - -/** - * XMaterial - Data Values/Pre-flattening
- * Supports 1.8-1.15
- * 1.13 and above as priority. + *

+ * This class will throw a "unsupported material" error if someone tries to use an item with an invalid data value which can only happen in 1.12 servers and below or when the + * utility is missing a new material in that specific version. + * To get an invalid item, (aka Missing Texture Block) you can use the command + * /give @p minecraft:dirt 1 10 where 1 is the item amount, and 10 is the data value. The material {@link #DIRT} with a data value of {@code 10} doesn't exist. * * @author Crypto Morin - * @version 3.1.0 + * @version 7.0.0.1 * @see Material * @see ItemStack */ public enum XMaterial { ACACIA_BOAT("BOAT_ACACIA"), ACACIA_BUTTON("WOOD_BUTTON"), - ACACIA_DOOR("ACACIA_DOOR_ITEM"), + ACACIA_DOOR("ACACIA_DOOR", "ACACIA_DOOR_ITEM"), ACACIA_FENCE, ACACIA_FENCE_GATE, ACACIA_LEAVES("LEAVES_2"), @@ -76,21 +76,23 @@ public enum XMaterial { ACACIA_PLANKS(4, "WOOD"), ACACIA_PRESSURE_PLATE("WOOD_PLATE"), ACACIA_SAPLING(4, "SAPLING"), - ACACIA_SIGN("SIGN"), - ACACIA_SLAB(4, "WOOD_STEP", "WOODEN_SLAB", "WOODEN_SLAB"), + ACACIA_SIGN("SIGN_POST", "SIGN"), + ACACIA_SLAB(4, "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB"), ACACIA_STAIRS, ACACIA_TRAPDOOR("TRAP_DOOR"), - ACACIA_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + ACACIA_WALL_SIGN("WALL_SIGN"), ACACIA_WOOD("LOG_2"), ACTIVATOR_RAIL, /** * https://minecraft.gamepedia.com/Air + * {@link Material#isAir()} * * @see #VOID_AIR * @see #CAVE_AIR */ AIR, ALLIUM(2, "RED_ROSE"), + ANCIENT_DEBRIS(16), ANDESITE(5, "STONE"), ANDESITE_SLAB, ANDESITE_STAIRS, @@ -103,25 +105,30 @@ public enum XMaterial { ATTACHED_PUMPKIN_STEM(7, "PUMPKIN_STEM"), AZURE_BLUET(3, "RED_ROSE"), BAKED_POTATO, - BAMBOO("1.14", "SUGAR_CANE"), - BAMBOO_SAPLING("1.14"), - BARREL("1.14", "CHEST"), + BAMBOO(0, 14, "SUGAR_CANE", ""), + BAMBOO_SAPLING(14), + BARREL(0, 14, "CHEST", ""), BARRIER, + BASALT(16), BAT_SPAWN_EGG(65, "MONSTER_EGG"), BEACON, BEDROCK, BEEF("RAW_BEEF"), - BEEHIVE("1.15"), + BEEHIVE(15), + /** + * Beetroot is a known material in pre-1.13 + * Use XBlock when comparing block types. + */ BEETROOT("BEETROOT_BLOCK"), BEETROOTS("BEETROOT"), BEETROOT_SEEDS, BEETROOT_SOUP, - BEE_NEST("1.15"), - BEE_SPAWN_EGG("1.15"), - BELL("1.14"), + BEE_NEST(15), + BEE_SPAWN_EGG(15), + BELL(14), BIRCH_BOAT("BOAT_BIRCH"), BIRCH_BUTTON("WOOD_BUTTON"), - BIRCH_DOOR("BIRCH_DOOR_ITEM"), + BIRCH_DOOR("BIRCH_DOOR", "BIRCH_DOOR_ITEM"), BIRCH_FENCE, BIRCH_FENCE_GATE, BIRCH_LEAVES(2, "LEAVES"), @@ -129,69 +136,73 @@ public enum XMaterial { BIRCH_PLANKS(2, "WOOD"), BIRCH_PRESSURE_PLATE("WOOD_PLATE"), BIRCH_SAPLING(2, "SAPLING"), - BIRCH_SIGN("SIGN"), - BIRCH_SLAB(2, "WOOD_STEP", "WOODEN_SLAB", "WOODEN_SLAB"), + BIRCH_SIGN("SIGN_POST", "SIGN"), + BIRCH_SLAB(2, "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB"), BIRCH_STAIRS("BIRCH_WOOD_STAIRS"), BIRCH_TRAPDOOR("TRAP_DOOR"), - BIRCH_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + BIRCH_WALL_SIGN("WALL_SIGN"), BIRCH_WOOD(2, "LOG"), - BLACK_BANNER("BANNER", "STANDING_BANNER"), - BLACK_BED(15, "BED", "BED_BLOCK"), + BLACKSTONE(16), + BLACKSTONE_SLAB(16), + BLACKSTONE_STAIRS(16), + BLACKSTONE_WALL(16), + BLACK_BANNER("STANDING_BANNER", "BANNER"), + BLACK_BED(15, "BED_BLOCK", "BED"), BLACK_CARPET(15, "CARPET"), BLACK_CONCRETE(15, "CONCRETE"), BLACK_CONCRETE_POWDER(15, "CONCRETE_POWDER"), - BLACK_DYE("1.14", "INK_SAC"), - BLACK_GLAZED_TERRACOTTA(15, "1.12", "HARD_CLAY", "STAINED_CLAY", "BLACK_TERRACOTTA"), + BLACK_DYE(0, 14, "INK_SACK", "INK_SAC"), + BLACK_GLAZED_TERRACOTTA(15, 12, "HARD_CLAY", "STAINED_CLAY", "BLACK_TERRACOTTA"), BLACK_SHULKER_BOX, BLACK_STAINED_GLASS(15, "STAINED_GLASS"), BLACK_STAINED_GLASS_PANE(15, "STAINED_GLASS_PANE"), BLACK_TERRACOTTA(15, "HARD_CLAY", "STAINED_CLAY"), BLACK_WALL_BANNER("WALL_BANNER"), BLACK_WOOL(15, "WOOL"), - BLAST_FURNACE("1.14", "FURNACE"), + BLAST_FURNACE(0, 14, "FURNACE", ""), BLAZE_POWDER, BLAZE_ROD, BLAZE_SPAWN_EGG(61, "MONSTER_EGG"), - BLUE_BANNER(11, "BANNER", "STANDING_BANNER"), - BLUE_BED(4, "BED", "BED_BLOCK"), + BLUE_BANNER(4, "STANDING_BANNER", "BANNER"), + BLUE_BED(11, "BED_BLOCK", "BED"), BLUE_CARPET(11, "CARPET"), BLUE_CONCRETE(11, "CONCRETE"), BLUE_CONCRETE_POWDER(11, "CONCRETE_POWDER"), - BLUE_DYE(4, "INK_SAC", "LAPIS_LAZULI"), - BLUE_GLAZED_TERRACOTTA(11, "1.12", "HARD_CLAY", "STAINED_CLAY", "BLUE_TERRACOTTA"), - BLUE_ICE("1.13", "PACKED_ICE"), + BLUE_DYE(4, "INK_SACK", "LAPIS_LAZULI"), + BLUE_GLAZED_TERRACOTTA(11, 12, "HARD_CLAY", "STAINED_CLAY", "BLUE_TERRACOTTA"), + BLUE_ICE(0, 13, "PACKED_ICE", ""), BLUE_ORCHID(1, "RED_ROSE"), BLUE_SHULKER_BOX, BLUE_STAINED_GLASS(11, "STAINED_GLASS"), BLUE_STAINED_GLASS_PANE(11, "THIN_GLASS", "STAINED_GLASS_PANE"), - BLUE_TERRACOTTA(11, "STAINED_CLAY"), - BLUE_WALL_BANNER(11, "WALL_BANNER"), + BLUE_TERRACOTTA(11, "HARD_CLAY", "STAINED_CLAY"), + BLUE_WALL_BANNER(4, "WALL_BANNER"), BLUE_WOOL(11, "WOOL"), BONE, BONE_BLOCK, - BONE_MEAL(15, "INK_SAC"), + BONE_MEAL(15, "INK_SACK"), BOOK, BOOKSHELF, BOW, BOWL, - BRAIN_CORAL("1.13"), - BRAIN_CORAL_BLOCK("1.13"), - BRAIN_CORAL_FAN("1.13"), + BRAIN_CORAL(13), + BRAIN_CORAL_BLOCK(13), + BRAIN_CORAL_FAN(13), BRAIN_CORAL_WALL_FAN, BREAD, - BREWING_STAND("BREWING_STAND_ITEM"), + BREWING_STAND("BREWING_STAND", "BREWING_STAND_ITEM"), BRICK("CLAY_BRICK"), BRICKS("BRICK"), BRICK_SLAB(4, "STEP"), BRICK_STAIRS, BRICK_WALL, - BROWN_BANNER(3, "BANNER", "STANDING_BANNER"), - BROWN_BED(12, "BED", "BED_BLOCK"), + BROWN_BANNER(3, "STANDING_BANNER", "BANNER"), + BROWN_BED(12, "BED_BLOCK", "BED"), BROWN_CARPET(12, "CARPET"), BROWN_CONCRETE(12, "CONCRETE"), BROWN_CONCRETE_POWDER(12, "CONCRETE_POWDER"), - BROWN_DYE(3, "INK_SAC", "COCOA", "DYE"), - BROWN_GLAZED_TERRACOTTA(12, "1.12", "HARD_CLAY", "STAINED_CLAY", "BROWN_TERRACOTTA"), + BROWN_DYE(3, "INK_SACK", "DYE", "COCOA_BEANS"), + BROWN_GLAZED_TERRACOTTA(12, 12, "HARD_CLAY", "STAINED_CLAY", "BROWN_TERRACOTTA"), BROWN_MUSHROOM, BROWN_MUSHROOM_BLOCK("BROWN_MUSHROOM", "HUGE_MUSHROOM_1"), BROWN_SHULKER_BOX, @@ -200,22 +211,22 @@ public enum XMaterial { BROWN_TERRACOTTA(12, "STAINED_CLAY"), BROWN_WALL_BANNER(3, "WALL_BANNER"), BROWN_WOOL(12, "WOOL"), - BUBBLE_COLUMN("1.13"), - BUBBLE_CORAL("1.13"), - BUBBLE_CORAL_BLOCK("1.13"), - BUBBLE_CORAL_FAN("1.13"), + BUBBLE_COLUMN(13), + BUBBLE_CORAL(13), + BUBBLE_CORAL_BLOCK(13), + BUBBLE_CORAL_FAN(13), BUBBLE_CORAL_WALL_FAN, BUCKET, CACTUS, CAKE("CAKE_BLOCK"), - CAMPFIRE("1.14"), + CAMPFIRE(14), CARROT("CARROT_ITEM"), CARROTS("CARROT"), CARROT_ON_A_STICK("CARROT_STICK"), - CARTOGRAPHY_TABLE("1.14", "CRAFTING_TABLE"), - CARVED_PUMPKIN(1, "1.13", "PUMPKIN"), + CARTOGRAPHY_TABLE(0, 14, "CRAFTING_TABLE", ""), + CARVED_PUMPKIN(1, 13, "PUMPKIN", ""), CAT_SPAWN_EGG, - CAULDRON("CAULDRON_ITEM"), + CAULDRON("CAULDRON", "CAULDRON_ITEM"), /** * 1.13 tag is not added because it's the same thing as {@link #AIR} * @@ -223,6 +234,7 @@ public enum XMaterial { */ CAVE_AIR("AIR"), CAVE_SPIDER_SPAWN_EGG(59, "MONSTER_EGG"), + CHAIN(16), CHAINMAIL_BOOTS, CHAINMAIL_CHESTPLATE, CHAINMAIL_HELMET, @@ -234,13 +246,15 @@ public enum XMaterial { CHICKEN("RAW_CHICKEN"), CHICKEN_SPAWN_EGG(93, "MONSTER_EGG"), CHIPPED_ANVIL(1, "ANVIL"), + CHISELED_NETHER_BRICKS(1, "NETHER_BRICKS"), + CHISELED_POLISHED_BLACKSTONE(0, 16, "POLISHED_BLACKSTONE"), CHISELED_QUARTZ_BLOCK(1, "QUARTZ_BLOCK"), CHISELED_RED_SANDSTONE(1, "RED_SANDSTONE"), CHISELED_SANDSTONE(1, "SANDSTONE"), CHISELED_STONE_BRICKS(3, "SMOOTH_BRICK"), - CHORUS_FLOWER, - CHORUS_FRUIT, - CHORUS_PLANT, + CHORUS_FLOWER(0, 9), + CHORUS_FRUIT(0, 9), + CHORUS_PLANT(0, 9), CLAY, CLAY_BALL, CLOCK("WATCH"), @@ -253,17 +267,24 @@ public enum XMaterial { COBBLESTONE_STAIRS, COBBLESTONE_WALL("COBBLE_WALL"), COBWEB("WEB"), - COCOA("1.15"), - COCOA_BEANS(3, "INK_SAC", "COCOA"), + COCOA(15), + COCOA_BEANS(3, "INK_SACK"), COD("RAW_FISH"), - COD_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), - COD_SPAWN_EGG("1.13", "MONSTER_EGG"), + COD_BUCKET(0, 13, "BUCKET", "WATER_BUCKET", ""), + COD_SPAWN_EGG(0, 13, "MONSTER_EGG", ""), COMMAND_BLOCK("COMMAND"), COMMAND_BLOCK_MINECART("COMMAND_MINECART"), - COMPARATOR("REDSTONE_COMPARATOR", "REDSTONE_COMPARATOR_ON", "REDSTONE_COMPARATOR"), + /** + * Unlike redstone torch and redstone lamp... neither REDTONE_COMPARATOR_OFF nor REDSTONE_COMPARATOR_ON + * are items. REDSTONE_COMPARATOR is. + * + * @see #REDSTONE_TORCH + * @see #REDSTONE_LAMP + */ + COMPARATOR("REDSTONE_COMPARATOR_OFF", "REDSTONE_COMPARATOR_ON", "REDSTONE_COMPARATOR"), COMPASS, - COMPOSTER("1.14", "CAULDRON"), - CONDUIT("1.13", "BEACON"), + COMPOSTER(0, 14, "CAULDRON", ""), + CONDUIT(0, 13, "BEACON"), COOKED_BEEF, COOKED_CHICKEN, COOKED_COD("COOKED_FISH"), @@ -272,26 +293,45 @@ public enum XMaterial { COOKED_RABBIT, COOKED_SALMON(1, "COOKED_FISH"), COOKIE, - CORNFLOWER(4, "1.14", "BLUE_DYE"), + CORNFLOWER(4, 14, "BLUE_DYE", ""), COW_SPAWN_EGG(92, "MONSTER_EGG"), + CRACKED_NETHER_BRICKS(2, "NETHER_BRICKS"), + CRACKED_POLISHED_BLACKSTONE_BRICKS(0, 16, "POLISHED_BLACKSTONE_BRICKS"), CRACKED_STONE_BRICKS(2, "SMOOTH_BRICK"), CRAFTING_TABLE("WORKBENCH"), CREEPER_BANNER_PATTERN, CREEPER_HEAD(4, "SKULL", "SKULL_ITEM"), CREEPER_SPAWN_EGG(50, "MONSTER_EGG"), CREEPER_WALL_HEAD(4, "SKULL", "SKULL_ITEM"), + CRIMSON_BUTTON(16), + CRIMSON_DOOR(16), + CRIMSON_FENCE(16), + CRIMSON_FENCE_GATE(16), + CRIMSON_FUNGUS(16), + CRIMSON_HYPHAE(16), + CRIMSON_NYLIUM(16), + CRIMSON_PLANKS(16), + CRIMSON_PRESSURE_PLATE(16), + CRIMSON_ROOTS(16), + CRIMSON_SIGN(0, 16, "SIGN_POST"), + CRIMSON_SLAB(16), + CRIMSON_STAIRS(16), + CRIMSON_STEM(16), + CRIMSON_TRAPDOOR(16), + CRIMSON_WALL_SIGN(0, 16, "WALL_SIGN"), CROSSBOW, - CUT_RED_SANDSTONE("1.13"), + CRYING_OBSIDIAN(16), + CUT_RED_SANDSTONE(13), CUT_RED_SANDSTONE_SLAB("STONE_SLAB2"), - CUT_SANDSTONE("1.13"), + CUT_SANDSTONE(13), CUT_SANDSTONE_SLAB("STEP"), - CYAN_BANNER(6, "BANNER", "STANDING_BANNER"), - CYAN_BED(9, "BED", "BED_BLOCK"), + CYAN_BANNER(6, "STANDING_BANNER", "BANNER"), + CYAN_BED(9, "BED_BLOCK", "BED"), CYAN_CARPET(9, "CARPET"), CYAN_CONCRETE(9, "CONCRETE"), CYAN_CONCRETE_POWDER(9, "CONCRETE_POWDER"), - CYAN_DYE(6, "INK_SAC"), - CYAN_GLAZED_TERRACOTTA(9, "1.12", "HARD_CLAY", "STAINED_CLAY", "CYAN_TERRACOTTA"), + CYAN_DYE(6, "INK_SACK"), + CYAN_GLAZED_TERRACOTTA(9, 12, "HARD_CLAY", "STAINED_CLAY", "CYAN_TERRACOTTA"), CYAN_SHULKER_BOX, CYAN_STAINED_GLASS(9, "STAINED_GLASS"), CYAN_STAINED_GLASS_PANE(9, "STAINED_GLASS_PANE"), @@ -302,46 +342,46 @@ public enum XMaterial { DANDELION("YELLOW_FLOWER"), DARK_OAK_BOAT("BOAT_DARK_OAK"), DARK_OAK_BUTTON("WOOD_BUTTON"), - DARK_OAK_DOOR("DARK_OAK_DOOR_ITEM"), + DARK_OAK_DOOR("DARK_OAK_DOOR", "DARK_OAK_DOOR_ITEM"), DARK_OAK_FENCE, DARK_OAK_FENCE_GATE, - DARK_OAK_LEAVES(1, "LEAVES", "LEAVES_2"), + DARK_OAK_LEAVES(4, "LEAVES", "LEAVES_2"), DARK_OAK_LOG(1, "LOG", "LOG_2"), DARK_OAK_PLANKS(5, "WOOD"), DARK_OAK_PRESSURE_PLATE("WOOD_PLATE"), DARK_OAK_SAPLING(5, "SAPLING"), - DARK_OAK_SIGN("SIGN"), - DARK_OAK_SLAB("WOOD_STEP", "WOODEN_SLAB", "WOODEN_SLAB"), + DARK_OAK_SIGN("SIGN_POST", "SIGN"), + DARK_OAK_SLAB(5, "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB"), DARK_OAK_STAIRS, DARK_OAK_TRAPDOOR("TRAP_DOOR"), - DARK_OAK_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + DARK_OAK_WALL_SIGN("WALL_SIGN"), DARK_OAK_WOOD(1, "LOG", "LOG_2"), DARK_PRISMARINE(1, "PRISMARINE"), - DARK_PRISMARINE_SLAB("1.13"), - DARK_PRISMARINE_STAIRS("1.13"), + DARK_PRISMARINE_SLAB(13), + DARK_PRISMARINE_STAIRS(13), DAYLIGHT_DETECTOR("DAYLIGHT_DETECTOR_INVERTED"), - DEAD_BRAIN_CORAL("1.13"), - DEAD_BRAIN_CORAL_BLOCK("1.13"), - DEAD_BRAIN_CORAL_FAN("1.13"), - DEAD_BRAIN_CORAL_WALL_FAN("1.13"), - DEAD_BUBBLE_CORAL("1.13"), - DEAD_BUBBLE_CORAL_BLOCK("1.13"), - DEAD_BUBBLE_CORAL_FAN("1.13"), - DEAD_BUBBLE_CORAL_WALL_FAN("1.13"), + DEAD_BRAIN_CORAL(13), + DEAD_BRAIN_CORAL_BLOCK(13), + DEAD_BRAIN_CORAL_FAN(13), + DEAD_BRAIN_CORAL_WALL_FAN(13), + DEAD_BUBBLE_CORAL(13), + DEAD_BUBBLE_CORAL_BLOCK(13), + DEAD_BUBBLE_CORAL_FAN(13), + DEAD_BUBBLE_CORAL_WALL_FAN(13), DEAD_BUSH, - DEAD_FIRE_CORAL("1.13"), - DEAD_FIRE_CORAL_BLOCK("1.13"), - DEAD_FIRE_CORAL_FAN("1.13"), - DEAD_FIRE_CORAL_WALL_FAN("1.13"), - DEAD_HORN_CORAL("1.13"), - DEAD_HORN_CORAL_BLOCK("1.13"), - DEAD_HORN_CORAL_FAN("1.13"), - DEAD_HORN_CORAL_WALL_FAN("1.13"), - DEAD_TUBE_CORAL("1.13"), - DEAD_TUBE_CORAL_BLOCK("1.13"), - DEAD_TUBE_CORAL_FAN("1.13"), - DEAD_TUBE_CORAL_WALL_FAN("1.13"), - DEBUG_STICK("1.13", "STICK"), + DEAD_FIRE_CORAL(13), + DEAD_FIRE_CORAL_BLOCK(13), + DEAD_FIRE_CORAL_FAN(13), + DEAD_FIRE_CORAL_WALL_FAN(13), + DEAD_HORN_CORAL(13), + DEAD_HORN_CORAL_BLOCK(13), + DEAD_HORN_CORAL_FAN(13), + DEAD_HORN_CORAL_WALL_FAN(13), + DEAD_TUBE_CORAL(13), + DEAD_TUBE_CORAL_BLOCK(13), + DEAD_TUBE_CORAL_FAN(13), + DEAD_TUBE_CORAL_WALL_FAN(13), + DEBUG_STICK(0, 13, "STICK", ""), DETECTOR_RAIL, DIAMOND, DIAMOND_AXE, @@ -362,16 +402,16 @@ public enum XMaterial { DIORITE_WALL, DIRT, DISPENSER, - DOLPHIN_SPAWN_EGG("1.13", "MONSTER_EGG"), + DOLPHIN_SPAWN_EGG(0, 13, "MONSTER_EGG", ""), DONKEY_SPAWN_EGG(32, "MONSTER_EGG"), DRAGON_BREATH("DRAGONS_BREATH"), DRAGON_EGG, - DRAGON_HEAD(5, "SKULL", "SKULL_ITEM"), + DRAGON_HEAD(5, 9, "SKULL", "SKULL_ITEM"), DRAGON_WALL_HEAD(5, "SKULL", "SKULL_ITEM"), - DRIED_KELP("1.13"), - DRIED_KELP_BLOCK("1.13"), + DRIED_KELP(13), + DRIED_KELP_BLOCK(13), DROPPER, - DROWNED_SPAWN_EGG("1.13", "MONSTER_EGG"), + DROWNED_SPAWN_EGG(0, 13, "MONSTER_EGG", ""), EGG, ELDER_GUARDIAN_SPAWN_EGG(4, "MONSTER_EGG"), ELYTRA, @@ -387,13 +427,13 @@ public enum XMaterial { ENDER_EYE("EYE_OF_ENDER"), ENDER_PEARL, END_CRYSTAL, - END_GATEWAY, + END_GATEWAY(0, 9), END_PORTAL("ENDER_PORTAL"), END_PORTAL_FRAME("ENDER_PORTAL_FRAME"), - END_ROD, + END_ROD(0, 9, "BLAZE_ROD", ""), END_STONE("ENDER_STONE"), END_STONE_BRICKS("END_BRICKS"), - END_STONE_BRICK_SLAB(4, "STEP"), + END_STONE_BRICK_SLAB(6, "STEP"), END_STONE_BRICK_STAIRS("SMOOTH_STAIRS"), END_STONE_BRICK_WALL, EVOKER_SPAWN_EGG(34, "MONSTER_EGG"), @@ -402,27 +442,36 @@ public enum XMaterial { FEATHER, FERMENTED_SPIDER_EYE, FERN(2, "LONG_GRASS"), + /** + * For some reasons filled map items are really special. + * Their data value starts from 0 and every time a player + * creates a new map that maps data value increases. + */ FILLED_MAP("MAP"), FIRE, FIREWORK_ROCKET("FIREWORK"), FIREWORK_STAR("FIREWORK_CHARGE"), FIRE_CHARGE("FIREBALL"), - FIRE_CORAL("1.13"), - FIRE_CORAL_BLOCK("1.13"), - FIRE_CORAL_FAN("1.13"), + FIRE_CORAL(13), + FIRE_CORAL_BLOCK(13), + FIRE_CORAL_FAN(13), FIRE_CORAL_WALL_FAN, FISHING_ROD, - FLETCHING_TABLE("1.14", "CRAFTING_TABLE"), + FLETCHING_TABLE(0, 14, "CRAFTING_TABLE", ""), FLINT, FLINT_AND_STEEL, FLOWER_BANNER_PATTERN, - FLOWER_POT("FLOWER_POT_ITEM"), // TODO Fix exceptional material - FOX_SPAWN_EGG("1.14"), - FROSTED_ICE, + FLOWER_POT("FLOWER_POT", "FLOWER_POT_ITEM"), + FOX_SPAWN_EGG(14), + /** + * This special material cannot be obtained as an item. + */ + FROSTED_ICE(0, 9, "PACKED_ICE", ""), FURNACE("BURNING_FURNACE"), FURNACE_MINECART("POWERED_MINECART"), GHAST_SPAWN_EGG(56, "MONSTER_EGG"), GHAST_TEAR, + GILDED_BLACKSTONE(16), GLASS, GLASS_BOTTLE, GLASS_PANE("THIN_GLASS"), @@ -450,51 +499,52 @@ public enum XMaterial { GRANITE_SLAB, GRANITE_STAIRS, GRANITE_WALL, - GRASS, + GRASS(1, "LONG_GRASS"), GRASS_BLOCK("GRASS"), GRASS_PATH, GRAVEL, - GRAY_BANNER(8, "BANNER", "STANDING_BANNER"), - GRAY_BED(7, "BED", "BED_BLOCK"), + GRAY_BANNER(8, "STANDING_BANNER", "BANNER"), + GRAY_BED(7, "BED_BLOCK", "BED"), GRAY_CARPET(7, "CARPET"), GRAY_CONCRETE(7, "CONCRETE"), GRAY_CONCRETE_POWDER(7, "CONCRETE_POWDER"), - GRAY_DYE(8, "INK_SAC"), - GRAY_GLAZED_TERRACOTTA(7, "1.12", "HARD_CLAY", "STAINED_CLAY", "GRAY_TERRACOTTA"), + GRAY_DYE(8, "INK_SACK"), + GRAY_GLAZED_TERRACOTTA(7, 12, "HARD_CLAY", "STAINED_CLAY", "GRAY_TERRACOTTA"), GRAY_SHULKER_BOX, - GRAY_STAINED_GLASS(8, "STAINED_GLASS"), + GRAY_STAINED_GLASS(7, "STAINED_GLASS"), GRAY_STAINED_GLASS_PANE(7, "THIN_GLASS", "STAINED_GLASS_PANE"), GRAY_TERRACOTTA(7, "HARD_CLAY", "STAINED_CLAY"), GRAY_WALL_BANNER(8, "WALL_BANNER"), - GRAY_WOOL(8, "WOOL"), - GREEN_BANNER(2, "BANNER", "STANDING_BANNER"), - GREEN_BED(13, "BED", "BED_BLOCK"), + GRAY_WOOL(7, "WOOL"), + GREEN_BANNER(2, "STANDING_BANNER", "BANNER"), + GREEN_BED(13, "BED_BLOCK", "BED"), GREEN_CARPET(13, "CARPET"), GREEN_CONCRETE(13, "CONCRETE"), GREEN_CONCRETE_POWDER(13, "CONCRETE_POWDER"), - GREEN_DYE(2, "INK_SAC", "CACTUS_GREEN"), - GREEN_GLAZED_TERRACOTTA(13, "1.12", "HARD_CLAY", "STAINED_CLAY", "GREEN_TERRACOTTA"), + GREEN_DYE(2, "INK_SACK", "CACTUS_GREEN"), + GREEN_GLAZED_TERRACOTTA(13, 12, "HARD_CLAY", "STAINED_CLAY", "GREEN_TERRACOTTA"), GREEN_SHULKER_BOX, GREEN_STAINED_GLASS(13, "STAINED_GLASS"), GREEN_STAINED_GLASS_PANE(13, "THIN_GLASS", "STAINED_GLASS_PANE"), GREEN_TERRACOTTA(13, "HARD_CLAY", "STAINED_CLAY"), GREEN_WALL_BANNER(2, "WALL_BANNER"), GREEN_WOOL(13, "WOOL"), - GRINDSTONE("1.14", "ANVIL"), + GRINDSTONE(0, 14, "ANVIL", ""), GUARDIAN_SPAWN_EGG(68, "MONSTER_EGG"), GUNPOWDER("SULPHUR"), HAY_BLOCK, - HEART_OF_THE_SEA("1.13"), + HEART_OF_THE_SEA(13), HEAVY_WEIGHTED_PRESSURE_PLATE("IRON_PLATE"), - HONEYCOMB("1.15"), - HONEYCOMB_BLOCK("1.15"), - HONEY_BLOCK("1.15", "SLIME_BLOCK"), - HONEY_BOTTLE("1.15", "GLASS_BOTTLE"), + HOGLIN_SPAWN_EGG(0, 16, "MONSTER_EGG"), + HONEYCOMB(15), + HONEYCOMB_BLOCK(15), + HONEY_BLOCK(0, 15, "SLIME_BLOCK", ""), + HONEY_BOTTLE(0, 15, "GLASS_BOTTLE", ""), HOPPER, HOPPER_MINECART, - HORN_CORAL("1.13"), - HORN_CORAL_BLOCK("1.13"), - HORN_CORAL_FAN("1.13"), + HORN_CORAL(13), + HORN_CORAL_BLOCK(13), + HORN_CORAL_FAN(13), HORN_CORAL_WALL_FAN, HORSE_SPAWN_EGG(100, "MONSTER_EGG"), HUSK_SPAWN_EGG(23, "MONSTER_EGG"), @@ -505,6 +555,11 @@ public enum XMaterial { INFESTED_MOSSY_STONE_BRICKS(3, "MONSTER_EGGS"), INFESTED_STONE("MONSTER_EGGS"), INFESTED_STONE_BRICKS(2, "MONSTER_EGGS", "SMOOTH_BRICK"), + /** + * We will only add "INK_SAC" for {@link #BLACK_DYE} since it's + * the only material (linked with this material) that is added + * after 1.13, which means it can use both INK_SACK and INK_SAC. + */ INK_SAC("INK_SACK"), IRON_AXE, IRON_BARS("IRON_FENCE"), @@ -525,11 +580,11 @@ public enum XMaterial { IRON_TRAPDOOR, ITEM_FRAME, JACK_O_LANTERN, - JIGSAW("1.14", "COMMAND_BLOCK", "STRUCTURE_BLOCK"), + JIGSAW(0, 14, "COMMAND_BLOCK", "STRUCTURE_BLOCK", ""), JUKEBOX, JUNGLE_BOAT("BOAT_JUNGLE"), JUNGLE_BUTTON("WOOD_BUTTON"), - JUNGLE_DOOR("JUNGLE_DOOR_ITEM"), + JUNGLE_DOOR("JUNGLE_DOOR", "JUNGLE_DOOR_ITEM"), JUNGLE_FENCE, JUNGLE_FENCE_GATE, JUNGLE_LEAVES(3, "LEAVES"), @@ -537,19 +592,19 @@ public enum XMaterial { JUNGLE_PLANKS(3, "WOOD"), JUNGLE_PRESSURE_PLATE("WOOD_PLATE"), JUNGLE_SAPLING(3, "SAPLING"), - JUNGLE_SIGN("SIGN"), - JUNGLE_SLAB(3, "WOOD_STEP", "WOODEN_SLAB", "WOODEN_SLAB"), + JUNGLE_SIGN("SIGN_POST", "SIGN"), + JUNGLE_SLAB(3, "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB"), JUNGLE_STAIRS("JUNGLE_WOOD_STAIRS"), JUNGLE_TRAPDOOR("TRAP_DOOR"), - JUNGLE_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + JUNGLE_WALL_SIGN("WALL_SIGN"), JUNGLE_WOOD(3, "LOG"), - KELP("1.13"), - KELP_PLANT("1.13"), - KNOWLEDGE_BOOK("1.12", "BOOK"), + KELP(13), + KELP_PLANT(13), + KNOWLEDGE_BOOK(0, 12, "BOOK"), LADDER, - LANTERN("1.14", "SEA_LANTERN"), + LANTERN(0, 14, "SEA_LANTERN", ""), LAPIS_BLOCK, - LAPIS_LAZULI(4, "INK_SAC"), + LAPIS_LAZULI(4, "INK_SACK"), LAPIS_ORE, LARGE_FERN(3, "DOUBLE_PLANT"), LAVA("STATIONARY_LAVA"), @@ -559,30 +614,34 @@ public enum XMaterial { LEATHER_BOOTS, LEATHER_CHESTPLATE, LEATHER_HELMET, - LEATHER_HORSE_ARMOR("1.14", "IRON_HORSE_ARMOR"), + LEATHER_HORSE_ARMOR(0, 14, "IRON_HORSE_ARMOR", ""), LEATHER_LEGGINGS, - LECTERN("1.14", "BOOKSHELF"), + LECTERN(0, 14, "BOOKSHELF", ""), LEVER, - LIGHT_BLUE_BANNER(3, "BANNER", "STANDING_BANNER"), - LIGHT_BLUE_BED(3, "BED", "BED_BLOCK"), + LIGHT_BLUE_BANNER(12, "STANDING_BANNER", "BANNER"), + LIGHT_BLUE_BED(3, "BED_BLOCK", "BED"), LIGHT_BLUE_CARPET(3, "CARPET"), LIGHT_BLUE_CONCRETE(3, "CONCRETE"), LIGHT_BLUE_CONCRETE_POWDER(3, "CONCRETE_POWDER"), - LIGHT_BLUE_DYE(12, "INK_SAC"), - LIGHT_BLUE_GLAZED_TERRACOTTA(3, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIGHT_BLUE_TERRACOTTA"), + LIGHT_BLUE_DYE(12, "INK_SACK"), + LIGHT_BLUE_GLAZED_TERRACOTTA(3, 12, "HARD_CLAY", "STAINED_CLAY", "LIGHT_BLUE_TERRACOTTA"), LIGHT_BLUE_SHULKER_BOX, LIGHT_BLUE_STAINED_GLASS(3, "STAINED_GLASS"), LIGHT_BLUE_STAINED_GLASS_PANE(3, "THIN_GLASS", "STAINED_GLASS_PANE"), LIGHT_BLUE_TERRACOTTA(3, "STAINED_CLAY"), - LIGHT_BLUE_WALL_BANNER(12, "WALL_BANNER", "BANNER", "STANDING_BANNER"), + LIGHT_BLUE_WALL_BANNER(12, "WALL_BANNER", "STANDING_BANNER", "BANNER"), LIGHT_BLUE_WOOL(3, "WOOL"), - LIGHT_GRAY_BANNER(7, "BANNER", "STANDING_BANNER"), - LIGHT_GRAY_BED(7, "BED", "BED_BLOCK"), + LIGHT_GRAY_BANNER(7, "STANDING_BANNER", "BANNER"), + LIGHT_GRAY_BED(8, "BED_BLOCK", "BED"), LIGHT_GRAY_CARPET(8, "CARPET"), LIGHT_GRAY_CONCRETE(8, "CONCRETE"), LIGHT_GRAY_CONCRETE_POWDER(8, "CONCRETE_POWDER"), - LIGHT_GRAY_DYE(7, "INK_SAC"), - LIGHT_GRAY_GLAZED_TERRACOTTA(8, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIGHT_GRAY_TERRACOTTA", "SILVER_GLAZED_TERRACOTTA/1.13"), + LIGHT_GRAY_DYE(7, "INK_SACK"), + /** + * Renamed to SILVER_GLAZED_TERRACOTTA in 1.12 + * Renamed to LIGHT_GRAY_GLAZED_TERRACOTTA in 1.14 + */ + LIGHT_GRAY_GLAZED_TERRACOTTA(0, 12, "HARD_CLAY", "STAINED_CLAY", "LIGHT_GRAY_TERRACOTTA", "SILVER_GLAZED_TERRACOTTA"), LIGHT_GRAY_SHULKER_BOX("SILVER_SHULKER_BOX"), LIGHT_GRAY_STAINED_GLASS(8, "STAINED_GLASS"), LIGHT_GRAY_STAINED_GLASS_PANE(8, "THIN_GLASS", "STAINED_GLASS_PANE"), @@ -591,15 +650,15 @@ public enum XMaterial { LIGHT_GRAY_WOOL(8, "WOOL"), LIGHT_WEIGHTED_PRESSURE_PLATE("GOLD_PLATE"), LILAC(1, "DOUBLE_PLANT"), - LILY_OF_THE_VALLEY(15, "1.14", "WHITE_DYE"), + LILY_OF_THE_VALLEY(15, 14, "WHITE_DYE", ""), LILY_PAD("WATER_LILY"), - LIME_BANNER(10, "BANNER", "STANDING_BANNER"), - LIME_BED(5, "BED", "BED_BLOCK"), + LIME_BANNER(10, "STANDING_BANNER", "BANNER"), + LIME_BED(5, "BED_BLOCK", "BED"), LIME_CARPET(5, "CARPET"), LIME_CONCRETE(5, "CONCRETE"), LIME_CONCRETE_POWDER(5, "CONCRETE_POWDER"), - LIME_DYE(10, "INK_SAC"), - LIME_GLAZED_TERRACOTTA(5, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIME_TERRACOTTA"), + LIME_DYE(10, "INK_SACK"), + LIME_GLAZED_TERRACOTTA(5, 12, "HARD_CLAY", "STAINED_CLAY", "LIME_TERRACOTTA"), LIME_SHULKER_BOX, LIME_STAINED_GLASS(5, "STAINED_GLASS"), LIME_STAINED_GLASS_PANE(5, "STAINED_GLASS_PANE"), @@ -608,23 +667,31 @@ public enum XMaterial { LIME_WOOL(5, "WOOL"), LINGERING_POTION, LLAMA_SPAWN_EGG(103, "MONSTER_EGG"), - LOOM("1.14"), - MAGENTA_BANNER(13, "BANNER", "STANDING_BANNER"), - MAGENTA_BED(2, "BED", "BED_BLOCK"), + LODESTONE(16), + LOOM(14), + MAGENTA_BANNER(13, "STANDING_BANNER", "BANNER"), + MAGENTA_BED(2, "BED_BLOCK", "BED"), MAGENTA_CARPET(2, "CARPET"), MAGENTA_CONCRETE(2, "CONCRETE"), MAGENTA_CONCRETE_POWDER(2, "CONCRETE_POWDER"), - MAGENTA_DYE(13, "INK_SAC"), - MAGENTA_GLAZED_TERRACOTTA(2, "1.12", "HARD_CLAY", "STAINED_CLAY", "MAGENTA_TERRACOTTA"), + MAGENTA_DYE(13, "INK_SACK"), + MAGENTA_GLAZED_TERRACOTTA(2, 12, "HARD_CLAY", "STAINED_CLAY", "MAGENTA_TERRACOTTA"), MAGENTA_SHULKER_BOX, MAGENTA_STAINED_GLASS(2, "STAINED_GLASS"), MAGENTA_STAINED_GLASS_PANE(2, "THIN_GLASS", "STAINED_GLASS_PANE"), MAGENTA_TERRACOTTA(2, "HARD_CLAY", "STAINED_CLAY"), MAGENTA_WALL_BANNER(13, "WALL_BANNER"), MAGENTA_WOOL(2, "WOOL"), - MAGMA_BLOCK("MAGMA"), + MAGMA_BLOCK(0, 10, "MAGMA"), MAGMA_CREAM, MAGMA_CUBE_SPAWN_EGG(62, "MONSTER_EGG"), + /** + * Adding this to the duplicated list will give you a filled map + * for 1.13+ versions and removing it from duplicated list will + * still give you a filled map in -1.12 versions. + * Since higher versions are our priority I'll keep 1.13+ support + * until I can come up with something to fix it. + */ MAP("EMPTY_MAP"), MELON("MELON_BLOCK"), MELON_SEEDS, @@ -639,7 +706,7 @@ public enum XMaterial { MOSSY_COBBLESTONE_STAIRS, MOSSY_COBBLESTONE_WALL(1, "COBBLE_WALL", "COBBLESTONE_WALL"), MOSSY_STONE_BRICKS(1, "SMOOTH_BRICK"), - MOSSY_STONE_BRICK_SLAB(4, "STEP"), + MOSSY_STONE_BRICK_SLAB(5, "STEP"), MOSSY_STONE_BRICK_STAIRS("SMOOTH_STAIRS"), MOSSY_STONE_BRICK_WALL, MOVING_PISTON("PISTON_BASE", "PISTON_MOVING_PIECE"), @@ -654,6 +721,7 @@ public enum XMaterial { MUSIC_DISC_FAR("RECORD_6"), MUSIC_DISC_MALL("RECORD_7"), MUSIC_DISC_MELLOHI("RECORD_8"), + MUSIC_DISC_PIGSTEP(16), MUSIC_DISC_STAL("RECORD_9"), MUSIC_DISC_STRAD("RECORD_10"), MUSIC_DISC_WAIT("RECORD_11"), @@ -661,23 +729,42 @@ public enum XMaterial { MUTTON, MYCELIUM("MYCEL"), NAME_TAG, - NAUTILUS_SHELL("1.13"), + NAUTILUS_SHELL(13), + NETHERITE_AXE(16), + NETHERITE_BLOCK(16), + NETHERITE_BOOTS(16), + NETHERITE_CHESTPLATE(16), + NETHERITE_HELMET(16), + NETHERITE_HOE(16), + NETHERITE_INGOT(16), + NETHERITE_LEGGINGS(16), + NETHERITE_PICKAXE(16), + NETHERITE_SCRAP(16), + NETHERITE_SHOVEL(16), + NETHERITE_SWORD(16), NETHERRACK, NETHER_BRICK("NETHER_BRICK_ITEM"), NETHER_BRICKS("NETHER_BRICK"), NETHER_BRICK_FENCE("NETHER_FENCE"), - NETHER_BRICK_SLAB(4, "STEP"), + NETHER_BRICK_SLAB(6, "STEP"), NETHER_BRICK_STAIRS, NETHER_BRICK_WALL, + NETHER_GOLD_ORE(16), NETHER_PORTAL("PORTAL"), NETHER_QUARTZ_ORE("QUARTZ_ORE"), + NETHER_SPROUTS(16), NETHER_STAR, - NETHER_WART("NETHER_STALK"), - NETHER_WART_BLOCK("NETHER_WARTS"), + /** + * Just like mentioned in https://minecraft.gamepedia.com/Nether_Wart + * Nether wart is also known as nether stalk in the code. + * NETHER_STALK is the planted state of nether warts. + */ + NETHER_WART("NETHER_WARTS", "NETHER_STALK"), + NETHER_WART_BLOCK, NOTE_BLOCK, OAK_BOAT("BOAT"), OAK_BUTTON("WOOD_BUTTON"), - OAK_DOOR("WOOD_DOOR", "WOODEN_DOOR"), + OAK_DOOR("WOODEN_DOOR", "WOOD_DOOR"), OAK_FENCE("FENCE"), OAK_FENCE_GATE("FENCE_GATE"), OAK_LEAVES("LEAVES"), @@ -685,22 +772,22 @@ public enum XMaterial { OAK_PLANKS("WOOD"), OAK_PRESSURE_PLATE("WOOD_PLATE"), OAK_SAPLING("SAPLING"), - OAK_SIGN("SIGN"), - OAK_SLAB("WOOD_STEP", "WOODEN_SLAB", "WOODEN_SLAB"), + OAK_SIGN("SIGN_POST", "SIGN"), + OAK_SLAB("WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB"), OAK_STAIRS("WOOD_STAIRS"), OAK_TRAPDOOR("TRAP_DOOR"), - OAK_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + OAK_WALL_SIGN("WALL_SIGN"), OAK_WOOD("LOG"), OBSERVER, OBSIDIAN, OCELOT_SPAWN_EGG(98, "MONSTER_EGG"), - ORANGE_BANNER(14, "BANNER", "STANDING_BANNER"), - ORANGE_BED(1, "BED", "BED_BLOCK"), + ORANGE_BANNER(14, "STANDING_BANNER", "BANNER"), + ORANGE_BED(1, "BED_BLOCK", "BED"), ORANGE_CARPET(1, "CARPET"), ORANGE_CONCRETE(1, "CONCRETE"), ORANGE_CONCRETE_POWDER(1, "CONCRETE_POWDER"), - ORANGE_DYE(14, "INK_SAC"), - ORANGE_GLAZED_TERRACOTTA(1, "1.12", "HARD_CLAY", "STAINED_CLAY", "ORANGE_TERRACOTTA"), + ORANGE_DYE(14, "INK_SACK"), + ORANGE_GLAZED_TERRACOTTA(1, 12, "HARD_CLAY", "STAINED_CLAY", "ORANGE_TERRACOTTA"), ORANGE_SHULKER_BOX, ORANGE_STAINED_GLASS(1, "STAINED_GLASS"), ORANGE_STAINED_GLASS_PANE(1, "STAINED_GLASS_PANE"), @@ -711,28 +798,31 @@ public enum XMaterial { OXEYE_DAISY(8, "RED_ROSE"), PACKED_ICE, PAINTING, - PANDA_SPAWN_EGG("1.14"), + PANDA_SPAWN_EGG(14), PAPER, PARROT_SPAWN_EGG(105, "MONSTER_EGG"), PEONY(5, "DOUBLE_PLANT"), PETRIFIED_OAK_SLAB("WOOD_STEP"), - PHANTOM_MEMBRANE("1.13"), - PHANTOM_SPAWN_EGG("1.13", "MONSTER_EGG"), + PHANTOM_MEMBRANE(13), + PHANTOM_SPAWN_EGG(0, 13, "MONSTER_EGG", ""), + PIGLIN_BANNER_PATTERN(16), + PIGLIN_BRUTE_SPAWN_EGG(16), + PIGLIN_SPAWN_EGG(57, "MONSTER_EGG"), PIG_SPAWN_EGG(90, "MONSTER_EGG"), - PILLAGER_SPAWN_EGG("1.14"), - PINK_BANNER(9, "BANNER", "STANDING_BANNER"), - PINK_BED(6, "BED", "BED_BLOCK"), + PILLAGER_SPAWN_EGG(14), + PINK_BANNER(9, "STANDING_BANNER", "BANNER"), + PINK_BED(6, "BED_BLOCK", "BED"), PINK_CARPET(6, "CARPET"), PINK_CONCRETE(6, "CONCRETE"), PINK_CONCRETE_POWDER(6, "CONCRETE_POWDER"), - PINK_DYE(9, "INK_SAC"), - PINK_GLAZED_TERRACOTTA(6, "1.12", "HARD_CLAY", "STAINED_CLAY", "PINK_TERRACOTTA"), + PINK_DYE(9, "INK_SACK"), + PINK_GLAZED_TERRACOTTA(6, 12, "HARD_CLAY", "STAINED_CLAY", "PINK_TERRACOTTA"), PINK_SHULKER_BOX, PINK_STAINED_GLASS(6, "STAINED_GLASS"), PINK_STAINED_GLASS_PANE(6, "THIN_GLASS", "STAINED_GLASS_PANE"), PINK_TERRACOTTA(6, "HARD_CLAY", "STAINED_CLAY"), PINK_TULIP(7, "RED_ROSE"), - PINK_WALL_BANNER(14, "WALL_BANNER"), + PINK_WALL_BANNER(9, "WALL_BANNER"), PINK_WOOL(6, "WOOL"), PISTON("PISTON_BASE"), PISTON_HEAD("PISTON_EXTENSION"), @@ -744,6 +834,17 @@ public enum XMaterial { POLISHED_ANDESITE(6, "STONE"), POLISHED_ANDESITE_SLAB, POLISHED_ANDESITE_STAIRS, + POLISHED_BASALT(16), + POLISHED_BLACKSTONE(16), + POLISHED_BLACKSTONE_BRICKS(16), + POLISHED_BLACKSTONE_BRICK_SLAB(16), + POLISHED_BLACKSTONE_BRICK_STAIRS(16), + POLISHED_BLACKSTONE_BRICK_WALL(16), + POLISHED_BLACKSTONE_BUTTON(16), + POLISHED_BLACKSTONE_PRESSURE_PLATE(16), + POLISHED_BLACKSTONE_SLAB(16), + POLISHED_BLACKSTONE_STAIRS(16), + POLISHED_BLACKSTONE_WALL(16), POLISHED_DIORITE(4, "STONE"), POLISHED_DIORITE_SLAB, POLISHED_DIORITE_STAIRS, @@ -765,6 +866,8 @@ public enum XMaterial { POTTED_BROWN_MUSHROOM("FLOWER_POT"), POTTED_CACTUS("FLOWER_POT"), POTTED_CORNFLOWER, + POTTED_CRIMSON_FUNGUS(16), + POTTED_CRIMSON_ROOTS(16), POTTED_DANDELION("YELLOW_FLOWER", "FLOWER_POT"), POTTED_DARK_OAK_SAPLING(5, "SAPLING", "FLOWER_POT"), POTTED_DEAD_BUSH("FLOWER_POT"), @@ -779,32 +882,34 @@ public enum XMaterial { POTTED_RED_MUSHROOM("FLOWER_POT"), POTTED_RED_TULIP(4, "RED_ROSE", "FLOWER_POT"), POTTED_SPRUCE_SAPLING(1, "SAPLING", "FLOWER_POT"), + POTTED_WARPED_FUNGUS(16), + POTTED_WARPED_ROOTS(16), POTTED_WHITE_TULIP(6, "RED_ROSE", "FLOWER_POT"), POTTED_WITHER_ROSE, POWERED_RAIL, PRISMARINE, PRISMARINE_BRICKS(2, "PRISMARINE"), PRISMARINE_BRICK_SLAB(4, "STEP"), - PRISMARINE_BRICK_STAIRS("1.13"), + PRISMARINE_BRICK_STAIRS(13), PRISMARINE_CRYSTALS, PRISMARINE_SHARD, - PRISMARINE_SLAB("1.13"), - PRISMARINE_STAIRS("1.13"), + PRISMARINE_SLAB(13), + PRISMARINE_STAIRS(13), PRISMARINE_WALL, PUFFERFISH(3, "RAW_FISH"), - PUFFERFISH_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), - PUFFERFISH_SPAWN_EGG("1.13", "MONSTER_EGG"), + PUFFERFISH_BUCKET(0, 13, "BUCKET", "WATER_BUCKET", ""), + PUFFERFISH_SPAWN_EGG(0, 13, "MONSTER_EGG", ""), PUMPKIN, PUMPKIN_PIE, PUMPKIN_SEEDS, PUMPKIN_STEM, - PURPLE_BANNER(5, "BANNER", "STANDING_BANNER"), - PURPLE_BED(10, "BED", "BED_BLOCK"), + PURPLE_BANNER(5, "STANDING_BANNER", "BANNER"), + PURPLE_BED(10, "BED_BLOCK", "BED"), PURPLE_CARPET(10, "CARPET"), PURPLE_CONCRETE(10, "CONCRETE"), PURPLE_CONCRETE_POWDER(10, "CONCRETE_POWDER"), - PURPLE_DYE(5, "INK_SAC"), - PURPLE_GLAZED_TERRACOTTA(10, "1.12", "HARD_CLAY", "STAINED_CLAY", "PURPLE_TERRACOTTA"), + PURPLE_DYE(5, "INK_SACK"), + PURPLE_GLAZED_TERRACOTTA(10, 12, "HARD_CLAY", "STAINED_CLAY", "PURPLE_TERRACOTTA"), PURPLE_SHULKER_BOX, PURPLE_STAINED_GLASS(10, "STAINED_GLASS"), PURPLE_STAINED_GLASS_PANE(10, "THIN_GLASS", "STAINED_GLASS_PANE"), @@ -817,6 +922,7 @@ public enum XMaterial { PURPUR_STAIRS, QUARTZ, QUARTZ_BLOCK, + QUARTZ_BRICKS(16), QUARTZ_PILLAR(2, "QUARTZ_BLOCK"), QUARTZ_SLAB(7, "STEP"), QUARTZ_STAIRS, @@ -826,21 +932,35 @@ public enum XMaterial { RABBIT_SPAWN_EGG(101, "MONSTER_EGG"), RABBIT_STEW, RAIL("RAILS"), - RAVAGER_SPAWN_EGG("1.14"), + RAVAGER_SPAWN_EGG(14), REDSTONE, REDSTONE_BLOCK, - REDSTONE_LAMP("REDSTONE_LAMP", "REDSTONE_LAMP"), + /** + * Unlike redstone torch, REDSTONE_LAMP_ON isn't an item. + * The name is just here on the list for matching. + * + * @see #REDSTONE_TORCH + */ + REDSTONE_LAMP("REDSTONE_LAMP_ON", "REDSTONE_LAMP_OFF"), REDSTONE_ORE("GLOWING_REDSTONE_ORE"), - REDSTONE_TORCH("REDSTONE_TORCH", "REDSTONE_TORCH_ON"), - REDSTONE_WALL_TORCH(1, "REDSTONE_TORCH_ON", "REDSTONE_TORCH"), + /** + * REDSTONE_TORCH_OFF isn't an item, but a block. + * But REDSTONE_TORCH_ON is the item. + * The name is just here on the list for matching. + */ + REDSTONE_TORCH("REDSTONE_TORCH_OFF", "REDSTONE_TORCH_ON"), + REDSTONE_WALL_TORCH, REDSTONE_WIRE, - RED_BANNER(1, "BANNER", "STANDING_BANNER"), - RED_BED(14, "BED", "BED_BLOCK"), + RED_BANNER(1, "STANDING_BANNER", "BANNER"), + /** + * Data value 14 or 0 + */ + RED_BED(0, "BED_BLOCK", "BED"), RED_CARPET(14, "CARPET"), RED_CONCRETE(14, "CONCRETE"), RED_CONCRETE_POWDER(14, "CONCRETE_POWDER"), - RED_DYE(1, "ROSE_RED"), - RED_GLAZED_TERRACOTTA(14, "1.12", "HARD_CLAY", "STAINED_CLAY", "RED_TERRACOTTA"), + RED_DYE(1, "INK_SACK", "ROSE_RED"), + RED_GLAZED_TERRACOTTA(14, 12, "HARD_CLAY", "STAINED_CLAY", "RED_TERRACOTTA"), RED_MUSHROOM, RED_MUSHROOM_BLOCK("RED_MUSHROOM", "HUGE_MUSHROOM_2"), RED_NETHER_BRICKS("RED_NETHER_BRICK"), @@ -849,7 +969,7 @@ public enum XMaterial { RED_NETHER_BRICK_WALL, RED_SAND(1, "SAND"), RED_SANDSTONE, - RED_SANDSTONE_SLAB("STONE_SLAB2", "DOUBLE_STONE_SLAB2"), + RED_SANDSTONE_SLAB("DOUBLE_STONE_SLAB2", "STONE_SLAB2"), RED_SANDSTONE_STAIRS, RED_SANDSTONE_WALL, RED_SHULKER_BOX, @@ -859,27 +979,29 @@ public enum XMaterial { RED_TULIP(4, "RED_ROSE"), RED_WALL_BANNER(1, "WALL_BANNER"), RED_WOOL(14, "WOOL"), - REPEATER("DIODE", "DIODE_BLOCK_ON", "DIODE_BLOCK_ON"), + REPEATER("DIODE_BLOCK_ON", "DIODE_BLOCK_OFF", "DIODE"), REPEATING_COMMAND_BLOCK("COMMAND", "COMMAND_REPEATING"), + RESPAWN_ANCHOR(16), ROSE_BUSH(4, "DOUBLE_PLANT"), ROTTEN_FLESH, SADDLE, SALMON(1, "RAW_FISH"), - SALMON_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), - SALMON_SPAWN_EGG("1.13", "MONSTER_EGG"), + SALMON_BUCKET(0, 13, "BUCKET", "WATER_BUCKET", ""), + SALMON_SPAWN_EGG(0, 13, "MONSTER_EGG", ""), SAND, SANDSTONE, - SANDSTONE_SLAB(1, "STEP", "STONE_SLAB", "STONE_SLAB"), + SANDSTONE_SLAB(1, "DOUBLE_STEP", "STEP", "STONE_SLAB"), SANDSTONE_STAIRS, SANDSTONE_WALL, - SCAFFOLDING("1.14", "SLIME_BLOCK"), - SCUTE("1.13"), - SEAGRASS("1.13", "GRASS"), + SCAFFOLDING(0, 14, "SLIME_BLOCK", ""), + SCUTE(13), + SEAGRASS(0, 13, "GRASS", ""), SEA_LANTERN, - SEA_PICKLE("1.13"), + SEA_PICKLE(13), SHEARS, SHEEP_SPAWN_EGG(91, "MONSTER_EGG"), SHIELD, + SHROOMLIGHT(16), SHULKER_BOX("PURPLE_SHULKER_BOX"), SHULKER_SHELL, SHULKER_SPAWN_EGG(69, "MONSTER_EGG"), @@ -893,8 +1015,8 @@ public enum XMaterial { SLIME_BLOCK, SLIME_SPAWN_EGG(55, "MONSTER_EGG"), SMITHING_TABLE, - SMOKER("1.14", "FURNACE"), - SMOOTH_QUARTZ("1.13"), + SMOKER(0, 14, "FURNACE", ""), + SMOOTH_QUARTZ(0, 13, "QUARTZ", ""), SMOOTH_QUARTZ_SLAB(7, "STEP"), SMOOTH_QUARTZ_STAIRS, SMOOTH_RED_SANDSTONE(2, "RED_SANDSTONE"), @@ -908,37 +1030,43 @@ public enum XMaterial { SNOW, SNOWBALL("SNOW_BALL"), SNOW_BLOCK, + SOUL_CAMPFIRE(16), + SOUL_FIRE(16), + SOUL_LANTERN(16), SOUL_SAND, + SOUL_SOIL(16), + SOUL_TORCH(16), + SOUL_WALL_TORCH(16), SPAWNER("MOB_SPAWNER"), - SPECTRAL_ARROW("1.9", "ARROW"), + SPECTRAL_ARROW(0, 9, "ARROW", ""), SPIDER_EYE, SPIDER_SPAWN_EGG(52, "MONSTER_EGG"), SPLASH_POTION, SPONGE, SPRUCE_BOAT("BOAT_SPRUCE"), SPRUCE_BUTTON("WOOD_BUTTON"), - SPRUCE_DOOR("SPRUCE_DOOR_ITEM"), + SPRUCE_DOOR("SPRUCE_DOOR", "SPRUCE_DOOR_ITEM"), SPRUCE_FENCE, SPRUCE_FENCE_GATE, - SPRUCE_LEAVES(1, "LEAVES"), + SPRUCE_LEAVES(1, "LEAVES", "LEAVES_2"), SPRUCE_LOG(1, "LOG"), SPRUCE_PLANKS(1, "WOOD"), SPRUCE_PRESSURE_PLATE("WOOD_PLATE"), SPRUCE_SAPLING(1, "SAPLING"), - SPRUCE_SIGN("SIGN"), - SPRUCE_SLAB(1, "WOOD_STEP", "WOODEN_SLAB", "WOODEN_SLAB"), + SPRUCE_SIGN("SIGN_POST", "SIGN"), + SPRUCE_SLAB(1, "WOOD_DOUBLE_STEP", "WOOD_STEP", "WOODEN_SLAB"), SPRUCE_STAIRS("SPRUCE_WOOD_STAIRS"), SPRUCE_TRAPDOOR("TRAP_DOOR"), - SPRUCE_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + SPRUCE_WALL_SIGN("WALL_SIGN"), SPRUCE_WOOD(1, "LOG"), SQUID_SPAWN_EGG(94, "MONSTER_EGG"), STICK, STICKY_PISTON("PISTON_BASE", "PISTON_STICKY_BASE"), STONE, - STONECUTTER("1.14"), + STONECUTTER(14), STONE_AXE, STONE_BRICKS("SMOOTH_BRICK"), - STONE_BRICK_SLAB(4, "STEP", "STONE_SLAB", "STONE_SLAB"), + STONE_BRICK_SLAB(4, "DOUBLE_STEP", "STEP", "STONE_SLAB"), STONE_BRICK_STAIRS("SMOOTH_STAIRS"), STONE_BRICK_WALL, STONE_BUTTON, @@ -946,15 +1074,18 @@ public enum XMaterial { STONE_PICKAXE, STONE_PRESSURE_PLATE("STONE_PLATE"), STONE_SHOVEL("STONE_SPADE"), - STONE_SLAB("STEP", "STONE_SLAB"), + STONE_SLAB("DOUBLE_STEP", "STEP"), STONE_STAIRS, STONE_SWORD, STRAY_SPAWN_EGG(6, "MONSTER_EGG"), + STRIDER_SPAWN_EGG(16), STRING, STRIPPED_ACACIA_LOG("LOG_2"), STRIPPED_ACACIA_WOOD("LOG_2"), STRIPPED_BIRCH_LOG(2, "LOG"), STRIPPED_BIRCH_WOOD(2, "LOG"), + STRIPPED_CRIMSON_HYPHAE(16), + STRIPPED_CRIMSON_STEM(16), STRIPPED_DARK_OAK_LOG("LOG"), STRIPPED_DARK_OAK_WOOD("LOG"), STRIPPED_JUNGLE_LOG(3, "LOG"), @@ -963,41 +1094,50 @@ public enum XMaterial { STRIPPED_OAK_WOOD("LOG"), STRIPPED_SPRUCE_LOG(1, "LOG"), STRIPPED_SPRUCE_WOOD(1, "LOG"), + STRIPPED_WARPED_HYPHAE(16), + STRIPPED_WARPED_STEM(16), STRUCTURE_BLOCK, /** * Originally developers used barrier blocks for its purpose. - * 1.10 will be parsed as 1.9 version. + * So technically this isn't really considered as a suggested material. */ - STRUCTURE_VOID("1.10", "BARRIER"), + STRUCTURE_VOID(10, "", "BARRIER"), SUGAR, + /** + * Sugar Cane is a known material in pre-1.13 + * Use XBlock when comparing block types. + */ SUGAR_CANE("SUGAR_CANE_BLOCK"), SUNFLOWER("DOUBLE_PLANT"), - SUSPICIOUS_STEW("1.14", "MUSHROOM_STEW"), - SWEET_BERRIES("1.14"), - SWEET_BERRY_BUSH("1.14", "GRASS"), + SUSPICIOUS_STEW(0, 14, "MUSHROOM_STEW", ""), + SWEET_BERRIES(14), + SWEET_BERRY_BUSH(0, 14, "GRASS", ""), TALL_GRASS(2, "DOUBLE_PLANT"), - TALL_SEAGRASS(2, "1.13", "TALL_GRASS"), + TALL_SEAGRASS(2, 13, "TALL_GRASS", ""), + TARGET(16), TERRACOTTA("HARD_CLAY"), - TIPPED_ARROW("1.9", "ARROW"), + TIPPED_ARROW(0, 9, "ARROW", ""), TNT, TNT_MINECART("EXPLOSIVE_MINECART"), TORCH, TOTEM_OF_UNDYING("TOTEM"), - TRADER_LLAMA_SPAWN_EGG(103, "1.14", "MONSTER_EGG"), + TRADER_LLAMA_SPAWN_EGG(103, 14, "MONSTER_EGG", ""), TRAPPED_CHEST, - TRIDENT("1.13"), + TRIDENT(13), TRIPWIRE, TRIPWIRE_HOOK, TROPICAL_FISH(2, "RAW_FISH"), - TROPICAL_FISH_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), - TROPICAL_FISH_SPAWN_EGG("1.13", "MONSTER_EGG"), - TUBE_CORAL("1.13"), - TUBE_CORAL_BLOCK("1.13"), - TUBE_CORAL_FAN("1.13"), + TROPICAL_FISH_BUCKET(0, 13, "BUCKET", "WATER_BUCKET"), + TROPICAL_FISH_SPAWN_EGG(0, 13, "MONSTER_EGG"), + TUBE_CORAL(13), + TUBE_CORAL_BLOCK(13), + TUBE_CORAL_FAN(13), TUBE_CORAL_WALL_FAN, - TURTLE_EGG("1.13", "EGG"), - TURTLE_HELMET("1.13", "IRON_HELMET"), - TURTLE_SPAWN_EGG("1.13", "CHICKEN_SPAWN_EGG"), + TURTLE_EGG(0, 13, "EGG", ""), + TURTLE_HELMET(0, 13, "IRON_HELMET", ""), + TURTLE_SPAWN_EGG(0, 13, "CHICKEN_SPAWN_EGG", ""), + TWISTING_VINES(16), + TWISTING_VINES_PLANT(16), VEX_SPAWN_EGG(35, "MONSTER_EGG"), VILLAGER_SPAWN_EGG(120, "MONSTER_EGG"), VINDICATOR_SPAWN_EGG(36, "MONSTER_EGG"), @@ -1009,28 +1149,59 @@ public enum XMaterial { */ VOID_AIR("AIR"), WALL_TORCH("TORCH"), - WANDERING_TRADER_SPAWN_EGG("1.14", "VILLAGER_SPAWN_EGG"), + WANDERING_TRADER_SPAWN_EGG(0, 14, "VILLAGER_SPAWN_EGG", ""), + WARPED_BUTTON(16), + WARPED_DOOR(16), + WARPED_FENCE(16), + WARPED_FENCE_GATE(16), + WARPED_FUNGUS(16), + WARPED_FUNGUS_ON_A_STICK(16), + WARPED_HYPHAE(16), + WARPED_NYLIUM(16), + WARPED_PLANKS(16), + WARPED_PRESSURE_PLATE(16), + WARPED_ROOTS(16), + WARPED_SIGN(0, 16, "SIGN_POST"), + WARPED_SLAB(16), + WARPED_STAIRS(16), + WARPED_STEM(16), + WARPED_TRAPDOOR(16), + WARPED_WALL_SIGN(0, 16, "WALL_SIGN"), + WARPED_WART_BLOCK(16), + /** + * This is used for blocks only. + * In 1.13- WATER will turn into STATIONARY_WATER after it finished spreading. + * After 1.13+ this uses + * https://hub.spigotmc.org/javadocs/spigot/org/bukkit/block/data/Levelled.html water flowing system. + * Use XBlock for this instead. + */ WATER("STATIONARY_WATER"), WATER_BUCKET, + WEEPING_VINES(16), + WEEPING_VINES_PLANT(16), WET_SPONGE(1, "SPONGE"), + /** + * Wheat is a known material in pre-1.13 + * Use XBlock when comparing block types. + */ WHEAT("CROPS"), WHEAT_SEEDS("SEEDS"), - WHITE_BANNER(15, "BANNER", "STANDING_BANNER"), - WHITE_BED("BED", "BED_BLOCK"), + WHITE_BANNER(15, "STANDING_BANNER", "BANNER"), + WHITE_BED("BED_BLOCK", "BED"), WHITE_CARPET("CARPET"), WHITE_CONCRETE("CONCRETE"), WHITE_CONCRETE_POWDER("CONCRETE_POWDER"), - WHITE_DYE(15, "1.14", "INK_SAC", "BONE_MEAL"), - WHITE_GLAZED_TERRACOTTA("1.12", "HARD_CLAY", "STAINED_CLAY", "WHITE_TERRACOTTA"), + WHITE_DYE(15, 14, "INK_SACK", "BONE_MEAL"), + WHITE_GLAZED_TERRACOTTA(0, 12, "HARD_CLAY", "STAINED_CLAY"), WHITE_SHULKER_BOX, WHITE_STAINED_GLASS("STAINED_GLASS"), WHITE_STAINED_GLASS_PANE("THIN_GLASS", "STAINED_GLASS_PANE"), - WHITE_TERRACOTTA("HARD_CLAY", "TERRACOTTA"), + WHITE_TERRACOTTA("HARD_CLAY", "STAINED_CLAY", "TERRACOTTA"), WHITE_TULIP(6, "RED_ROSE"), WHITE_WALL_BANNER(15, "WALL_BANNER"), WHITE_WOOL("WOOL"), WITCH_SPAWN_EGG(66, "MONSTER_EGG"), - WITHER_ROSE("1.14", "BLACK_DYE"), + WITHER_ROSE(0, 14, "BLACK_DYE", ""), WITHER_SKELETON_SKULL(1, "SKULL", "SKULL_ITEM"), WITHER_SKELETON_SPAWN_EGG(5, "MONSTER_EGG"), WITHER_SKELETON_WALL_SKULL(1, "SKULL", "SKULL_ITEM"), @@ -1042,49 +1213,62 @@ public enum XMaterial { WOODEN_SWORD("WOOD_SWORD"), WRITABLE_BOOK("BOOK_AND_QUILL"), WRITTEN_BOOK, - YELLOW_BANNER(11, "BANNER", "STANDING_BANNER"), - YELLOW_BED(4, "BED", "BED_BLOCK"), + YELLOW_BANNER(11, "STANDING_BANNER", "BANNER"), + YELLOW_BED(4, "BED_BLOCK", "BED"), YELLOW_CARPET(4, "CARPET"), YELLOW_CONCRETE(4, "CONCRETE"), YELLOW_CONCRETE_POWDER(4, "CONCRETE_POWDER"), - YELLOW_DYE(11, "INK_SAC", "DANDELION_YELLOW"), - YELLOW_GLAZED_TERRACOTTA(4, "1.12", "HARD_CLAY", "STAINED_CLAY", "YELLOW_TERRACOTTA"), + YELLOW_DYE(11, "INK_SACK", "DANDELION_YELLOW"), + YELLOW_GLAZED_TERRACOTTA(4, 12, "HARD_CLAY", "STAINED_CLAY", "YELLOW_TERRACOTTA"), YELLOW_SHULKER_BOX, YELLOW_STAINED_GLASS(4, "STAINED_GLASS"), YELLOW_STAINED_GLASS_PANE(4, "THIN_GLASS", "STAINED_GLASS_PANE"), YELLOW_TERRACOTTA(4, "HARD_CLAY", "STAINED_CLAY"), YELLOW_WALL_BANNER(11, "WALL_BANNER"), YELLOW_WOOL(4, "WOOL"), + ZOGLIN_SPAWN_EGG(16), ZOMBIE_HEAD(2, "SKULL", "SKULL_ITEM"), ZOMBIE_HORSE_SPAWN_EGG(29, "MONSTER_EGG"), - ZOMBIE_PIGMAN_SPAWN_EGG(57, "MONSTER_EGG"), ZOMBIE_SPAWN_EGG(54, "MONSTER_EGG"), ZOMBIE_VILLAGER_SPAWN_EGG(27, "MONSTER_EGG"), - ZOMBIE_WALL_HEAD(2, "SKULL", "SKULL_ITEM"); + ZOMBIE_WALL_HEAD(2, "SKULL", "SKULL_ITEM"), + ZOMBIFIED_PIGLIN_SPAWN_EGG(57, "MONSTER_EGG", "ZOMBIE_PIGMAN_SPAWN_EGG"); /** - * An immutable cached set of {@link XMaterial#values()} to avoid allocating memory for + * Cached array of {@link XMaterial#values()} to avoid allocating memory for * calling the method every time. + * This list is unmodifiable. * * @since 2.0.0 */ - public static final EnumSet VALUES = EnumSet.allOf(XMaterial.class); + public static final XMaterial[] VALUES = values(); + + /** + * We don't want to use {@link Enums#getIfPresent(Class, String)} to avoid a few checks. + * + * @since 5.1.0 + */ + private static final Map NAMES = new HashMap<>(); + /** - * A set of material names that can be damaged. + * An array of material names that can be damaged. *

* Most of the names are not complete as this list is intended to be - * checked with {@link String#contains} for memory usage. + * checked with {@link String#contains} for memory usage and maintainability. + *

+ * New items will probably not be added to the list since they're new and it + * doesn't matter what their data value is. * * @since 1.0.0 */ - private static final ImmutableSet DAMAGEABLE = ImmutableSet.of( + private static final String[] DAMAGEABLE = { "HELMET", "CHESTPLATE", "LEGGINGS", "BOOTS", "SWORD", "AXE", "PICKAXE", "SHOVEL", "HOE", "ELYTRA", "TRIDENT", "HORSE_ARMOR", "BARDING", "SHEARS", "FLINT_AND_STEEL", "BOW", "FISHING_ROD", - "CARROT_ON_A_STICK", "CARROT_STICK" - ); + "CARROT_ON_A_STICK", "CARROT_STICK", "SPADE", "SHIELD" + }; /** * XMaterial Paradox (Duplication Check) *

@@ -1095,32 +1279,7 @@ public enum XMaterial { * * @since 3.0.0 */ - private static final ImmutableMap DUPLICATED = Maps.immutableEnumMap(ImmutableMap.builder() - .put(MELON, MELON_SLICE) - .put(CARROT, CARROTS) - .put(POTATO, POTATOES) - .put(BEETROOT, BEETROOTS) - .put(BROWN_MUSHROOM, BROWN_MUSHROOM_BLOCK) - .put(BRICK, BRICKS) - .put(RED_MUSHROOM, RED_MUSHROOM_BLOCK) - .put(MAP, FILLED_MAP) - .put(NETHER_BRICK, NETHER_BRICKS) - .build() - ); - /** - * A set of all the legacy names without duplicates. - *

- * REMOVE THIS IF YOU DON'T NEED IT. - * It'll help to free up a lot of memory. - * - * @see #containsLegacy(String) - * @since 2.2.0 - */ - private static final ImmutableSet LEGACY_VALUES = VALUES.stream().map(XMaterial::getLegacy) - .flatMap(Arrays::stream) - .filter(m -> m.charAt(1) == '.') - .collect(Collectors.collectingAndThen(Collectors.toSet(), ImmutableSet::copyOf)); - + private static final EnumMap DUPLICATED = new EnumMap<>(XMaterial.class); /** * Guava (Google Core Libraries for Java)'s cache for performance and timed caches. * For strings that match a certain XMaterial. Mostly cached for configs. @@ -1128,8 +1287,7 @@ public enum XMaterial { * @since 1.0.0 */ private static final Cache NAME_CACHE = CacheBuilder.newBuilder() - .softValues() - .expireAfterAccess(15, TimeUnit.MINUTES) + .expireAfterAccess(30, TimeUnit.MINUTES) .build(); /** * Guava (Google Core Libraries for Java)'s cache for performance and timed caches. @@ -1137,32 +1295,82 @@ public enum XMaterial { * * @since 3.0.0 */ - private static final Cache PARSED_CACHE = CacheBuilder.newBuilder() - .softValues() + private static final Cache> PARSED_CACHE = CacheBuilder.newBuilder() .expireAfterAccess(10, TimeUnit.MINUTES) - .concurrencyLevel(Runtime.getRuntime().availableProcessors()) .build(); - + /* + * A set of all the legacy names without duplicates. + *

+ * It'll help to free up a lot of memory if it's not used. + * Add it back if you need it. + * + * @see #containsLegacy(String) + * @since 2.2.0 + * + private static final ImmutableSet LEGACY_VALUES = VALUES.stream().map(XMaterial::getLegacy) + .flatMap(Arrays::stream) + .filter(m -> m.charAt(1) == '.') + .collect(Collectors.collectingAndThen(Collectors.toSet(), ImmutableSet::copyOf)); + */ /** - * Pre-compiled RegEx pattern. - * Include both replacements to avoid recreating string multiple times with multiple RegEx checks. + * This is used for {@link #isOneOf(Collection)} * - * @since 3.0.0 + * @since 3.4.0 */ - private static final Pattern FORMAT_PATTERN = Pattern.compile("\\W+"); + private static final LoadingCache CACHED_REGEX = CacheBuilder.newBuilder() + .expireAfterAccess(1, TimeUnit.HOURS) + .build(new CacheLoader() { + @Override + public Pattern load(@Nonnull String str) { + try { + return Pattern.compile(str); + } catch (PatternSyntaxException ex) { + ex.printStackTrace(); + return null; + } + } + }); /** - * The current version of the server in the a form of a major {@link MinecraftVersion} version. + * The current version of the server in the a form of a major version. * * @since 1.0.0 */ - private static final MinecraftVersion VERSION = valueOfVersion(Bukkit.getVersion()); + private static final int VERSION = Integer.parseInt(getMajorVersion(Bukkit.getVersion()).substring(2)); /** - * Cached result if the server version is after the flattening ({@link MinecraftVersion#V1_13}) update. - * Please don't mistake this with flat-chested people. It happened. + * Cached result if the server version is after the v1.13 flattening update. * * @since 3.0.0 */ - private static final boolean ISFLAT = isVersionOrHigher(MinecraftVersion.V1_13); + private static final boolean ISFLAT = supports(13); + + static { + DUPLICATED.put(MELON, MELON_SLICE); + DUPLICATED.put(CARROT, CARROTS); + DUPLICATED.put(POTATO, POTATOES); + DUPLICATED.put(BEETROOT, BEETROOTS); + DUPLICATED.put(BROWN_MUSHROOM, BROWN_MUSHROOM_BLOCK); + DUPLICATED.put(BRICK, BRICKS); + DUPLICATED.put(NETHER_BRICK, NETHER_BRICKS); + + // Illegal Elements + // Since both 1.12 and 1.13 have _DOOR XMaterial will use it + // for 1.12 to parse the material, but it needs _DOOR_ITEM. + // We'll trick XMaterial into thinking this needs to be parsed + // using the old methods. + // Some of these materials have their enum name added to the legacy list as well. + DUPLICATED.put(DARK_OAK_DOOR, DARK_OAK_DOOR); + DUPLICATED.put(ACACIA_DOOR, ACACIA_DOOR); + DUPLICATED.put(BIRCH_DOOR, BIRCH_DOOR); + DUPLICATED.put(JUNGLE_DOOR, JUNGLE_DOOR); + DUPLICATED.put(SPRUCE_DOOR, SPRUCE_DOOR); + DUPLICATED.put(CAULDRON, CAULDRON); + DUPLICATED.put(BREWING_STAND, BREWING_STAND); + DUPLICATED.put(FLOWER_POT, FLOWER_POT); + } + + static { + for (XMaterial material : VALUES) NAMES.put(material.name(), material); + } /** * The data value of this material https://minecraft.gamepedia.com/Java_Edition_data_values/Pre-flattening @@ -1170,37 +1378,53 @@ public enum XMaterial { * @see #getData() */ private final byte data; + /** + * The version that this material was added in. + * + * @since 7.0.0 + */ + private final byte version; /** * A list of material names that was being used for older verions. * * @see #getLegacy() */ + @Nonnull private final String[] legacy; - XMaterial(int data, String... legacy) { + XMaterial(int data, int version, @Nonnull String... legacy) { this.data = (byte) data; + this.version = (byte) version; this.legacy = legacy; } + XMaterial(int data, @Nonnull String... legacy) { + this(data, 0, legacy); + } + + XMaterial(int version) { + this(0, version); + } + XMaterial() { - this(0); + this(0, 0); } XMaterial(String... legacy) { - this(0, legacy); + this(0, 0, legacy); } /** - * Checks if the version is {@link MinecraftVersion#V1_13} (Aquatic Update) or higher. + * Checks if the version is 1.13 Aquatic Update or higher. * An invocation of this method yields the cached result from the expression: *

*

- * {@link #isVersionOrHigher(MinecraftVersion V1_13)} + * {@link #supports(int) 13}} *
* * @return true if 1.13 or higher. * @see #getVersion() - * @see #isVersionOrHigher(MinecraftVersion) + * @see #supports(int) * @since 1.0.0 */ public static boolean isNewVersion() { @@ -1216,24 +1440,35 @@ public static boolean isNewVersion() { * An invocation of this method yields exactly the same result as the expression: *

*

- * {@link #getVersion()} == {@link MinecraftVersion#V1_8} + * !{@link #supports(int)} 9 *
* * @since 2.0.0 */ public static boolean isOneEight() { - return VERSION == MinecraftVersion.V1_8; + return !supports(9); + } + + /** + * Gets the {@link XMaterial} with this name without throwing an exception. + * + * @param name the name of the material. + * @return an optional that can be empty. + * @since 5.1.0 + */ + @Nonnull + private static Optional getIfPresent(@Nonnull String name) { + return Optional.ofNullable(NAMES.get(name)); } /** * The current version of the server. * - * @return the current server version or {@link MinecraftVersion#UNKNOWN} if unknown or below 1.8. + * @return the current server version or 0.0 if unknown. * @see #isNewVersion() * @since 2.0.0 */ - @Nonnull - public static MinecraftVersion getVersion() { + public static int getVersion() { return VERSION; } @@ -1247,102 +1482,43 @@ public static MinecraftVersion getVersion() { @Nullable private static XMaterial requestOldXMaterial(@Nonnull String name, byte data) { String holder = name + data; - XMaterial material = NAME_CACHE.getIfPresent(holder); - if (material != null) return material; - - for (XMaterial materials : VALUES) { - if ((data == -1 || data == materials.data) && materials.anyMatchLegacy(name)) { - material = materials; - break; + XMaterial cache = NAME_CACHE.getIfPresent(holder); + if (cache != null) return cache; + + for (XMaterial material : VALUES) { + // Not using material.name().equals(name) check is intended. + if ((data == -1 || data == material.data) && material.anyMatchLegacy(name)) { + NAME_CACHE.put(holder, material); + return material; } } - if (material != null) NAME_CACHE.put(holder, material); - return material; - } - - /** - * Checks if XMaterial enum contains a material with the given name. - *

- * You should use {@link #matchXMaterial(String)} instead if you're going - * to get the XMaterial object after checking if it's available in the list - * by doing a simple {@link Optional#isPresent()} check. - * This is just to avoid multiple loops for maximum performance. - * - * @param name name of the material. - * @return true if XMaterial enum has this material. - * @see #containsLegacy(String) - * @since 1.0.0 - */ - public static boolean contains(@Nonnull String name) { - Validate.notEmpty(name, "Cannot check for null or empty material name"); - name = format(name); - - for (XMaterial materials : VALUES) - if (materials.name().equals(name)) return true; - return false; - } - - /** - * Checks if the given material matches any of the available legacy names. - * Changed names between the {@code 1.9} and {@code 1.12} versions are not supported (there are only a few anyway). - * - * @param name the material name. - * @return true if it's a legacy name. - * @see #contains(String) - * @see #anyMatchLegacy(String) - * @since 2.0.0 - */ - public static boolean containsLegacy(@Nonnull String name) { - Validate.notEmpty(name, "Cannot check legacy names for null or empty material name"); - return LEGACY_VALUES.contains(format(name)); + return null; } /** * Parses the given material name as an XMaterial with unspecified data value. * - * @see #matchXMaterial(String, byte) + * @see #matchXMaterialWithData(String) * @since 2.0.0 */ @Nonnull public static Optional matchXMaterial(@Nonnull String name) { - return matchXMaterial(name, (byte) -1); - } - - /** - * Parses the given material name as an XMaterial. - * Can also be used like: MATERIAL:DATA - *

- * Examples - *

-     *     INK_SAC:1 -> RED_DYE
-     *     WOOL, 14  -> RED_WOOL
-     * 
- * - * @see #matchDefinedXMaterial(String, byte) - * @see #matchXMaterial(ItemStack) - * @since 2.0.0 - */ - @Nonnull - public static Optional matchXMaterial(@Nonnull String name, byte data) { Validate.notEmpty(name, "Cannot match a material with null or empty material name"); Optional oldMatch = matchXMaterialWithData(name); if (oldMatch.isPresent()) return oldMatch; - - // -1 Determines whether the item's data value is unknown and only the name is given. - // Checking if the item is damageable won't do anything as the data is not going to be checked in requestOldMaterial anyway. - return matchDefinedXMaterial(format(name), data); + return matchDefinedXMaterial(format(name), (byte) -1); } /** * Parses material name and data value from the specified string. - * The seperators are: , or : + * The separator for the material name and its data value is {@code :} * Spaces are allowed. Mostly used when getting materials from config for old school minecrafters. *

* Examples *

-     *     INK_SAC:1 -> RED_DYE
-     *     WOOL, 14  -> RED_WOOL
+     *     {@code INK_SACK:1 -> RED_DYE}
+     *     {@code WOOL: 14  -> RED_WOOL}
      * 
* * @param name the material string that consists of the material name, data and separator character. @@ -1350,14 +1526,17 @@ public static Optional matchXMaterial(@Nonnull String name, byte data * @see #matchXMaterial(String) * @since 3.0.0 */ - private static Optional matchXMaterialWithData(String name) { - for (char separator : new char[]{',', ':'}) { - int index = name.indexOf(separator); - if (index == -1) continue; - + @Nonnull + private static Optional matchXMaterialWithData(@Nonnull String name) { + int index = name.indexOf(':'); + if (index != -1) { String mat = format(name.substring(0, index)); - byte data = Byte.parseByte(StringUtils.deleteWhitespace(name.substring(index + 1))); - return matchDefinedXMaterial(mat, data); + + try { + byte data = Byte.parseByte(StringUtils.deleteWhitespace(name.substring(index + 1))); + return matchDefinedXMaterial(mat, data); + } catch (NumberFormatException ignored) { + } } return Optional.empty(); @@ -1375,7 +1554,7 @@ private static Optional matchXMaterialWithData(String name) { public static XMaterial matchXMaterial(@Nonnull Material material) { Objects.requireNonNull(material, "Cannot match null material"); return matchDefinedXMaterial(material.name(), (byte) -1) - .orElseThrow(() -> new IllegalArgumentException("Unsupported Material: " + material)); + .orElseThrow(() -> new IllegalArgumentException("Unsupported material with no data value: " + material.name())); } /** @@ -1392,9 +1571,10 @@ public static XMaterial matchXMaterial(@Nonnull Material material) { public static XMaterial matchXMaterial(@Nonnull ItemStack item) { Objects.requireNonNull(item, "Cannot match null ItemStack"); String material = item.getType().name(); - return matchDefinedXMaterial(material, - isDamageable(material) ? (byte) 0 : (byte) item.getDurability()) - .orElseThrow(() -> new IllegalArgumentException("Unsupported Material: " + material)); + byte data = (byte) (ISFLAT || isDamageable(material) ? 0 : item.getDurability()); + + return matchDefinedXMaterial(material, data) + .orElseThrow(() -> new IllegalArgumentException("Unsupported material: " + material + " (" + data + ')')); } /** @@ -1404,12 +1584,12 @@ public static XMaterial matchXMaterial(@Nonnull ItemStack item) { * @param name the formatted name of the material. * @param data the data value of the material. * @return an XMaterial (with the same data value if specified) - * @see #matchXMaterial(String, byte) * @see #matchXMaterial(Material) * @see #matchXMaterial(int, byte) * @see #matchXMaterial(ItemStack) * @since 3.0.0 */ + @SuppressWarnings("OptionalAssignedToNull") @Nonnull private static Optional matchDefinedXMaterial(@Nonnull String name, byte data) { boolean duplicated = isDuplicated(name); @@ -1417,19 +1597,32 @@ private static Optional matchDefinedXMaterial(@Nonnull String name, b // Do basic number and boolean checks before accessing more complex enum stuff. // Maybe we can simplify (ISFLAT || !duplicated) with the (!ISFLAT && duplicated) under it to save a few nanoseconds? // if (!Boolean.valueOf(Boolean.getBoolean(Boolean.TRUE.toString())).equals(Boolean.FALSE.booleanValue())) return null; + Optional xMaterial = null; if (data <= 0 && (ISFLAT || !duplicated)) { // Apparently the transform method is more efficient than toJavaUtil() // toJavaUtil isn't even supported in older versions. - Optional xMat = Enums.getIfPresent(XMaterial.class, name).transform(Optional::of).or(Optional.empty()); - if (xMat.isPresent()) return xMat; + xMaterial = getIfPresent(name); + if (xMaterial.isPresent()) return xMaterial; } // XMaterial Paradox (Duplication Check) // I've concluded that this is just an infinite loop that keeps // going around the Singular Form and the Plural Form materials. A waste of brain cells and a waste of time. // This solution works just fine anyway. - if (!ISFLAT && duplicated) return Optional.ofNullable(requestDuplicatedXMaterial(name, data)); - return Optional.ofNullable(requestOldXMaterial(name, data)); + XMaterial xMat = requestOldXMaterial(name, data); + if (xMat == null) { + // Special case. Refer to FILLED_MAP for more info. + if (data > 0 && name.endsWith("MAP")) return Optional.of(FILLED_MAP); + return Optional.empty(); + } + + if (!ISFLAT && duplicated && xMat.name().charAt(xMat.name().length() - 1) == 'S') { + // A solution for XMaterial Paradox. + // Manually parses the duplicated materials to find the exact material based on the server version. + // If ends with "S" -> Plural Form Material + return xMaterial == null ? getIfPresent(name) : xMaterial; + } + return Optional.ofNullable(xMat); } /** @@ -1444,13 +1637,12 @@ private static Optional matchDefinedXMaterial(@Nonnull String name, b * @see #isDuplicated() * @since 2.0.0 */ - public static boolean isDuplicated(@Nonnull String name) { - Validate.notEmpty(name, "Cannot check duplication for null or empty material name"); - name = format(name); - + private static boolean isDuplicated(@Nonnull String name) { // Don't use matchXMaterial() since this method is being called from matchXMaterial() itself and will cause a StackOverflowError. - for (Map.Entry duplicated : DUPLICATED.entrySet()) - if (duplicated.getKey().name().equals(name) || duplicated.getKey().anyMatchLegacy(name)) return true; + for (Map.Entry duplicated : DUPLICATED.entrySet()) { + XMaterial material = duplicated.getKey(); + if (material.name().equals(name) || material.anyMatchLegacy(name)) return true; + } return false; } @@ -1469,102 +1661,60 @@ public static Optional matchXMaterial(int id, byte data) { if (id < 0 || data < 0) return Optional.empty(); // Looping through Material.values() will take longer. - for (XMaterial materials : VALUES) + for (XMaterial materials : VALUES) { if (materials.data == data && materials.getId() == id) return Optional.of(materials); + } return Optional.empty(); } - /** - * A solution for XMaterial Paradox. - * Manually parses the duplicated materials to find the exact material based on the server version. - * - * @param name the name of the material. - * @return the duplicated XMaterial based on the version. - * @throws IllegalArgumentException may be thrown. If thrown, it's a bug. - * @since 2.0.0 - */ - @Nullable - private static XMaterial requestDuplicatedXMaterial(@Nonnull String name, byte data) { - XMaterial mat = requestOldXMaterial(name, data); - // If ends with "S" -> Plural Form Material - return mat.name().charAt(mat.name().length() - 1) == 'S' ? valueOf(name) : mat; - } - - /** - * Always returns the value with the given duplicated material key name. - * - * @param name the name of the material. - * @return the new XMaterial of this duplicated material. - * @see #getXMaterialIfDuplicated(String) - * @since 2.0.0 - */ - @Nonnull - public static Optional getNewXMaterialIfDuplicated(@Nonnull String name) { - Validate.notEmpty(name, "Cannot get new duplicated material for null or empty material name"); - name = format(name); - - for (Map.Entry duplicated : DUPLICATED.entrySet()) - if (duplicated.getKey().name().equals(name)) return Optional.of(duplicated.getKey()); - return Optional.empty(); - } - - /** - * Checks if the item is duplicated for a different purpose in new versions from {@link #DUPLICATED}. - * - * @param name the name of the material. - * @return the other XMaterial (key or value) of the XMaterial (key or value). - * @see #matchXMaterial(String, byte) - * @since 2.0.0 - */ - @Nullable - public static XMaterial getXMaterialIfDuplicated(@Nonnull String name) { - Validate.notEmpty(name, "Cannot get duplicated material for null or empty material name"); - name = format(name); - - for (Map.Entry duplicated : DUPLICATED.entrySet()) - if (duplicated.getKey().name().equals(name)) return duplicated.getValue(); - else if (duplicated.getValue().name().equals(name)) return duplicated.getKey(); - - return null; - } - /** * Attempts to build the string like an enum name. - * Removes all the spaces, numbers and extra non-English characters. Also removes some config/in-game based strings. + * Removes all the spaces, and extra non-English characters. Also removes some config/in-game based strings. + * While this method is hard to maintain, it's extremely efficient. It's approximately more than x5 times faster than + * the normal RegEx + String Methods approach for both formatted and unformatted material names. * * @param name the material name to modify. * @return a Material enum name. * @since 2.0.0 */ @Nonnull - private static String format(@Nonnull String name) { - return FORMAT_PATTERN.matcher( - name.trim().replace('-', '_').replace(' ', '_')).replaceAll("").toUpperCase(Locale.ENGLISH); - } + protected static String format(@Nonnull String name) { + int len = name.length(); + char[] chs = new char[len]; + int count = 0; + boolean appendUnderline = false; + + for (int i = 0; i < len; i++) { + char ch = name.charAt(i); + + if (!appendUnderline && count != 0 && (ch == '-' || ch == ' ' || ch == '_') && chs[count] != '_') appendUnderline = true; + else { + boolean number = false; + // Old materials have numbers in them. + if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (number = (ch >= '0' && ch <= '9'))) { + if (appendUnderline) { + chs[count++] = '_'; + appendUnderline = false; + } + + if (number) chs[count++] = ch; + else chs[count++] = (char) (ch & 0x5f); + } + } + } - /** - * Parses the material name if the legacy name has a version attached to it. - * - * @param name the material name to parse. - * @return the material name with the version removed. - * @since 2.0.0 - */ - @Nonnull - private static String parseLegacyMaterialName(String name) { - int index = name.indexOf('/'); - return index == -1 ? name : name.substring(0, index); + return new String(chs, 0, count); } /** * Checks if the specified version is the same version or higher than the current server version. * - * @param version the version to be checked. + * @param version the major version to be checked. "1." is ignored. E.g. 1.12 = 12 | 1.9 = 9 * @return true of the version is equal or higher than the current version. * @since 2.0.0 */ - public static boolean isVersionOrHigher(@Nonnull MinecraftVersion version) { - Objects.requireNonNull(version, "Cannot compare to a null version"); - return VERSION.ordinal() >= version.ordinal(); + public static boolean supports(int version) { + return VERSION >= version; } /** @@ -1604,43 +1754,28 @@ private static String toWord(@Nonnull String name) { * Gets the exact major version (..., 1.9, 1.10, ..., 1.14) * * @param version Supports {@link Bukkit#getVersion()}, {@link Bukkit#getBukkitVersion()} and normal formats such as "1.14" - * @return the exact major version, or {@link MinecraftVersion#UNKNOWN} if unknown or unsupported. + * @return the exact major version. * @since 2.0.0 */ @Nonnull public static String getMajorVersion(@Nonnull String version) { - Validate.notEmpty(version, "Cannot get exact major minecraft version for null or empty version"); - - // getBukkitVersion() - if (version.contains("-R") || version.endsWith("SNAPSHOT")) version = version.substring(0, version.indexOf('-')); + Validate.notEmpty(version, "Cannot get major Minecraft version from null or empty string"); // getVersion() - int index = version.indexOf("MC:"); - if (index != -1) version = version.substring(index + 4, version.length() - 1); + int index = version.lastIndexOf("MC:"); + if (index != -1) { + version = version.substring(index + 4, version.length() - 1); + } else if (version.endsWith("SNAPSHOT")) { + // getBukkitVersion() + index = version.indexOf('-'); + version = version.substring(0, index); + } // 1.13.2, 1.14.4, etc... int lastDot = version.lastIndexOf('.'); if (version.indexOf('.') != lastDot) version = version.substring(0, lastDot); - return version; - } - /** - * Parses the string arugment to a version. - * Supports {@link Bukkit#getVersion()}, {@link Bukkit#getBukkitVersion()} and normal formats such as "1.14" - * - * @param version the server version. - * @return the Minecraft version represented by the string. - * @since 2.0.0 - */ - @Nonnull - public static MinecraftVersion valueOfVersion(@Nonnull String version) { - Validate.notEmpty(version, "Cannot get minecraft version for null or empty version"); - - version = getMajorVersion(version); - if (version.equals("1.10") || version.equals("1.11") || version.equals("1.12")) return MinecraftVersion.V1_9; - - version = 'V' + version.replace('.', '_'); - return Enums.getIfPresent(MinecraftVersion.class, version).or(MinecraftVersion.UNKNOWN); + return version; } /** @@ -1654,48 +1789,12 @@ public static MinecraftVersion valueOfVersion(@Nonnull String version) { */ public static boolean isDamageable(@Nonnull String name) { Objects.requireNonNull(name, "Material name cannot be null"); - for (String damageable : DAMAGEABLE) + for (String damageable : DAMAGEABLE) { if (name.contains(damageable)) return true; + } return false; } - /** - * Gets the version which this material was added in. - * If the material was added before {@link MinecraftVersion#V1_13} then - * it'll return {@link MinecraftVersion#UNKNOWN} - * - * @return the Minecraft version which tihs material was added in. - * @since 3.0.0 - */ - @Nonnull - public MinecraftVersion getMaterialVersion() { - if (this.legacy.length == 0) return MinecraftVersion.UNKNOWN; - String version = this.legacy[0]; - if (version.charAt(1) != '.') return MinecraftVersion.UNKNOWN; - - return MinecraftVersion.valueOf('V' + version.replace('.', '_')); - } - - /** - * Sets the {@link Material} (and data value on older versions) of an item. - * Damageable materials will not have their durability changed. - *

- * Use {@link #parseItem()} instead when creating new ItemStacks. - * - * @param item the item to change its type. - * @see #parseItem() - * @since 3.0.0 - */ - @Nonnull - @SuppressWarnings("deprecation") - public ItemStack setType(@Nonnull ItemStack item) { - Objects.requireNonNull(item, "Cannot set material for null ItemStack"); - - item.setType(this.parseMaterial()); - if (!ISFLAT && !this.isDamageable()) item.setDurability(this.data); - return item; - } - /** * Checks if the list of given material names matches the given base material. * Mostly used for configs. @@ -1710,14 +1809,14 @@ public ItemStack setType(@Nonnull ItemStack item) { *
* {@code CONTAINS} Examples: *

-     *     "CONTAINS:CHEST" -> CHEST, ENDERCHEST, TRAPPED_CHEST -> true
-     *     "cOnTaINS:dYe" -> GREEN_DYE, YELLOW_DYE, BLUE_DYE, INK_SACK -> true
+     *     {@code "CONTAINS:CHEST" -> CHEST, ENDERCHEST, TRAPPED_CHEST -> true}
+     *     {@code "cOnTaINS:dYe" -> GREEN_DYE, YELLOW_DYE, BLUE_DYE, INK_SACK -> true}
      * 
*

* {@code REGEX} Examples *

-     *     "REGEX:^.+_.+_.+$" -> Every Material with 3 underlines or more: SHULKER_SPAWN_EGG, SILVERFISH_SPAWN_EGG, SKELETON_HORSE_SPAWN_EGG
-     *     "REGEX:^.{1,3}$" -> Material names that have 3 letters only: BED, MAP, AIR
+     *     {@code "REGEX:^.+_.+_.+$" -> Every Material with 3 underlines or more: SHULKER_SPAWN_EGG, SILVERFISH_SPAWN_EGG, SKELETON_HORSE_SPAWN_EGG}
+     *     {@code "REGEX:^.{1,3}$" -> Material names that have 3 letters only: BED, MAP, AIR}
      * 
*

* The reason that there are tags for {@code CONTAINS} and {@code REGEX} @@ -1734,54 +1833,73 @@ public ItemStack setType(@Nonnull ItemStack item) { * * @param materials the material names to check base material on. * @return true if one of the given material names is similar to the base material. - * @since 3.0.0 + * @since 3.1.1 */ - public boolean isOneOf(@Nullable List materials) { + public boolean isOneOf(@Nullable Collection materials) { if (materials == null || materials.isEmpty()) return false; - Material baseMat = this.parseMaterial(); - if (baseMat == null) return false; + String name = this.name(); for (String comp : materials) { - comp = comp.toUpperCase(); - if (comp.startsWith("CONTAINS:")) { - comp = format(comp.substring(9)); - if (this.name().contains(comp)) return true; + String checker = comp.toUpperCase(Locale.ENGLISH); + if (checker.startsWith("CONTAINS:")) { + comp = format(checker.substring(9)); + if (name.contains(comp)) return true; continue; - } else if (comp.startsWith("REGEX:")) { + } + if (checker.startsWith("REGEX:")) { comp = comp.substring(6); - if (this.name().matches(comp)) return true; + Pattern pattern = CACHED_REGEX.getUnchecked(comp); + if (pattern != null && pattern.matcher(name).matches()) return true; continue; } - // Normal handling - Equals - Optional mat = matchXMaterial(comp); - if (mat.isPresent() && mat.get().parseMaterial() == baseMat) return true; + // Direct Object Equals + Optional xMat = matchXMaterial(comp); + if (xMat.isPresent() && xMat.get() == this) return true; } return false; } + /** + * Sets the {@link Material} (and data value on older versions) of an item. + * Damageable materials will not have their durability changed. + *

+ * Use {@link #parseItem()} instead when creating new ItemStacks. + * + * @param item the item to change its type. + * @see #parseItem() + * @since 3.0.0 + */ + @Nonnull + @SuppressWarnings("deprecation") + public ItemStack setType(@Nonnull ItemStack item) { + Objects.requireNonNull(item, "Cannot set material for null ItemStack"); + Material material = this.parseMaterial(); + Objects.requireNonNull(material, "Unsupported material: " + this.name()); + + item.setType(material); + if (!ISFLAT && !this.isDamageable()) item.setDurability(this.data); + return item; + } + /** * Checks if the given string matches any of this material's legacy material names. + * All the values passed to this method will not be null or empty and are formatted correctly. * * @param name the name to check * @return true if it's one of the legacy names. - * @see #containsLegacy(String) * @since 2.0.0 */ public boolean anyMatchLegacy(@Nonnull String name) { - Validate.notEmpty(name, "Cannot check for legacy name for null or empty material name"); - // If it's a new material, everything after this is a suggestion. - // At least until now except one or two materials. - if (this.isNew()) return false; - - name = format(name); - for (String legacy : this.legacy) - if (parseLegacyMaterialName(legacy).equals(name)) return true; + for (String legacy : this.legacy) { + if (legacy.isEmpty()) break; // Left-side suggestion list + if (name.equals(legacy)) return true; + } return false; } /** - * Friendly readable string for this material + * User-friendly readable name for this material * In most cases you should be using {@link #name()} instead. * * @return string of this object. @@ -1789,6 +1907,7 @@ public boolean anyMatchLegacy(@Nonnull String name) { * @since 3.0.0 */ @Override + @Nonnull public String toString() { return toWord(this.name()); } @@ -1802,7 +1921,7 @@ public String toString() { */ @SuppressWarnings("deprecation") public int getId() { - if (this.isNew()) return -1; + if (this.data != 0 || (this.version >= 13)) return -1; Material material = this.parseMaterial(); return material == null ? -1 : material.getId(); } @@ -1811,7 +1930,6 @@ public int getId() { * Checks if the material has any duplicates. * * @return true if there is a duplicated name for this material, otherwise false. - * @see #getXMaterialIfDuplicated() * @see #isDuplicated(String) * @since 2.0.0 */ @@ -1819,19 +1937,6 @@ public boolean isDuplicated() { return DUPLICATED.containsKey(this); } - /** - * Checks if the item is duplicated for a different purpose in new versions. - * - * @return true if the item's name is duplicated, otherwise false. - * @see #isDuplicated() - * @see #getNewXMaterialIfDuplicated(String) - * @since 2.0.0 - */ - @Nullable - public XMaterial getXMaterialIfDuplicated() { - return DUPLICATED.get(this); - } - /** * Checks if the material can be damaged by using it. * Names going through this method are not formatted. @@ -1853,6 +1958,7 @@ public boolean isDamageable() { * @return data of this material, or 0 if none. * @since 1.0.0 */ + @SuppressWarnings("deprecation") public byte getData() { return data; } @@ -1860,7 +1966,7 @@ public byte getData() { /** * Get a list of materials names that was previously used by older versions. * If the material was added in a new version {@link #isNewVersion()}, - * then the first element will indicate which version the material was added in {@link MinecraftVersion}. + * then the first element will indicate which version the material was added in. * * @return a list of legacy material names and the first element as the version the material was added in if new. * @since 1.0.0 @@ -1888,7 +1994,7 @@ public ItemStack parseItem() { * Parses an item from this XMaterial. * Uses data values on older versions. * - * @param suggest if true {@link #parseMaterial(boolean true)} will be used. + * @param suggest if true {@link #parseMaterial(boolean)} true will be used. * @return an ItemStack with the same material (and data value if in older versions.) * @see #setType(ItemStack) * @since 2.0.0 @@ -1918,13 +2024,14 @@ public Material parseMaterial() { * * @param suggest use a suggested material (from older materials) if the material is added in a later version of Minecraft. * @return the material related to this XMaterial based on the server version. - * @see #matchXMaterial(String, byte) * @since 2.0.0 */ + @SuppressWarnings("OptionalAssignedToNull") @Nullable public Material parseMaterial(boolean suggest) { - Material mat = PARSED_CACHE.getIfPresent(this); - if (mat != null) return mat; + Optional cache = PARSED_CACHE.getIfPresent(this); + if (cache != null) return cache.orElse(null); + Material mat; if (!ISFLAT && this.isDuplicated()) mat = requestOldMaterial(suggest); else { @@ -1932,7 +2039,8 @@ public Material parseMaterial(boolean suggest) { if (mat == null) mat = requestOldMaterial(suggest); } - if (mat != null) PARSED_CACHE.put(this, mat); + Optional opt = Optional.ofNullable(mat); + PARSED_CACHE.put(this, opt); return mat; } @@ -1947,27 +2055,22 @@ public Material parseMaterial(boolean suggest) { */ @Nullable private Material requestOldMaterial(boolean suggest) { - boolean noMaterialParse = this.isNew() && !suggest; - Material material; - for (int i = this.legacy.length - 1; i >= 0; i--) { String legacy = this.legacy[i]; - // Slash means it's just another name for the material in another version. - int index = legacy.indexOf('/'); - if (index != -1) { - legacy = legacy.substring(0, index); - material = Material.getMaterial(legacy); + // Check if we've reached the end and the last string is our + // material version. + if (i == 0 && legacy.charAt(1) == '.') return null; - if (material != null) return material; - else continue; + // According to the suggestion list format, all the other names continuing + // from here are considered as a "suggestion" + // The empty string is an indicator for suggestion list on the left side. + if (legacy.isEmpty()) { + if (suggest) continue; + break; } - // According to the suggestion format list, all the other names continuing - // from here are considered as a "suggestion" if there's no slash anymore. - // But continue if it's not even a new material. - if (noMaterialParse) return null; - material = Material.getMaterial(legacy); + Material material = Material.getMaterial(legacy); if (material != null) return material; } return null; @@ -1984,7 +2087,7 @@ private Material requestOldMaterial(boolean suggest) { public boolean isSimilar(@Nonnull ItemStack item) { Objects.requireNonNull(item, "Cannot compare with null ItemStack"); if (item.getType() != this.parseMaterial()) return false; - return (ISFLAT || this.isDamageable()) || item.getDurability() == this.data; + return ISFLAT || this.isDamageable() || item.getDurability() == this.data; } /** @@ -1997,7 +2100,13 @@ public boolean isSimilar(@Nonnull ItemStack item) { */ @Nonnull public List getSuggestions() { - return this.isNew() ? Arrays.stream(this.legacy).skip(1).collect(Collectors.toList()) : new ArrayList<>(); + if (this.legacy.length == 0 || this.version == 0) return new ArrayList<>(); + List suggestions = new ArrayList<>(); + for (String legacy : this.legacy) { + if (legacy.isEmpty()) break; + suggestions.add(legacy); + } + return suggestions; } /** @@ -2008,92 +2117,17 @@ public List getSuggestions() { * if you're going to parse and use the material later. * * @return true if the material exists in {@link Material} list. - * @see #isNew() * @since 2.0.0 */ public boolean isSupported() { - MinecraftVersion version = this.getMaterialVersion(); - if (version != MinecraftVersion.UNKNOWN) return isVersionOrHigher(version); + if (this.version != 0) return supports(this.version); Material material = Material.getMaterial(this.name()); - if (material == null) { - for (int i = this.legacy.length - 1; i != -1; i--) { - String legacy = this.legacy[i]; - if (StringUtils.contains(legacy, '/')) continue; - - material = Material.getMaterial(legacy); - if (material != null) break; - } - } - return material != null; - } - - /** - * Checks if the material is newly added after the 1.13 Aquatic Update ({@link MinecraftVersion#V1_13}). - * - * @return true if the material was newly added, otherwise false. - * @see #getMaterialVersion() - * @since 2.0.0 - */ - public boolean isNew() { - return this.legacy.length != 0 && this.legacy[0].charAt(1) == '.'; + if (material != null) return true; + return requestOldMaterial(false) != null; } - /** - * Only major Minecraft versions related to most changes. - * The enum's order should not be changed. - * - * @since 2.0.0 - */ - public enum MinecraftVersion { - /** - * 1.7 or below. - * Using {@link #getMaterialVersion()} it means 1.12 or below. - * https://minecraft.gamepedia.com/Java_Edition_1.7 - * - * @since 2.0.0 - */ - UNKNOWN, - - /** - * Bountiful Update - * https://minecraft.gamepedia.com/Java_Edition_1.18 - * - * @since 2.0.0 - */ - V1_8, - - /** - * Combat Update (Pitiful Update? 90% of the reason why that this class is a thing) - * https://minecraft.gamepedia.com/Java_Edition_1.9 - * - * @since 2.0.0 - */ - V1_9, - - /** - * Aquatic Update - * Includes 1.10, 1.11 and 1.12 - * https://minecraft.gamepedia.com/Java_Edition_1.13 - * - * @since 2.0.0 - */ - V1_13, - - /** - * Village Pillage Update - * https://minecraft.gamepedia.com/Java_Edition_1.14 - * - * @since 2.0.0 - */ - V1_14, - - /** - * Buzzy Bees Update - * https://minecraft.gamepedia.com/Java_Edition_1.15 - * - * @since 3.0.0 - */ - V1_15 + public byte getMaterialVersion() { + return version; } } \ No newline at end of file