diff --git a/build.gradle b/build.gradle index 1f279b7..f2bdbf0 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { } group = 'me.skymc' -version = '5.13' +version = '5.14' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/src/main/resources/__resources__/lang/en_US.yml b/src/main/resources/__resources__/lang/en_US.yml index 4ae9b2b..2ae707b 100644 --- a/src/main/resources/__resources__/lang/en_US.yml +++ b/src/main/resources/__resources__/lang/en_US.yml @@ -13,26 +13,26 @@ MISC: FIELD-COPY-ERROR: 'Error when copy {0}:{1}' MYSQL-HIKARI: - CREATE-SUCCESS: '&7插件 &f{0} &7注册新的连接池: &f{1}' - CREATE-EXISTS: '&7插件 &f{0} &7引用插件 &f{1} &7注册的连接池.' - CLOSE-SUCCESS: '&7插件 &f{0} &7注册的连接池 &f{1} &7已被注销.' - CLOSE-FAIL: '&7插件 &f{0} &7注册的连接池正在被 &f{1} &7个插件使用, 无法注销!' + CREATE-SUCCESS: '&7Plugin &f{0} &7registered connection: &f{1}' + CREATE-EXISTS: '&7Plugin &f{0} &7reference the connection registered by plugin: &f{1}' + CLOSE-SUCCESS: '&7Plugin &f{0} &7deregistered connection &f{1}' + CLOSE-FAIL: '&7Plugin &f{0} &7Try to deregister connection used by &f{1} &7plugins.' COMMANDS: GLOBAL: ONLY-PLAYER: '&8[&3&lTabooLib&8] &4This is only for player.' - ONLY-STORAGE-SQL: '&8[&3&lTabooLib&8] &4只有启用数据库储存时才能这么做' + ONLY-STORAGE-SQL: '&8[&3&lTabooLib&8] &4Can only be done when SQL-Mode is enabled.' INTERNAL: TYPE-ERROR: '&8[&3&lTabooLib&8] &7Command &f{0} &7can only be executed by &f{1} &7.' TYPE-PLAYER: 'Player' TYPE-CONSOLE: 'Console' ERROR-USAGE: - '&8[&3&lTabooLib&8] &7Command &f{0} &7' - - '&8[&3&lTabooLib&8] &7正确用法:' + - '&8[&3&lTabooLib&8] &7Usage:' - '&8[&3&lTabooLib&8] &7{1}' ERROR-COMMAND: - - '&8[&3&lTabooLib&8] &7指令 &f{0} &7不存在' - - '&8[&3&lTabooLib&8] &7你可能想要:' + - '&8[&3&lTabooLib&8] &7Command &f{0} &7not found' + - '&8[&3&lTabooLib&8] &7Maybe:' - '&8[&3&lTabooLib&8] &7{1}' COMMAND-CREATE-FAILED: '&c插件 &7{0} &c的 &7{1} &c命令注册失败: &7{2}' COMMAND-HELP: ' §f/{0} {1} {2}§6- §e{3}' @@ -40,8 +40,8 @@ COMMANDS: COMMAND-ARGUMENT: '§7<§8{0}§7>' COMMAND-ARGUMENT-REQUIRE: '§7[§8{0}§7]' PARAMETER: - UNKNOWN: '&8[&3&lTabooLib&8] &4指令错误' - INSUFFICIENT: '&8[&3&lTabooLib&8] &4参数不足' + UNKNOWN: '&8[&3&lTabooLib&8] &4Invalid command.' + INSUFFICIENT: '&8[&3&lTabooLib&8] &4Invalid arguments.' COMMUNICATION: FAILED-LOAD-SETTINGS: '§8[§3§lTabooLibClient§8] &4配置载入失败: {0}' diff --git a/src/main/scala/io/izzel/taboolib/module/config/TConfig.java b/src/main/scala/io/izzel/taboolib/module/config/TConfig.java index fd1df4d..2fe6e33 100644 --- a/src/main/scala/io/izzel/taboolib/module/config/TConfig.java +++ b/src/main/scala/io/izzel/taboolib/module/config/TConfig.java @@ -1,5 +1,6 @@ package io.izzel.taboolib.module.config; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import io.izzel.taboolib.TabooLib; import io.izzel.taboolib.TabooLibAPI; @@ -16,7 +17,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.Optional; /** * @Author sky @@ -26,7 +26,7 @@ public class TConfig extends YamlConfiguration { private static Map> files = Maps.newHashMap(); private File file; - private Runnable runnable; + private List runnable = Lists.newArrayList(); private TConfig(File file, Plugin plugin) { files.computeIfAbsent(plugin.getName(), name -> new ArrayList<>()).add(file); @@ -100,19 +100,25 @@ public class TConfig extends YamlConfiguration { } public Runnable getListener() { + return runnable.get(0); + } + + public List getListeners() { return runnable; } public TConfig listener(Runnable runnable) { - this.runnable = runnable; + this.runnable.add(runnable); return this; } public void runListener() { - try { - Optional.ofNullable(runnable).ifPresent(Runnable::run); - } catch (Exception e) { - e.printStackTrace(); + for (Runnable listener : runnable) { + try { + listener.run(); + } catch (Throwable t) { + t.printStackTrace(); + } } } } diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TInject.java b/src/main/scala/io/izzel/taboolib/module/inject/TInject.java index 0d1afd7..86cb8ff 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TInject.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInject.java @@ -27,6 +27,8 @@ public @interface TInject { String reload() default ""; + String locale() default ""; + State state() default State.NONE; enum State { diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java index 383c5dd..bdf99a0 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java @@ -1,14 +1,17 @@ package io.izzel.taboolib.module.inject; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import io.izzel.taboolib.TabooLibAPI; import io.izzel.taboolib.TabooLibLoader; import io.izzel.taboolib.module.command.lite.CommandBuilder; import io.izzel.taboolib.module.config.TConfig; +import io.izzel.taboolib.module.locale.TLocaleLoader; import io.izzel.taboolib.module.locale.logger.TLogger; import io.izzel.taboolib.module.packet.TPacketHandler; import io.izzel.taboolib.module.packet.TPacketListener; import io.izzel.taboolib.util.Ref; +import io.izzel.taboolib.util.Strings; import io.izzel.taboolib.util.lite.cooldown.Cooldown; import io.izzel.taboolib.util.lite.cooldown.Cooldowns; import org.bukkit.Bukkit; @@ -16,6 +19,7 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import java.lang.reflect.Field; +import java.util.List; import java.util.Map; /** @@ -56,7 +60,22 @@ public class TInjectLoader implements TabooLibLoader.Loader { try { TConfig config = TConfig.create(plugin, args.value().length == 0 ? "config.yml" : args.value()[0]); field.set(instance, config); - if (!args.reload().isEmpty()) { + if (Strings.nonEmpty(args.locale())) { + config.listener(() -> { + List localePriority = Lists.newArrayList(); + if (config.isList(args.locale())) { + localePriority.addAll(config.getStringList(args.locale())); + } else { + localePriority.add(String.valueOf(config.get(args.locale()))); + } + if (TLocaleLoader.getLocalePriority(plugin).equals(localePriority)) { + return; + } + TLocaleLoader.setLocalePriority(plugin, localePriority); + TLocaleLoader.load(plugin, true, true); + }); + } + if (Strings.nonEmpty(args.reload())) { try { Ref.getDeclaredMethods(pluginClass).forEach(method -> { if (method.getName().equals(args.reload())) { @@ -68,13 +87,13 @@ public class TInjectLoader implements TabooLibLoader.Loader { t.printStackTrace(); } }); - TabooLibLoader.runTask(config::runListener); } }); } catch (Throwable t) { t.printStackTrace(); } } + TabooLibLoader.runTask(config::runListener); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/scala/io/izzel/taboolib/module/locale/TLocaleLoader.java b/src/main/scala/io/izzel/taboolib/module/locale/TLocaleLoader.java index 5bcf1eb..2afc336 100644 --- a/src/main/scala/io/izzel/taboolib/module/locale/TLocaleLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/locale/TLocaleLoader.java @@ -13,7 +13,6 @@ import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerialization; import org.bukkit.plugin.Plugin; -import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; @@ -76,14 +75,12 @@ public class TLocaleLoader { } public static void load(Plugin plugin, boolean isCover) { + load(plugin, isCover, false); + } + + public static void load(Plugin plugin, boolean isCover, boolean hideMessage) { try { if (isLoadLocale(plugin, isCover)) { - // 启用插件指定的独立语言加载顺序 - File settings = new File("plugins/" + plugin.getName() + "/settings.yml"); - List priority = settings.exists() ? YamlConfiguration.loadConfiguration(settings).getStringList("LOCALE-PRIORITY") : plugin.getResource("settings.yml") != null ? YamlConfiguration.loadConfiguration(new BufferedReader(new InputStreamReader(plugin.getResource("settings.yml")))).getStringList("LOCALE-PRIORITY") : new ArrayList<>(); - if (!priority.isEmpty()) { - setLocalePriority(plugin, priority); - } // 获取文件 File localeFile = getLocaleFile(plugin); if (localeFile == null) { @@ -93,10 +90,10 @@ public class TLocaleLoader { YamlConfiguration localeConfiguration = Files.loadYaml(localeFile); YamlConfiguration localeConfigurationAtStream = getLocaleAsPlugin(plugin, localeFile); // 载入配置 - loadPluginLocale(plugin, localeFile, localeConfiguration, localeConfigurationAtStream); + loadPluginLocale(plugin, localeFile, localeConfiguration, localeConfigurationAtStream, hideMessage); // 注册监听 TConfigWatcher.getInst().removeListener(localeFile); - TConfigWatcher.getInst().addListener(localeFile, null, obj -> loadPluginLocale(plugin, localeFile, Files.loadYaml(localeFile), getLocaleAsPlugin(plugin, localeFile))); + TConfigWatcher.getInst().addListener(localeFile, null, obj -> loadPluginLocale(plugin, localeFile, Files.loadYaml(localeFile), getLocaleAsPlugin(plugin, localeFile), false)); } } catch (Exception e) { errorLogger("ERROR-LOADING-LANG", plugin.getName(), e.toString() + "\n" + e.getStackTrace()[0].toString()); @@ -159,12 +156,15 @@ public class TLocaleLoader { return new YamlConfiguration(); } - private static void loadPluginLocale(Plugin plugin, File localeFile, YamlConfiguration localeConfiguration, YamlConfiguration localeConfigurationAtStream) { + private static void loadPluginLocale(Plugin plugin, File localeFile, YamlConfiguration localeConfiguration, YamlConfiguration localeConfigurationAtStream, boolean hideMessage) { TLocaleInstance localeInstance = getLocaleInstance(plugin); if (localeConfigurationAtStream != null) { localeInstance.load(localeConfigurationAtStream); } localeInstance.load(localeConfiguration); + if (hideMessage) { + return; + } if (localeInstance.getLatestUpdateNodes().get() <= 0) { infoLogger("SUCCESS-LOADING-LANG-NORMAL", plugin.getName(), localeFile.getName().split("\\.")[0], String.valueOf(localeInstance.size())); } else { diff --git a/src/main/scala/io/izzel/taboolib/util/item/inventory/stored/MenuStored.java b/src/main/scala/io/izzel/taboolib/util/item/inventory/stored/MenuStored.java index 1cdc954..295b3e3 100644 --- a/src/main/scala/io/izzel/taboolib/util/item/inventory/stored/MenuStored.java +++ b/src/main/scala/io/izzel/taboolib/util/item/inventory/stored/MenuStored.java @@ -5,6 +5,7 @@ import io.izzel.taboolib.util.item.inventory.ClickEvent; import io.izzel.taboolib.util.item.inventory.ClickType; import io.izzel.taboolib.util.item.inventory.MenuBuilder; import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryAction; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; @@ -62,6 +63,11 @@ public abstract class MenuStored { } // 手动装填 else { + // todo 合并物品 + if (e.castClick().getAction() == InventoryAction.COLLECT_TO_CURSOR) { + e.setCancelled(true); + return; + } Action action; if (e.castClick().getClick().isShiftClick() && e.getRawSlot() >= 0 && e.getRawSlot() < e.getInventory().getSize()) { action = new ActionQuickTake(); diff --git a/src/main/scala/io/izzel/taboolib/util/lite/Materials.java b/src/main/scala/io/izzel/taboolib/util/lite/Materials.java index f5bd98e..4e2ed38 100644 --- a/src/main/scala/io/izzel/taboolib/util/lite/Materials.java +++ b/src/main/scala/io/izzel/taboolib/util/lite/Materials.java @@ -1,122 +1,156 @@ -/* +package io.izzel.taboolib.util.lite;/* * The MIT License (MIT) * - * Original work Copyright (c) 2018 Hex_27 - * v2.0 Copyright (c) 2019 Crypto Morin + * Copyright (c) 2018 Hex_27 + * 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 in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 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. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * 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 io.izzel.taboolib.util.lite; - +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 org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.apache.commons.lang.WordUtils; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import org.bukkit.util.NumberConversions; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Objects; -import java.util.Optional; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/* + * References + * + * * * GitHub: https://github.com/CryptoMorin/XSeries/blob/master/Materials.java + * * XSeries: https://www.spigotmc.org/threads/378136/ + * 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 + * 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 + * Materials v1: https://www.spigotmc.org/threads/329630/ + */ /** - * @author CryptoMorin + * Materials - Data Values/Pre-flattening
+ * Supports 1.8-1.15
+ * 1.13 and above as priority. + * + * @author Crypto Morin + * @version 3.2.0 + * @see Material + * @see ItemStack */ public enum Materials { - - ACACIA_BOAT(0, "BOAT_ACACIA"), - ACACIA_BUTTON(0, "WOOD_BUTTON"), - ACACIA_DOOR(0, "ACACIA_DOOR_ITEM"), - ACACIA_FENCE(0, ""), - ACACIA_FENCE_GATE(0, ""), - ACACIA_LEAVES(0, "LEAVES_2"), - ACACIA_LOG(0, "LOG_2"), + + ACACIA_BOAT("BOAT_ACACIA"), + ACACIA_BUTTON("WOOD_BUTTON"), + ACACIA_DOOR("ACACIA_DOOR_ITEM"), + ACACIA_FENCE, + ACACIA_FENCE_GATE, + ACACIA_LEAVES("LEAVES_2"), + ACACIA_LOG("LOG_2"), ACACIA_PLANKS(4, "WOOD"), - ACACIA_PRESSURE_PLATE(0, "WOOD_PLATE"), + ACACIA_PRESSURE_PLATE("WOOD_PLATE"), ACACIA_SAPLING(4, "SAPLING"), - ACACIA_SIGN(0, "SIGN"), + ACACIA_SIGN("SIGN"), ACACIA_SLAB(4, "WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), - ACACIA_STAIRS(0, ""), - ACACIA_TRAPDOOR(0, "TRAP_DOOR"), - ACACIA_WALL_SIGN(0, "SIGN_POST", "WALL_SIGN"), - ACACIA_WOOD(0, "LOG_2"), - ACTIVATOR_RAIL(0, ""), - AIR(0, ""), + ACACIA_STAIRS, + ACACIA_TRAPDOOR("TRAP_DOOR"), + ACACIA_WALL_SIGN("SIGN_POST", "WALL_SIGN"), + ACACIA_WOOD("LOG_2"), + ACTIVATOR_RAIL, + /** + * https://minecraft.gamepedia.com/Air + * + * @see #VOID_AIR + * @see #CAVE_AIR + */ + AIR, ALLIUM(2, "RED_ROSE"), - ANDESITE(5, "STONEZ"), - ANDESITE_SLAB(0, ""), - ANDESITE_STAIRS(0, ""), - ANDESITE_WALL(0, ""), - ANVIL(0, ""), - APPLE(0, ""), - ARMOR_STAND(0, ""), - ARROW(0, ""), + ANDESITE(5, "STONE"), + ANDESITE_SLAB, + ANDESITE_STAIRS, + ANDESITE_WALL, + ANVIL, + APPLE, + ARMOR_STAND, + ARROW, ATTACHED_MELON_STEM(7, "MELON_STEM"), ATTACHED_PUMPKIN_STEM(7, "PUMPKIN_STEM"), AZURE_BLUET(3, "RED_ROSE"), - BAKED_POTATO(0, ""), - BAMBOO(0, "1.14", "SUGAR_CANE"), - BAMBOO_SAPLING(0, "1.14"), - BARREL(0, "1.14", "CHEST"), - BARRIER(0, ""), + BAKED_POTATO, + BAMBOO("1.14", "SUGAR_CANE"), + BAMBOO_SAPLING("1.14"), + BARREL("1.14", "CHEST"), + BARRIER, BAT_SPAWN_EGG(65, "MONSTER_EGG"), - BEACON(0, ""), - BEDROCK(0, ""), - BEEF(0, "RAW_BEEF"), - BEETROOT(0, "BEETROOT_BLOCK"), - BEETROOTS(0, "BEETROOT"), - BEETROOT_SEEDS(0, ""), - BEETROOT_SOUP(0, ""), - BELL(0, "1.14"), - BIRCH_BOAT(0, "BOAT_BIRCH"), - BIRCH_BUTTON(0, "WOOD_BUTTON"), - BIRCH_DOOR(0, "BIRCH_DOOR_ITEM"), - BIRCH_FENCE(0, ""), - BIRCH_FENCE_GATE(0, ""), + BEACON, + BEDROCK, + BEEF("RAW_BEEF"), + BEEHIVE("1.15"), + BEETROOT("BEETROOT_BLOCK"), + BEETROOTS("BEETROOT"), + BEETROOT_SEEDS, + BEETROOT_SOUP, + BEE_NEST("1.15"), + BEE_SPAWN_EGG("1.15"), + BELL("1.14"), + BIRCH_BOAT("BOAT_BIRCH"), + BIRCH_BUTTON("WOOD_BUTTON"), + BIRCH_DOOR("BIRCH_DOOR_ITEM"), + BIRCH_FENCE, + BIRCH_FENCE_GATE, BIRCH_LEAVES(2, "LEAVES"), BIRCH_LOG(2, "LOG"), BIRCH_PLANKS(2, "WOOD"), - BIRCH_PRESSURE_PLATE(0, "WOOD_PLATE"), + BIRCH_PRESSURE_PLATE("WOOD_PLATE"), BIRCH_SAPLING(2, "SAPLING"), - BIRCH_SIGN(0, "SIGN"), + BIRCH_SIGN("SIGN"), BIRCH_SLAB(2, "WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), - BIRCH_STAIRS(0, "BIRCH_WOOD_STAIRS"), - BIRCH_TRAPDOOR(0, "TRAP_DOOR"), - BIRCH_WALL_SIGN(0, "SIGN_POST", "WALL_SIGN"), + BIRCH_STAIRS("BIRCH_WOOD_STAIRS"), + BIRCH_TRAPDOOR("TRAP_DOOR"), + BIRCH_WALL_SIGN("SIGN_POST", "WALL_SIGN"), BIRCH_WOOD(2, "LOG"), - BLACK_BANNER(0, "BANNER", "STANDING_BANNER"), + BLACK_BANNER("BANNER", "STANDING_BANNER"), BLACK_BED(15, "BED", "BED_BLOCK"), BLACK_CARPET(15, "CARPET"), BLACK_CONCRETE(15, "CONCRETE"), BLACK_CONCRETE_POWDER(15, "CONCRETE_POWDER"), - BLACK_DYE(0, "1.14", "INK_SACK"), + BLACK_DYE("1.14", "INK_SACK"), BLACK_GLAZED_TERRACOTTA(15, "1.12", "HARD_CLAY", "STAINED_CLAY", "BLACK_TERRACOTTA"), - BLACK_SHULKER_BOX(0, ""), + 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(0, "WALL_BANNER"), + BLACK_WALL_BANNER("WALL_BANNER"), BLACK_WOOL(15, "WOOL"), - BLAST_FURNACE(0, "1.14", "FURNACE"), - BLAZE_POWDER(0, ""), - BLAZE_ROD(0, ""), + BLAST_FURNACE("1.14", "FURNACE"), + BLAZE_POWDER, + BLAZE_ROD, BLAZE_SPAWN_EGG(61, "MONSTER_EGG"), BLUE_BANNER(11, "BANNER", "STANDING_BANNER"), BLUE_BED(4, "BED", "BED_BLOCK"), @@ -125,126 +159,132 @@ public enum Materials { BLUE_CONCRETE_POWDER(11, "CONCRETE_POWDER"), BLUE_DYE(4, "INK_SACK", "LAPIS_LAZULI"), BLUE_GLAZED_TERRACOTTA(11, "1.12", "HARD_CLAY", "STAINED_CLAY", "BLUE_TERRACOTTA"), - BLUE_ICE(0, "1.13", "PACKED_ICE"), + BLUE_ICE("1.13", "PACKED_ICE"), BLUE_ORCHID(1, "RED_ROSE"), - BLUE_SHULKER_BOX(0, ""), + 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_WOOL(11, "WOOL"), - BONE(0, ""), - BONE_BLOCK(0, ""), + BONE, + BONE_BLOCK, BONE_MEAL(15, "INK_SACK"), - BOOK(0, ""), - BOOKSHELF(0, ""), - BOW(0, ""), - BOWL(0, ""), - BRAIN_CORAL(0, "1.13"), - BRAIN_CORAL_BLOCK(0, "1.13"), - BRAIN_CORAL_FAN(0, "1.13"), - BRAIN_CORAL_WALL_FAN(0, ""), - BREAD(0, ""), - BREWING_STAND(0, "BREWING_STAND_ITEM"), - BRICK(0, "CLAY_BRICK"), - BRICKS(0, "BRICK"), + BOOK, + BOOKSHELF, + BOW, + BOWL, + BRAIN_CORAL("1.13"), + BRAIN_CORAL_BLOCK("1.13"), + BRAIN_CORAL_FAN("1.13"), + BRAIN_CORAL_WALL_FAN, + BREAD, + BREWING_STAND("BREWING_STAND_ITEM"), + BRICK("CLAY_BRICK"), + BRICKS("BRICK"), BRICK_SLAB(4, "STEP"), - BRICK_STAIRS(0, ""), - BRICK_WALL(0, ""), + BRICK_STAIRS, + BRICK_WALL, BROWN_BANNER(3, "BANNER", "STANDING_BANNER"), BROWN_BED(12, "BED", "BED_BLOCK"), - BROWN_DYE(3, "INK_SACK", "COCOA", "COCOA_BEANS"), BROWN_CARPET(12, "CARPET"), BROWN_CONCRETE(12, "CONCRETE"), BROWN_CONCRETE_POWDER(12, "CONCRETE_POWDER"), + BROWN_DYE(3, "INK_SACK", "COCOA", "COCOA_BEANS"), BROWN_GLAZED_TERRACOTTA(12, "1.12", "HARD_CLAY", "STAINED_CLAY", "BROWN_TERRACOTTA"), - BROWN_MUSHROOM(0, ""), - BROWN_MUSHROOM_BLOCK(0, "BROWN_MUSHROOM", "HUGE_MUSHROOM_1"), - BROWN_SHULKER_BOX(0, ""), + BROWN_MUSHROOM, + BROWN_MUSHROOM_BLOCK("BROWN_MUSHROOM", "HUGE_MUSHROOM_1"), + BROWN_SHULKER_BOX, BROWN_STAINED_GLASS(12, "STAINED_GLASS"), BROWN_STAINED_GLASS_PANE(12, "THIN_GLASS", "STAINED_GLASS_PANE"), BROWN_TERRACOTTA(12, "STAINED_CLAY"), BROWN_WALL_BANNER(3, "WALL_BANNER"), BROWN_WOOL(12, "WOOL"), - BUBBLE_COLUMN(0, "1.13"), - BUBBLE_CORAL(0, "1.13"), - BUBBLE_CORAL_BLOCK(0, "1.13"), - BUBBLE_CORAL_FAN(0, "1.13"), - BUBBLE_CORAL_WALL_FAN(0, ""), - BUCKET(0, ""), - CACTUS(0, ""), - CAKE(0, "CAKE_BLOCK"), - CAMPFIRE(0, "1.14"), - CARROT(0, "CARROT_ITEM"), - CARROTS(0, "CARROT"), - CARROT_ON_A_STICK(0, "CARROT_STICK"), - CARTOGRAPHY_TABLE(0, "1.14", "CRAFTING_TABLE"), - CARVED_PUMPKIN(1, "PUMPKIN"), - CAT_SPAWN_EGG(0, ""), - CAULDRON(0, "CAULDRON_ITEM"), - CAVE_AIR(0, "AIR"), + BUBBLE_COLUMN("1.13"), + BUBBLE_CORAL("1.13"), + BUBBLE_CORAL_BLOCK("1.13"), + BUBBLE_CORAL_FAN("1.13"), + BUBBLE_CORAL_WALL_FAN, + BUCKET, + CACTUS, + CAKE("CAKE_BLOCK"), + CAMPFIRE("1.14"), + CARROT("CARROT_ITEM"), + CARROTS("CARROT"), + CARROT_ON_A_STICK("CARROT_STICK"), + CARTOGRAPHY_TABLE("1.14", "CRAFTING_TABLE"), + CARVED_PUMPKIN(1, "1.13", "PUMPKIN"), + CAT_SPAWN_EGG, + CAULDRON("CAULDRON_ITEM"), + /** + * 1.13 tag is not added because it's the same thing as {@link #AIR} + * + * @see #VOID_AIR + */ + CAVE_AIR("AIR"), CAVE_SPIDER_SPAWN_EGG(59, "MONSTER_EGG"), - CHAINMAIL_BOOTS(0, ""), - CHAINMAIL_CHESTPLATE(0, ""), - CHAINMAIL_HELMET(0, ""), - CHAINMAIL_LEGGINGS(0, ""), - CHAIN_COMMAND_BLOCK(0, "COMMAND", "COMMAND_CHAIN"), + CHAINMAIL_BOOTS, + CHAINMAIL_CHESTPLATE, + CHAINMAIL_HELMET, + CHAINMAIL_LEGGINGS, + CHAIN_COMMAND_BLOCK("COMMAND", "COMMAND_CHAIN"), CHARCOAL(1, "COAL"), - CHEST(0, "LOCKED_CHEST"), - CHEST_MINECART(0, "STORAGE_MINECART"), - CHICKEN(0, "RAW_CHICKEN"), + CHEST("LOCKED_CHEST"), + CHEST_MINECART("STORAGE_MINECART"), + CHICKEN("RAW_CHICKEN"), CHICKEN_SPAWN_EGG(93, "MONSTER_EGG"), CHIPPED_ANVIL(1, "ANVIL"), CHISELED_QUARTZ_BLOCK(1, "QUARTZ_BLOCK"), CHISELED_RED_SANDSTONE(1, "RED_SANDSTONE"), CHISELED_SANDSTONE(1, "SANDSTONE"), CHISELED_STONE_BRICKS(3, "SMOOTH_BRICK"), - CHORUS_FLOWER(0, ""), - CHORUS_FRUIT(0, ""), - CHORUS_PLANT(0, ""), - CLAY(0, ""), - CLAY_BALL(0, ""), - CLOCK(0, "WATCH"), - COAL(0, ""), - COAL_BLOCK(0, ""), - COAL_ORE(0, ""), + CHORUS_FLOWER, + CHORUS_FRUIT, + CHORUS_PLANT, + CLAY, + CLAY_BALL, + CLOCK("WATCH"), + COAL, + COAL_BLOCK, + COAL_ORE, COARSE_DIRT(1, "DIRT"), - COBBLESTONE(0, ""), + COBBLESTONE, COBBLESTONE_SLAB(3, "STEP"), - COBBLESTONE_STAIRS(0, ""), - COBBLESTONE_WALL(0, "COBBLE_WALL"), - COBWEB(0, "WEB"), + COBBLESTONE_STAIRS, + COBBLESTONE_WALL("COBBLE_WALL"), + COBWEB("WEB"), + COCOA("1.15"), COCOA_BEANS(3, "INK_SACK", "COCOA"), - COD(0, "RAW_FISH"), - COD_BUCKET(0, "1.13", "BUCKET", "WATER_BUCKET"), - COD_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), - COMMAND_BLOCK(0, "COMMAND"), - COMMAND_BLOCK_MINECART(0, "COMMAND_MINECART"), - COMPARATOR(0, "REDSTONE_COMPARATOR"), - COMPASS(0, ""), - COMPOSTER(0, "1.14", "CAULDRON"), - CONDUIT(0, "1.13"), - COOKED_BEEF(0, ""), - COOKED_CHICKEN(0, ""), - COOKED_COD(0, "COOKED_FISH"), - COOKED_MUTTON(0, ""), - COOKED_PORKCHOP(0, "PORK", "GRILLED_PORK"), - COOKED_RABBIT(0, ""), + COD("RAW_FISH"), + COD_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), + COD_SPAWN_EGG("1.13", "MONSTER_EGG"), + COMMAND_BLOCK("COMMAND"), + COMMAND_BLOCK_MINECART("COMMAND_MINECART"), + COMPARATOR("REDSTONE_COMPARATOR", "REDSTONE_COMPARATOR_ON", "REDSTONE_COMPARATOR_OFF"), + COMPASS, + COMPOSTER("1.14", "CAULDRON"), + CONDUIT("1.13", "BEACON"), + COOKED_BEEF, + COOKED_CHICKEN, + COOKED_COD("COOKED_FISH"), + COOKED_MUTTON, + COOKED_PORKCHOP("PORK", "GRILLED_PORK"), + COOKED_RABBIT, COOKED_SALMON(1, "COOKED_FISH"), - COOKIE(0, ""), + COOKIE, CORNFLOWER(4, "1.14", "BLUE_DYE"), COW_SPAWN_EGG(92, "MONSTER_EGG"), CRACKED_STONE_BRICKS(2, "SMOOTH_BRICK"), - CRAFTING_TABLE(0, "WORKBENCH"), - CREEPER_BANNER_PATTERN(0, ""), + 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"), - CROSSBOW(0, ""), - CUT_RED_SANDSTONE(0, "1.13"), - CUT_RED_SANDSTONE_SLAB(0, "STONE_SLAB2"), - CUT_SANDSTONE(0, "1.13"), - CUT_SANDSTONE_SLAB(0, "STEP"), + CROSSBOW, + CUT_RED_SANDSTONE("1.13"), + CUT_RED_SANDSTONE_SLAB("STONE_SLAB2"), + CUT_SANDSTONE("1.13"), + CUT_SANDSTONE_SLAB("STEP"), CYAN_BANNER(6, "BANNER", "STANDING_BANNER"), CYAN_BED(9, "BED", "BED_BLOCK"), CYAN_CARPET(9, "CARPET"), @@ -252,168 +292,168 @@ public enum Materials { CYAN_CONCRETE_POWDER(9, "CONCRETE_POWDER"), CYAN_DYE(6, "INK_SACK"), CYAN_GLAZED_TERRACOTTA(9, "1.12", "HARD_CLAY", "STAINED_CLAY", "CYAN_TERRACOTTA"), - CYAN_SHULKER_BOX(0, ""), + CYAN_SHULKER_BOX, CYAN_STAINED_GLASS(9, "STAINED_GLASS"), CYAN_STAINED_GLASS_PANE(9, "STAINED_GLASS_PANE"), CYAN_TERRACOTTA(9, "HARD_CLAY", "STAINED_CLAY"), CYAN_WALL_BANNER(6, "WALL_BANNER"), CYAN_WOOL(9, "WOOL"), DAMAGED_ANVIL(2, "ANVIL"), - DANDELION(0, "YELLOW_FLOWER"), - DARK_OAK_BOAT(0, "BOAT_DARK_OAK"), - DARK_OAK_BUTTON(0, "WOOD_BUTTON"), - DARK_OAK_DOOR(0, "DARK_OAK_DOOR_ITEM"), - DARK_OAK_FENCE(0, ""), - DARK_OAK_FENCE_GATE(0, ""), + DANDELION("YELLOW_FLOWER"), + DARK_OAK_BOAT("BOAT_DARK_OAK"), + DARK_OAK_BUTTON("WOOD_BUTTON"), + DARK_OAK_DOOR("DARK_OAK_DOOR_ITEM"), + DARK_OAK_FENCE, + DARK_OAK_FENCE_GATE, DARK_OAK_LEAVES(1, "LEAVES", "LEAVES_2"), DARK_OAK_LOG(1, "LOG", "LOG_2"), DARK_OAK_PLANKS(5, "WOOD"), - DARK_OAK_PRESSURE_PLATE(0, "WOOD_PLATE"), + DARK_OAK_PRESSURE_PLATE("WOOD_PLATE"), DARK_OAK_SAPLING(5, "SAPLING"), - DARK_OAK_SIGN(0, "SIGN"), - DARK_OAK_SLAB(0, "WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), - DARK_OAK_STAIRS(0, ""), - DARK_OAK_TRAPDOOR(0, "TRAP_DOOR"), - DARK_OAK_WALL_SIGN(0, "SIGN_POST", "WALL_SIGN"), + DARK_OAK_SIGN("SIGN"), + DARK_OAK_SLAB("WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), + DARK_OAK_STAIRS, + DARK_OAK_TRAPDOOR("TRAP_DOOR"), + DARK_OAK_WALL_SIGN("SIGN_POST", "WALL_SIGN"), DARK_OAK_WOOD(1, "LOG", "LOG_2"), DARK_PRISMARINE(1, "PRISMARINE"), - DARK_PRISMARINE_SLAB(0, "1.13"), - DARK_PRISMARINE_STAIRS(0, "1.13"), - DAYLIGHT_DETECTOR(0, "DAYLIGHT_DETECTOR_INVERTED"), - DEAD_BRAIN_CORAL(0, ""), - DEAD_BRAIN_CORAL_BLOCK(0, "1.13"), - DEAD_BRAIN_CORAL_FAN(0, ""), - DEAD_BRAIN_CORAL_WALL_FAN(0, ""), - DEAD_BUBBLE_CORAL(0, ""), - DEAD_BUBBLE_CORAL_BLOCK(0, "1.13"), - DEAD_BUBBLE_CORAL_FAN(0, ""), - DEAD_BUBBLE_CORAL_WALL_FAN(0, ""), - DEAD_BUSH(0, ""), - DEAD_FIRE_CORAL(0, ""), - DEAD_FIRE_CORAL_BLOCK(0, "1.13"), - DEAD_FIRE_CORAL_FAN(0, ""), - DEAD_FIRE_CORAL_WALL_FAN(0, ""), - DEAD_HORN_CORAL(0, ""), - DEAD_HORN_CORAL_BLOCK(0, "1.13"), - DEAD_HORN_CORAL_FAN(0, ""), - DEAD_HORN_CORAL_WALL_FAN(0, ""), - DEAD_TUBE_CORAL(0, ""), - DEAD_TUBE_CORAL_BLOCK(0, "1.13"), - DEAD_TUBE_CORAL_FAN(0, ""), - DEAD_TUBE_CORAL_WALL_FAN(0, ""), - DEBUG_STICK(0, "1.13", "STICK"), - DETECTOR_RAIL(0, ""), - DIAMOND(0, ""), - DIAMOND_AXE(0, ""), - DIAMOND_BLOCK(0, ""), - DIAMOND_BOOTS(0, ""), - DIAMOND_CHESTPLATE(0, ""), - DIAMOND_HELMET(0, ""), - DIAMOND_HOE(0, ""), - DIAMOND_HORSE_ARMOR(0, "DIAMOND_BARDING"), - DIAMOND_LEGGINGS(0, ""), - DIAMOND_ORE(0, ""), - DIAMOND_PICKAXE(0, ""), - DIAMOND_SHOVEL(0, "DIAMOND_SPADE"), - DIAMOND_SWORD(0, ""), - DIORITE(3, "1.13"), - DIORITE_SLAB(0, ""), - DIORITE_STAIRS(0, ""), - DIORITE_WALL(0, ""), - DIRT(0, ""), - DISPENSER(0, ""), - DOLPHIN_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), + DARK_PRISMARINE_SLAB("1.13"), + DARK_PRISMARINE_STAIRS("1.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_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"), + DETECTOR_RAIL, + DIAMOND, + DIAMOND_AXE, + DIAMOND_BLOCK, + DIAMOND_BOOTS, + DIAMOND_CHESTPLATE, + DIAMOND_HELMET, + DIAMOND_HOE, + DIAMOND_HORSE_ARMOR("DIAMOND_BARDING"), + DIAMOND_LEGGINGS, + DIAMOND_ORE, + DIAMOND_PICKAXE, + DIAMOND_SHOVEL("DIAMOND_SPADE"), + DIAMOND_SWORD, + DIORITE(3, "STONE"), + DIORITE_SLAB, + DIORITE_STAIRS, + DIORITE_WALL, + DIRT, + DISPENSER, + DOLPHIN_SPAWN_EGG("1.13", "MONSTER_EGG"), DONKEY_SPAWN_EGG(32, "MONSTER_EGG"), - DRAGON_BREATH(0, "DRAGONS_BREATH"), - DRAGON_EGG(0, ""), + DRAGON_BREATH("DRAGONS_BREATH"), + DRAGON_EGG, DRAGON_HEAD(5, "SKULL", "SKULL_ITEM"), DRAGON_WALL_HEAD(5, "SKULL", "SKULL_ITEM"), - DRIED_KELP(0, "1.13"), - DRIED_KELP_BLOCK(0, "1.13"), - DROPPER(0, ""), - DROWNED_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), - EGG(0, ""), + DRIED_KELP("1.13"), + DRIED_KELP_BLOCK("1.13"), + DROPPER, + DROWNED_SPAWN_EGG("1.13", "MONSTER_EGG"), + EGG, ELDER_GUARDIAN_SPAWN_EGG(4, "MONSTER_EGG"), - ELYTRA(0, ""), - EMERALD(0, ""), - EMERALD_BLOCK(0, ""), - EMERALD_ORE(0, ""), - ENCHANTED_BOOK(0, ""), + ELYTRA, + EMERALD, + EMERALD_BLOCK, + EMERALD_ORE, + ENCHANTED_BOOK, ENCHANTED_GOLDEN_APPLE(1, "GOLDEN_APPLE"), - ENCHANTING_TABLE(0, "ENCHANTMENT_TABLE"), + ENCHANTING_TABLE("ENCHANTMENT_TABLE"), ENDERMAN_SPAWN_EGG(58, "MONSTER_EGG"), ENDERMITE_SPAWN_EGG(67, "MONSTER_EGG"), - ENDER_CHEST(0, ""), - ENDER_EYE(0, "EYE_OF_ENDER"), - ENDER_PEARL(0, ""), - END_CRYSTAL(0, ""), - END_GATEWAY(0, ""), - END_PORTAL(0, "ENDER_PORTAL"), - END_PORTAL_FRAME(0, "ENDER_PORTAL_FRAME"), - END_ROD(0, ""), - END_STONE(0, "ENDER_STONE"), - END_STONE_BRICKS(0, "END_BRICKS"), + ENDER_CHEST, + ENDER_EYE("EYE_OF_ENDER"), + ENDER_PEARL, + END_CRYSTAL, + END_GATEWAY, + END_PORTAL("ENDER_PORTAL"), + END_PORTAL_FRAME("ENDER_PORTAL_FRAME"), + END_ROD, + END_STONE("ENDER_STONE"), + END_STONE_BRICKS("END_BRICKS"), END_STONE_BRICK_SLAB(4, "STEP"), - END_STONE_BRICK_STAIRS(0, "SMOOTH_STAIRS"), - END_STONE_BRICK_WALL(0, ""), + END_STONE_BRICK_STAIRS("SMOOTH_STAIRS"), + END_STONE_BRICK_WALL, EVOKER_SPAWN_EGG(34, "MONSTER_EGG"), - EXPERIENCE_BOTTLE(0, "EXP_BOTTLE"), - FARMLAND(0, "SOIL"), - FEATHER(0, ""), - FERMENTED_SPIDER_EYE(0, ""), + EXPERIENCE_BOTTLE("EXP_BOTTLE"), + FARMLAND("SOIL"), + FEATHER, + FERMENTED_SPIDER_EYE, FERN(2, "LONG_GRASS"), - FILLED_MAP(0, "MAP"), - FIRE(0, ""), - FIREWORK_ROCKET(0, "FIREWORK"), - FIREWORK_STAR(0, "FIREWORK_CHARGE"), - FIRE_CHARGE(0, "FIREBALL"), - FIRE_CORAL(0, "1.13"), - FIRE_CORAL_BLOCK(0, "1.13"), - FIRE_CORAL_FAN(0, "1.13"), - FIRE_CORAL_WALL_FAN(0, ""), - FISHING_ROD(0, ""), - FLETCHING_TABLE(0, "1.14", "CRAFTING_TABLE"), - FLINT(0, ""), - FLINT_AND_STEEL(0, ""), - FLOWER_BANNER_PATTERN(0, ""), - FLOWER_POT(0, "FLOWER_POT_ITEM"), - FOX_SPAWN_EGG(0, "1.14"), - FROSTED_ICE(0, ""), - FURNACE(0, "BURNING_FURNACE"), - FURNACE_MINECART(0, "POWERED_MINECART"), + 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_WALL_FAN, + FISHING_ROD, + FLETCHING_TABLE("1.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, + FURNACE("BURNING_FURNACE"), + FURNACE_MINECART("POWERED_MINECART"), GHAST_SPAWN_EGG(56, "MONSTER_EGG"), - GHAST_TEAR(0, ""), - GLASS(0, ""), - GLASS_BOTTLE(0, ""), - GLASS_PANE(0, "THIN_GLASS"), - GLISTERING_MELON_SLICE(0, "SPECKLED_MELON"), - GLOBE_BANNER_PATTERN(0, ""), - GLOWSTONE(0, ""), - GLOWSTONE_DUST(0, ""), - GOLDEN_APPLE(0, ""), - GOLDEN_AXE(0, "GOLD_AXE"), - GOLDEN_BOOTS(0, "GOLD_BOOTS"), - GOLDEN_CARROT(0, ""), - GOLDEN_CHESTPLATE(0, "GOLD_CHESTPLATE"), - GOLDEN_HELMET(0, "GOLD_HELMET"), - GOLDEN_HOE(0, "GOLD_HOE"), - GOLDEN_HORSE_ARMOR(0, "GOLD_BARDING"), - GOLDEN_LEGGINGS(0, "GOLD_LEGGINGS"), - GOLDEN_PICKAXE(0, "GOLD_PICKAXE"), - GOLDEN_SHOVEL(0, "GOLD_SPADE"), - GOLDEN_SWORD(0, "GOLD_SWORD"), - GOLD_BLOCK(0, ""), - GOLD_INGOT(0, ""), - GOLD_NUGGET(0, ""), - GOLD_ORE(0, ""), - GRANITE(1, "1.13"), - GRANITE_SLAB(0, ""), - GRANITE_STAIRS(0, ""), - GRANITE_WALL(0, ""), - GRASS(0, ""), - GRASS_BLOCK(0, "GRASS"), - GRASS_PATH(0, ""), - GRAVEL(0, ""), + GHAST_TEAR, + GLASS, + GLASS_BOTTLE, + GLASS_PANE("THIN_GLASS"), + GLISTERING_MELON_SLICE("SPECKLED_MELON"), + GLOBE_BANNER_PATTERN, + GLOWSTONE, + GLOWSTONE_DUST, + GOLDEN_APPLE, + GOLDEN_AXE("GOLD_AXE"), + GOLDEN_BOOTS("GOLD_BOOTS"), + GOLDEN_CARROT, + GOLDEN_CHESTPLATE("GOLD_CHESTPLATE"), + GOLDEN_HELMET("GOLD_HELMET"), + GOLDEN_HOE("GOLD_HOE"), + GOLDEN_HORSE_ARMOR("GOLD_BARDING"), + GOLDEN_LEGGINGS("GOLD_LEGGINGS"), + GOLDEN_PICKAXE("GOLD_PICKAXE"), + GOLDEN_SHOVEL("GOLD_SPADE"), + GOLDEN_SWORD("GOLD_SWORD"), + GOLD_BLOCK, + GOLD_INGOT, + GOLD_NUGGET, + GOLD_ORE, + GRANITE(1, "STONE"), + GRANITE_SLAB, + GRANITE_STAIRS, + GRANITE_WALL, + GRASS, + GRASS_BLOCK("GRASS"), + GRASS_PATH, + GRAVEL, GRAY_BANNER(8, "BANNER", "STANDING_BANNER"), GRAY_BED(7, "BED", "BED_BLOCK"), GRAY_CARPET(7, "CARPET"), @@ -421,12 +461,12 @@ public enum Materials { GRAY_CONCRETE_POWDER(7, "CONCRETE_POWDER"), GRAY_DYE(8, "INK_SACK"), GRAY_GLAZED_TERRACOTTA(7, "1.12", "HARD_CLAY", "STAINED_CLAY", "GRAY_TERRACOTTA"), - GRAY_SHULKER_BOX(0, ""), - GRAY_STAINED_GLASS(8, "STAINED_GLASS"), + GRAY_SHULKER_BOX, + 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"), + GRAY_WOOL(7, "WOOL"), GREEN_BANNER(2, "BANNER", "STANDING_BANNER"), GREEN_BED(13, "BED", "BED_BLOCK"), GREEN_CARPET(13, "CARPET"), @@ -434,121 +474,125 @@ public enum Materials { GREEN_CONCRETE_POWDER(13, "CONCRETE_POWDER"), GREEN_DYE(2, "INK_SACK", "CACTUS_GREEN"), GREEN_GLAZED_TERRACOTTA(13, "1.12", "HARD_CLAY", "STAINED_CLAY", "GREEN_TERRACOTTA"), - GREEN_SHULKER_BOX(0, ""), + 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(0, "1.14", "ANVIL"), + GRINDSTONE("1.14", "ANVIL"), GUARDIAN_SPAWN_EGG(68, "MONSTER_EGG"), - GUNPOWDER(0, "SULPHUR"), - HAY_BLOCK(0, ""), - HEART_OF_THE_SEA(0, "1.13"), - HEAVY_WEIGHTED_PRESSURE_PLATE(0, "IRON_PLATE"), - HOPPER(0, ""), - HOPPER_MINECART(0, ""), - HORN_CORAL(0, "1.13"), - HORN_CORAL_BLOCK(0, "1.13"), - HORN_CORAL_FAN(0, "1.13"), - HORN_CORAL_WALL_FAN(0, ""), + GUNPOWDER("SULPHUR"), + HAY_BLOCK, + HEART_OF_THE_SEA("1.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"), + HOPPER, + HOPPER_MINECART, + HORN_CORAL("1.13"), + HORN_CORAL_BLOCK("1.13"), + HORN_CORAL_FAN("1.13"), + HORN_CORAL_WALL_FAN, HORSE_SPAWN_EGG(100, "MONSTER_EGG"), HUSK_SPAWN_EGG(23, "MONSTER_EGG"), - ICE(0, ""), + ICE, INFESTED_CHISELED_STONE_BRICKS(5, "MONSTER_EGGS", "SMOOTH_BRICK"), INFESTED_COBBLESTONE(1, "MONSTER_EGGS"), INFESTED_CRACKED_STONE_BRICKS(4, "MONSTER_EGGS", "SMOOTH_BRICK"), INFESTED_MOSSY_STONE_BRICKS(3, "MONSTER_EGGS"), - INFESTED_STONE(0, "MONSTER_EGGS"), + INFESTED_STONE("MONSTER_EGGS"), INFESTED_STONE_BRICKS(2, "MONSTER_EGGS", "SMOOTH_BRICK"), - INK_SAC(0, "INK_SACK"), - IRON_AXE(0, ""), - IRON_BARS(0, "IRON_FENCE"), - IRON_BLOCK(0, ""), - IRON_BOOTS(0, ""), - IRON_CHESTPLATE(0, ""), - IRON_DOOR(0, "IRON_DOOR_BLOCK"), - IRON_HELMET(0, ""), - IRON_HOE(0, ""), - IRON_HORSE_ARMOR(0, "IRON_BARDING"), - IRON_INGOT(0, ""), - IRON_LEGGINGS(0, ""), - IRON_NUGGET(0, ""), - IRON_ORE(0, ""), - IRON_PICKAXE(0, ""), - IRON_SHOVEL(0, "IRON_SPADE"), - IRON_SWORD(0, ""), - IRON_TRAPDOOR(0, ""), - ITEM_FRAME(0, ""), - JACK_O_LANTERN(0, ""), - JIGSAW(0, "1.14", "COMMAND_BLOCK", "STRUCTURE_BLOCK"), - JUKEBOX(0, ""), - JUNGLE_BOAT(0, "BOAT_JUNGLE"), - JUNGLE_BUTTON(0, "WOOD_BUTTON"), - JUNGLE_DOOR(0, "JUNGLE_DOOR_ITEM"), - JUNGLE_FENCE(0, ""), - JUNGLE_FENCE_GATE(0, ""), + INK_SAC("INK_SACK"), + IRON_AXE, + IRON_BARS("IRON_FENCE"), + IRON_BLOCK, + IRON_BOOTS, + IRON_CHESTPLATE, + IRON_DOOR("IRON_DOOR_BLOCK"), + IRON_HELMET, + IRON_HOE, + IRON_HORSE_ARMOR("IRON_BARDING"), + IRON_INGOT, + IRON_LEGGINGS, + IRON_NUGGET, + IRON_ORE, + IRON_PICKAXE, + IRON_SHOVEL("IRON_SPADE"), + IRON_SWORD, + IRON_TRAPDOOR, + ITEM_FRAME, + JACK_O_LANTERN, + JIGSAW("1.14", "COMMAND_BLOCK", "STRUCTURE_BLOCK"), + JUKEBOX, + JUNGLE_BOAT("BOAT_JUNGLE"), + JUNGLE_BUTTON("WOOD_BUTTON"), + JUNGLE_DOOR("JUNGLE_DOOR_ITEM"), + JUNGLE_FENCE, + JUNGLE_FENCE_GATE, JUNGLE_LEAVES(3, "LEAVES"), JUNGLE_LOG(3, "LOG"), JUNGLE_PLANKS(3, "WOOD"), - JUNGLE_PRESSURE_PLATE(0, "WOOD_PLATE"), + JUNGLE_PRESSURE_PLATE("WOOD_PLATE"), JUNGLE_SAPLING(3, "SAPLING"), - JUNGLE_SIGN(0, "SIGN"), + JUNGLE_SIGN("SIGN"), JUNGLE_SLAB(3, "WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), - JUNGLE_STAIRS(0, "JUNGLE_WOOD_STAIRS"), - JUNGLE_TRAPDOOR(0, "TRAP_DOOR"), - JUNGLE_WALL_SIGN(0, "SIGN_POST", "WALL_SIGN"), + JUNGLE_STAIRS("JUNGLE_WOOD_STAIRS"), + JUNGLE_TRAPDOOR("TRAP_DOOR"), + JUNGLE_WALL_SIGN("SIGN_POST", "WALL_SIGN"), JUNGLE_WOOD(3, "LOG"), - KELP(0, "1.13"), - KELP_PLANT(0, "1.13"), - KNOWLEDGE_BOOK(0, ""), - LADDER(0, ""), - LANTERN(0, "1.14", "SEA_LANTERN"), - LAPIS_BLOCK(0, ""), + KELP("1.13"), + KELP_PLANT("1.13"), + KNOWLEDGE_BOOK("1.12", "BOOK"), + LADDER, + LANTERN("1.14", "SEA_LANTERN"), + LAPIS_BLOCK, LAPIS_LAZULI(4, "INK_SACK"), - LAPIS_ORE(0, ""), + LAPIS_ORE, LARGE_FERN(3, "DOUBLE_PLANT"), - LAVA(0, "STATIONARY_LAVA"), - LAVA_BUCKET(0, ""), - LEAD(0, "LEASH"), - LEATHER(0, ""), - LEATHER_BOOTS(0, ""), - LEATHER_CHESTPLATE(0, ""), - LEATHER_HELMET(0, ""), - LEATHER_HORSE_ARMOR(0, "1.14", "IRON_HORSE_ARMOR"), - LEATHER_LEGGINGS(0, ""), - LECTERN(0, "1.14", "BOOKSHELF"), - LEVER(0, ""), - LIGHT_BLUE_BANNER(11, "BANNER", "STANDING_BANNER"), + LAVA("STATIONARY_LAVA"), + LAVA_BUCKET, + LEAD("LEASH"), + LEATHER, + LEATHER_BOOTS, + LEATHER_CHESTPLATE, + LEATHER_HELMET, + LEATHER_HORSE_ARMOR("1.14", "IRON_HORSE_ARMOR"), + LEATHER_LEGGINGS, + LECTERN("1.14", "BOOKSHELF"), + LEVER, + LIGHT_BLUE_BANNER(3, "BANNER", "STANDING_BANNER"), LIGHT_BLUE_BED(3, "BED", "BED_BLOCK"), LIGHT_BLUE_CARPET(3, "CARPET"), LIGHT_BLUE_CONCRETE(3, "CONCRETE"), LIGHT_BLUE_CONCRETE_POWDER(3, "CONCRETE_POWDER"), LIGHT_BLUE_DYE(12, "INK_SACK"), LIGHT_BLUE_GLAZED_TERRACOTTA(3, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIGHT_BLUE_TERRACOTTA"), - LIGHT_BLUE_SHULKER_BOX(0, ""), - LIGHT_BLUE_STAINED_GLASS(11, "STAINED_GLASS"), + 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_WOOL(11, "WOOL"), + LIGHT_BLUE_WOOL(3, "WOOL"), LIGHT_GRAY_BANNER(7, "BANNER", "STANDING_BANNER"), - LIGHT_GRAY_BED(7, "BED", "BED_BLOCK"), + LIGHT_GRAY_BED(8, "BED", "BED_BLOCK"), LIGHT_GRAY_CARPET(8, "CARPET"), LIGHT_GRAY_CONCRETE(8, "CONCRETE"), LIGHT_GRAY_CONCRETE_POWDER(8, "CONCRETE_POWDER"), LIGHT_GRAY_DYE(7, "INK_SACK"), LIGHT_GRAY_GLAZED_TERRACOTTA(8, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIGHT_GRAY_TERRACOTTA", "SILVER_GLAZED_TERRACOTTA/1.13"), - LIGHT_GRAY_SHULKER_BOX(0, "SILVER_SHULKER_BOX"), + 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"), LIGHT_GRAY_TERRACOTTA(8, "HARD_CLAY", "STAINED_CLAY"), LIGHT_GRAY_WALL_BANNER(7, "WALL_BANNER"), LIGHT_GRAY_WOOL(8, "WOOL"), - LIGHT_WEIGHTED_PRESSURE_PLATE(0, "GOLD_PLATE"), + LIGHT_WEIGHTED_PRESSURE_PLATE("GOLD_PLATE"), LILAC(1, "DOUBLE_PLANT"), LILY_OF_THE_VALLEY(15, "1.14", "WHITE_DYE"), - LILY_PAD(0, "WATER_LILY"), + LILY_PAD("WATER_LILY"), LIME_BANNER(10, "BANNER", "STANDING_BANNER"), LIME_BED(5, "BED", "BED_BLOCK"), LIME_CARPET(5, "CARPET"), @@ -556,15 +600,15 @@ public enum Materials { LIME_CONCRETE_POWDER(5, "CONCRETE_POWDER"), LIME_DYE(10, "INK_SACK"), LIME_GLAZED_TERRACOTTA(5, "1.12", "HARD_CLAY", "STAINED_CLAY", "LIME_TERRACOTTA"), - LIME_SHULKER_BOX(0, ""), + LIME_SHULKER_BOX, LIME_STAINED_GLASS(5, "STAINED_GLASS"), LIME_STAINED_GLASS_PANE(5, "STAINED_GLASS_PANE"), LIME_TERRACOTTA(5, "HARD_CLAY", "STAINED_CLAY"), LIME_WALL_BANNER(10, "WALL_BANNER"), LIME_WOOL(5, "WOOL"), - LINGERING_POTION(0, ""), + LINGERING_POTION, LLAMA_SPAWN_EGG(103, "MONSTER_EGG"), - LOOM(0, "1.14"), + LOOM("1.14"), MAGENTA_BANNER(13, "BANNER", "STANDING_BANNER"), MAGENTA_BED(2, "BED", "BED_BLOCK"), MAGENTA_CARPET(2, "CARPET"), @@ -572,83 +616,83 @@ public enum Materials { MAGENTA_CONCRETE_POWDER(2, "CONCRETE_POWDER"), MAGENTA_DYE(13, "INK_SACK"), MAGENTA_GLAZED_TERRACOTTA(2, "1.12", "HARD_CLAY", "STAINED_CLAY", "MAGENTA_TERRACOTTA"), - MAGENTA_SHULKER_BOX(0, ""), + 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(0, "MAGMA"), - MAGMA_CREAM(0, ""), + MAGMA_BLOCK("MAGMA"), + MAGMA_CREAM, MAGMA_CUBE_SPAWN_EGG(62, "MONSTER_EGG"), - MAP(0, "EMPTY_MAP"), - MELON(0, "MELON_BLOCK"), - MELON_SEEDS(0, ""), - MELON_SLICE(0, "MELON"), - MELON_STEM(0, ""), - MILK_BUCKET(0, ""), - MINECART(0, ""), - MOJANG_BANNER_PATTERN(0, ""), + MAP("EMPTY_MAP"), + MELON("MELON_BLOCK"), + MELON_SEEDS, + MELON_SLICE("MELON"), + MELON_STEM, + MILK_BUCKET, + MINECART, + MOJANG_BANNER_PATTERN, MOOSHROOM_SPAWN_EGG(96, "MONSTER_EGG"), - MOSSY_COBBLESTONE(0, ""), + MOSSY_COBBLESTONE, MOSSY_COBBLESTONE_SLAB(3, "STEP"), - MOSSY_COBBLESTONE_STAIRS(0, ""), + 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_STAIRS(0, "SMOOTH_STAIRS"), - MOSSY_STONE_BRICK_WALL(0, ""), - MOVING_PISTON(0, "PISTON_BASE", "PISTON_MOVING_PIECE"), + MOSSY_STONE_BRICK_STAIRS("SMOOTH_STAIRS"), + MOSSY_STONE_BRICK_WALL, + MOVING_PISTON("PISTON_BASE", "PISTON_MOVING_PIECE"), MULE_SPAWN_EGG(32, "MONSTER_EGG"), - MUSHROOM_STEM(0, "BROWN_MUSHROOM"), - MUSHROOM_STEW(0, "MUSHROOM_SOUP"), - MUSIC_DISC_11(0, "GOLD_RECORD"), - MUSIC_DISC_13(0, "GREEN_RECORD"), - MUSIC_DISC_BLOCKS(0, "RECORD_3"), - MUSIC_DISC_CAT(0, "RECORD_4"), - MUSIC_DISC_CHIRP(0, "RECORD_5"), - MUSIC_DISC_FAR(0, "RECORD_6"), - MUSIC_DISC_MALL(0, "RECORD_7"), - MUSIC_DISC_MELLOHI(0, "RECORD_8"), - MUSIC_DISC_STAL(0, "RECORD_9"), - MUSIC_DISC_STRAD(0, "RECORD_10"), - MUSIC_DISC_WAIT(0, "RECORD_11"), - MUSIC_DISC_WARD(0, "RECORD_12"), - MUTTON(0, ""), - MYCELIUM(0, "MYCEL"), - NAME_TAG(0, ""), - NAUTILUS_SHELL(0, "1.13"), - NETHERRACK(0, ""), - NETHER_BRICK(0, "NETHER_BRICK_ITEM"), - NETHER_BRICKS(0, "NETHER_BRICK"), - NETHER_BRICK_FENCE(0, "NETHER_FENCE"), + MUSHROOM_STEM("BROWN_MUSHROOM"), + MUSHROOM_STEW("MUSHROOM_SOUP"), + MUSIC_DISC_11("GOLD_RECORD"), + MUSIC_DISC_13("GREEN_RECORD"), + MUSIC_DISC_BLOCKS("RECORD_3"), + MUSIC_DISC_CAT("RECORD_4"), + MUSIC_DISC_CHIRP("RECORD_5"), + MUSIC_DISC_FAR("RECORD_6"), + MUSIC_DISC_MALL("RECORD_7"), + MUSIC_DISC_MELLOHI("RECORD_8"), + MUSIC_DISC_STAL("RECORD_9"), + MUSIC_DISC_STRAD("RECORD_10"), + MUSIC_DISC_WAIT("RECORD_11"), + MUSIC_DISC_WARD("RECORD_12"), + MUTTON, + MYCELIUM("MYCEL"), + NAME_TAG, + NAUTILUS_SHELL("1.13"), + NETHERRACK, + NETHER_BRICK("NETHER_BRICK_ITEM"), + NETHER_BRICKS("NETHER_BRICK"), + NETHER_BRICK_FENCE("NETHER_FENCE"), NETHER_BRICK_SLAB(4, "STEP"), - NETHER_BRICK_STAIRS(0, ""), - NETHER_BRICK_WALL(0, ""), - NETHER_PORTAL(0, "PORTAL"), - NETHER_QUARTZ_ORE(0, "QUARTZ_ORE"), - NETHER_STAR(0, ""), - NETHER_WART(0, "NETHER_STALK"), - NETHER_WART_BLOCK(0, "NETHER_WARTS"), - NOTE_BLOCK(0, ""), - OAK_BOAT(0, "BOAT"), - OAK_BUTTON(0, "WOOD_BUTTON"), - OAK_DOOR(0, "WOOD_DOOR", "WOODEN_DOOR"), - OAK_FENCE(0, "FENCE"), - OAK_FENCE_GATE(0, "FENCE_GATE"), - OAK_LEAVES(0, "LEAVES"), - OAK_LOG(0, "LOG"), - OAK_PLANKS(0, "WOOD"), - OAK_PRESSURE_PLATE(0, "WOOD_PLATE"), - OAK_SAPLING(0, "SAPLING"), - OAK_SIGN(0, "SIGN"), - OAK_SLAB(0, "WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), - OAK_STAIRS(0, "WOOD_STAIRS"), - OAK_TRAPDOOR(0, "TRAP_DOOR"), - OAK_WALL_SIGN(0, "SIGN_POST", "WALL_SIGN"), - OAK_WOOD(0, "LOG"), - OBSERVER(0, ""), - OBSIDIAN(0, ""), + NETHER_BRICK_STAIRS, + NETHER_BRICK_WALL, + NETHER_PORTAL("PORTAL"), + NETHER_QUARTZ_ORE("QUARTZ_ORE"), + NETHER_STAR, + NETHER_WART("NETHER_STALK"), + NETHER_WART_BLOCK("NETHER_WARTS"), + NOTE_BLOCK, + OAK_BOAT("BOAT"), + OAK_BUTTON("WOOD_BUTTON"), + OAK_DOOR("WOOD_DOOR", "WOODEN_DOOR"), + OAK_FENCE("FENCE"), + OAK_FENCE_GATE("FENCE_GATE"), + OAK_LEAVES("LEAVES"), + OAK_LOG("LOG"), + OAK_PLANKS("WOOD"), + OAK_PRESSURE_PLATE("WOOD_PLATE"), + OAK_SAPLING("SAPLING"), + OAK_SIGN("SIGN"), + OAK_SLAB("WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), + OAK_STAIRS("WOOD_STAIRS"), + OAK_TRAPDOOR("TRAP_DOOR"), + OAK_WALL_SIGN("SIGN_POST", "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"), @@ -657,7 +701,7 @@ public enum Materials { ORANGE_CONCRETE_POWDER(1, "CONCRETE_POWDER"), ORANGE_DYE(14, "INK_SACK"), ORANGE_GLAZED_TERRACOTTA(1, "1.12", "HARD_CLAY", "STAINED_CLAY", "ORANGE_TERRACOTTA"), - ORANGE_SHULKER_BOX(0, ""), + ORANGE_SHULKER_BOX, ORANGE_STAINED_GLASS(1, "STAINED_GLASS"), ORANGE_STAINED_GLASS_PANE(1, "STAINED_GLASS_PANE"), ORANGE_TERRACOTTA(1, "HARD_CLAY", "STAINED_CLAY"), @@ -665,17 +709,17 @@ public enum Materials { ORANGE_WALL_BANNER(14, "WALL_BANNER"), ORANGE_WOOL(1, "WOOL"), OXEYE_DAISY(8, "RED_ROSE"), - PACKED_ICE(0, ""), - PAINTING(0, ""), - PANDA_SPAWN_EGG(0, "1.14"), - PAPER(0, ""), + PACKED_ICE, + PAINTING, + PANDA_SPAWN_EGG("1.14"), + PAPER, PARROT_SPAWN_EGG(105, "MONSTER_EGG"), PEONY(5, "DOUBLE_PLANT"), - PETRIFIED_OAK_SLAB(0, "WOOD_STEP"), - PHANTOM_MEMBRANE(0, "1.13"), - PHANTOM_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), + PETRIFIED_OAK_SLAB("WOOD_STEP"), + PHANTOM_MEMBRANE("1.13"), + PHANTOM_SPAWN_EGG("1.13", "MONSTER_EGG"), PIG_SPAWN_EGG(90, "MONSTER_EGG"), - PILLAGER_SPAWN_EGG(0, "1.14"), + PILLAGER_SPAWN_EGG("1.14"), PINK_BANNER(9, "BANNER", "STANDING_BANNER"), PINK_BED(6, "BED", "BED_BLOCK"), PINK_CARPET(6, "CARPET"), @@ -683,77 +727,77 @@ public enum Materials { PINK_CONCRETE_POWDER(6, "CONCRETE_POWDER"), PINK_DYE(9, "INK_SACK"), PINK_GLAZED_TERRACOTTA(6, "1.12", "HARD_CLAY", "STAINED_CLAY", "PINK_TERRACOTTA"), - PINK_SHULKER_BOX(0, ""), + 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_WOOL(6, "WOOL"), - PISTON(0, "PISTON_BASE"), - PISTON_HEAD(0, "PISTON_EXTENSION"), - PLAYER_HEAD(3, "SKULL", "SKULL_ITEM", "HEAD"), + PISTON("PISTON_BASE"), + PISTON_HEAD("PISTON_EXTENSION"), + PLAYER_HEAD(3, "SKULL", "SKULL_ITEM"), PLAYER_WALL_HEAD(3, "SKULL", "SKULL_ITEM"), PODZOL(2, "DIRT"), - POISONOUS_POTATO(0, ""), + POISONOUS_POTATO, POLAR_BEAR_SPAWN_EGG(102, "MONSTER_EGG"), - POLISHED_ANDESITE(6, "1.13"), - POLISHED_ANDESITE_SLAB(0, ""), - POLISHED_ANDESITE_STAIRS(0, ""), - POLISHED_DIORITE(4, "1.13"), - POLISHED_DIORITE_SLAB(0, ""), - POLISHED_DIORITE_STAIRS(0, ""), - POLISHED_GRANITE(2, "1.13"), - POLISHED_GRANITE_SLAB(0, ""), - POLISHED_GRANITE_STAIRS(0, ""), - POPPED_CHORUS_FRUIT(0, "CHORUS_FRUIT_POPPED"), - POPPY(0, "RED_ROSE"), - PORKCHOP(0, "PORK"), - POTATO(0, "POTATO_ITEM"), - POTATOES(0, "POTATO"), - POTION(0, ""), + POLISHED_ANDESITE(6, "STONE"), + POLISHED_ANDESITE_SLAB, + POLISHED_ANDESITE_STAIRS, + POLISHED_DIORITE(4, "STONE"), + POLISHED_DIORITE_SLAB, + POLISHED_DIORITE_STAIRS, + POLISHED_GRANITE(2, "STONE"), + POLISHED_GRANITE_SLAB, + POLISHED_GRANITE_STAIRS, + POPPED_CHORUS_FRUIT("CHORUS_FRUIT_POPPED"), + POPPY("RED_ROSE"), + PORKCHOP("PORK"), + POTATO("POTATO_ITEM"), + POTATOES("POTATO"), + POTION, POTTED_ACACIA_SAPLING(4, "SAPLING", "FLOWER_POT"), POTTED_ALLIUM(2, "RED_ROSE", "FLOWER_POT"), POTTED_AZURE_BLUET(3, "RED_ROSE", "FLOWER_POT"), - POTTED_BAMBOO(0, ""), + POTTED_BAMBOO, POTTED_BIRCH_SAPLING(2, "SAPLING", "FLOWER_POT"), POTTED_BLUE_ORCHID(1, "RED_ROSE", "FLOWER_POT"), - POTTED_BROWN_MUSHROOM(0, "FLOWER_POT"), - POTTED_CACTUS(0, "FLOWER_POT"), - POTTED_CORNFLOWER(0, ""), - POTTED_DANDELION(0, "YELLOW_FLOWER", "FLOWER_POT"), + POTTED_BROWN_MUSHROOM("FLOWER_POT"), + POTTED_CACTUS("FLOWER_POT"), + POTTED_CORNFLOWER, + POTTED_DANDELION("YELLOW_FLOWER", "FLOWER_POT"), POTTED_DARK_OAK_SAPLING(5, "SAPLING", "FLOWER_POT"), - POTTED_DEAD_BUSH(0, "FLOWER_POT"), + POTTED_DEAD_BUSH("FLOWER_POT"), POTTED_FERN(2, "LONG_GRASS", "FLOWER_POT"), POTTED_JUNGLE_SAPLING(3, "SAPLING", "FLOWER_POT"), - POTTED_LILY_OF_THE_VALLEY(0, ""), - POTTED_OAK_SAPLING(0, "SAPLING", "FLOWER_POT"), + POTTED_LILY_OF_THE_VALLEY, + POTTED_OAK_SAPLING("SAPLING", "FLOWER_POT"), POTTED_ORANGE_TULIP(5, "RED_ROSE", "FLOWER_POT"), POTTED_OXEYE_DAISY(8, "RED_ROSE", "FLOWER_POT"), POTTED_PINK_TULIP(7, "RED_ROSE", "FLOWER_POT"), - POTTED_POPPY(0, "RED_ROSE", "FLOWER_POT"), - POTTED_RED_MUSHROOM(0, "FLOWER_POT"), + POTTED_POPPY("RED_ROSE", "FLOWER_POT"), + POTTED_RED_MUSHROOM("FLOWER_POT"), POTTED_RED_TULIP(4, "RED_ROSE", "FLOWER_POT"), POTTED_SPRUCE_SAPLING(1, "SAPLING", "FLOWER_POT"), POTTED_WHITE_TULIP(6, "RED_ROSE", "FLOWER_POT"), - POTTED_WITHER_ROSE(0, ""), - POWERED_RAIL(0, ""), - PRISMARINE(0, ""), + POTTED_WITHER_ROSE, + POWERED_RAIL, + PRISMARINE, PRISMARINE_BRICKS(2, "PRISMARINE"), PRISMARINE_BRICK_SLAB(4, "STEP"), - PRISMARINE_BRICK_STAIRS(0, "1.13"), - PRISMARINE_CRYSTALS(0, ""), - PRISMARINE_SHARD(0, ""), - PRISMARINE_SLAB(0, "1.13"), - PRISMARINE_STAIRS(0, "1.13"), - PRISMARINE_WALL(0, ""), + PRISMARINE_BRICK_STAIRS("1.13"), + PRISMARINE_CRYSTALS, + PRISMARINE_SHARD, + PRISMARINE_SLAB("1.13"), + PRISMARINE_STAIRS("1.13"), + PRISMARINE_WALL, PUFFERFISH(3, "RAW_FISH"), - PUFFERFISH_BUCKET(0, "1.13", "BUCKET", "WATER_BUCKET"), - PUFFERFISH_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), - PUMPKIN(0, ""), - PUMPKIN_PIE(0, ""), - PUMPKIN_SEEDS(0, ""), - PUMPKIN_STEM(0, ""), + PUFFERFISH_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), + PUFFERFISH_SPAWN_EGG("1.13", "MONSTER_EGG"), + PUMPKIN, + PUMPKIN_PIE, + PUMPKIN_SEEDS, + PUMPKIN_STEM, PURPLE_BANNER(5, "BANNER", "STANDING_BANNER"), PURPLE_BED(10, "BED", "BED_BLOCK"), PURPLE_CARPET(10, "CARPET"), @@ -761,35 +805,35 @@ public enum Materials { PURPLE_CONCRETE_POWDER(10, "CONCRETE_POWDER"), PURPLE_DYE(5, "INK_SACK"), PURPLE_GLAZED_TERRACOTTA(10, "1.12", "HARD_CLAY", "STAINED_CLAY", "PURPLE_TERRACOTTA"), - PURPLE_SHULKER_BOX(0, ""), + PURPLE_SHULKER_BOX, PURPLE_STAINED_GLASS(10, "STAINED_GLASS"), PURPLE_STAINED_GLASS_PANE(10, "THIN_GLASS", "STAINED_GLASS_PANE"), PURPLE_TERRACOTTA(10, "HARD_CLAY", "STAINED_CLAY"), PURPLE_WALL_BANNER(5, "WALL_BANNER"), PURPLE_WOOL(10, "WOOL"), - PURPUR_BLOCK(0, ""), - PURPUR_PILLAR(0, ""), - PURPUR_SLAB(0, "PURPUR_DOUBLE_SLAB"), - PURPUR_STAIRS(0, ""), - QUARTZ(0, ""), - QUARTZ_BLOCK(0, ""), + PURPUR_BLOCK, + PURPUR_PILLAR, + PURPUR_SLAB("PURPUR_DOUBLE_SLAB"), + PURPUR_STAIRS, + QUARTZ, + QUARTZ_BLOCK, QUARTZ_PILLAR(2, "QUARTZ_BLOCK"), QUARTZ_SLAB(7, "STEP"), - QUARTZ_STAIRS(0, ""), - RABBIT(0, ""), - RABBIT_FOOT(0, ""), - RABBIT_HIDE(0, ""), + QUARTZ_STAIRS, + RABBIT, + RABBIT_FOOT, + RABBIT_HIDE, RABBIT_SPAWN_EGG(101, "MONSTER_EGG"), - RABBIT_STEW(0, ""), - RAIL(0, "RAILS"), - RAVAGER_SPAWN_EGG(0, "1.14"), - REDSTONE(0, ""), - REDSTONE_BLOCK(0, ""), - REDSTONE_LAMP(0, "REDSTONE_LAMP_OFF", "REDSTONE_LAMP_ON"), - REDSTONE_ORE(0, "GLOWING_REDSTONE_ORE"), - REDSTONE_TORCH(0, "REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"), + RABBIT_STEW, + RAIL("RAILS"), + RAVAGER_SPAWN_EGG("1.14"), + REDSTONE, + REDSTONE_BLOCK, + REDSTONE_LAMP("REDSTONE_LAMP_OFF", "REDSTONE_LAMP_ON"), + REDSTONE_ORE("GLOWING_REDSTONE_ORE"), + REDSTONE_TORCH("REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"), REDSTONE_WALL_TORCH(1, "REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"), - REDSTONE_WIRE(0, ""), + REDSTONE_WIRE, RED_BANNER(1, "BANNER", "STANDING_BANNER"), RED_BED(14, "BED", "BED_BLOCK"), RED_CARPET(14, "CARPET"), @@ -797,200 +841,214 @@ public enum Materials { RED_CONCRETE_POWDER(14, "CONCRETE_POWDER"), RED_DYE(1, "ROSE_RED"), RED_GLAZED_TERRACOTTA(14, "1.12", "HARD_CLAY", "STAINED_CLAY", "RED_TERRACOTTA"), - RED_MUSHROOM(0, ""), - RED_MUSHROOM_BLOCK(0, "RED_MUSHROOM", "HUGE_MUSHROOM_2"), - RED_NETHER_BRICKS(0, "RED_NETHER_BRICK"), + RED_MUSHROOM, + RED_MUSHROOM_BLOCK("RED_MUSHROOM", "HUGE_MUSHROOM_2"), + RED_NETHER_BRICKS("RED_NETHER_BRICK"), RED_NETHER_BRICK_SLAB(4, "STEP"), - RED_NETHER_BRICK_STAIRS(0, ""), - RED_NETHER_BRICK_WALL(0, ""), + RED_NETHER_BRICK_STAIRS, + RED_NETHER_BRICK_WALL, RED_SAND(1, "SAND"), - RED_SANDSTONE(0, ""), - RED_SANDSTONE_SLAB(0, "STONE_SLAB2", "DOUBLE_STONE_SLAB2"), - RED_SANDSTONE_STAIRS(0, ""), - RED_SANDSTONE_WALL(0, ""), - RED_SHULKER_BOX(0, ""), + RED_SANDSTONE, + RED_SANDSTONE_SLAB("STONE_SLAB2", "DOUBLE_STONE_SLAB2"), + RED_SANDSTONE_STAIRS, + RED_SANDSTONE_WALL, + RED_SHULKER_BOX, RED_STAINED_GLASS(14, "STAINED_GLASS"), RED_STAINED_GLASS_PANE(14, "THIN_GLASS", "STAINED_GLASS_PANE"), RED_TERRACOTTA(14, "HARD_CLAY", "STAINED_CLAY"), RED_TULIP(4, "RED_ROSE"), RED_WALL_BANNER(1, "WALL_BANNER"), RED_WOOL(14, "WOOL"), - - // remove "DIODE_BLOCK_ON", "DIODE_BLOCK_OFF" - REPEATER(0, "DIODE"), - REPEATING_COMMAND_BLOCK(0, "COMMAND", "COMMAND_REPEATING"), + REPEATER("DIODE", "DIODE_BLOCK_ON", "DIODE_BLOCK_OFF"), + REPEATING_COMMAND_BLOCK("COMMAND", "COMMAND_REPEATING"), ROSE_BUSH(4, "DOUBLE_PLANT"), - ROTTEN_FLESH(0, ""), - SADDLE(0, ""), + ROTTEN_FLESH, + SADDLE, SALMON(1, "RAW_FISH"), - SALMON_BUCKET(0, "1.13", "BUCKET", "WATER_BUCKET"), - SALMON_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), - SAND(0, ""), - SANDSTONE(0, ""), + SALMON_BUCKET("1.13", "BUCKET", "WATER_BUCKET"), + SALMON_SPAWN_EGG("1.13", "MONSTER_EGG"), + SAND, + SANDSTONE, SANDSTONE_SLAB(1, "STEP", "STONE_SLAB", "DOUBLE_STEP"), - SANDSTONE_STAIRS(0, ""), - SANDSTONE_WALL(0, ""), - SCAFFOLDING(0, "1.14", "SLIME_BLOCK"), - SCUTE(0, "1.13"), - SEAGRASS(0, "1.13"), - SEA_LANTERN(0, ""), - SEA_PICKLE(0, "1.13"), - SHEARS(0, ""), + SANDSTONE_STAIRS, + SANDSTONE_WALL, + SCAFFOLDING("1.14", "SLIME_BLOCK"), + SCUTE("1.13"), + SEAGRASS("1.13", "GRASS"), + SEA_LANTERN, + SEA_PICKLE("1.13"), + SHEARS, SHEEP_SPAWN_EGG(91, "MONSTER_EGG"), - SHIELD(0, ""), - SHULKER_BOX(0, "PURPLE_SHULKER_BOX"), - SHULKER_SHELL(0, ""), + SHIELD, + SHULKER_BOX("PURPLE_SHULKER_BOX"), + SHULKER_SHELL, SHULKER_SPAWN_EGG(69, "MONSTER_EGG"), SILVERFISH_SPAWN_EGG(60, "MONSTER_EGG"), SKELETON_HORSE_SPAWN_EGG(28, "MONSTER_EGG"), - SKELETON_SKULL(0, "SKULL", "SKULL_ITEM"), + SKELETON_SKULL("SKULL", "SKULL_ITEM"), SKELETON_SPAWN_EGG(51, "MONSTER_EGG"), - SKELETON_WALL_SKULL(0, "SKULL", "SKULL_ITEM"), - SKULL_BANNER_PATTERN(0, ""), - SLIME_BALL(0, ""), - SLIME_BLOCK(0, ""), + SKELETON_WALL_SKULL("SKULL", "SKULL_ITEM"), + SKULL_BANNER_PATTERN, + SLIME_BALL, + SLIME_BLOCK, SLIME_SPAWN_EGG(55, "MONSTER_EGG"), - SMITHING_TABLE(0, ""), - SMOKER(0, "1.14", "FURNACE"), - SMOOTH_QUARTZ(0, "1.13"), + SMITHING_TABLE, + SMOKER("1.14", "FURNACE"), + SMOOTH_QUARTZ("1.13"), SMOOTH_QUARTZ_SLAB(7, "STEP"), - SMOOTH_QUARTZ_STAIRS(0, ""), + SMOOTH_QUARTZ_STAIRS, SMOOTH_RED_SANDSTONE(2, "RED_SANDSTONE"), - SMOOTH_RED_SANDSTONE_SLAB(0, "STONE_SLAB2"), - SMOOTH_RED_SANDSTONE_STAIRS(0, ""), + SMOOTH_RED_SANDSTONE_SLAB("STONE_SLAB2"), + SMOOTH_RED_SANDSTONE_STAIRS, SMOOTH_SANDSTONE(2, "SANDSTONE"), - SMOOTH_SANDSTONE_SLAB(0, "STEP"), - SMOOTH_SANDSTONE_STAIRS(0, ""), - SMOOTH_STONE(0, "STEP"), - SMOOTH_STONE_SLAB(0, "STEP"), - SNOW(0, ""), - SNOWBALL(0, "SNOW_BALL"), - SNOW_BLOCK(0, ""), - SOUL_SAND(0, ""), - SPAWNER(0, "MOB_SPAWNER"), - SPECTRAL_ARROW(0, ""), - SPIDER_EYE(0, ""), + SMOOTH_SANDSTONE_SLAB("STEP"), + SMOOTH_SANDSTONE_STAIRS, + SMOOTH_STONE("STEP"), + SMOOTH_STONE_SLAB("STEP"), + SNOW, + SNOWBALL("SNOW_BALL"), + SNOW_BLOCK, + SOUL_SAND, + SPAWNER("MOB_SPAWNER"), + SPECTRAL_ARROW("1.9", "ARROW"), + SPIDER_EYE, SPIDER_SPAWN_EGG(52, "MONSTER_EGG"), - SPLASH_POTION(0, ""), - SPONGE(0, ""), - SPRUCE_BOAT(0, "BOAT_SPRUCE"), - SPRUCE_BUTTON(0, "WOOD_BUTTON"), - SPRUCE_DOOR(0, "SPRUCE_DOOR_ITEM"), - SPRUCE_FENCE(0, ""), - SPRUCE_FENCE_GATE(0, ""), + SPLASH_POTION, + SPONGE, + SPRUCE_BOAT("BOAT_SPRUCE"), + SPRUCE_BUTTON("WOOD_BUTTON"), + SPRUCE_DOOR("SPRUCE_DOOR_ITEM"), + SPRUCE_FENCE, + SPRUCE_FENCE_GATE, SPRUCE_LEAVES(1, "LEAVES"), SPRUCE_LOG(1, "LOG"), SPRUCE_PLANKS(1, "WOOD"), - SPRUCE_PRESSURE_PLATE(0, "WOOD_PLATE"), + SPRUCE_PRESSURE_PLATE("WOOD_PLATE"), SPRUCE_SAPLING(1, "SAPLING"), - SPRUCE_SIGN(0, "SIGN"), + SPRUCE_SIGN("SIGN"), SPRUCE_SLAB(1, "WOOD_STEP", "WOODEN_SLAB", "WOOD_DOUBLE_STEP"), - SPRUCE_STAIRS(0, "SPRUCE_WOOD_STAIRS"), - SPRUCE_TRAPDOOR(0, "TRAP_DOOR"), - SPRUCE_WALL_SIGN(0, "SIGN_POST", "WALL_SIGN"), + SPRUCE_STAIRS("SPRUCE_WOOD_STAIRS"), + SPRUCE_TRAPDOOR("TRAP_DOOR"), + SPRUCE_WALL_SIGN("SIGN_POST", "WALL_SIGN"), SPRUCE_WOOD(1, "LOG"), SQUID_SPAWN_EGG(94, "MONSTER_EGG"), - STICK(0, ""), - STICKY_PISTON(0, "PISTON_BASE", "PISTON_STICKY_BASE"), - STONE(0, ""), - STONECUTTER(0, "1.14"), - STONE_AXE(0, ""), - STONE_BRICKS(0, "SMOOTH_BRICK"), + STICK, + STICKY_PISTON("PISTON_BASE", "PISTON_STICKY_BASE"), + STONE, + STONECUTTER("1.14"), + STONE_AXE, + STONE_BRICKS("SMOOTH_BRICK"), STONE_BRICK_SLAB(4, "STEP", "STONE_SLAB", "DOUBLE_STEP"), - STONE_BRICK_STAIRS(0, "SMOOTH_STAIRS"), - STONE_BRICK_WALL(0, ""), - STONE_BUTTON(0, ""), - STONE_HOE(0, ""), - STONE_PICKAXE(0, ""), - STONE_PRESSURE_PLATE(0, "STONE_PLATE"), - STONE_SHOVEL(0, "STONE_SPADE"), - STONE_SLAB(0, "STEP", "DOUBLE_STEP"), - STONE_STAIRS(0, ""), - STONE_SWORD(0, ""), + STONE_BRICK_STAIRS("SMOOTH_STAIRS"), + STONE_BRICK_WALL, + STONE_BUTTON, + STONE_HOE, + STONE_PICKAXE, + STONE_PRESSURE_PLATE("STONE_PLATE"), + STONE_SHOVEL("STONE_SPADE"), + STONE_SLAB("STEP", "DOUBLE_STEP"), + STONE_STAIRS, + STONE_SWORD, STRAY_SPAWN_EGG(6, "MONSTER_EGG"), - STRING(0, ""), - STRIPPED_ACACIA_LOG(0, "LOG_2"), - STRIPPED_ACACIA_WOOD(0, "LOG_2"), + STRING, + STRIPPED_ACACIA_LOG("LOG_2"), + STRIPPED_ACACIA_WOOD("LOG_2"), STRIPPED_BIRCH_LOG(2, "LOG"), STRIPPED_BIRCH_WOOD(2, "LOG"), - STRIPPED_DARK_OAK_LOG(0, "LOG"), - STRIPPED_DARK_OAK_WOOD(0, "LOG"), + STRIPPED_DARK_OAK_LOG("LOG"), + STRIPPED_DARK_OAK_WOOD("LOG"), STRIPPED_JUNGLE_LOG(3, "LOG"), STRIPPED_JUNGLE_WOOD(3, "LOG"), - STRIPPED_OAK_LOG(0, "LOG"), - STRIPPED_OAK_WOOD(0, "LOG"), + STRIPPED_OAK_LOG("LOG"), + STRIPPED_OAK_WOOD("LOG"), STRIPPED_SPRUCE_LOG(1, "LOG"), STRIPPED_SPRUCE_WOOD(1, "LOG"), - STRUCTURE_BLOCK(0, ""), - STRUCTURE_VOID(0, "1.10", "BARRIER/1.9"), - SUGAR(0, ""), - SUGAR_CANE(0, "SUGAR_CANE_BLOCK"), - SUNFLOWER(0, "DOUBLE_PLANT"), - SUSPICIOUS_STEW(0, "1.14", "MUSHROOM_STEW"), - SWEET_BERRIES(0, "1.14"), - SWEET_BERRY_BUSH(0, "1.14", "GRASS"), + STRUCTURE_BLOCK, + /** + * Originally developers used barrier blocks for its purpose. + * 1.10 will be parsed as 1.9 version. + */ + STRUCTURE_VOID("1.10", "BARRIER"), + SUGAR, + SUGAR_CANE("SUGAR_CANE_BLOCK"), + SUNFLOWER("DOUBLE_PLANT"), + SUSPICIOUS_STEW("1.14", "MUSHROOM_STEW"), + SWEET_BERRIES("1.14"), + SWEET_BERRY_BUSH("1.14", "GRASS"), TALL_GRASS(2, "DOUBLE_PLANT"), - TALL_SEAGRASS(0, "1.13"), - TERRACOTTA(0, "HARD_CLAY"), - TIPPED_ARROW(0, ""), - TNT(0, ""), - TNT_MINECART(0, "EXPLOSIVE_MINECART"), - TORCH(0, ""), - TOTEM_OF_UNDYING(0, "TOTEM"), + TALL_SEAGRASS(2, "1.13", "TALL_GRASS"), + TERRACOTTA("HARD_CLAY"), + TIPPED_ARROW("1.9", "ARROW"), + TNT, + TNT_MINECART("EXPLOSIVE_MINECART"), + TORCH, + TOTEM_OF_UNDYING("TOTEM"), TRADER_LLAMA_SPAWN_EGG(103, "1.14", "MONSTER_EGG"), - TRAPPED_CHEST(0, ""), - TRIDENT(0, "1.13"), - TRIPWIRE(0, ""), - TRIPWIRE_HOOK(0, ""), + TRAPPED_CHEST, + TRIDENT("1.13"), + TRIPWIRE, + TRIPWIRE_HOOK, TROPICAL_FISH(2, "RAW_FISH"), - TROPICAL_FISH_BUCKET(0, "1.13", "BUCKET", "WATER_BUCKET"), - TROPICAL_FISH_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), - TUBE_CORAL(0, "1.13"), - TUBE_CORAL_BLOCK(0, "1.13"), - TUBE_CORAL_FAN(0, "1.13"), - TUBE_CORAL_WALL_FAN(0, ""), - TURTLE_EGG(0, "1.13", "EGG"), - TURTLE_HELMET(0, "1.13"), - TURTLE_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), + 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"), + TUBE_CORAL_WALL_FAN, + TURTLE_EGG("1.13", "EGG"), + TURTLE_HELMET("1.13", "IRON_HELMET"), + TURTLE_SPAWN_EGG("1.13", "CHICKEN_SPAWN_EGG"), VEX_SPAWN_EGG(35, "MONSTER_EGG"), VILLAGER_SPAWN_EGG(120, "MONSTER_EGG"), VINDICATOR_SPAWN_EGG(36, "MONSTER_EGG"), - VINE(0, ""), - VOID_AIR(0, "AIR"), - WALL_TORCH(0, "TORCH"), - WANDERING_TRADER_SPAWN_EGG(0, "1.14", "VILLAGER_SPAWN_EGG"), - WATER(0, "STATIONARY_WATER"), - WATER_BUCKET(0, ""), + VINE, + /** + * 1.13 tag is not added because it's the same thing as {@link #AIR} + * + * @see #CAVE_AIR + */ + VOID_AIR("AIR"), + WALL_TORCH("TORCH"), + WANDERING_TRADER_SPAWN_EGG("1.14", "VILLAGER_SPAWN_EGG"), + /** + * 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, WET_SPONGE(1, "SPONGE"), - WHEAT(0, "CROPS"), - WHEAT_SEEDS(0, "SEEDS"), + WHEAT("CROPS"), + WHEAT_SEEDS("SEEDS"), WHITE_BANNER(15, "BANNER", "STANDING_BANNER"), - WHITE_BED(0, "BED", "BED_BLOCK"), - WHITE_CARPET(0, "CARPET"), - WHITE_CONCRETE(0, "CONCRETE"), - WHITE_CONCRETE_POWDER(0, "CONCRETE_POWDER"), + WHITE_BED("BED", "BED_BLOCK"), + WHITE_CARPET("CARPET"), + WHITE_CONCRETE("CONCRETE"), + WHITE_CONCRETE_POWDER("CONCRETE_POWDER"), WHITE_DYE(15, "1.14", "INK_SACK", "BONE_MEAL"), - WHITE_GLAZED_TERRACOTTA(0, "1.12", "HARD_CLAY", "STAINED_CLAY", "WHITE_TERRACOTTA"), - WHITE_SHULKER_BOX(0, ""), - WHITE_STAINED_GLASS(0, "STAINED_GLASS"), - WHITE_STAINED_GLASS_PANE(0, "THIN_GLASS", "STAINED_GLASS_PANE"), - WHITE_TERRACOTTA(0, "HARD_CLAY", "TERRACOTTA"), + WHITE_GLAZED_TERRACOTTA("1.12", "HARD_CLAY", "STAINED_CLAY", "WHITE_TERRACOTTA"), + WHITE_SHULKER_BOX, + WHITE_STAINED_GLASS("STAINED_GLASS"), + WHITE_STAINED_GLASS_PANE("THIN_GLASS", "STAINED_GLASS_PANE"), + WHITE_TERRACOTTA("HARD_CLAY", "TERRACOTTA"), WHITE_TULIP(6, "RED_ROSE"), WHITE_WALL_BANNER(15, "WALL_BANNER"), - WHITE_WOOL(0, "WOOL"), + WHITE_WOOL("WOOL"), WITCH_SPAWN_EGG(66, "MONSTER_EGG"), - WITHER_ROSE(0, "1.14", "BLACK_DYE"), + WITHER_ROSE("1.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"), WOLF_SPAWN_EGG(95, "MONSTER_EGG"), - WOODEN_AXE(0, "WOOD_AXE"), - WOODEN_HOE(0, "WOOD_HOE"), - WOODEN_PICKAXE(0, "WOOD_PICKAXE"), - WOODEN_SHOVEL(0, "WOOD_SPADE"), - WOODEN_SWORD(0, "WOOD_SWORD"), - WRITABLE_BOOK(0, "BOOK_AND_QUILL"), - WRITTEN_BOOK(0, ""), + WOODEN_AXE("WOOD_AXE"), + WOODEN_HOE("WOOD_HOE"), + WOODEN_PICKAXE("WOOD_PICKAXE"), + WOODEN_SHOVEL("WOOD_SPADE"), + WOODEN_SWORD("WOOD_SWORD"), + WRITABLE_BOOK("BOOK_AND_QUILL"), + WRITTEN_BOOK, YELLOW_BANNER(11, "BANNER", "STANDING_BANNER"), YELLOW_BED(4, "BED", "BED_BLOCK"), YELLOW_CARPET(4, "CARPET"), @@ -998,7 +1056,7 @@ public enum Materials { YELLOW_CONCRETE_POWDER(4, "CONCRETE_POWDER"), YELLOW_DYE(11, "INK_SACK", "DANDELION_YELLOW"), YELLOW_GLAZED_TERRACOTTA(4, "1.12", "HARD_CLAY", "STAINED_CLAY", "YELLOW_TERRACOTTA"), - YELLOW_SHULKER_BOX(0, ""), + 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"), @@ -1013,39 +1071,118 @@ public enum Materials { /** - * A list of material names that can be damaged. - * Some names are not complete as this list needs to be - * checked with {@link String#contains}. + * An immutable cached set of {@link Materials#values()} to avoid allocating memory for + * calling the method every time. + * + * @since 2.0.0 */ - public static final String[] DAMAGEABLE = { + public static final EnumSet VALUES = EnumSet.allOf(Materials.class); + /** + * A set 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. + * + * @since 1.0.0 + */ + private static final ImmutableSet DAMAGEABLE = ImmutableSet.of( "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" + ); /** - * A list of duplicated items in 1.13 and 1.12 with different purpose. + * Materials Paradox (Duplication Check) + *

+ * A map of duplicated material names in 1.13 and 1.12 that will conflict with the legacy names. * Values are the new material names. - * Duplicates are only checked by keys not values. - * Checked with {@link String#equals} + *
+ * Duplicates are normally only checked by keys, not values. + * + * @since 3.0.0 + */ + @SuppressWarnings("UnstableApiUsage") + 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(Materials::getLegacy) + .flatMap(Arrays::stream) + .filter(m -> m.charAt(1) == '.') + .collect(Collectors.collectingAndThen(Collectors.toSet(), ImmutableSet::copyOf)); + + /** + * Guava (Google Core Libraries for Java)'s cache for performance and timed caches. + * For strings that match a certain Materials. Mostly cached for configs. + * + * @since 1.0.0 + */ + private static final Cache NAME_CACHE = CacheBuilder.newBuilder() + .softValues() + .expireAfterAccess(15, TimeUnit.MINUTES) + .build(); + /** + * Guava (Google Core Libraries for Java)'s cache for performance and timed caches. + * For Materialss that are already parsed once. + * + * @since 3.0.0 + */ + private static final Cache PARSED_CACHE = CacheBuilder.newBuilder() + .softValues() + .expireAfterAccess(10, TimeUnit.MINUTES) + .concurrencyLevel(Runtime.getRuntime().availableProcessors()) + .build(); + + /** + * Pre-compiled RegEx pattern. + * Include both replacements to avoid recreating string multiple times with multiple RegEx checks. + * + * @since 3.0.0 + */ + private static final Pattern FORMAT_PATTERN = Pattern.compile("\\W+"); + /** + * The current version of the server in the a form of a major {@link MinecraftVersion} version. + * + * @since 1.0.0 + */ + private static final MinecraftVersion VERSION = valueOfVersion(Bukkit.getVersion()); + /** + * 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. + * + * @since 3.0.0 + */ + private static final boolean ISFLAT = isVersionOrHigher(MinecraftVersion.V1_13); + + /** + * The data value of this material https://minecraft.gamepedia.com/Java_Edition_data_values/Pre-flattening + * + * @see #getData() */ - public static final HashMap DUPLICATED = new HashMap() {{ - put(Materials.MELON, Materials.MELON_SLICE); - put(Materials.CARROT, Materials.CARROTS); - put(Materials.POTATO, Materials.POTATOES); - put(Materials.BEETROOT, Materials.BEETROOTS); - put(Materials.BROWN_MUSHROOM, Materials.BROWN_MUSHROOM_BLOCK); - put(Materials.BRICK, Materials.BRICKS); - put(Materials.RED_MUSHROOM, Materials.RED_MUSHROOM_BLOCK); - put(Materials.MAP, Materials.FILLED_MAP); - put(Materials.NETHER_BRICK, Materials.NETHER_BRICKS); - }}; - public static final Materials[] VALUES = Materials.values(); - private static final HashMap CACHED_SEARCH = new HashMap<>(); - private static MinecraftVersion version; - private static Boolean isNewVersion; private final byte data; + /** + * A list of material names that was being used for older verions. + * + * @see #getLegacy() + */ private final String[] legacy; Materials(int data, String... legacy) { @@ -1053,149 +1190,363 @@ public enum Materials { this.legacy = legacy; } - public static String[] collect(boolean newVersion) { - Materials[] values = values(); - return Arrays.stream(values).map(value -> newVersion ? value.name() : value.name()).toArray(String[]::new); + Materials() { + this(0); } - public static String[] collectCurrent() { - Material[] values = Material.values(); - return Arrays.stream(values).map(Enum::name).toArray(String[]::new); + Materials(String... legacy) { + this(0, legacy); } /** - * Checks if the version is 1.13 (Aquatic Update) or higher. + * Checks if the version is {@link MinecraftVersion#V1_13} (Aquatic Update) or higher. + * An invocation of this method yields the cached result from the expression: + *

+ *

+ * {@link #isVersionOrHigher(MinecraftVersion V1_13)} + *
* * @return true if 1.13 or higher. + * @see #getVersion() + * @see #isVersionOrHigher(MinecraftVersion) + * @since 1.0.0 */ public static boolean isNewVersion() { - if (isNewVersion != null) { - return isNewVersion; - } - return isNewVersion = isVersionOrHigher(MinecraftVersion.VERSION_1_13); + return ISFLAT; } + /** + * This is just an extra method that method that can be used for many cases. + * It can be used in {@link org.bukkit.event.player.PlayerInteractEvent} + * or when accessing {@link org.bukkit.entity.Player#getMainHand()}, + * or other compatibility related methods. + *

+ * An invocation of this method yields exactly the same result as the expression: + *

+ *

+ * {@link #getVersion()} == {@link MinecraftVersion#V1_8} + *
+ * + * @since 2.0.0 + */ public static boolean isOneEight() { - return getVersion() == MinecraftVersion.VERSION_1_8; + return VERSION == MinecraftVersion.V1_8; } /** - * Uses newly added materials to minecraft to detect the server version. + * The current version of the server. * - * @return the current server version. + * @return the current server version or {@link MinecraftVersion#UNKNOWN} if unknown or below 1.8. + * @see #isNewVersion() + * @since 2.0.0 */ + @Nonnull public static MinecraftVersion getVersion() { - if (version != null) { - return version; - } - return version = valueOfVersion(Bukkit.getVersion()); + return VERSION; } /** - * When using newer versions of Minecraft {@link #isNewVersion()} this helps - * to find the old material name with its data using a cached search for optimization. + * When using newer versions of Minecraft ({@link #isNewVersion()}), helps + * to find the old material name with its data value using a cached search for optimization. * - * @see #matchMaterials(String, byte) + * @see #matchDefinedMaterials(String, byte) + * @since 1.0.0 */ - private static Materials requestOldMaterials(String name, byte data) { - Materials cached = CACHED_SEARCH.get(name + "," + data); + @Nullable + private static Materials requestOldMaterials(@Nonnull String name, byte data) { + String holder = name + data; + Materials material = NAME_CACHE.getIfPresent(holder); + if (material != null) return material; - if (cached != null) { - return cached; + for (Materials materials : VALUES) { + if ((data == -1 || data == materials.data) && materials.anyMatchLegacy(name)) { + NAME_CACHE.put(holder, materials); + return materials; + } } - Optional search = data == -1 ? Arrays.stream(Materials.VALUES).filter(mat -> mat.matchAnyLegacy(name)).findFirst() - : Arrays.stream(Materials.VALUES).filter(mat -> mat.matchAnyLegacy(name) && mat.data == data).findFirst(); - if (search.isPresent()) { - Materials found = search.get(); - CACHED_SEARCH.put(found.legacy[0] + "," + found.getData(), found); - return found; - } return null; } /** - * Checks if Materials enum contains a material with this name. + * Checks if Materials enum contains a material with the given name. + *

+ * You should use {@link #matchMaterials(String)} instead if you're going + * to get the Materials 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 + * @param name name of the material. * @return true if Materials enum has this material. + * @see #containsLegacy(String) + * @since 1.0.0 */ - public static boolean contains(String name) { - String formatted = format(name); - return Arrays.stream(Materials.VALUES).anyMatch(mat -> mat.name().equals(formatted)); + public static boolean contains(@Nonnull String name) { + Validate.notEmpty(name, "Cannot check for null or empty material name"); + name = format(name); + + for (Materials materials : VALUES) + if (materials.name().equals(name)) return true; + return false; } /** - * @see #matchMaterials(String, byte) + * 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 Materials matchMaterials(Material material) { - return matchMaterials(material.name()); + 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)); } /** + * Parses the given material name as an Materials with unspecified data value. + * * @see #matchMaterials(String, byte) + * @since 2.0.0 */ - public static Materials matchMaterials(String name) { - // -1 Determines whether the item's data 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. + @Nonnull + public static Optional matchMaterials(@Nonnull String name) { return matchMaterials(name, (byte) -1); } /** - * Matches the argument string and its data with a Materials. + * Parses the given material name as an Materials. + * Can also be used like: MATERIAL:DATA + *

+ * Examples + *

+     *     INK_SACK:1 -> RED_DYE
+     *     WOOL, 14  -> RED_WOOL
+     * 
* - * @param name the name of the material - * @param data the data byte of the material - * @return a Materials from the enum (with the same legacy name and data if in older versions.) + * @see #matchDefinedMaterials(String, byte) + * @see #matchMaterials(ItemStack) + * @since 2.0.0 */ - public static Materials matchMaterials(String name, byte data) { + @Nonnull + public static Optional matchMaterials(@Nonnull String name, byte data) { + Validate.notEmpty(name, "Cannot match a material with null or empty material name"); + Optional oldMatch = matchMaterialsWithData(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 matchDefinedMaterials(format(name), data); + } + + /** + * Parses material name and data value from the specified string. + * The seperators are: , or : + * Spaces are allowed. Mostly used when getting materials from config for old school minecrafters. + *

+ * Examples + *

+     *     INK_SACK:1 -> RED_DYE
+     *     WOOL, 14  -> RED_WOOL
+     * 
+ * + * @param name the material string that consists of the material name, data and separator character. + * @return the parsed Materials. + * @see #matchMaterials(String) + * @since 3.0.0 + */ + private static Optional matchMaterialsWithData(String name) { + for (char separator : new char[]{',', ':'}) { + int index = name.indexOf(separator); + if (index == -1) continue; + + String mat = format(name.substring(0, index)); + byte data = Byte.parseByte(StringUtils.deleteWhitespace(name.substring(index + 1))); + return matchDefinedMaterials(mat, data); + } + + return Optional.empty(); + } + + /** + * Parses the given material as an Materials. + * + * @throws IllegalArgumentException may be thrown as an unexpected exception. + * @see #matchDefinedMaterials(String, byte) + * @see #matchMaterials(ItemStack) + * @since 2.0.0 + */ + @Nonnull + public static Materials matchMaterials(@Nonnull Material material) { + Objects.requireNonNull(material, "Cannot match null material"); + return matchDefinedMaterials(material.name(), (byte) -1) + .orElseThrow(() -> new IllegalArgumentException("Unsupported Material: " + material)); + } + + /** + * Parses the given item as an Materials using its material and data value (durability). + * + * @param item the ItemStack to match. + * @return an Materials if matched any. + * @throws IllegalArgumentException may be thrown as an unexpected exception. + * @see #matchDefinedMaterials(String, byte) + * @since 2.0.0 + */ + @Nonnull + @SuppressWarnings("deprecation") + public static Materials matchMaterials(@Nonnull ItemStack item) { + Objects.requireNonNull(item, "Cannot match null ItemStack"); + String material = item.getType().name(); + return matchDefinedMaterials(material, + isDamageable(material) ? (byte) 0 : (byte) item.getDurability()) + .orElseThrow(() -> new IllegalArgumentException("Unsupported Material: " + material)); + } + + /** + * Parses the given material name and data value as an Materials. + * All the values passed to this method will not be null or empty and are formatted correctly. + * + * @param name the formatted name of the material. + * @param data the data value of the material. + * @return an Materials (with the same data value if specified) + * @see #matchMaterials(String, byte) + * @see #matchMaterials(Material) + * @see #matchMaterials(int, byte) + * @see #matchMaterials(ItemStack) + * @since 3.0.0 + */ + @Nonnull + private static Optional matchDefinedMaterials(@Nonnull String name, byte data) { + boolean duplicated = isDuplicated(name); + + // 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; + 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(Materials.class, name).transform(Optional::of).or(Optional.empty()); + if (xMat.isPresent()) return xMat; + } + + // Materials 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(requestDuplicatedMaterials(name, data)); + return Optional.ofNullable(requestOldMaterials(name, data)); + } + + /** + * Materials Paradox (Duplication Check) + * Checks if the material has any duplicates. + *

+ * Example: + *

{@code MELON, CARROT, POTATO, BEETROOT -> true} + * + * @param name the name of the material to check. + * @return true if there's a duplicated material for this material, otherwise false. + * @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); - if ((contains(name) && data <= 0) && (isNewVersion() || !isDuplicated(name))) { - return valueOf(name); - } - - // TODO Temporary but works - Please find a more reasonable fix for duplicated materials. - if (isDuplicated(name) && !isNewVersion()) { - return requestDuplicatedMaterials(name, data); - } - - return requestOldMaterials(name, data); + // Don't use matchMaterials() since this method is being called from matchMaterials() itself and will cause a StackOverflowError. + for (Map.Entry duplicated : DUPLICATED.entrySet()) + if (duplicated.getKey().name().equals(name) || duplicated.getKey().anyMatchLegacy(name)) return true; + return false; } /** - * Gets the Materials based on the Material's ID and data. - * You should avoid using this for performance reasons. + * Gets the Materials based on the material's ID (Magic Value) and data value.
+ * You should avoid using this for performance issues. * * @param id the ID (Magic value) of the material. - * @param data the data of the material. - * @return some Materials, or null. + * @param data the data value of the material. + * @return a parsed Materials with the same ID and data value. + * @see #matchMaterials(ItemStack) + * @since 2.0.0 */ - public static Materials matchMaterials(int id, byte data) { + @Nonnull + public static Optional matchMaterials(int id, byte data) { + if (id < 0 || data < 0) return Optional.empty(); + // Looping through Material.values() will take longer. - return Arrays.stream(Materials.VALUES).filter(mat -> mat.getId() == id && mat.data == data).findFirst().orElse(null); + for (Materials materials : VALUES) + if (materials.data == data && materials.getId() == id) return Optional.of(materials); + return Optional.empty(); } /** - * This method is temporary. Do not use this. + * A solution for Materials 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 Materials based on the version. + * @throws IllegalArgumentException may be thrown. If thrown, it's a bug. + * @since 2.0.0 */ - private static Materials requestDuplicatedMaterials(String name, byte data) { + @Nullable + private static Materials requestDuplicatedMaterials(@Nonnull String name, byte data) { Materials mat = requestOldMaterials(name, data); - return mat == null ? null : mat.name().endsWith("S") ? valueOf(name) : mat; + // If ends with "S" -> Plural Form Material + return mat.name().charAt(mat.name().length() - 1) == 'S' ? Enums.getIfPresent(Materials.class, name).orNull() : mat; + } + + /** + * Always returns the value with the given duplicated material key name. + * + * @param name the name of the material. + * @return the new Materials of this duplicated material. + * @see #getMaterialsIfDuplicated(String) + * @since 2.0.0 + */ + @Nonnull + public static Optional getNewMaterialsIfDuplicated(@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 Materials (key or value) of the Materials (key or value). + * @see #matchMaterials(String, byte) + * @since 2.0.0 + */ + @Nullable + public static Materials getMaterialsIfDuplicated(@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. * * @param name the material name to modify. * @return a Material enum name. + * @since 2.0.0 */ - private static String format(String name) { - return name.toUpperCase().replace("MINECRAFT:", "").replace('-', '_').replaceAll("\\s+", "_").replaceAll("\\W", ""); + @Nonnull + private static String format(@Nonnull String name) { + return FORMAT_PATTERN.matcher( + name.trim().replace('-', '_').replace(' ', '_')).replaceAll("").toUpperCase(Locale.ENGLISH); } /** @@ -1203,79 +1554,80 @@ public enum Materials { * * @param name the material name to parse. * @return the material name with the version removed. + * @since 2.0.0 */ - private static String parseLegacyVersionMaterialName(String name) { - if (!name.contains("/")) { - return name; - } - return name.substring(0, name.indexOf('/')); + @Nonnull + private static String parseLegacyMaterialName(String name) { + int index = name.indexOf('/'); + return index == -1 ? name : name.substring(0, index); } /** - * Checks if the version argument is the same or higher than the current server version. + * Checks if the specified version is the same version or higher than the current server version. * * @param version the version to be checked. * @return true of the version is equal or higher than the current version. + * @since 2.0.0 */ - public static boolean isVersionOrHigher(MinecraftVersion version) { - MinecraftVersion current = getVersion(); - - if (version == current) { - return true; - } - if (version == MinecraftVersion.UNKNOWN) { - return false; - } - if (current == MinecraftVersion.UNKNOWN) { - return true; - } - - int ver = Integer.parseInt(version.name().replace("VERSION_", "").replace("_", "")); - int currentVer = Integer.parseInt(current.name().replace("VERSION_", "").replace("_", "")); - - return currentVer >= ver; + public static boolean isVersionOrHigher(@Nonnull MinecraftVersion version) { + Objects.requireNonNull(version, "Cannot compare to a null version"); + return VERSION.ordinal() >= version.ordinal(); } /** - * Converts the material's name to a string with the first letter uppercase. + * Converts the enum names to a more friendly and readable string. * - * @return a converted string. + * @return a formatted string. + * @see #toWord(String) + * @since 2.1.0 */ - public static String toWord(Material material) { - return material.name().charAt(0) + material.name().substring(1).toLowerCase(); + @Nonnull + public static String toWord(@Nonnull Material material) { + Objects.requireNonNull(material, "Cannot translate a null material to a word"); + return toWord(material.name()); } /** - * Compares two major versions. The current server version and the given version. + * Parses an enum name to a normal word. + * Normal names have underlines removed and each word capitalized. + *

+ * Examples: + *

+     *     EMERALD                 -> Emerald
+     *     EMERALD_BLOCK           -> Emerald Block
+     *     ENCHANTED_GOLDEN_APPLE  -> Enchanted Golden Apple
+     * 
* - * @param version the version to check. - * @return true if is the same as the current version or higher. + * @param name the name of the enum. + * @return a cleaned more readable enum name. + * @since 2.1.0 */ - public static boolean isVersionOrHigher(String version) { - int currentVer = Integer.parseInt(getExactMajorVersion(Bukkit.getVersion()).replace(".", "")); - int versionNumber = Integer.parseInt(version.replace(".", "")); - - return currentVer >= versionNumber; + @Nonnull + private static String toWord(@Nonnull String name) { + return WordUtils.capitalize(name.replace('_', ' ').toLowerCase(Locale.ENGLISH)); } /** * 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. + * @return the exact major version, or {@link MinecraftVersion#UNKNOWN} if unknown or unsupported. + * @since 2.0.0 */ - public static String getExactMajorVersion(String version) { + @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("SNAPSHOT") || version.contains("-R")) { - version = version.substring(0, version.indexOf("-")); - } + if (version.contains("-R") || version.endsWith("SNAPSHOT")) version = version.substring(0, version.indexOf('-')); + // getVersion() - if (version.contains("git")) { - version = version.substring(version.indexOf("MC:") + 4).replace(")", ""); - } - if (version.split(Pattern.quote(".")).length > 2) { - version = version.substring(0, version.lastIndexOf(".")); - } + int index = version.indexOf("MC:"); + if (index != -1) version = version.substring(index + 4, version.length() - 1); + + // 1.13.2, 1.14.4, etc... + int lastDot = version.lastIndexOf('.'); + if (version.indexOf('.') != lastDot) version = version.substring(0, lastDot); return version; } @@ -1285,296 +1637,487 @@ public enum Materials { * * @param version the server version. * @return the Minecraft version represented by the string. + * @since 2.0.0 */ - private static MinecraftVersion valueOfVersion(String version) { - version = getExactMajorVersion(version); - if (version.equals("1.10") || version.equals("1.11") || version.equals("1.12")) { - return MinecraftVersion.VERSION_1_9; - } - version = version.replace(".", "_"); - if (!version.startsWith("VERSION_")) { - version = "VERSION_" + version; - } - String check = version; - return Arrays.stream(MinecraftVersion.VALUES).anyMatch(v -> v.name().equals(check)) ? MinecraftVersion.valueOf(version) : MinecraftVersion.UNKNOWN; + @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); } /** - * Checks if the material can be damaged from {@link #DAMAGEABLE}. + * Checks if the material can be damaged by using it. + * Names going through this method are not formatted. * * @param name the name of the material. * @return true of the material can be damaged. + * @see #isDamageable() + * @since 1.0.0 */ - public static boolean isDamageable(String name) { - return Arrays.stream(DAMAGEABLE).anyMatch(name::contains); + public static boolean isDamageable(@Nonnull String name) { + Objects.requireNonNull(name, "Material name cannot be null"); + for (String damageable : DAMAGEABLE) + if (name.contains(damageable)) return true; + return false; } - public static boolean isDuplicated(String name) { - String formatted = format(name); - return DUPLICATED.entrySet().stream().anyMatch(x -> x.getKey().name().equals(formatted)); + /** + * Checks if the list of given material names matches the given base material. + * Mostly used for configs. + *

+ * Supports {@link String#contains} {@code CONTAINS:NAME} and Regular Expression {@code REGEX:PATTERN} formats. + *

+ * Example: + *

+     *     Materials material = {@link #matchMaterials(ItemStack)};
+     *     if (material.isOneOf(plugin.getConfig().getStringList("disabled-items")) return;
+     * 
+ *
+ * {@code CONTAINS} Examples: + *
+     *     "CONTAINS:CHEST" -> CHEST, ENDERCHEST, TRAPPED_CHEST -> true
+     *     "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
+     * 
+ *

+ * The reason that there are tags for {@code CONTAINS} and {@code REGEX} + * is for the performance. + * Please avoid using the {@code REGEX} tag if you can use the {@code CONTAINS} tag. + * It'll have a huge impact on performance. + * Please avoid using {@code (capturing groups)} there's no use for them in this case. + * If you want to use groups, use {@code (?: non-capturing groups)}. It's faster. + *

+ * You can make a cache for pre-compiled RegEx patterns from your config. + * It's better, but not much faster since these patterns are not that complex. + *

+ * Want to learn RegEx? You can mess around in RegExr website. + * + * @param material the base material to match other materials with. + * @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.1.1 + */ + public static boolean isOneOf(@Nonnull Material material, @Nullable List materials) { + if (materials == null || materials.isEmpty()) return false; + Objects.requireNonNull(material, "Cannot match materials with a null material"); + String name = material.name(); + + for (String comp : materials) { + comp = comp.toUpperCase(); + if (comp.startsWith("CONTAINS:")) { + comp = format(comp.substring(9)); + if (name.contains(comp)) return true; + continue; + } + if (comp.startsWith("REGEX:")) { + comp = comp.substring(6); + if (name.matches(comp)) return true; + continue; + } + + // Direct Object Equals + Optional mat = matchMaterials(comp); + if (mat.isPresent() && mat.get().parseMaterial() == material) 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. + * + * @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. + * @see #isOneOf(Material, List) + * @since 3.0.0 + */ + public boolean isOneOf(@Nullable List materials) { + Material material = this.parseMaterial(); + if (material == null) return false; + return isOneOf(material, materials); + } + + /** + * 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 + */ + private boolean anyMatchLegacy(@Nonnull String 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; + + for (String legacy : this.legacy) + if (parseLegacyMaterialName(legacy).equals(name)) return true; + return false; + } + + /** + * User-friendly readable name for this material + * In most cases you should be using {@link #name()} instead. + * + * @return string of this object. + * @see #toWord(String) + * @since 3.0.0 + */ + @Override + public String toString() { + return toWord(this.name()); } /** * Gets the ID (Magic value) of the material. - * If an {@link IllegalArgumentException} was thrown from this method, - * you should definitely report it. * - * @return the ID of the material. -1 if it's a new block. + * @return the ID of the material or -1 if it's a new block or the material is not supported. + * @see #matchMaterials(int, byte) + * @since 2.2.0 */ @SuppressWarnings("deprecation") public int getId() { - return this.isNew() ? -1 : this.parseMaterial().getId(); + if (this.isNew()) return -1; + Material material = this.parseMaterial(); + return material == null ? -1 : material.getId(); } + /** + * Checks if the material has any duplicates. + * + * @return true if there is a duplicated name for this material, otherwise false. + * @see #getMaterialsIfDuplicated() + * @see #isDuplicated(String) + * @since 2.0.0 + */ public boolean isDuplicated() { return DUPLICATED.containsKey(this); } /** - * Checks if the given string matches any of this material's legacy material names. + * Checks if the item is duplicated for a different purpose in new versions. * - * @param name the name to check - * @return true if it's one of the legacy names. + * @return true if the item's name is duplicated, otherwise false. + * @see #isDuplicated() + * @see #getNewMaterialsIfDuplicated(String) + * @since 2.0.0 */ - public boolean matchAnyLegacy(String name) { - String formatted = format(name); - return Arrays.asList(this.legacy).contains(formatted); + @Nullable + public Materials getMaterialsIfDuplicated() { + return DUPLICATED.get(this); } /** - * @return true if the item can be damaged. + * Checks if the material can be damaged by using it. + * Names going through this method are not formatted. + * + * @return true if the item can be damaged (have its durability changed), otherwise false. * @see #isDamageable(String) + * @since 1.0.0 */ public boolean isDamageable() { return isDamageable(this.name()); } /** - * Get the {@link ItemStack} data of this material in older versions. - * Which can be accessed with {@link ItemStack#getData()} then MaterialData#getData() + * The data value of this material pre-flattening. + *

+ * Can be accessed with {@link ItemStack#getData()} then {@code MaterialData#getData()} * or {@link ItemStack#getDurability()} if not damageable. * - * @return data of this material. + * @return data of this material, or 0 if none. + * @since 1.0.0 */ - public int getData() { - return this.data; + @SuppressWarnings("deprecation") + public byte getData() { + return data; } /** - * Parses the Materials as an {@link ItemStack}. + * 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}. * - * @return an ItemStack with the same material (and data if in older versions.) + * @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 */ + @Nonnull + public String[] getLegacy() { + return legacy; + } + + /** + * Parses an item from this Materials. + * Uses data values on older versions. + * + * @return an ItemStack with the same material (and data value if in older versions.) + * @see #parseItem(boolean) + * @see #setType(ItemStack) + * @since 1.0.0 + */ + @Nullable public ItemStack parseItem() { return parseItem(false); } /** - * Parses the Materials as an {@link ItemStack}. + * Parses an item from this Materials. + * Uses data values on older versions. * - * @param suggest if true {@link #parseMaterial(boolean)} - * @return an ItemStack with the same material (and data if in older versions.) + * @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 */ + @Nullable @SuppressWarnings("deprecation") public ItemStack parseItem(boolean suggest) { Material material = this.parseMaterial(suggest); - return isNewVersion() ? new ItemStack(material) : new ItemStack(material, 1, this.data); + if (material == null) return null; + return ISFLAT ? new ItemStack(material) : new ItemStack(material, 1, this.data); } /** - * Parses the Materials as a {@link Material}. + * Parses the material of this Materials. * - * @return the Material related to this Materials based on the server version. + * @return the material related to this Materials based on the server version. + * @see #parseMaterial(boolean) + * @since 1.0.0 */ + @Nullable public Material parseMaterial() { return parseMaterial(false); } /** - * Parses the Materials as a {@link Material}. + * Parses the material of this Materials and accepts suggestions. * - * @param suggest Use a suggested material if the material is added in the new version. - * @return the Material related to this Materials based on the server version. + * @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 Materials based on the server version. * @see #matchMaterials(String, byte) + * @since 2.0.0 */ + @Nullable public Material parseMaterial(boolean suggest) { - Material newMat = Material.getMaterial(this.name()); + Material mat = PARSED_CACHE.getIfPresent(this); + if (mat != null) return mat; - // If the name is not null it's probably the new version. - // So you can still use this name even if it's a duplicated name. - // Since duplicated names only apply to older versions. - if (newMat != null && (isNewVersion() || !this.isDuplicated())) { - return newMat; + if (!ISFLAT && this.isDuplicated()) mat = requestOldMaterial(suggest); + else { + mat = Material.getMaterial(this.name()); + if (mat == null) mat = requestOldMaterial(suggest); } - return requestOldMaterial(suggest); + + if (mat != null) PARSED_CACHE.put(this, mat); + return mat; } /** - * Parses from old material names and can accept suggestions. + * Parses a material for older versions of Minecraft. + * Accepts suggestions if specified. * - * @param suggest Accept suggestions for newly added blocks - * @return A parsed Material suitable for this minecraft version. + * @param suggest if true suggested materials will be considered for old versions. + * @return a parsed material suitable for the current Minecraft version. + * @see #parseMaterial(boolean) + * @since 2.0.0 */ + @Nullable private Material requestOldMaterial(boolean suggest) { - Material oldMat; - boolean isNew = getVersionIfNew() != MinecraftVersion.UNKNOWN; - for (int i = legacy.length - 1; i >= 0; i--) { - String legacyName = legacy[i]; - // Slash means it's just another name for the material in another version. - if (legacyName.contains("/")) { - oldMat = Material.getMaterial(parseLegacyVersionMaterialName(legacyName)); + boolean noMaterialParse = this.isNew() && !suggest; + Material material; - if (oldMat != null) { - return oldMat; - } else { - continue; - } - } - if (isNew) { - if (suggest) { - oldMat = Material.getMaterial(legacyName); - if (oldMat != null) { - return oldMat; - } - } else { - return null; - } - // According to the suggestion format list, all the other names continuing - // from here are considered as a "suggestion" if there's no slash anymore. - } - oldMat = Material.getMaterial(legacyName); - if (oldMat != null) { - return oldMat; + 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); + + if (material != null) return material; + else continue; } + + // 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); + if (material != null) return material; } return null; } /** - * Checks if an item is similar to the material and its data (if in older versions.) + * Checks if an item has the same material (and data value on older versions). * * @param item item to check. - * @return true if the material is the same as the item's material (and data if in older versions.) + * @return true if the material is the same as the item's material (and data value if on older versions), otherwise false. + * @since 1.0.0 */ @SuppressWarnings("deprecation") - public boolean isSimilar(ItemStack item) { - Objects.requireNonNull(item, "ItemStack cannot be null"); - Objects.requireNonNull(item.getType(), "ItemStack's material cannot be null"); - return (isNewVersion() || this.isDamageable()) ? item.getType() == this.parseMaterial() : item.getType() == this.parseMaterial() && item.getDurability() == this.data; + 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; } /** - * Get the suggested material names that can be used instead of this material. + * Gets the suggested material names that can be used + * if the material is not supported in the current version. * * @return a list of suggested material names. + * @see #parseMaterial(boolean) + * @since 2.0.0 */ - public String[] getSuggestions() { - if (!this.legacy[0].contains(".")) { - return new String[0]; - } - return Arrays.stream(this.legacy).filter(mat -> !mat.contains(".")).toArray(String[]::new); + @Nonnull + public List getSuggestions() { + return this.isNew() ? Arrays.stream(this.legacy).skip(1).collect(Collectors.toList()) : new ArrayList<>(); } /** * Checks if this material is supported in the current version. - * It'll check both the newest matetrial name and for legacy names. + * Suggested materials will be ignored. + *

+ * Note that you should use {@link #parseMaterial()} and check if it's null + * 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() { - return Arrays.stream(Material.values()).anyMatch(mat -> mat.name().equals(this.name()) || this.matchAnyLegacy(mat.name())); + MinecraftVersion version = this.getMaterialVersion(); + if (version != MinecraftVersion.UNKNOWN) return isVersionOrHigher(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; } /** - * Gets the added version if the material is newly added after the 1.13 Aquatic Update and higher. + * Checks if the material is newly added after the 1.13 Aquatic Update ({@link MinecraftVersion#V1_13}). * - * @return the version which the material was added in. {@link MinecraftVersion#UNKNOWN} if not new. - * @see #isNew() - */ - public MinecraftVersion getVersionIfNew() { - return this.isNew() ? valueOfVersion(this.legacy[0]) : MinecraftVersion.UNKNOWN; - } - - /** - * Checks if the material is newly added after the 1.13 Aquatic Update. - * - * @return true if it was newly added. + * @return true if the material was newly added, otherwise false. + * @see #getMaterialVersion() + * @since 2.0.0 */ public boolean isNew() { - return this.legacy[0].contains("."); + return this.legacy.length != 0 && this.legacy[0].charAt(1) == '.'; } /** - * Gets the suggested material instead of returning null for unsupported versions. - * This is somehow similar to what ProtcolSupport and ViaVersion are doing to new materials. - * Don't use this if you want to parse to a {@link Material} + * Only major Minecraft versions related to most changes. + * The enum's order should not be changed. * - * @return The suggested material that is similar. - * @see #parseMaterial() - */ - public Materials suggestOldMaterialIfNew() { - if (getVersionIfNew() == MinecraftVersion.UNKNOWN || this.legacy.length == 1) { - return null; - } - - // We need a loop because: Newest -> Oldest - for (int i = this.legacy.length - 1; i >= 0; i--) { - String legacyName = this.legacy[i]; - - if (legacyName.contains("/")) { - continue; - } - Materials mat = matchMaterials(parseLegacyVersionMaterialName(legacyName), this.data); - if (mat != null && this != mat) { - return mat; - } - } - return null; - } - - public static Materials fromString(Object in) { - return fromString(String.valueOf(in)); - } - - public static Materials fromString(String in) { - String[] v = in.split(":"); - return matchMaterials(v[0], (byte) (v.length > 1 ? NumberConversions.toInt(v[1]) : -1)); - } - - public static Materials fromItem(ItemStack item) { - if (isNewVersion()) { - return matchMaterials(item.getType()); - } else { - return matchMaterials(item.getType().name(), (byte) item.getDurability()); - } - } - - /** - * Only major versions related to material changes. + * @since 2.0.0 */ public enum MinecraftVersion { /** - * Bountiful Update + * 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 */ - VERSION_1_8, + UNKNOWN, + /** - * Combat Update (Pitiful Update?) + * Bountiful Update + * https://minecraft.gamepedia.com/Java_Edition_1.18 + * + * @since 2.0.0 */ - VERSION_1_9, + 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 */ - VERSION_1_13, + V1_13, + /** * Village Pillage Update + * https://minecraft.gamepedia.com/Java_Edition_1.14 + * + * @since 2.0.0 */ - VERSION_1_14, - /** - * 1.7 or below. - * Using {@link #getVersionIfNew()} it means 1.12 or below. - */ - UNKNOWN; + V1_14, - public static final MinecraftVersion[] VALUES = MinecraftVersion.values(); + /** + * Buzzy Bees Update + * https://minecraft.gamepedia.com/Java_Edition_1.15 + * + * @since 3.0.0 + */ + V1_15 } -} \ No newline at end of file +} diff --git a/src/main/scala/io/izzel/taboolib/util/lite/Sounds.java b/src/main/scala/io/izzel/taboolib/util/lite/Sounds.java new file mode 100644 index 0000000..081108b --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/util/lite/Sounds.java @@ -0,0 +1,1268 @@ +package io.izzel.taboolib.util.lite;/* + * The MIT License (MIT) + * + * Copyright (c) 2019 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE + * 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. + */ +import com.google.common.base.Enums; +import com.google.common.base.Strings; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang.Validate; +import org.apache.commons.lang.WordUtils; +import org.bukkit.Instrument; +import org.bukkit.Location; +import org.bukkit.Note; +import org.bukkit.Sound; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +/* References + * + * * * GitHub: https://github.com/CryptoMorin/XSeries/blob/master/Sounds.java + * * XSeries: https://www.spigotmc.org/threads/378136/ + * 1.8: http://docs.codelanx.com/Bukkit/1.8/org/bukkit/Sound.html + * Latest: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/Sound.html + * Basics: https://bukkit.org/threads/151517/ + * playSound command: https://minecraft.gamepedia.com/Commands/playsound + */ + +/** + * Sounds - Universal Minecraft Sound Support
+ * Supports 1.8-1.15
+ * 1.13 and above as priority. + *

+ * Sounds are thread-safe. But this doesn't mean you should + * use a bukkit async scheduler for every {@link Player#playSound} call. + *

+ * Volume: 0.0-∞ - 1.0f (normal) - Using higher values increase the distance from which the sound can be heard.
+ * Pitch: 0.5-2.0 - 1.0f (normal) - How fast the sound is play. + * + * @author Crypto Morin + * @version 2.2.1 + * @see Sound + */ +public enum Sounds { + AMBIENT_CAVE("AMBIENCE_CAVE"), + AMBIENT_UNDERWATER_ENTER, + AMBIENT_UNDERWATER_EXIT, + AMBIENT_UNDERWATER_LOOP("AMBIENT_UNDERWATER_EXIT"), + AMBIENT_UNDERWATER_LOOP_ADDITIONS("AMBIENT_UNDERWATER_EXIT"), + AMBIENT_UNDERWATER_LOOP_ADDITIONS_RARE("AMBIENT_UNDERWATER_EXIT"), + AMBIENT_UNDERWATER_LOOP_ADDITIONS_ULTRA_RARE("AMBIENT_UNDERWATER_EXIT"), + BLOCK_ANVIL_BREAK("ANVIL_BREAK"), + BLOCK_ANVIL_DESTROY, + BLOCK_ANVIL_FALL, + BLOCK_ANVIL_HIT("BLOCK_ANVIL_FALL"), + BLOCK_ANVIL_LAND("ANVIL_LAND"), + BLOCK_ANVIL_PLACE("BLOCK_ANVIL_FALL"), + BLOCK_ANVIL_STEP("BLOCK_ANVIL_FALL"), + BLOCK_ANVIL_USE("ANVIL_USE"), + BLOCK_BAMBOO_BREAK, + BLOCK_BAMBOO_FALL, + BLOCK_BAMBOO_HIT, + BLOCK_BAMBOO_PLACE, + BLOCK_BAMBOO_SAPLING_BREAK, + BLOCK_BAMBOO_SAPLING_HIT, + BLOCK_BAMBOO_SAPLING_PLACE, + BLOCK_BAMBOO_STEP, + BLOCK_BARREL_CLOSE, + BLOCK_BARREL_OPEN, + BLOCK_BEACON_ACTIVATE, + BLOCK_BEACON_AMBIENT, + BLOCK_BEACON_DEACTIVATE("BLOCK_BEACON_AMBIENT"), + BLOCK_BEACON_POWER_SELECT("BLOCK_BEACON_AMBIENT"), + BLOCK_BEEHIVE_DRIP, + BLOCK_BEEHIVE_ENTER, + BLOCK_BEEHIVE_EXIT, + BLOCK_BEEHIVE_SHEAR, + BLOCK_BEEHIVE_WORK, + BLOCK_BELL_RESONATE, + BLOCK_BELL_USE, + BLOCK_BLASTFURNACE_FIRE_CRACKLE, + BLOCK_BREWING_STAND_BREW, + BLOCK_BUBBLE_COLUMN_BUBBLE_POP, + BLOCK_BUBBLE_COLUMN_UPWARDS_AMBIENT, + BLOCK_BUBBLE_COLUMN_UPWARDS_INSIDE, + BLOCK_BUBBLE_COLUMN_WHIRLPOOL_AMBIENT, + BLOCK_BUBBLE_COLUMN_WHIRLPOOL_INSIDE, + BLOCK_CAMPFIRE_CRACKLE, + BLOCK_CHEST_CLOSE("CHEST_CLOSE", "ENTITY_CHEST_CLOSE"), + BLOCK_CHEST_LOCKED, + BLOCK_CHEST_OPEN("CHEST_OPEN", "ENTITY_CHEST_OPEN"), + BLOCK_CHORUS_FLOWER_DEATH, + BLOCK_CHORUS_FLOWER_GROW, + BLOCK_COMPARATOR_CLICK, + BLOCK_COMPOSTER_EMPTY, + BLOCK_COMPOSTER_FILL, + BLOCK_COMPOSTER_FILL_SUCCESS, + BLOCK_COMPOSTER_READY, + BLOCK_CONDUIT_ACTIVATE, + BLOCK_CONDUIT_AMBIENT, + BLOCK_CONDUIT_AMBIENT_SHORT, + BLOCK_CONDUIT_ATTACK_TARGET, + BLOCK_CONDUIT_DEACTIVATE, + BLOCK_CORAL_BLOCK_BREAK, + BLOCK_CORAL_BLOCK_FALL, + BLOCK_CORAL_BLOCK_HIT, + BLOCK_CORAL_BLOCK_PLACE, + BLOCK_CORAL_BLOCK_STEP, + BLOCK_CROP_BREAK, + BLOCK_DISPENSER_DISPENSE, + BLOCK_DISPENSER_FAIL, + BLOCK_DISPENSER_LAUNCH, + BLOCK_ENCHANTMENT_TABLE_USE, + BLOCK_ENDER_CHEST_CLOSE, + BLOCK_ENDER_CHEST_OPEN, + BLOCK_END_GATEWAY_SPAWN, + BLOCK_END_PORTAL_FRAME_FILL, + BLOCK_END_PORTAL_SPAWN, + BLOCK_FENCE_GATE_CLOSE, + BLOCK_FENCE_GATE_OPEN, + BLOCK_FIRE_AMBIENT("FIRE"), + BLOCK_FIRE_EXTINGUISH("FIZZ"), + BLOCK_FURNACE_FIRE_CRACKLE, + BLOCK_GLASS_BREAK("GLASS"), + BLOCK_GLASS_FALL, + BLOCK_GLASS_HIT, + BLOCK_GLASS_PLACE, + BLOCK_GLASS_STEP, + BLOCK_GRASS_BREAK("DIG_GRASS"), + BLOCK_GRASS_FALL, + BLOCK_GRASS_HIT, + BLOCK_GRASS_PLACE, + BLOCK_GRASS_STEP("STEP_GRASS"), + BLOCK_GRAVEL_BREAK("DIG_GRAVEL"), + BLOCK_GRAVEL_FALL, + BLOCK_GRAVEL_HIT, + BLOCK_GRAVEL_PLACE, + BLOCK_GRAVEL_STEP("STEP_GRAVEL"), + BLOCK_GRINDSTONE_USE, + BLOCK_HONEY_BLOCK_BREAK, + BLOCK_HONEY_BLOCK_FALL, + BLOCK_HONEY_BLOCK_HIT, + BLOCK_HONEY_BLOCK_PLACE, + BLOCK_HONEY_BLOCK_SLIDE, + BLOCK_HONEY_BLOCK_STEP, + BLOCK_IRON_DOOR_CLOSE, + BLOCK_IRON_DOOR_OPEN, + BLOCK_IRON_TRAPDOOR_CLOSE, + BLOCK_IRON_TRAPDOOR_OPEN, + BLOCK_LADDER_BREAK, + BLOCK_LADDER_FALL, + BLOCK_LADDER_HIT, + BLOCK_LADDER_PLACE, + BLOCK_LADDER_STEP("STEP_LADDER"), + BLOCK_LANTERN_BREAK, + BLOCK_LANTERN_FALL, + BLOCK_LANTERN_HIT, + BLOCK_LANTERN_PLACE, + BLOCK_LANTERN_STEP, + BLOCK_LAVA_AMBIENT("LAVA"), + BLOCK_LAVA_EXTINGUISH, + BLOCK_LAVA_POP("LAVA_POP"), + BLOCK_LEVER_CLICK, + BLOCK_LILY_PAD_PLACE("BLOCK_WATERLILY_PLACE"), + BLOCK_METAL_BREAK, + BLOCK_METAL_FALL, + BLOCK_METAL_HIT, + BLOCK_METAL_PLACE, + BLOCK_METAL_PRESSURE_PLATE_CLICK_OFF("BLOCK_METAL_PRESSUREPLATE_CLICK_OFF"), + BLOCK_METAL_PRESSURE_PLATE_CLICK_ON("BLOCK_METAL_PRESSUREPLATE_CLICK_ON"), + BLOCK_METAL_STEP, + BLOCK_NETHER_WART_BREAK, + BLOCK_NOTE_BLOCK_BANJO, + BLOCK_NOTE_BLOCK_BASEDRUM("NOTE_BASS_DRUM", "BLOCK_NOTE_BASEDRUM"), + BLOCK_NOTE_BLOCK_BASS("NOTE_BASS", "BLOCK_NOTE_BASS"), + BLOCK_NOTE_BLOCK_BELL("BLOCK_NOTE_BELL"), + BLOCK_NOTE_BLOCK_BIT, + BLOCK_NOTE_BLOCK_CHIME("BLOCK_NOTE_CHIME"), + BLOCK_NOTE_BLOCK_COW_BELL, + BLOCK_NOTE_BLOCK_DIDGERIDOO, + BLOCK_NOTE_BLOCK_FLUTE("BLOCK_NOTE_FLUTE"), + BLOCK_NOTE_BLOCK_GUITAR("NOTE_BASS_GUITAR", "BLOCK_NOTE_GUITAR"), + BLOCK_NOTE_BLOCK_HARP("NOTE_PIANO", "BLOCK_NOTE_HARP"), + BLOCK_NOTE_BLOCK_HAT("NOTE_STICKS", "BLOCK_NOTE_HAT"), + BLOCK_NOTE_BLOCK_IRON_XYLOPHONE, + BLOCK_NOTE_BLOCK_PLING("NOTE_PLING", "BLOCK_NOTE_PLING"), + BLOCK_NOTE_BLOCK_SNARE("NOTE_SNARE_DRUM", "BLOCK_NOTE_SNARE"), + BLOCK_NOTE_BLOCK_XYLOPHONE("BLOCK_NOTE_XYLOPHONE"), + BLOCK_PISTON_CONTRACT("PISTON_RETRACT"), + BLOCK_PISTON_EXTEND("PISTON_EXTEND"), + BLOCK_PORTAL_AMBIENT("PORTAL"), + BLOCK_PORTAL_TRAVEL("PORTAL_TRAVEL"), + BLOCK_PORTAL_TRIGGER("PORTAL_TRIGGER"), + BLOCK_PUMPKIN_CARVE, + BLOCK_REDSTONE_TORCH_BURNOUT, + BLOCK_SAND_BREAK("DIG_SAND"), + BLOCK_SAND_FALL, + BLOCK_SAND_HIT, + BLOCK_SAND_PLACE, + BLOCK_SAND_STEP("STEP_SAND"), + BLOCK_SCAFFOLDING_BREAK, + BLOCK_SCAFFOLDING_FALL, + BLOCK_SCAFFOLDING_HIT, + BLOCK_SCAFFOLDING_PLACE, + BLOCK_SCAFFOLDING_STEP, + BLOCK_SHULKER_BOX_CLOSE, + BLOCK_SHULKER_BOX_OPEN, + BLOCK_SLIME_BLOCK_BREAK("BLOCK_SLIME_BREAK"), + BLOCK_SLIME_BLOCK_FALL("BLOCK_SLIME_FALL"), + BLOCK_SLIME_BLOCK_HIT("BLOCK_SLIME_HIT"), + BLOCK_SLIME_BLOCK_PLACE("BLOCK_SLIME_PLACE"), + BLOCK_SLIME_BLOCK_STEP("BLOCK_SLIME_STEP"), + BLOCK_SMOKER_SMOKE, + BLOCK_SNOW_BREAK("DIG_SNOW"), + BLOCK_SNOW_FALL, + BLOCK_SNOW_HIT, + BLOCK_SNOW_PLACE, + BLOCK_SNOW_STEP("STEP_SNOW"), + BLOCK_STONE_BREAK("DIG_STONE"), + BLOCK_STONE_BUTTON_CLICK_OFF, + BLOCK_STONE_BUTTON_CLICK_ON, + BLOCK_STONE_FALL, + BLOCK_STONE_HIT, + BLOCK_STONE_PLACE, + BLOCK_STONE_PRESSURE_PLATE_CLICK_OFF("BLOCK_STONE_PRESSUREPLATE_CLICK_OFF"), + BLOCK_STONE_PRESSURE_PLATE_CLICK_ON("BLOCK_STONE_PRESSUREPLATE_CLICK_ON"), + BLOCK_STONE_STEP("STEP_STONE"), + BLOCK_SWEET_BERRY_BUSH_BREAK, + BLOCK_SWEET_BERRY_BUSH_PLACE, + BLOCK_TRIPWIRE_ATTACH, + BLOCK_TRIPWIRE_CLICK_OFF, + BLOCK_TRIPWIRE_CLICK_ON, + BLOCK_TRIPWIRE_DETACH, + BLOCK_WATER_AMBIENT("WATER"), + BLOCK_WET_GRASS_BREAK, + BLOCK_WET_GRASS_FALL, + BLOCK_WET_GRASS_HIT, + BLOCK_WET_GRASS_PLACE("BLOCK_WET_GRASS_HIT"), + BLOCK_WET_GRASS_STEP("BLOCK_WET_GRASS_HIT"), + BLOCK_WOODEN_BUTTON_CLICK_OFF("WOOD_CLICK", "BLOCK_WOOD_BUTTON_CLICK_OFF"), + BLOCK_WOODEN_BUTTON_CLICK_ON("WOOD_CLICK", "BLOCK_WOOD_BUTTON_CLICK_ON"), + BLOCK_WOODEN_DOOR_CLOSE("DOOR_CLOSE"), + BLOCK_WOODEN_DOOR_OPEN("DOOR_OPEN"), + BLOCK_WOODEN_PRESSURE_PLATE_CLICK_OFF("BLOCK_WOOD_PRESSUREPLATE_CLICK_OFF"), + BLOCK_WOODEN_PRESSURE_PLATE_CLICK_ON("BLOCK_WOOD_PRESSUREPLATE_CLICK_ON"), + BLOCK_WOODEN_TRAPDOOR_CLOSE, + BLOCK_WOODEN_TRAPDOOR_OPEN, + BLOCK_WOOD_BREAK("DIG_WOOD"), + BLOCK_WOOD_FALL, + BLOCK_WOOD_HIT, + BLOCK_WOOD_PLACE, + BLOCK_WOOD_STEP("STEP_WOOD"), + BLOCK_WOOL_BREAK("DIG_WOOL", "BLOCK_CLOTH_BREAK"), + BLOCK_WOOL_FALL, + BLOCK_WOOL_HIT("BLOCK_WOOL_FALL"), + BLOCK_WOOL_PLACE("BLOCK_WOOL_FALL"), + BLOCK_WOOL_STEP("STEP_WOOL", "BLOCK_CLOTH_STEP"), + ENCHANT_THORNS_HIT, + ENTITY_ARMOR_STAND_BREAK("ENTITY_ARMORSTAND_BREAK"), + ENTITY_ARMOR_STAND_FALL("ENTITY_ARMORSTAND_FALL"), + ENTITY_ARMOR_STAND_HIT("ENTITY_ARMORSTAND_HIT"), + ENTITY_ARMOR_STAND_PLACE("ENTITY_ARMORSTAND_PLACE"), + ENTITY_ARROW_HIT("ARROW_HIT"), + ENTITY_ARROW_HIT_PLAYER, + ENTITY_ARROW_SHOOT("SHOOT_ARROW"), + ENTITY_BAT_AMBIENT("BAT_IDLE"), + ENTITY_BAT_DEATH("BAT_DEATH"), + ENTITY_BAT_HURT("BAT_HURT"), + ENTITY_BAT_LOOP("BAT_LOOP"), + ENTITY_BAT_TAKEOFF("BAT_TAKEOFF"), + ENTITY_BEE_DEATH, + ENTITY_BEE_HURT, + ENTITY_BEE_LOOP, + ENTITY_BEE_LOOP_AGGRESSIVE, + ENTITY_BEE_POLLINATE, + ENTITY_BEE_STING, + ENTITY_BLAZE_AMBIENT("BLAZE_BREATH"), + ENTITY_BLAZE_BURN, + ENTITY_BLAZE_DEATH("BLAZE_DEATH"), + ENTITY_BLAZE_HURT("BLAZE_HIT"), + ENTITY_BLAZE_SHOOT, + ENTITY_BOAT_PADDLE_LAND, + ENTITY_BOAT_PADDLE_WATER, + ENTITY_CAT_AMBIENT("CAT_MEOW"), + ENTITY_CAT_BEG_FOR_FOOD, + ENTITY_CAT_DEATH, + ENTITY_CAT_EAT, + ENTITY_CAT_HISS("CAT_HISS"), + ENTITY_CAT_HURT("CAT_HIT"), + ENTITY_CAT_PURR("CAT_PURR"), + ENTITY_CAT_PURREOW("CAT_PURREOW"), + ENTITY_CAT_STRAY_AMBIENT, + ENTITY_CHICKEN_AMBIENT("CHICKEN_IDLE"), + ENTITY_CHICKEN_DEATH, + ENTITY_CHICKEN_EGG("CHICKEN_EGG_POP"), + ENTITY_CHICKEN_HURT("CHICKEN_HURT"), + ENTITY_CHICKEN_STEP("CHICKEN_WALK"), + ENTITY_COD_AMBIENT, + ENTITY_COD_DEATH, + ENTITY_COD_FLOP, + ENTITY_COD_HURT, + ENTITY_COW_AMBIENT("COW_IDLE"), + ENTITY_COW_DEATH, + ENTITY_COW_HURT("COW_HURT"), + ENTITY_COW_MILK, + ENTITY_COW_STEP("COW_WALK"), + ENTITY_CREEPER_DEATH("CREEPER_DEATH"), + ENTITY_CREEPER_HURT, + ENTITY_CREEPER_PRIMED("CREEPER_HISS"), + ENTITY_DOLPHIN_AMBIENT, + ENTITY_DOLPHIN_AMBIENT_WATER, + ENTITY_DOLPHIN_ATTACK, + ENTITY_DOLPHIN_DEATH, + ENTITY_DOLPHIN_EAT, + ENTITY_DOLPHIN_HURT, + ENTITY_DOLPHIN_JUMP, + ENTITY_DOLPHIN_PLAY, + ENTITY_DOLPHIN_SPLASH, + ENTITY_DOLPHIN_SWIM, + ENTITY_DONKEY_AMBIENT("DONKEY_IDLE"), + ENTITY_DONKEY_ANGRY("DONKEY_ANGRY"), + ENTITY_DONKEY_CHEST, + ENTITY_DONKEY_DEATH("DONKEY_DEATH"), + ENTITY_DONKEY_HURT("DONKEY_HIT"), + ENTITY_DRAGON_FIREBALL_EXPLODE("ENTITY_ENDERDRAGON_FIREBALL_EXPLODE"), + ENTITY_DROWNED_AMBIENT, + ENTITY_DROWNED_AMBIENT_WATER, + ENTITY_DROWNED_DEATH, + ENTITY_DROWNED_DEATH_WATER, + ENTITY_DROWNED_HURT, + ENTITY_DROWNED_HURT_WATER, + ENTITY_DROWNED_SHOOT, + ENTITY_DROWNED_STEP, + ENTITY_DROWNED_SWIM, + ENTITY_EGG_THROW, + ENTITY_ELDER_GUARDIAN_AMBIENT, + ENTITY_ELDER_GUARDIAN_AMBIENT_LAND, + ENTITY_ELDER_GUARDIAN_CURSE, + ENTITY_ELDER_GUARDIAN_DEATH, + ENTITY_ELDER_GUARDIAN_DEATH_LAND, + ENTITY_ELDER_GUARDIAN_FLOP, + ENTITY_ELDER_GUARDIAN_HURT, + ENTITY_ELDER_GUARDIAN_HURT_LAND, + ENTITY_ENDERMAN_AMBIENT("ENDERMAN_IDLE", "ENTITY_ENDERMEN_AMBIENT"), + ENTITY_ENDERMAN_DEATH("ENDERMAN_DEATH", "ENTITY_ENDERMEN_DEATH"), + ENTITY_ENDERMAN_HURT("ENDERMAN_HIT", "ENTITY_ENDERMEN_HURT"), + ENTITY_ENDERMAN_SCREAM("ENDERMAN_SCREAM", "ENTITY_ENDERMEN_SCREAM"), + ENTITY_ENDERMAN_STARE("ENDERMAN_STARE", "ENTITY_ENDERMEN_STARE"), + ENTITY_ENDERMAN_TELEPORT("ENDERMAN_TELEPORT", "ENTITY_ENDERMEN_TELEPORT"), + ENTITY_ENDERMITE_AMBIENT, + ENTITY_ENDERMITE_DEATH, + ENTITY_ENDERMITE_HURT, + ENTITY_ENDERMITE_STEP, + ENTITY_ENDER_DRAGON_AMBIENT("ENDERDRAGON_WINGS", "ENTITY_ENDERDRAGON_AMBIENT"), + ENTITY_ENDER_DRAGON_DEATH("ENDERDRAGON_DEATH", "ENTITY_ENDERDRAGON_DEATH"), + ENTITY_ENDER_DRAGON_FLAP("ENDERDRAGON_WINGS", "ENTITY_ENDERDRAGON_FLAP"), + ENTITY_ENDER_DRAGON_GROWL("ENDERDRAGON_GROWL", "ENTITY_ENDERDRAGON_GROWL"), + ENTITY_ENDER_DRAGON_HURT("ENDERDRAGON_HIT", "ENTITY_ENDERDRAGON_HURT"), + ENTITY_ENDER_DRAGON_SHOOT("ENTITY_ENDERDRAGON_SHOOT"), + ENTITY_ENDER_EYE_DEATH, + ENTITY_ENDER_EYE_LAUNCH("ENTITY_ENDER_EYE_DEATH", "ENTITY_ENDEREYE_DEATH"), + ENTITY_ENDER_PEARL_THROW("ENTITY_ENDERPEARL_THROW"), + ENTITY_EVOKER_AMBIENT("ENTITY_EVOCATION_ILLAGER_AMBIENT"), + ENTITY_EVOKER_CAST_SPELL("ENTITY_EVOCATION_ILLAGER_CAST_SPELL"), + ENTITY_EVOKER_CELEBRATE, + ENTITY_EVOKER_DEATH("ENTITY_EVOCATION_ILLAGER_DEATH"), + ENTITY_EVOKER_FANGS_ATTACK("ENTITY_EVOCATION_FANGS_ATTACK"), + ENTITY_EVOKER_HURT("ENTITY_EVOCATION_ILLAGER_HURT"), + ENTITY_EVOKER_PREPARE_ATTACK("ENTITY_EVOCATION_ILLAGER_PREPARE_ATTACK"), + ENTITY_EVOKER_PREPARE_SUMMON("ENTITY_EVOCATION_ILLAGER_PREPARE_SUMMON"), + ENTITY_EVOKER_PREPARE_WOLOLO("ENTITY_EVOCATION_ILLAGER_PREPARE_WOLOLO"), + ENTITY_EXPERIENCE_BOTTLE_THROW, + ENTITY_EXPERIENCE_ORB_PICKUP("ORB_PICKUP"), + ENTITY_FIREWORK_ROCKET_BLAST("FIREWORK_BLAST", "ENTITY_FIREWORK_BLAST"), + ENTITY_FIREWORK_ROCKET_BLAST_FAR("FIREWORK_BLAST2", "ENTITY_FIREWORK_BLAST_FAR"), + ENTITY_FIREWORK_ROCKET_LARGE_BLAST("FIREWORK_LARGE_BLAST", "ENTITY_FIREWORK_LARGE_BLAST"), + ENTITY_FIREWORK_ROCKET_LARGE_BLAST_FAR("FIREWORK_LARGE_BLAST2", "ENTITY_FIREWORK_LARGE_BLAST_FAR"), + ENTITY_FIREWORK_ROCKET_LAUNCH("FIREWORK_LAUNCH", "ENTITY_FIREWORK_LAUNCH"), + ENTITY_FIREWORK_ROCKET_SHOOT, + ENTITY_FIREWORK_ROCKET_TWINKLE("FIREWORK_TWINKLE", "ENTITY_FIREWORK_TWINKLE"), + ENTITY_FIREWORK_ROCKET_TWINKLE_FAR("FIREWORK_TWINKLE2", "ENTITY_FIREWORK_TWINKLE_FAR"), + ENTITY_FISHING_BOBBER_RETRIEVE, + ENTITY_FISHING_BOBBER_SPLASH("SPLASH2", "ENTITY_BOBBER_SPLASH"), + ENTITY_FISHING_BOBBER_THROW("ENTITY_BOBBER_THROW"), + ENTITY_FISH_SWIM, + ENTITY_FOX_AGGRO, + ENTITY_FOX_AMBIENT, + ENTITY_FOX_BITE, + ENTITY_FOX_DEATH, + ENTITY_FOX_EAT, + ENTITY_FOX_HURT, + ENTITY_FOX_SCREECH, + ENTITY_FOX_SLEEP, + ENTITY_FOX_SNIFF, + ENTITY_FOX_SPIT, + ENTITY_GENERIC_BIG_FALL("FALL_BIG"), + ENTITY_GENERIC_BURN, + ENTITY_GENERIC_DEATH, + ENTITY_GENERIC_DRINK("DRINK"), + ENTITY_GENERIC_EAT("EAT"), + ENTITY_GENERIC_EXPLODE("EXPLODE"), + ENTITY_GENERIC_EXTINGUISH_FIRE, + ENTITY_GENERIC_HURT, + ENTITY_GENERIC_SMALL_FALL("FALL_SMALL"), + ENTITY_GENERIC_SPLASH("SPLASH"), + ENTITY_GENERIC_SWIM("SWIM"), + ENTITY_GHAST_AMBIENT("GHAST_MOAN"), + ENTITY_GHAST_DEATH("GHAST_DEATH"), + ENTITY_GHAST_HURT("GHAST_SCREAM2"), + ENTITY_GHAST_SCREAM("GHAST_SCREAM"), + ENTITY_GHAST_SHOOT("GHAST_FIREBALL"), + ENTITY_GHAST_WARN("GHAST_CHARGE"), + ENTITY_GUARDIAN_AMBIENT, + ENTITY_GUARDIAN_AMBIENT_LAND, + ENTITY_GUARDIAN_ATTACK, + ENTITY_GUARDIAN_DEATH, + ENTITY_GUARDIAN_DEATH_LAND, + ENTITY_GUARDIAN_FLOP, + ENTITY_GUARDIAN_HURT, + ENTITY_GUARDIAN_HURT_LAND, + ENTITY_HORSE_AMBIENT("HORSE_IDLE"), + ENTITY_HORSE_ANGRY("HORSE_ANGRY"), + ENTITY_HORSE_ARMOR("HORSE_ARMOR"), + ENTITY_HORSE_BREATHE("HORSE_BREATHE"), + ENTITY_HORSE_DEATH("HORSE_DEATH"), + ENTITY_HORSE_EAT, + ENTITY_HORSE_GALLOP("HORSE_GALLOP"), + ENTITY_HORSE_HURT("HORSE_HIT"), + ENTITY_HORSE_JUMP("HORSE_JUMP"), + ENTITY_HORSE_LAND("HORSE_LAND"), + ENTITY_HORSE_SADDLE("HORSE_SADDLE"), + ENTITY_HORSE_STEP("HORSE_SOFT"), + ENTITY_HORSE_STEP_WOOD("HORSE_WOOD"), + ENTITY_HOSTILE_BIG_FALL("FALL_BIG"), + ENTITY_HOSTILE_DEATH, + ENTITY_HOSTILE_HURT, + ENTITY_HOSTILE_SMALL_FALL("FALL_SMALL"), + ENTITY_HOSTILE_SPLASH("SPLASH"), + ENTITY_HOSTILE_SWIM("SWIM"), + ENTITY_HUSK_AMBIENT, + ENTITY_HUSK_CONVERTED_TO_ZOMBIE, + ENTITY_HUSK_DEATH, + ENTITY_HUSK_HURT, + ENTITY_HUSK_STEP, + ENTITY_ILLUSIONER_AMBIENT("ENTITY_ILLUSION_ILLAGER_AMBIENT"), + ENTITY_ILLUSIONER_CAST_SPELL("ENTITY_ILLUSION_ILLAGER_CAST_SPELL"), + ENTITY_ILLUSIONER_DEATH("ENTITY_ILLUSIONER_CAST_DEATH", "ENTITY_ILLUSION_ILLAGER_DEATH"), + ENTITY_ILLUSIONER_HURT("ENTITY_ILLUSION_ILLAGER_HURT"), + ENTITY_ILLUSIONER_MIRROR_MOVE("ENTITY_ILLUSION_ILLAGER_MIRROR_MOVE"), + ENTITY_ILLUSIONER_PREPARE_BLINDNESS("ENTITY_ILLUSION_ILLAGER_PREPARE_BLINDNESS"), + ENTITY_ILLUSIONER_PREPARE_MIRROR("ENTITY_ILLUSION_ILLAGER_PREPARE_MIRROR"), + ENTITY_IRON_GOLEM_ATTACK("IRONGOLEM_THROW", "ENTITY_IRONGOLEM_ATTACK"), + ENTITY_IRON_GOLEM_DAMAGE, + ENTITY_IRON_GOLEM_DEATH("IRONGOLEM_DEATH", "ENTITY_IRONGOLEM_DEATH"), + ENTITY_IRON_GOLEM_HURT("IRONGOLEM_HIT", "ENTITY_IRONGOLEM_HURT"), + ENTITY_IRON_GOLEM_REPAIR, + ENTITY_IRON_GOLEM_STEP("IRONGOLEM_WALK", "ENTITY_IRONGOLEM_STEP"), + ENTITY_ITEM_BREAK("ITEM_BREAK"), + ENTITY_ITEM_FRAME_ADD_ITEM("ENTITY_ITEMFRAME_ADD_ITEM"), + ENTITY_ITEM_FRAME_BREAK("ENTITY_ITEMFRAME_BREAK"), + ENTITY_ITEM_FRAME_PLACE("ENTITY_ITEMFRAME_PLACE"), + ENTITY_ITEM_FRAME_REMOVE_ITEM("ENTITY_ITEMFRAME_REMOVE_ITEM"), + ENTITY_ITEM_FRAME_ROTATE_ITEM("ENTITY_ITEMFRAME_ROTATE_ITEM"), + ENTITY_ITEM_PICKUP("ITEM_PICKUP"), + ENTITY_LEASH_KNOT_BREAK("ENTITY_LEASHKNOT_BREAK"), + ENTITY_LEASH_KNOT_PLACE("ENTITY_LEASHKNOT_PLACE"), + ENTITY_LIGHTNING_BOLT_IMPACT("AMBIENCE_THUNDER", "ENTITY_LIGHTNING_IMPACT"), + ENTITY_LIGHTNING_BOLT_THUNDER("AMBIENCE_THUNDER", "ENTITY_LIGHTNING_THUNDER"), + ENTITY_LINGERING_POTION_THROW, + ENTITY_LLAMA_AMBIENT, + ENTITY_LLAMA_ANGRY, + ENTITY_LLAMA_CHEST, + ENTITY_LLAMA_DEATH, + ENTITY_LLAMA_EAT, + ENTITY_LLAMA_HURT, + ENTITY_LLAMA_SPIT, + ENTITY_LLAMA_STEP, + ENTITY_LLAMA_SWAG, + ENTITY_MAGMA_CUBE_DEATH("ENTITY_MAGMACUBE_DEATH"), + ENTITY_MAGMA_CUBE_DEATH_SMALL("ENTITY_SMALL_MAGMACUBE_DEATH"), + ENTITY_MAGMA_CUBE_HURT("ENTITY_MAGMACUBE_HURT"), + ENTITY_MAGMA_CUBE_HURT_SMALL("ENTITY_SMALL_MAGMACUBE_HURT"), + ENTITY_MAGMA_CUBE_JUMP("MAGMACUBE_JUMP", "ENTITY_MAGMACUBE_JUMP"), + ENTITY_MAGMA_CUBE_SQUISH("MAGMACUBE_WALK", "ENTITY_MAGMACUBE_SQUISH"), + ENTITY_MAGMA_CUBE_SQUISH_SMALL("MAGMACUBE_WALK2", "ENTITY_SMALL_MAGMACUBE_SQUISH"), + ENTITY_MINECART_INSIDE("MINECART_INSIDE"), + ENTITY_MINECART_RIDING("MINECART_BASE"), + ENTITY_MOOSHROOM_CONVERT, + ENTITY_MOOSHROOM_EAT, + ENTITY_MOOSHROOM_MILK, + ENTITY_MOOSHROOM_SHEAR, + ENTITY_MOOSHROOM_SUSPICIOUS_MILK, + ENTITY_MULE_AMBIENT, + ENTITY_MULE_CHEST("ENTITY_MULE_AMBIENT"), + ENTITY_MULE_DEATH("ENTITY_MULE_AMBIENT"), + ENTITY_MULE_HURT("ENTITY_MULE_AMBIENT"), + ENTITY_OCELOT_AMBIENT, + ENTITY_OCELOT_DEATH, + ENTITY_OCELOT_HURT, + ENTITY_PAINTING_BREAK, + ENTITY_PAINTING_PLACE, + ENTITY_PANDA_AGGRESSIVE_AMBIENT, + ENTITY_PANDA_AMBIENT, + ENTITY_PANDA_BITE, + ENTITY_PANDA_CANT_BREED, + ENTITY_PANDA_DEATH, + ENTITY_PANDA_EAT, + ENTITY_PANDA_HURT, + ENTITY_PANDA_PRE_SNEEZE, + ENTITY_PANDA_SNEEZE, + ENTITY_PANDA_STEP, + ENTITY_PANDA_WORRIED_AMBIENT, + ENTITY_PARROT_AMBIENT, + ENTITY_PARROT_DEATH, + ENTITY_PARROT_EAT, + ENTITY_PARROT_FLY, + ENTITY_PARROT_HURT, + ENTITY_PARROT_IMITATE_BLAZE, + ENTITY_PARROT_IMITATE_CREEPER, + ENTITY_PARROT_IMITATE_DROWNED, + ENTITY_PARROT_IMITATE_ELDER_GUARDIAN, + ENTITY_PARROT_IMITATE_ENDERMAN, + ENTITY_PARROT_IMITATE_ENDERMITE, + ENTITY_PARROT_IMITATE_ENDER_DRAGON, + ENTITY_PARROT_IMITATE_EVOKER, + ENTITY_PARROT_IMITATE_GHAST, + ENTITY_PARROT_IMITATE_GUARDIAN, + ENTITY_PARROT_IMITATE_HUSK, + ENTITY_PARROT_IMITATE_ILLUSIONER, + ENTITY_PARROT_IMITATE_MAGMA_CUBE, + ENTITY_PARROT_IMITATE_PHANTOM, + ENTITY_PARROT_IMITATE_PILLAGER, + ENTITY_PARROT_IMITATE_POLAR_BEAR, + ENTITY_PARROT_IMITATE_RAVAGER, + ENTITY_PARROT_IMITATE_SHULKER, + ENTITY_PARROT_IMITATE_SILVERFISH, + ENTITY_PARROT_IMITATE_SKELETON, + ENTITY_PARROT_IMITATE_SLIME, + ENTITY_PARROT_IMITATE_SPIDER, + ENTITY_PARROT_IMITATE_STRAY, + ENTITY_PARROT_IMITATE_VEX, + ENTITY_PARROT_IMITATE_VINDICATOR, + ENTITY_PARROT_IMITATE_WITCH, + ENTITY_PARROT_IMITATE_WITHER, + ENTITY_PARROT_IMITATE_WITHER_SKELETON, + ENTITY_PARROT_IMITATE_WOLF, + ENTITY_PARROT_IMITATE_ZOMBIE, + ENTITY_PARROT_IMITATE_ZOMBIE_PIGMAN, + ENTITY_PARROT_IMITATE_ZOMBIE_VILLAGER, + ENTITY_PARROT_STEP, + ENTITY_PHANTOM_AMBIENT, + ENTITY_PHANTOM_BITE, + ENTITY_PHANTOM_DEATH, + ENTITY_PHANTOM_FLAP, + ENTITY_PHANTOM_HURT, + ENTITY_PHANTOM_SWOOP, + ENTITY_PIG_AMBIENT("PIG_IDLE"), + ENTITY_PIG_DEATH("PIG_DEATH"), + ENTITY_PIG_HURT, + ENTITY_PIG_SADDLE("ENTITY_PIG_HURT"), + ENTITY_PIG_STEP("PIG_WALK"), + ENTITY_PILLAGER_AMBIENT, + ENTITY_PILLAGER_CELEBRATE, + ENTITY_PILLAGER_DEATH, + ENTITY_PILLAGER_HURT, + ENTITY_PLAYER_ATTACK_CRIT, + ENTITY_PLAYER_ATTACK_KNOCKBACK, + ENTITY_PLAYER_ATTACK_NODAMAGE, + ENTITY_PLAYER_ATTACK_STRONG("SUCCESSFUL_HIT"), + ENTITY_PLAYER_ATTACK_SWEEP, + ENTITY_PLAYER_ATTACK_WEAK, + ENTITY_PLAYER_BIG_FALL("FALL_BIG"), + ENTITY_PLAYER_BREATH, + ENTITY_PLAYER_BURP("BURP"), + ENTITY_PLAYER_DEATH, + ENTITY_PLAYER_HURT("HURT_FLESH"), + ENTITY_PLAYER_HURT_DROWN, + ENTITY_PLAYER_HURT_ON_FIRE, + ENTITY_PLAYER_HURT_SWEET_BERRY_BUSH, + ENTITY_PLAYER_LEVELUP("LEVEL_UP"), + ENTITY_PLAYER_SMALL_FALL("FALL_SMALL"), + ENTITY_PLAYER_SPLASH("SLASH"), + ENTITY_PLAYER_SPLASH_HIGH_SPEED("SPLASH"), + ENTITY_PLAYER_SWIM("SWIM"), + ENTITY_POLAR_BEAR_AMBIENT, + ENTITY_POLAR_BEAR_AMBIENT_BABY("ENTITY_POLAR_BEAR_BABY_AMBIENT"), + ENTITY_POLAR_BEAR_DEATH, + ENTITY_POLAR_BEAR_HURT, + ENTITY_POLAR_BEAR_STEP, + ENTITY_POLAR_BEAR_WARNING, + ENTITY_PUFFER_FISH_AMBIENT, + ENTITY_PUFFER_FISH_BLOW_OUT, + ENTITY_PUFFER_FISH_BLOW_UP, + ENTITY_PUFFER_FISH_DEATH, + ENTITY_PUFFER_FISH_FLOP, + ENTITY_PUFFER_FISH_HURT, + ENTITY_PUFFER_FISH_STING, + ENTITY_RABBIT_AMBIENT, + ENTITY_RABBIT_ATTACK, + ENTITY_RABBIT_DEATH, + ENTITY_RABBIT_HURT, + ENTITY_RABBIT_JUMP, + ENTITY_RAVAGER_AMBIENT, + ENTITY_RAVAGER_ATTACK, + ENTITY_RAVAGER_CELEBRATE, + ENTITY_RAVAGER_DEATH, + ENTITY_RAVAGER_HURT, + ENTITY_RAVAGER_ROAR, + ENTITY_RAVAGER_STEP, + ENTITY_RAVAGER_STUNNED, + ENTITY_SALMON_AMBIENT, + ENTITY_SALMON_DEATH, + ENTITY_SALMON_FLOP, + ENTITY_SALMON_HURT("ENTITY_SALMON_FLOP"), + ENTITY_SHEEP_AMBIENT("SHEEP_IDLE"), + ENTITY_SHEEP_DEATH, + ENTITY_SHEEP_HURT, + ENTITY_SHEEP_SHEAR("SHEEP_SHEAR"), + ENTITY_SHEEP_STEP("SHEEP_WALK"), + ENTITY_SHULKER_AMBIENT, + ENTITY_SHULKER_BULLET_HIT, + ENTITY_SHULKER_BULLET_HURT, + ENTITY_SHULKER_CLOSE, + ENTITY_SHULKER_DEATH, + ENTITY_SHULKER_HURT, + ENTITY_SHULKER_HURT_CLOSED, + ENTITY_SHULKER_OPEN, + ENTITY_SHULKER_SHOOT, + ENTITY_SHULKER_TELEPORT, + ENTITY_SILVERFISH_AMBIENT("SILVERFISH_IDLE"), + ENTITY_SILVERFISH_DEATH("SILVERFISH_KILL"), + ENTITY_SILVERFISH_HURT("SILVERFISH_HIT"), + ENTITY_SILVERFISH_STEP("SILVERFISH_WALK"), + ENTITY_SKELETON_AMBIENT("SKELETON_IDLE"), + ENTITY_SKELETON_DEATH("SKELETON_DEATH"), + ENTITY_SKELETON_HORSE_AMBIENT("HORSE_SKELETON_IDLE"), + ENTITY_SKELETON_HORSE_AMBIENT_WATER, + ENTITY_SKELETON_HORSE_DEATH("HORSE_SKELETON_DEATH"), + ENTITY_SKELETON_HORSE_GALLOP_WATER, + ENTITY_SKELETON_HORSE_HURT("HORSE_SKELETON_HIT"), + ENTITY_SKELETON_HORSE_JUMP_WATER, + ENTITY_SKELETON_HORSE_STEP_WATER, + ENTITY_SKELETON_HORSE_SWIM, + ENTITY_SKELETON_HURT("SKELETON_HURT"), + ENTITY_SKELETON_SHOOT, + ENTITY_SKELETON_STEP("SKELETON_WALK"), + ENTITY_SLIME_ATTACK("SLIME_ATTACK"), + ENTITY_SLIME_DEATH, + ENTITY_SLIME_DEATH_SMALL, + ENTITY_SLIME_HURT, + ENTITY_SLIME_HURT_SMALL("ENTITY_SMALL_SLIME_HURT"), + ENTITY_SLIME_JUMP("SLIME_WALK"), + ENTITY_SLIME_JUMP_SMALL("SLIME_WALK2", "ENTITY_SMALL_SLIME_SQUISH"), + ENTITY_SLIME_SQUISH("SLIME_WALK2"), + ENTITY_SLIME_SQUISH_SMALL("ENTITY_SMALL_SLIME_SQUISH"), + ENTITY_SNOWBALL_THROW, + ENTITY_SNOW_GOLEM_AMBIENT("ENTITY_SNOWMAN_AMBIENT"), + ENTITY_SNOW_GOLEM_DEATH("ENTITY_SNOWMAN_DEATH"), + ENTITY_SNOW_GOLEM_HURT("ENTITY_SNOWMAN_HURT"), + ENTITY_SNOW_GOLEM_SHOOT("ENTITY_SNOWMAN_SHOOT"), + ENTITY_SPIDER_AMBIENT("SPIDER_IDLE"), + ENTITY_SPIDER_DEATH("SPIDER_DEATH"), + ENTITY_SPIDER_HURT, + ENTITY_SPIDER_STEP("SPIDER_WALK"), + ENTITY_SPLASH_POTION_BREAK, + ENTITY_SPLASH_POTION_THROW, + ENTITY_SQUID_AMBIENT, + ENTITY_SQUID_DEATH, + ENTITY_SQUID_HURT, + ENTITY_SQUID_SQUIRT, + ENTITY_STRAY_AMBIENT, + ENTITY_STRAY_DEATH, + ENTITY_STRAY_HURT, + ENTITY_STRAY_STEP, + ENTITY_TNT_PRIMED("FUSE"), + ENTITY_TROPICAL_FISH_AMBIENT, + ENTITY_TROPICAL_FISH_DEATH, + ENTITY_TROPICAL_FISH_FLOP("ENTITY_TROPICAL_FISH_DEATH"), + ENTITY_TROPICAL_FISH_HURT, + ENTITY_TURTLE_AMBIENT_LAND, + ENTITY_TURTLE_DEATH, + ENTITY_TURTLE_DEATH_BABY, + ENTITY_TURTLE_EGG_BREAK, + ENTITY_TURTLE_EGG_CRACK, + ENTITY_TURTLE_EGG_HATCH, + ENTITY_TURTLE_HURT, + ENTITY_TURTLE_HURT_BABY, + ENTITY_TURTLE_LAY_EGG, + ENTITY_TURTLE_SHAMBLE, + ENTITY_TURTLE_SHAMBLE_BABY, + ENTITY_TURTLE_SWIM, + ENTITY_VEX_AMBIENT, + ENTITY_VEX_CHARGE, + ENTITY_VEX_DEATH, + ENTITY_VEX_HURT, + ENTITY_VILLAGER_AMBIENT("VILLAGER_IDLE"), + ENTITY_VILLAGER_CELEBRATE, + ENTITY_VILLAGER_DEATH("VILLAGER_DEATH"), + ENTITY_VILLAGER_HURT("VILLAGER_HIT"), + ENTITY_VILLAGER_NO("VILLAGER_NO"), + ENTITY_VILLAGER_TRADE("VILLAGER_HAGGLE", "ENTITY_VILLAGER_TRADING"), + ENTITY_VILLAGER_WORK_ARMORER, + ENTITY_VILLAGER_WORK_BUTCHER, + ENTITY_VILLAGER_WORK_CARTOGRAPHER, + ENTITY_VILLAGER_WORK_CLERIC, + ENTITY_VILLAGER_WORK_FARMER, + ENTITY_VILLAGER_WORK_FISHERMAN, + ENTITY_VILLAGER_WORK_FLETCHER, + ENTITY_VILLAGER_WORK_LEATHERWORKER, + ENTITY_VILLAGER_WORK_LIBRARIAN, + ENTITY_VILLAGER_WORK_MASON, + ENTITY_VILLAGER_WORK_SHEPHERD, + ENTITY_VILLAGER_WORK_TOOLSMITH, + ENTITY_VILLAGER_WORK_WEAPONSMITH, + ENTITY_VILLAGER_YES("VILLAGER_YES"), + ENTITY_VINDICATOR_AMBIENT("ENTITY_VINDICATION_ILLAGER_AMBIENT"), + ENTITY_VINDICATOR_CELEBRATE, + ENTITY_VINDICATOR_DEATH("ENTITY_VINDICATION_ILLAGER_DEATH"), + ENTITY_VINDICATOR_HURT("ENTITY_VINDICATION_ILLAGER_HURT"), + ENTITY_WANDERING_TRADER_AMBIENT, + ENTITY_WANDERING_TRADER_DEATH, + ENTITY_WANDERING_TRADER_DISAPPEARED, + ENTITY_WANDERING_TRADER_DRINK_MILK, + ENTITY_WANDERING_TRADER_DRINK_POTION, + ENTITY_WANDERING_TRADER_HURT, + ENTITY_WANDERING_TRADER_NO, + ENTITY_WANDERING_TRADER_REAPPEARED, + ENTITY_WANDERING_TRADER_TRADE, + ENTITY_WANDERING_TRADER_YES, + ENTITY_WITCH_AMBIENT, + ENTITY_WITCH_CELEBRATE, + ENTITY_WITCH_DEATH, + ENTITY_WITCH_DRINK, + ENTITY_WITCH_HURT, + ENTITY_WITCH_THROW, + ENTITY_WITHER_AMBIENT("WITHER_IDLE"), + ENTITY_WITHER_BREAK_BLOCK, + ENTITY_WITHER_DEATH("WITHER_DEATH"), + ENTITY_WITHER_HURT("WITHER_HURT"), + ENTITY_WITHER_SHOOT("WITHER_SHOOT"), + ENTITY_WITHER_SKELETON_AMBIENT, + ENTITY_WITHER_SKELETON_DEATH, + ENTITY_WITHER_SKELETON_HURT, + ENTITY_WITHER_SKELETON_STEP, + ENTITY_WITHER_SPAWN("WITHER_SPAWN"), + ENTITY_WOLF_AMBIENT("WOLF_BARK"), + ENTITY_WOLF_DEATH("WOLF_DEATH"), + ENTITY_WOLF_GROWL("WOLF_GROWL"), + ENTITY_WOLF_HOWL("WOLF_HOWL"), + ENTITY_WOLF_HURT("WOLF_HURT"), + ENTITY_WOLF_PANT("WOLF_PANT"), + ENTITY_WOLF_SHAKE("WOLF_SHAKE"), + ENTITY_WOLF_STEP("WOLF_WALK"), + ENTITY_WOLF_WHINE("WOLF_WHINE"), + ENTITY_ZOMBIE_AMBIENT("ZOMBIE_IDLE"), + ENTITY_ZOMBIE_ATTACK_IRON_DOOR("ZOMBIE_METAL"), + ENTITY_ZOMBIE_ATTACK_WOODEN_DOOR("ZOMBIE_WOOD", "ENTITY_ZOMBIE_ATTACK_DOOR_WOOD"), + ENTITY_ZOMBIE_BREAK_WOODEN_DOOR("ZOMBIE_WOODBREAK", "ENTITY_ZOMBIE_BREAK_DOOR_WOOD"), + ENTITY_ZOMBIE_CONVERTED_TO_DROWNED, + ENTITY_ZOMBIE_DEATH("ZOMBIE_DEATH"), + ENTITY_ZOMBIE_DESTROY_EGG, + ENTITY_ZOMBIE_HORSE_AMBIENT("HORSE_ZOMBIE_IDLE"), + ENTITY_ZOMBIE_HORSE_DEATH("HORSE_ZOMBIE_DEATH"), + ENTITY_ZOMBIE_HORSE_HURT("HORSE_ZOMBIE_HIT"), + ENTITY_ZOMBIE_HURT("ZOMBIE_HURT"), + ENTITY_ZOMBIE_INFECT("ZOMBIE_INFECT"), + ENTITY_ZOMBIE_PIGMAN_AMBIENT("ZOMBIE_PIG_IDLE", "ENTITY_ZOMBIE_PIG_AMBIENT"), + ENTITY_ZOMBIE_PIGMAN_ANGRY("ZOMBIE_PIG_ANGRY", "ENTITY_ZOMBIE_PIG_ANGRY"), + ENTITY_ZOMBIE_PIGMAN_DEATH("ZOMBIE_PIG_DEATH", "ENTITY_ZOMBIE_PIG_DEATH"), + ENTITY_ZOMBIE_PIGMAN_HURT("ZOMBIE_PIG_HURT", "ENTITY_ZOMBIE_PIG_HURT"), + ENTITY_ZOMBIE_STEP("ZOMBIE_WALK"), + ENTITY_ZOMBIE_VILLAGER_AMBIENT, + ENTITY_ZOMBIE_VILLAGER_CONVERTED("ZOMBIE_UNFECT"), + ENTITY_ZOMBIE_VILLAGER_CURE("ZOMBIE_REMEDY"), + ENTITY_ZOMBIE_VILLAGER_DEATH, + ENTITY_ZOMBIE_VILLAGER_HURT, + ENTITY_ZOMBIE_VILLAGER_STEP, + EVENT_RAID_HORN, + ITEM_ARMOR_EQUIP_CHAIN, + ITEM_ARMOR_EQUIP_DIAMOND, + ITEM_ARMOR_EQUIP_ELYTRA, + ITEM_ARMOR_EQUIP_GENERIC, + ITEM_ARMOR_EQUIP_GOLD, + ITEM_ARMOR_EQUIP_IRON, + ITEM_ARMOR_EQUIP_LEATHER, + ITEM_ARMOR_EQUIP_TURTLE, + ITEM_AXE_STRIP, + ITEM_BOOK_PAGE_TURN, + ITEM_BOOK_PUT, + ITEM_BOTTLE_EMPTY, + ITEM_BOTTLE_FILL, + ITEM_BOTTLE_FILL_DRAGONBREATH, + ITEM_BUCKET_EMPTY, + ITEM_BUCKET_EMPTY_FISH, + ITEM_BUCKET_EMPTY_LAVA, + ITEM_BUCKET_FILL, + ITEM_BUCKET_FILL_FISH, + ITEM_BUCKET_FILL_LAVA, + ITEM_CHORUS_FRUIT_TELEPORT, + ITEM_CROP_PLANT, + ITEM_CROSSBOW_HIT, + ITEM_CROSSBOW_LOADING_END, + ITEM_CROSSBOW_LOADING_MIDDLE, + ITEM_CROSSBOW_LOADING_START, + ITEM_CROSSBOW_QUICK_CHARGE_1, + ITEM_CROSSBOW_QUICK_CHARGE_2, + ITEM_CROSSBOW_QUICK_CHARGE_3, + ITEM_CROSSBOW_SHOOT, + ITEM_ELYTRA_FLYING, + ITEM_FIRECHARGE_USE, + ITEM_FLINTANDSTEEL_USE("FIRE_IGNITE"), + ITEM_HOE_TILL, + ITEM_HONEY_BOTTLE_DRINK, + ITEM_NETHER_WART_PLANT, + ITEM_SHIELD_BLOCK, + ITEM_SHIELD_BREAK, + ITEM_SHOVEL_FLATTEN, + ITEM_SWEET_BERRIES_PICK_FROM_BUSH, + ITEM_TOTEM_USE, + ITEM_TRIDENT_HIT, + ITEM_TRIDENT_HIT_GROUND, + ITEM_TRIDENT_RETURN, + ITEM_TRIDENT_RIPTIDE_1, + ITEM_TRIDENT_RIPTIDE_2("ITEM_TRIDENT_RIPTIDE_1"), + ITEM_TRIDENT_RIPTIDE_3("ITEM_TRIDENT_RIPTIDE_1"), + ITEM_TRIDENT_THROW, + ITEM_TRIDENT_THUNDER, + MUSIC_CREATIVE, + MUSIC_CREDITS, + MUSIC_DISC_11("RECORD_11"), + MUSIC_DISC_13("RECORD_13"), + MUSIC_DISC_BLOCKS("RECORD_BLOCKS"), + MUSIC_DISC_CAT("RECORD_CAT"), + MUSIC_DISC_CHIRP("RECORD_CHIRP"), + MUSIC_DISC_FAR("RECORD_FAR"), + MUSIC_DISC_MALL("RECORD_MALL"), + MUSIC_DISC_MELLOHI("RECORD_MELLOHI"), + MUSIC_DISC_STAL("RECORD_STAL"), + MUSIC_DISC_STRAD("RECORD_STRAD"), + MUSIC_DISC_WAIT("RECORD_WAIT"), + MUSIC_DISC_WARD("RECORD_WARD"), + MUSIC_DRAGON, + MUSIC_END, + MUSIC_GAME, + MUSIC_MENU, + MUSIC_NETHER, + MUSIC_UNDER_WATER, + UI_BUTTON_CLICK("CLICK"), + UI_CARTOGRAPHY_TABLE_TAKE_RESULT, + UI_LOOM_SELECT_PATTERN, + UI_LOOM_TAKE_RESULT, + UI_STONECUTTER_SELECT_RECIPE, + UI_STONECUTTER_TAKE_RESULT, + UI_TOAST_CHALLENGE_COMPLETE, + UI_TOAST_IN, + UI_TOAST_OUT, + WEATHER_RAIN("AMBIENCE_RAIN"), + WEATHER_RAIN_ABOVE; + + + /** + * An immutable cached list of {@link Sounds#values()} to avoid allocating memory for + * calling the method every time. + * + * @since 2.0.0 + */ + public static final EnumSet VALUES = EnumSet.allOf(Sounds.class); + /** + * Guava (Google Core Libraries for Java)'s cache for performance and timed caches. + * Caches the parsed {@link Sound} objects instead of string. Because it has to go through catching exceptions again + * since {@link Sound} class doesn't have a method like {@link org.bukkit.Material#getMaterial(String)}. + * So caching these would be more efficient. + * + * @since 2.0.0 + */ + private static final Cache> CACHE = CacheBuilder.newBuilder() + .expireAfterAccess(10, TimeUnit.MINUTES) + .softValues() + .build(); + /** + * Pre-compiled RegEx pattern. + * Include both replacements to avoid creating string multiple times and multiple RegEx checks. + * + * @since 1.0.0 + */ + private static final Pattern FORMAT_PATTERN = Pattern.compile("\\d+|\\W+"); + private final String[] legacy; + + Sounds(String... legacy) { + this.legacy = legacy; + } + + /** + * 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. + * + * @param name the sound name to modify. + * @return a Sound enum name. + * @since 1.0.0 + */ + @Nonnull + private static String format(@Nonnull String name) { + return FORMAT_PATTERN.matcher( + name.trim().replace('-', '_').replace(' ', '_')).replaceAll("").toUpperCase(Locale.ENGLISH); + } + + /** + * Checks if Sounds enum and the legacy names contains a sound with this name. + * + * @param sound name of the sound + * @return true if Sounds enum has this sound. + * @since 1.0.0 + */ + public static boolean contains(@Nonnull String sound) { + Validate.notEmpty(sound, "Cannot check for null or empty sound name"); + sound = format(sound); + + for (Sounds sounds : VALUES) + if (sounds.name().equals(sound) || sounds.anyMatchLegacy(sound)) return true; + return false; + } + + /** + * Parses the Sounds with the given name. + * + * @param sound the name of the sound. + * @return a matched Sounds. + * @since 1.0.0 + */ + @Nonnull + public static Optional matchSounds(@Nonnull String sound) { + Validate.notEmpty(sound, "Cannot match Sounds of a null or empty sound name"); + sound = format(sound); + + for (Sounds sounds : VALUES) + if (sounds.name().equals(sound) || sounds.anyMatchLegacy(sound)) return Optional.of(sounds); + return Optional.empty(); + } + + /** + * Parses the Sounds with the given bukkit sound. + * + * @param sound the Bukkit sound. + * @return a matched sound. + * @throws IllegalArgumentException may be thrown as an unexpected exception. + * @since 2.0.0 + */ + @Nonnull + public static Sounds matchSounds(@Nonnull Sound sound) { + Objects.requireNonNull(sound, "Cannot match Sounds of a null sound"); + return matchSounds(sound.name()) + .orElseThrow(() -> new IllegalArgumentException("Unsupported Sound: " + sound.name())); + } + + /** + * Just an extra feature that loads sounds from strings. + * Useful for getting sounds from config files. + *

+ * This will also ignore {@code none} and {@code null} strings. + *

+ * Format: Sound, Volume, Pitch
+ * Comma separators are optional. + *

+ * Examples: + *

+ *

+     *     ENTITY_PLAYER_BURP, 0.5, 1f
+     *     BURP 0.5f 1
+     *     MUSIC_END, 10f
+     *     none
+     *     null
+     * 
+ * + * @param player the player to play the sound to. + * @param sound the string of the sound with volume and pitch (if needed). + * @since 1.0.0 + */ + public static CompletableFuture playSoundFromString(@Nonnull Player player, @Nullable String sound) { + Objects.requireNonNull(player, "Cannot play sound to null player"); + return CompletableFuture.runAsync(() -> { + if (Strings.isNullOrEmpty(sound) || sound.equalsIgnoreCase("none")) return; + + String[] split = StringUtils.contains(sound, ',') ? + StringUtils.split(StringUtils.deleteWhitespace(sound), ',') : + StringUtils.split(sound.replaceAll(" +", " "), ' '); + + // You should replace the exception with your own message handler. + Validate.isTrue(split.length != 0, "Sound string must at least have a sound name: ", sound); + + String name = split[0]; + Optional typeOpt = matchSounds(name); + if (!typeOpt.isPresent()) return; + Sound type = typeOpt.get().parseSound(); + if (type == null) return; + + float volume = 1.0f; + float pitch = 1.0f; + + try { + if (split.length > 1) { + volume = Float.parseFloat(split[1]); + if (split.length > 2) pitch = Float.parseFloat(split[2]); + } + } catch (NumberFormatException ignored) { + } + + if (player.isOnline()) player.playSound(player.getLocation(), type, volume, pitch); + }); + } + + /** + * Stops all the playing musics (not all the sounds) + *

+ * Note that this method will only work for the sound + * that are sent from {@link Player#playSound} and + * the sounds played from the client will not be + * affected by this. + * + * @param player the player to stop all the sounds from. + * @see #stopSound(Player) + * @since 2.0.0 + */ + public static CompletableFuture stopMusic(@Nonnull Player player) { + Objects.requireNonNull(player, "Cannot stop playing musics from null player"); + + // We don't need to cache because it's rarely used. + EnumSet musics = EnumSet.of(MUSIC_CREATIVE, MUSIC_CREDITS, + MUSIC_DISC_11, MUSIC_DISC_13, MUSIC_DISC_BLOCKS, MUSIC_DISC_CAT, MUSIC_DISC_CHIRP, + MUSIC_DISC_FAR, MUSIC_DISC_MALL, MUSIC_DISC_MELLOHI, MUSIC_DISC_STAL, + MUSIC_DISC_STRAD, MUSIC_DISC_WAIT, MUSIC_DISC_WARD, + MUSIC_DRAGON, MUSIC_END, MUSIC_GAME, MUSIC_MENU, MUSIC_NETHER, MUSIC_UNDER_WATER); + + return CompletableFuture.runAsync(() -> { + for (Sounds music : musics) { + Sound sound = music.parseSound(); + if (sound != null) player.stopSound(sound); + } + }); + } + + /** + * In most cases your should be using {@link #name()} instead. + * + * @return a friendly readable string name. + */ + @Override + public String toString() { + return WordUtils.capitalize(this.name().replace('_', ' ').toLowerCase(Locale.ENGLISH)); + } + + /** + * Gets all the previous sound names used for this sound. + * + * @return a list of legacy sound names. + * @since 1.0.0 + */ + @Nonnull + public String[] getLegacy() { + return legacy; + } + + /** + * Parses the Sounds as a {@link Sound} based on the server version. + * + * @return the vanilla sound. + * @since 1.0.0 + */ + @Nullable + @SuppressWarnings({"Guava", "OptionalAssignedToNull"}) + public Sound parseSound() { + com.google.common.base.Optional cachedSound = CACHE.getIfPresent(this); + if (cachedSound != null) return cachedSound.orNull(); + com.google.common.base.Optional sound; + + // Since Sound class doesn't have a getSound() method we'll use Guava so + // it can cache it for us. + sound = Enums.getIfPresent(Sound.class, this.name()); + + if (!sound.isPresent()) { + for (String legacy : this.legacy) { + sound = Enums.getIfPresent(Sound.class, legacy); + if (sound.isPresent()) break; + } + } + + // Put nulls too, because there's no point of parsing them again if it's going to give us null again. + CACHE.put(this, sound); + return sound.orNull(); + } + + /** + * Checks if this sound is supported in the current Minecraft version. + *

+ * An invocation of this method yields exactly the same result as the expression: + *

+ *

+ * {@link #parseSound()} != null + *
+ * + * @return true if the current version has this sound, otherwise false. + * @since 1.0.0 + */ + public boolean isSupported() { + return this.parseSound() != null; + } + + /** + * Checks if the given string matches any of this sound's legacy sound names. + * + * @param name the sound name to check + * @return true if it's one of the legacy names. + * @since 1.0.0 + */ + public boolean anyMatchLegacy(@Nonnull String name) { + Validate.notEmpty(name, "Cannot check for legacy name for null or empty sound name"); + return Arrays.asList(this.legacy).contains(format(name)); + } + + /** + * Plays a sound repeatedly with the given delay at a moving target's location. + * + * @param plugin the plugin handling schedulers. (You can replace this with a static instance) + * @param entity the entity to play the sound to. We exactly need an entity to keep the track of location changes. + * @param volume the volume of the sound. + * @param pitch the pitch of the sound. + * @param repeat the amount of times to repeat playing. + * @param delay the delay between each repeat. + * @see #playSound(Location, float, float) + * @since 2.0.0 + */ + public void playSoundRepeatedly(JavaPlugin plugin, Entity entity, float volume, float pitch, int repeat, int delay) { + Objects.requireNonNull(plugin, "Cannot play repeating sound from null plugin"); + Objects.requireNonNull(entity, "Cannot play repeating sound at null location"); + + Validate.isTrue(repeat > 0, "Cannot repeat playing sound " + repeat + " times"); + Validate.isTrue(delay > 0, "Delay ticks must be at least 1"); + + new BukkitRunnable() { + int repeating = repeat; + + @Override + public void run() { + playSound(entity.getLocation(), volume, pitch); + if (repeating-- == 0) cancel(); + } + }.runTaskTimer(plugin, 0, delay); + } + + /** + * Plays an instrument's notes in an ascending form. + * This method is not really relevant to this utility class, but a nice feature. + * + * @param plugin the plugin handling schedulers. + * @param player the player to play the note from. + * @param playTo the entity to play the note to. + * @param instrument the instrument. + * @param ascendLevel the ascend level of notes. Can only be positive and not higher than 7 + * @param delay the delay between each play. + * @since 2.0.0 + */ + public void playAscendingNote(@Nonnull JavaPlugin plugin, @Nonnull Player player, @Nonnull Entity playTo, Instrument instrument, int ascendLevel, int delay) { + Objects.requireNonNull(player, "Cannot play note from null player"); + Objects.requireNonNull(playTo, "Cannot play note to null entity"); + + Validate.isTrue(ascendLevel > 0, "Note ascend level cannot be lower than 1"); + Validate.isTrue(ascendLevel <= 7, "Note ascend level cannot be greater than 7"); + Validate.isTrue(delay > 0, "Delay ticks must be at least 1"); + + new BukkitRunnable() { + int repeating = ascendLevel; + + @Override + public void run() { + player.playNote(playTo.getLocation(), instrument, Note.natural(1, Note.Tone.values()[ascendLevel - repeating])); + if (repeating-- == 0) cancel(); + } + }.runTaskTimerAsynchronously(plugin, 0, delay); + } + + /** + * Stops playing the specified sound from the player. + * + * @param player the player to stop playing the sound to. + * @see #stopMusic(Player) + * @since 2.0.0 + */ + public void stopSound(@Nonnull Player player) { + Objects.requireNonNull(player, "Cannot stop playing sound from null player"); + + Sound sound = this.parseSound(); + if (sound != null) player.stopSound(sound); + } + + /** + * Plays a normal sound to an entity. + * + * @param entity the entity to play the sound to. + * @since 1.0.0 + */ + public void playSound(@Nonnull Entity entity) { + playSound(entity, 1.0f, 1.0f); + } + + /** + * Plays a sound to an entity with the given volume and pitch. + * + * @param entity the entity to play the sound to. + * @param volume the volume of the sound, 1 is normal. + * @param pitch the pitch of the sound, 0 is normal. + * @since 1.0.0 + */ + public void playSound(@Nonnull Entity entity, float volume, float pitch) { + Objects.requireNonNull(entity, "Cannot play sound to a null entity"); + playSound(entity.getLocation(), volume, pitch); + } + + /** + * Plays a normal sound in a location. + * + * @param location the location to play the sound in. + * @since 2.0.0 + */ + public void playSound(@Nonnull Location location) { + playSound(location, 1.0f, 1.0f); + } + + /** + * Plays a sound in a location with the given volume and pitch. + * + * @param location the location to play this sound. + * @param volume the volume of the sound, 1 is normal. + * @param pitch the pitch of the sound, 0 is normal. + * @since 2.0.0 + */ + public void playSound(@Nonnull Location location, float volume, float pitch) { + Objects.requireNonNull(location, "Cannot play sound to null location"); + Sound sound = this.parseSound(); + + Validate.isTrue(sound != null, "Unsupported sound type: ", this.name()); + location.getWorld().playSound(location, sound, volume, pitch); + } +}