From a102bcaf7fb5b3d999efc2ba6079137db3632b0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9D=8F=E9=BB=91?= Date: Sun, 18 Aug 2019 00:38:45 +0800 Subject: [PATCH] update 5.03 --- build.gradle | 2 +- .../scala/io/izzel/taboolib/PluginLoader.java | 8 +- .../io/izzel/taboolib/TabooLibLoader.java | 83 +- .../common/plugin/InternalPluginBridge.java | 4 + .../common/plugin/bridge/BridgeImpl.java | 15 + .../io/izzel/taboolib/cronus/CronusUtils.java | 8 + .../taboolib/cronus/util/StringNumber.java | 61 +- .../izzel/taboolib/module/config/TConfig.java | 12 + .../taboolib/module/db/local/LocalLoader.java | 8 +- .../module/inject/PlayerContainerLoader.java | 2 +- .../izzel/taboolib/module/inject/THook.java | 15 + .../taboolib/module/inject/THookLoader.java | 22 + .../izzel/taboolib/module/inject/TInject.java | 18 + .../module/inject/TInjectCreator.java | 156 ++ .../taboolib/module/inject/TInjectHelper.java | 26 + .../taboolib/module/inject/TInjectLoader.java | 58 +- .../taboolib/module/inject/TInjectTask.java | 2 +- .../module/inject/TScheduleLoader.java | 6 +- .../izzel/taboolib/module/locale/TLocale.java | 38 + .../izzel/taboolib/util/lite/Materials.java | 1582 +++++++++++++++++ .../io/izzel/taboolib/util/lite/Vectors.java | 86 + 21 files changed, 2107 insertions(+), 105 deletions(-) create mode 100644 src/main/scala/io/izzel/taboolib/module/inject/THook.java create mode 100644 src/main/scala/io/izzel/taboolib/module/inject/THookLoader.java create mode 100644 src/main/scala/io/izzel/taboolib/module/inject/TInjectCreator.java create mode 100644 src/main/scala/io/izzel/taboolib/module/inject/TInjectHelper.java create mode 100644 src/main/scala/io/izzel/taboolib/util/lite/Materials.java create mode 100644 src/main/scala/io/izzel/taboolib/util/lite/Vectors.java diff --git a/build.gradle b/build.gradle index b3ff759..2a411f8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id 'com.github.johnrengelman.shadow' version '4.0.4' } group = 'me.skymc' -version = '5.02' +version = '5.03' sourceCompatibility = 1.8 targetCompatibility = 1.8 diff --git a/src/main/scala/io/izzel/taboolib/PluginLoader.java b/src/main/scala/io/izzel/taboolib/PluginLoader.java index c12ded2..5f4a72f 100644 --- a/src/main/scala/io/izzel/taboolib/PluginLoader.java +++ b/src/main/scala/io/izzel/taboolib/PluginLoader.java @@ -40,7 +40,7 @@ public abstract class PluginLoader { // 读取插件类 TabooLibLoader.setupClasses(plugin); // 加载插件类 - TabooLibLoader.getPluginClassSafely(plugin).forEach(c -> TabooLibLoader.preLoadClass(plugin, c)); + TabooLibLoader.preLoadClass(plugin, TabooLibLoader.getPluginClassSafely(plugin)); } @Override @@ -48,7 +48,7 @@ public abstract class PluginLoader { // 加载监听器 TListenerHandler.setupListener(plugin); // 加载插件类 - TabooLibLoader.getPluginClassSafely(plugin).forEach(c -> TabooLibLoader.postLoadClass(plugin, c)); + TabooLibLoader.postLoadClass(plugin, TabooLibLoader.getPluginClassSafely(plugin)); // 注册插件命令 TCommandHandler.registerCommand(plugin); } @@ -57,6 +57,8 @@ public abstract class PluginLoader { public void onActivated(Plugin plugin) { // 注册监听器 TListenerHandler.registerListener(plugin); + // 加载插件类 + TabooLibLoader.activeLoadClass(plugin, TabooLibLoader.getPluginClassSafely(plugin)); // 注册调度器 TScheduleLoader.run(plugin); } @@ -71,7 +73,7 @@ public abstract class PluginLoader { // 注销监听器 TListenerHandler.cancelListener(plugin); // 注销插件类 - TabooLibLoader.getPluginClassSafely(plugin).forEach(c -> TabooLibLoader.unloadClass(plugin, c)); + TabooLibLoader.unloadClass(plugin, TabooLibLoader.getPluginClassSafely(plugin)); // 释放文检读取 Optional.ofNullable(TConfig.getFiles().remove(plugin.getName())).ifPresent(files -> files.forEach(file -> TConfigWatcher.getInst().removeListener(file))); // 注销数据库连接 diff --git a/src/main/scala/io/izzel/taboolib/TabooLibLoader.java b/src/main/scala/io/izzel/taboolib/TabooLibLoader.java index 8058c8a..d51546d 100644 --- a/src/main/scala/io/izzel/taboolib/TabooLibLoader.java +++ b/src/main/scala/io/izzel/taboolib/TabooLibLoader.java @@ -26,6 +26,8 @@ public class TabooLibLoader { static Map> pluginClasses = Maps.newHashMap(); static List loaders = Lists.newArrayList(); + static List runnables = Lists.newArrayList(); + static boolean started; static void init() { // 加载依赖 @@ -58,6 +60,14 @@ public class TabooLibLoader { return classes == null ? new ArrayList<>() : new ArrayList<>(classes); } + public static void runTask(Runnable runnable) { + if (started) { + runnable.run(); + } else { + runnables.add(runnable); + } + } + static boolean isLoader(Class pluginClass) { return !Loader.class.equals(pluginClass) && Loader.class.isAssignableFrom(pluginClass); } @@ -71,6 +81,15 @@ public class TabooLibLoader { } // 通讯网络客户端 TabooLibClient.init(); + // 执行动作 + for (Runnable runnable : runnables) { + try { + runnable.run(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + started = true; } static void setupClasses(Plugin plugin) { @@ -92,48 +111,70 @@ public class TabooLibLoader { } } - static void preLoadClass(Plugin plugin, Class loadClass) { + static void preLoadClass(Plugin plugin, List loadClass) { loaders.forEach(loader -> { - try { - loader.preLoad(plugin, loadClass); - } catch (NoClassDefFoundError ignore) { - } catch (Throwable e) { - e.printStackTrace(); + for (Class pluginClass : loadClass) { + try { + loader.preLoad(plugin, pluginClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } } }); } - static void postLoadClass(Plugin plugin, Class loadClass) { + static void postLoadClass(Plugin plugin, List loadClass) { loaders.forEach(loader -> { - try { - loader.postLoad(plugin, loadClass); - } catch (NoClassDefFoundError ignore) { - } catch (Throwable e) { - e.printStackTrace(); + for (Class pluginClass : loadClass) { + try { + loader.postLoad(plugin, pluginClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } } }); } - static void unloadClass(Plugin plugin, Class loadClass) { + static void activeLoadClass(Plugin plugin, List loadClass) { loaders.forEach(loader -> { - try { - loader.unload(plugin, loadClass); - } catch (NoClassDefFoundError ignore) { - } catch (Throwable e) { - e.printStackTrace(); + for (Class pluginClass : loadClass) { + try { + loader.activeLoad(plugin, pluginClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } + } + }); + } + + static void unloadClass(Plugin plugin, List loadClass) { + loaders.forEach(loader -> { + for (Class pluginClass : loadClass) { + try { + loader.unload(plugin, pluginClass); + } catch (NoClassDefFoundError ignore) { + } catch (Throwable e) { + e.printStackTrace(); + } } }); } public interface Loader { - default void preLoad(org.bukkit.plugin.Plugin plugin, Class loadClass) { + default void preLoad(org.bukkit.plugin.Plugin plugin, Class pluginClass) { } - default void postLoad(org.bukkit.plugin.Plugin plugin, Class loadClass) { + default void postLoad(org.bukkit.plugin.Plugin plugin, Class pluginClass) { } - default void unload(Plugin plugin, Class cancelClass) { + default void activeLoad(org.bukkit.plugin.Plugin plugin, Class pluginClass) { + } + + default void unload(Plugin plugin, Class pluginClass) { } default int priority() { diff --git a/src/main/scala/io/izzel/taboolib/common/plugin/InternalPluginBridge.java b/src/main/scala/io/izzel/taboolib/common/plugin/InternalPluginBridge.java index 5e45571..cef32aa 100644 --- a/src/main/scala/io/izzel/taboolib/common/plugin/InternalPluginBridge.java +++ b/src/main/scala/io/izzel/taboolib/common/plugin/InternalPluginBridge.java @@ -66,6 +66,10 @@ public abstract class InternalPluginBridge { abstract public boolean worldguardHooked(); + abstract public boolean isPlaceholderExpansion(Class pluginClass); + + abstract public void registerExpansion(Class pluginClass); + abstract public Map taboolibTLocaleSerialize(Object in); abstract public FileConfiguration taboolibGetPlayerData(String username); diff --git a/src/main/scala/io/izzel/taboolib/common/plugin/bridge/BridgeImpl.java b/src/main/scala/io/izzel/taboolib/common/plugin/bridge/BridgeImpl.java index ff659be..099afc0 100644 --- a/src/main/scala/io/izzel/taboolib/common/plugin/bridge/BridgeImpl.java +++ b/src/main/scala/io/izzel/taboolib/common/plugin/bridge/BridgeImpl.java @@ -9,6 +9,7 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import io.izzel.taboolib.common.plugin.InternalPluginBridge; import io.izzel.taboolib.util.Reflection; import me.clip.placeholderapi.PlaceholderAPI; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; import me.skymc.taboolib.database.PlayerDataManager; import me.skymc.taboolib.sound.SoundPack; import net.milkbowl.vault.economy.Economy; @@ -161,6 +162,20 @@ public class BridgeImpl extends InternalPluginBridge { return worldguard; } + @Override + public boolean isPlaceholderExpansion(Class pluginClass) { + return PlaceholderExpansion.class.isAssignableFrom(pluginClass); + } + + @Override + public void registerExpansion(Class pluginClass) { + try { + ((PlaceholderExpansion) pluginClass.newInstance()).register(); + } catch (Throwable t) { + t.printStackTrace(); + } + } + @Override public Map taboolibTLocaleSerialize(Object in) { switch (in.getClass().getSimpleName()) { diff --git a/src/main/scala/io/izzel/taboolib/cronus/CronusUtils.java b/src/main/scala/io/izzel/taboolib/cronus/CronusUtils.java index 901c2c9..e5d8710 100644 --- a/src/main/scala/io/izzel/taboolib/cronus/CronusUtils.java +++ b/src/main/scala/io/izzel/taboolib/cronus/CronusUtils.java @@ -30,10 +30,18 @@ public class CronusUtils { return player.getItemInHand().getType() == material ? player.getItemInHand() : player.getInventory().getItemInOffHand(); } + public static Object parseInt(double in) { + return isInt(in) ? (int) in : in; + } + public static boolean next(int page, int size, int entry) { return size / (double) entry > page + 1; } + public static boolean isInt(double in) { + return NumberConversions.toInt(in) == in; + } + public static boolean isInt(String in) { try { Integer.parseInt(in); diff --git a/src/main/scala/io/izzel/taboolib/cronus/util/StringNumber.java b/src/main/scala/io/izzel/taboolib/cronus/util/StringNumber.java index e0a4c09..1de35b7 100644 --- a/src/main/scala/io/izzel/taboolib/cronus/util/StringNumber.java +++ b/src/main/scala/io/izzel/taboolib/cronus/util/StringNumber.java @@ -1,5 +1,7 @@ package io.izzel.taboolib.cronus.util; +import io.izzel.taboolib.cronus.CronusUtils; + /** * @Author 坏黑 * @Since 2019-05-29 21:43 @@ -23,30 +25,21 @@ public class StringNumber { public StringNumber(String source) { this.source = source; try { - number = Long.valueOf(source); - type = NumberType.INT; + this.number = Double.parseDouble(this.source); + this.type = CronusUtils.isInt(this.number.doubleValue()) ? NumberType.INT : NumberType.DOUBLE; } catch (Throwable ignored) { - try { - number = Double.valueOf(source); - type = NumberType.DOUBLE; - } catch (Throwable ignored2) { - type = NumberType.STRING; - } + this.type = NumberType.STRING; } } public StringNumber add(String v) { StringNumber numberFormat = new StringNumber(v); if (isNumber() && numberFormat.isNumber()) { - if (type == NumberType.INT && numberFormat.getType() == NumberType.INT) { - number = number.longValue() + numberFormat.getNumber().longValue(); - } else { - number = number.doubleValue() + numberFormat.getNumber().doubleValue(); - type = NumberType.DOUBLE; - } + this.number = this.number.doubleValue() + numberFormat.getNumber().doubleValue(); + this.type = CronusUtils.isInt(this.number.doubleValue()) ? NumberType.INT : NumberType.DOUBLE; } else { - source += numberFormat.getSource(); - type = NumberType.STRING; + this.source += numberFormat.getSource(); + this.type = NumberType.STRING; } return this; } @@ -54,39 +47,8 @@ public class StringNumber { public StringNumber subtract(String v) { StringNumber numberFormat = new StringNumber(v); if (isNumber() && numberFormat.isNumber()) { - if (type == NumberType.INT && numberFormat.getType() == NumberType.INT) { - number = number.longValue() - numberFormat.getNumber().longValue(); - } else { - number = number.doubleValue() - numberFormat.getNumber().doubleValue(); - type = NumberType.DOUBLE; - } - } - return this; - } - - public StringNumber multiply(String v) { - StringNumber numberFormat = new StringNumber(v); - if (isNumber() && numberFormat.isNumber()) { - if (type == NumberType.INT && numberFormat.getType() == NumberType.INT) { - number = number.longValue() * numberFormat.getNumber().longValue(); - } else { - number = number.doubleValue() * numberFormat.getNumber().doubleValue(); - type = NumberType.DOUBLE; - } - } - return this; - } - - public StringNumber division(String v) { - StringNumber numberFormat = new StringNumber(v); - if (isNumber() && numberFormat.isNumber()) { - if (type == NumberType.INT && numberFormat.getType() == NumberType.INT) { - number = number.longValue() / numberFormat.getNumber().longValue(); - } else { - number = number.doubleValue() / numberFormat.getNumber().doubleValue(); - type = NumberType.DOUBLE; - } - + this.number = this.number.doubleValue() - numberFormat.getNumber().doubleValue(); + this.type = CronusUtils.isInt(this.number.doubleValue()) ? NumberType.INT : NumberType.DOUBLE; } return this; } @@ -121,7 +83,6 @@ public class StringNumber { public enum NumberType { DOUBLE, INT, STRING - } @Override 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 db84d0d..fd1df4d 100644 --- a/src/main/scala/io/izzel/taboolib/module/config/TConfig.java +++ b/src/main/scala/io/izzel/taboolib/module/config/TConfig.java @@ -81,6 +81,14 @@ public class TConfig extends YamlConfiguration { } } + public void saveToFile() { + try { + save(file); + } catch (Throwable t) { + t.printStackTrace(); + } + } + // ********************************* // // Getter and Setter @@ -91,6 +99,10 @@ public class TConfig extends YamlConfiguration { return file; } + public Runnable getListener() { + return runnable; + } + public TConfig listener(Runnable runnable) { this.runnable = runnable; return this; diff --git a/src/main/scala/io/izzel/taboolib/module/db/local/LocalLoader.java b/src/main/scala/io/izzel/taboolib/module/db/local/LocalLoader.java index 940e37e..ed17b8c 100644 --- a/src/main/scala/io/izzel/taboolib/module/db/local/LocalLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/db/local/LocalLoader.java @@ -14,8 +14,8 @@ import java.lang.reflect.Modifier; public class LocalLoader implements TabooLibLoader.Loader { @Override - public void preLoad(Plugin plugin, Class loadClass) { - for (Field field : loadClass.getDeclaredFields()) { + public void preLoad(Plugin plugin, Class pluginClass) { + for (Field field : pluginClass.getDeclaredFields()) { LocalFile annotation = field.getAnnotation(LocalFile.class); if (annotation == null) { continue; @@ -24,10 +24,10 @@ public class LocalLoader implements TabooLibLoader.Loader { // 如果是非静态类型 if (!Modifier.isStatic(field.getModifiers())) { // 是否为主类 - if (loadClass.equals(plugin.getClass())) { + if (pluginClass.equals(plugin.getClass())) { instance = plugin; } else { - TLogger.getGlobalLogger().error(field.getName() + " is not a static field. (" + loadClass.getName() + ")"); + TLogger.getGlobalLogger().error(field.getName() + " is not a static field. (" + pluginClass.getName() + ")"); continue; } } diff --git a/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java index 7fff410..718dedb 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/PlayerContainerLoader.java @@ -40,7 +40,7 @@ public class PlayerContainerLoader implements Listener, TabooLibLoader.Loader { } @Override - public void unload(Plugin plugin, Class cancelClass) { + public void unload(Plugin plugin, Class pluginClass) { pluginContainer.remove(plugin.getName()); } diff --git a/src/main/scala/io/izzel/taboolib/module/inject/THook.java b/src/main/scala/io/izzel/taboolib/module/inject/THook.java new file mode 100644 index 0000000..e826801 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/inject/THook.java @@ -0,0 +1,15 @@ +package io.izzel.taboolib.module.inject; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @Author sky + * @Since 2018-08-22 13:41 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface THook { +} \ No newline at end of file diff --git a/src/main/scala/io/izzel/taboolib/module/inject/THookLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/THookLoader.java new file mode 100644 index 0000000..8ce4692 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/inject/THookLoader.java @@ -0,0 +1,22 @@ +package io.izzel.taboolib.module.inject; + +import io.izzel.taboolib.TabooLibAPI; +import io.izzel.taboolib.TabooLibLoader; +import org.bukkit.plugin.Plugin; + +/** + * @Author sky + * @Since 2019-08-17 22:32 + */ +public class THookLoader implements TabooLibLoader.Loader { + + @Override + public void activeLoad(Plugin plugin, Class pluginClass) { + if (pluginClass.isAnnotationPresent(THook.class)) { + // PlaceholderAPI + if (TabooLibAPI.getPluginBridge().placeholderHooked() && TabooLibAPI.getPluginBridge().isPlaceholderExpansion(pluginClass)) { + TabooLibAPI.getPluginBridge().registerExpansion(pluginClass); + } + } + } +} 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 08b617e..0d1afd7 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TInject.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInject.java @@ -15,4 +15,22 @@ public @interface TInject { String[] value() default {}; + String asm() default ""; + + String load() default ""; + + String init() default ""; + + String active() default ""; + + String cancel() default ""; + + String reload() default ""; + + State state() default State.NONE; + + enum State { + + LOADING, STARTING, ACTIVATED, NONE + } } \ No newline at end of file diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TInjectCreator.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectCreator.java new file mode 100644 index 0000000..a74427c --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectCreator.java @@ -0,0 +1,156 @@ +package io.izzel.taboolib.module.inject; + +import com.google.common.collect.Maps; +import io.izzel.taboolib.TabooLibLoader; +import io.izzel.taboolib.module.locale.logger.TLogger; +import io.izzel.taboolib.util.Reflection; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.Objects; + +/** + * @Author sky + * @Since 2019-08-17 22:50 + */ +public class TInjectCreator implements TabooLibLoader.Loader { + + private static Map instanceMap = Maps.newHashMap(); + + @Override + public int priority() { + return 999; + } + + @Override + public void preLoad(Plugin plugin, Class pluginClass) { + instance(plugin, pluginClass, TInject.State.LOADING); + eval(pluginClass, TInjectHelper.State.PRE); + } + + @Override + public void postLoad(Plugin plugin, Class pluginClass) { + instance(plugin, pluginClass, TInject.State.STARTING); + eval(pluginClass, TInjectHelper.State.POST); + } + + @Override + public void activeLoad(Plugin plugin, Class pluginClass) { + instance(plugin, pluginClass, TInject.State.ACTIVATED); + eval(pluginClass, TInjectHelper.State.ACTIVE); + } + + @Override + public void unload(Plugin plugin, Class pluginClass) { + eval(pluginClass, TInjectHelper.State.CANCEL); + } + + public void instance(Plugin plugin, Class loadClass, TInject.State state) { + for (Field declaredField : loadClass.getDeclaredFields()) { + TInject annotation = declaredField.getAnnotation(TInject.class); + if (annotation == null || annotation.state() != state) { + continue; + } + ClassData classData = new ClassData(loadClass, declaredField.getType()); + Object instance = null; + // 非静态类型 + if (!Modifier.isStatic(declaredField.getModifiers())) { + // 在插件主类 + if (loadClass.equals(plugin.getClass())) { + instance = plugin; + } + // 判断 pluginCLass 是否为 TInject 创建 + else if (instanceMap.containsKey(classData)) { + instance = instanceMap.get(classData).getInstance(); + } else { + TLogger.getGlobalLogger().error(declaredField.getName() + " is not a static field. (" + loadClass.getName() + ")"); + continue; + } + } + declaredField.setAccessible(true); + try { + InstanceData instanceData = new InstanceData(declaredField.getType().newInstance(), annotation); + declaredField.set(instance, instanceData.getInstance()); + instanceMap.put(classData, instanceData); + } catch (Throwable t) { + TLogger.getGlobalLogger().error(declaredField.getName() + " instantiation failed: " + t.getMessage()); + } + } + } + + public void eval(Class loadClass, TInjectHelper.State state) { + for (Map.Entry entry : instanceMap.entrySet()) { + if (entry.getKey().getParent().equals(loadClass) && !TInjectHelper.fromState(entry.getValue().getInject(), state).isEmpty()) { + try { + Reflection.invokeMethod(entry.getValue().getInstance(), TInjectHelper.fromState(entry.getValue().getInject(), state)); + } catch (Throwable t) { + t.printStackTrace(); + } + } + } + } + + public static Map getInstanceMap() { + return instanceMap; + } + + /** + * 用于防止多个类使用同一个类型 + */ + public class ClassData { + + private Class parent; + private Class type; + + public ClassData(Class parent, Class type) { + this.parent = parent; + this.type = type; + } + + public Class getParent() { + return parent; + } + + public Class getType() { + return type; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ClassData)) { + return false; + } + ClassData classData = (ClassData) o; + return Objects.equals(getParent(), classData.getParent()) && Objects.equals(getType(), classData.getType()); + } + + @Override + public int hashCode() { + return Objects.hash(getParent(), getType()); + } + } + + public class InstanceData { + + private Object instance; + private TInject inject; + + public InstanceData(Object instance, TInject inject) { + this.instance = instance; + this.inject = inject; + } + + public Object getInstance() { + return instance; + } + + public TInject getInject() { + return inject; + } + } +} diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TInjectHelper.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectHelper.java new file mode 100644 index 0000000..3df82fa --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectHelper.java @@ -0,0 +1,26 @@ +package io.izzel.taboolib.module.inject; + +/** + * @Author sky + * @Since 2019-08-17 23:22 + */ +public class TInjectHelper { + + enum State { + + PRE, POST, ACTIVE, CANCEL + } + + public static String fromState(TInject inject, State state) { + switch (state) { + case PRE: + return inject.load(); + case POST: + return inject.init(); + case ACTIVE: + return inject.active(); + default: + return inject.cancel(); + } + } +} 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 acb4189..79f49aa 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectLoader.java @@ -13,6 +13,7 @@ import io.izzel.taboolib.util.lite.cooldown.Cooldowns; import org.bukkit.plugin.Plugin; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Map; @@ -26,7 +27,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { static { // Instance Inject - injectTypes.put(Plugin.class, (plugin, field, args, instance) -> { + injectTypes.put(Plugin.class, (plugin, field, args, pluginClass, instance) -> { try { field.set(instance, plugin); } catch (Exception e) { @@ -34,15 +35,15 @@ public class TInjectLoader implements TabooLibLoader.Loader { } }); // TLogger Inject - injectTypes.put(TLogger.class, (plugin, field, args, instance) -> { + injectTypes.put(TLogger.class, (plugin, field, args, pluginClass, instance) -> { try { - field.set(instance, args.length == 0 ? TLogger.getUnformatted(plugin) : TLogger.getUnformatted(args[0])); + field.set(instance, args.value().length == 0 ? TLogger.getUnformatted(plugin) : TLogger.getUnformatted(args.value()[0])); } catch (Exception e) { e.printStackTrace(); } }); // TPacketListener Inject - injectTypes.put(TPacketListener.class, (plugin, field, args, instance) -> { + injectTypes.put(TPacketListener.class, (plugin, field, args, pluginClass, instance) -> { try { TPacketHandler.addListener(plugin, ((TPacketListener) field.get(instance))); } catch (Exception e) { @@ -50,20 +51,35 @@ public class TInjectLoader implements TabooLibLoader.Loader { } }); // TConfiguration Inject - injectTypes.put(TConfig.class, (plugin, field, args, instance) -> { + injectTypes.put(TConfig.class, (plugin, field, args, pluginClass, instance) -> { try { - field.set(instance, TConfig.create(plugin, args.length == 0 ? "config.yml" : args[0])); + TConfig config = TConfig.create(plugin, args.value().length == 0 ? "config.yml" : args.value()[0]); + if (!args.reload().isEmpty()) { + try { + Method declaredMethod = pluginClass.getDeclaredMethod(args.reload()); + declaredMethod.setAccessible(true); + config.listener(() -> { + try { + declaredMethod.invoke(null); + } catch (Throwable t) { + t.printStackTrace(); + } + }); + TabooLibLoader.runTask(config::runListener); + } catch (Throwable t) { + t.printStackTrace(); + } + } + field.set(instance, config); } catch (Exception e) { e.printStackTrace(); } }); // SimpleCommandBuilder Inject - injectTypes.put(CommandBuilder.class, (plugin, field, args, instance) -> { + injectTypes.put(CommandBuilder.class, (plugin, field, args, pluginClass, instance) -> { try { CommandBuilder builder = (CommandBuilder) field.get(instance); - if (builder.isBuild()) { - TLogger.getGlobalLogger().error("Command was registered. (" + field.getType().getName() + ")"); - } else { + if (!builder.isBuild()) { if (builder.getPlugin() == null) { builder.plugin(plugin); } @@ -74,12 +90,12 @@ public class TInjectLoader implements TabooLibLoader.Loader { } }); // CooldownPack Inject - injectTypes.put(Cooldown.class, (plugin, field, args, instance) -> { - try { - Cooldowns.register((Cooldown) field.get(instance), plugin); - } catch (Throwable t) { - t.printStackTrace(); - } + injectTypes.put(Cooldown.class, (plugin, field, args, pluginClass, instance) -> { + try { + Cooldowns.register((Cooldown) field.get(instance), plugin); + } catch (Throwable t) { + t.printStackTrace(); + } }); } @@ -107,7 +123,7 @@ public class TInjectLoader implements TabooLibLoader.Loader { continue; } } - inject(plugin, declaredField, instance, annotation, injectTypes.get(Plugin.class)); + inject(plugin, declaredField, instance, annotation, injectTypes.get(Plugin.class), pluginClass); } } @@ -131,17 +147,17 @@ public class TInjectLoader implements TabooLibLoader.Loader { } TInjectTask tInjectTask = injectTypes.get(declaredField.getType()); if (tInjectTask != null) { - inject(plugin, declaredField, instance, annotation, tInjectTask); - } else { + inject(plugin, declaredField, instance, annotation, tInjectTask, pluginClass); + } else if (annotation.state() == TInject.State.NONE) { TLogger.getGlobalLogger().error(declaredField.getName() + " is an invalid inject type. (" + pluginClass.getName() + ")"); } } } - public void inject(Plugin plugin, Field field, Object instance, TInject annotation, TInjectTask injectTask) { + public void inject(Plugin plugin, Field field, Object instance, TInject annotation, TInjectTask injectTask, Class pluginClass) { try { field.setAccessible(true); - injectTask.run(plugin, field, annotation.value(), instance); + injectTask.run(plugin, field, annotation, pluginClass, instance); TabooLibAPI.debug(field.getName() + " injected. (" + field.getType().getName() + ")"); } catch (Throwable e) { TLogger.getGlobalLogger().error(field.getName() + " inject failed: " + e.getMessage() + " (" + field.getType().getName() + ")"); diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java b/src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java index e0f342a..75fa1a9 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TInjectTask.java @@ -10,6 +10,6 @@ import java.lang.reflect.Field; */ public interface TInjectTask { - void run(Plugin plugin, Field field, String[] args, Object instance); + void run(Plugin plugin, Field field, TInject inject, Class pluginClass, Object instance); } diff --git a/src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java b/src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java index 6775521..104e740 100644 --- a/src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java +++ b/src/main/scala/io/izzel/taboolib/module/inject/TScheduleLoader.java @@ -37,13 +37,13 @@ public class TScheduleLoader implements TabooLibLoader.Loader { } @Override - public void postLoad(Plugin plugin, Class loadClass) { - for (Method method : loadClass.getDeclaredMethods()) { + public void postLoad(Plugin plugin, Class pluginClass) { + for (Method method : pluginClass.getDeclaredMethods()) { TSchedule annotation = method.getAnnotation(TSchedule.class); if (annotation == null) { continue; } - Object instance = loadClass.equals(plugin.getClass()) ? plugin : null; + Object instance = pluginClass.equals(plugin.getClass()) ? plugin : null; // 如果是非静态类型 if (!Modifier.isStatic(method.getModifiers()) && instance == null) { // 是否为主类 diff --git a/src/main/scala/io/izzel/taboolib/module/locale/TLocale.java b/src/main/scala/io/izzel/taboolib/module/locale/TLocale.java index 851bb26..31725b5 100644 --- a/src/main/scala/io/izzel/taboolib/module/locale/TLocale.java +++ b/src/main/scala/io/izzel/taboolib/module/locale/TLocale.java @@ -14,6 +14,7 @@ import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -27,6 +28,10 @@ public class TLocale { throw new AssertionError(); } + static String[] toArray(Object... obj) { + return Arrays.stream(obj).map(String::valueOf).toArray(String[]::new); + } + static void sendTo(String path, CommandSender sender, String[] args, Class callerClass) { TLocaleLoader.sendTo(Ref.getCallerPlugin(callerClass), path, sender, args); } @@ -39,18 +44,40 @@ public class TLocale { return TLocaleLoader.asStringList(Ref.getCallerPlugin(callerClass), path, args); } + public static void sendTo(CommandSender sender, String path, Object... args) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, toArray(args), clazz)); + } + public static void sendTo(CommandSender sender, String path, String... args) { Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, args, clazz)); } + public static void sendToConsole(String path, Object... args) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, Bukkit.getConsoleSender(), toArray(args), clazz)); + } + public static void sendToConsole(String path, String... args) { Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, Bukkit.getConsoleSender(), args, clazz)); } + public static void broadcast(String path, Object... args) { + Ref.getCallerClass(3).ifPresent(clazz -> Bukkit.getOnlinePlayers().forEach(player -> sendTo(path, player, toArray(args), clazz))); + } + public static void broadcast(String path, String... args) { Ref.getCallerClass(3).ifPresent(clazz -> Bukkit.getOnlinePlayers().forEach(player -> sendTo(path, player, args, clazz))); } + public static String asString(String path, Object... args) { + try { + return asString(path, Ref.getCallerClass(3).orElse(TabooLib.class), toArray(args)); + } catch (Exception e) { + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("FETCH-LOCALE-ERROR"), path)); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("LOCALE-ERROR-REASON"), e.getMessage())); + return "§4<" + path + "§4>"; + } + } + public static String asString(String path, String... args) { try { return asString(path, Ref.getCallerClass(3).orElse(TabooLib.class), args); @@ -61,10 +88,21 @@ public class TLocale { } } + public static List asStringList(String path, Object... args) { + try { + return asStringList(path, Ref.getCallerClass(3).orElse(TabooLib.class), toArray(args)); + } catch (Exception e) { + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("FETCH-LOCALE-ERROR"), path)); + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("LOCALE-ERROR-REASON"), e.getMessage())); + return Collections.singletonList("§4<" + path + "§4>"); + } + } + public static List asStringList(String path, String... args) { try { return asStringList(path, Ref.getCallerClass(3).orElse(TabooLib.class), args); } catch (Exception e) { + TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("FETCH-LOCALE-ERROR"), path)); TabooLib.getLogger().error(Strings.replaceWithOrder(TabooLib.getInst().getInternal().getString("LOCALE-ERROR-REASON"), e.getMessage())); return Collections.singletonList("§4<" + path + "§4>"); } diff --git a/src/main/scala/io/izzel/taboolib/util/lite/Materials.java b/src/main/scala/io/izzel/taboolib/util/lite/Materials.java new file mode 100644 index 0000000..d776edb --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/util/lite/Materials.java @@ -0,0 +1,1582 @@ +/* + * The MIT License (MIT) + * + * Original work Copyright (c) 2018 Hex_27 + * v2.0 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. + */ + +package io.izzel.taboolib.util.lite; + +import org.apache.commons.lang.Validate; +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 java.util.regex.Pattern; + +/** + * @author CryptoMorin + */ +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_PLANKS(4, "WOOD"), + ACACIA_PRESSURE_PLATE(0, "WOOD_PLATE"), + ACACIA_SAPLING(4, "SAPLING"), + ACACIA_SIGN(0, "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, ""), + 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, ""), + 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, ""), + 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, ""), + BIRCH_LEAVES(2, "LEAVES"), + BIRCH_LOG(2, "LOG"), + BIRCH_PLANKS(2, "WOOD"), + BIRCH_PRESSURE_PLATE(0, "WOOD_PLATE"), + BIRCH_SAPLING(2, "SAPLING"), + BIRCH_SIGN(0, "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_WOOD(2, "LOG"), + BLACK_BANNER(0, "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_GLAZED_TERRACOTTA(15, "1.12", "HARD_CLAY", "STAINED_CLAY", "BLACK_TERRACOTTA"), + BLACK_SHULKER_BOX(0, ""), + 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_WOOL(15, "WOOL"), + BLAST_FURNACE(0, "1.14", "FURNACE"), + BLAZE_POWDER(0, ""), + BLAZE_ROD(0, ""), + BLAZE_SPAWN_EGG(61, "MONSTER_EGG"), + BLUE_BANNER(11, "BANNER", "STANDING_BANNER"), + BLUE_BED(4, "BED", "BED_BLOCK"), + BLUE_CARPET(11, "CARPET"), + BLUE_CONCRETE(11, "CONCRETE"), + 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_ORCHID(1, "RED_ROSE"), + BLUE_SHULKER_BOX(0, ""), + 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_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"), + BRICK_SLAB(4, "STEP"), + BRICK_STAIRS(0, ""), + BRICK_WALL(0, ""), + 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_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_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"), + 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"), + CHARCOAL(1, "COAL"), + CHEST(0, "LOCKED_CHEST"), + CHEST_MINECART(0, "STORAGE_MINECART"), + CHICKEN(0, "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, ""), + COARSE_DIRT(1, "DIRT"), + COBBLESTONE(0, ""), + COBBLESTONE_SLAB(3, "STEP"), + COBBLESTONE_STAIRS(0, ""), + COBBLESTONE_WALL(0, "COBBLE_WALL"), + COBWEB(0, "WEB"), + 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, ""), + COOKED_SALMON(1, "COOKED_FISH"), + COOKIE(0, ""), + 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, ""), + 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"), + CYAN_BANNER(6, "BANNER", "STANDING_BANNER"), + CYAN_BED(9, "BED", "BED_BLOCK"), + CYAN_CARPET(9, "CARPET"), + CYAN_CONCRETE(9, "CONCRETE"), + 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_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, ""), + 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_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_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"), + DONKEY_SPAWN_EGG(32, "MONSTER_EGG"), + DRAGON_BREATH(0, "DRAGONS_BREATH"), + DRAGON_EGG(0, ""), + 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, ""), + ELDER_GUARDIAN_SPAWN_EGG(4, "MONSTER_EGG"), + ELYTRA(0, ""), + EMERALD(0, ""), + EMERALD_BLOCK(0, ""), + EMERALD_ORE(0, ""), + ENCHANTED_BOOK(0, ""), + ENCHANTED_GOLDEN_APPLE(1, "GOLDEN_APPLE"), + ENCHANTING_TABLE(0, "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"), + END_STONE_BRICK_SLAB(4, "STEP"), + END_STONE_BRICK_STAIRS(0, "SMOOTH_STAIRS"), + END_STONE_BRICK_WALL(0, ""), + EVOKER_SPAWN_EGG(34, "MONSTER_EGG"), + EXPERIENCE_BOTTLE(0, "EXP_BOTTLE"), + FARMLAND(0, "SOIL"), + FEATHER(0, ""), + FERMENTED_SPIDER_EYE(0, ""), + 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"), + 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, ""), + GRAY_BANNER(8, "BANNER", "STANDING_BANNER"), + GRAY_BED(7, "BED", "BED_BLOCK"), + GRAY_CARPET(7, "CARPET"), + GRAY_CONCRETE(7, "CONCRETE"), + 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_STAINED_GLASS_PANE(7, "THIN_GLASS", "STAINED_GLASS_PANE"), + GRAY_TERRACOTTA(7, "HARD_CLAY", "STAINED_CLAY"), + GRAY_WALL_BANNER(8, "WALL_BANNER"), + GRAY_WOOL(8, "WOOL"), + GREEN_BANNER(2, "BANNER", "STANDING_BANNER"), + GREEN_BED(13, "BED", "BED_BLOCK"), + GREEN_CARPET(13, "CARPET"), + GREEN_CONCRETE(13, "CONCRETE"), + 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_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"), + 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, ""), + HORSE_SPAWN_EGG(100, "MONSTER_EGG"), + HUSK_SPAWN_EGG(23, "MONSTER_EGG"), + ICE(0, ""), + 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_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, ""), + JUNGLE_LEAVES(3, "LEAVES"), + JUNGLE_LOG(3, "LOG"), + JUNGLE_PLANKS(3, "WOOD"), + JUNGLE_PRESSURE_PLATE(0, "WOOD_PLATE"), + JUNGLE_SAPLING(3, "SAPLING"), + JUNGLE_SIGN(0, "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_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, ""), + LAPIS_LAZULI(4, "INK_SACK"), + LAPIS_ORE(0, ""), + 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"), + 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_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_GRAY_BANNER(7, "BANNER", "STANDING_BANNER"), + LIGHT_GRAY_BED(7, "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_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"), + LILAC(1, "DOUBLE_PLANT"), + LILY_OF_THE_VALLEY(15, "1.14", "WHITE_DYE"), + LILY_PAD(0, "WATER_LILY"), + LIME_BANNER(10, "BANNER", "STANDING_BANNER"), + LIME_BED(5, "BED", "BED_BLOCK"), + LIME_CARPET(5, "CARPET"), + LIME_CONCRETE(5, "CONCRETE"), + 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_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, ""), + LLAMA_SPAWN_EGG(103, "MONSTER_EGG"), + LOOM(0, "1.14"), + MAGENTA_BANNER(13, "BANNER", "STANDING_BANNER"), + MAGENTA_BED(2, "BED", "BED_BLOCK"), + MAGENTA_CARPET(2, "CARPET"), + MAGENTA_CONCRETE(2, "CONCRETE"), + 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_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_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, ""), + MOOSHROOM_SPAWN_EGG(96, "MONSTER_EGG"), + MOSSY_COBBLESTONE(0, ""), + MOSSY_COBBLESTONE_SLAB(3, "STEP"), + MOSSY_COBBLESTONE_STAIRS(0, ""), + 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"), + 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"), + 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, ""), + OCELOT_SPAWN_EGG(98, "MONSTER_EGG"), + ORANGE_BANNER(14, "BANNER", "STANDING_BANNER"), + ORANGE_BED(1, "BED", "BED_BLOCK"), + ORANGE_CARPET(1, "CARPET"), + ORANGE_CONCRETE(1, "CONCRETE"), + 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_STAINED_GLASS(1, "STAINED_GLASS"), + ORANGE_STAINED_GLASS_PANE(1, "STAINED_GLASS_PANE"), + ORANGE_TERRACOTTA(1, "HARD_CLAY", "STAINED_CLAY"), + ORANGE_TULIP(5, "RED_ROSE"), + 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, ""), + 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"), + PIG_SPAWN_EGG(90, "MONSTER_EGG"), + PILLAGER_SPAWN_EGG(0, "1.14"), + PINK_BANNER(9, "BANNER", "STANDING_BANNER"), + PINK_BED(6, "BED", "BED_BLOCK"), + PINK_CARPET(6, "CARPET"), + PINK_CONCRETE(6, "CONCRETE"), + 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_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"), + PLAYER_WALL_HEAD(3, "SKULL", "SKULL_ITEM"), + PODZOL(2, "DIRT"), + POISONOUS_POTATO(0, ""), + 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, ""), + 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_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_DARK_OAK_SAPLING(5, "SAPLING", "FLOWER_POT"), + POTTED_DEAD_BUSH(0, "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_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_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, ""), + 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, ""), + 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, ""), + PURPLE_BANNER(5, "BANNER", "STANDING_BANNER"), + PURPLE_BED(10, "BED", "BED_BLOCK"), + PURPLE_CARPET(10, "CARPET"), + PURPLE_CONCRETE(10, "CONCRETE"), + 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_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, ""), + QUARTZ_PILLAR(2, "QUARTZ_BLOCK"), + QUARTZ_SLAB(7, "STEP"), + QUARTZ_STAIRS(0, ""), + RABBIT(0, ""), + RABBIT_FOOT(0, ""), + RABBIT_HIDE(0, ""), + 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"), + REDSTONE_WALL_TORCH(1, "REDSTONE_TORCH_ON", "REDSTONE_TORCH_OFF"), + REDSTONE_WIRE(0, ""), + RED_BANNER(1, "BANNER", "STANDING_BANNER"), + RED_BED(14, "BED", "BED_BLOCK"), + RED_CARPET(14, "CARPET"), + RED_CONCRETE(14, "CONCRETE"), + RED_CONCRETE_POWDER(14, "CONCRETE_POWDER"), + RED_DYE(1, "ROSE_RED"), + RED_GLAZED_TERRACOTTA(14, "1.12", "HARD_CLAY", "STAINED_CLAY", "RED_TERRACOTTA"), + RED_MUSHROOM(0, ""), + RED_MUSHROOM_BLOCK(0, "RED_MUSHROOM", "HUGE_MUSHROOM_2"), + RED_NETHER_BRICKS(0, "RED_NETHER_BRICK"), + RED_NETHER_BRICK_SLAB(4, "STEP"), + RED_NETHER_BRICK_STAIRS(0, ""), + RED_NETHER_BRICK_WALL(0, ""), + 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_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"), + ROSE_BUSH(4, "DOUBLE_PLANT"), + ROTTEN_FLESH(0, ""), + SADDLE(0, ""), + SALMON(1, "RAW_FISH"), + SALMON_BUCKET(0, "1.13", "BUCKET", "WATER_BUCKET"), + SALMON_SPAWN_EGG(0, "1.13", "MONSTER_EGG"), + SAND(0, ""), + SANDSTONE(0, ""), + 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, ""), + SHEEP_SPAWN_EGG(91, "MONSTER_EGG"), + SHIELD(0, ""), + SHULKER_BOX(0, "PURPLE_SHULKER_BOX"), + SHULKER_SHELL(0, ""), + 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_SPAWN_EGG(51, "MONSTER_EGG"), + SKELETON_WALL_SKULL(0, "SKULL", "SKULL_ITEM"), + SKULL_BANNER_PATTERN(0, ""), + SLIME_BALL(0, ""), + SLIME_BLOCK(0, ""), + SLIME_SPAWN_EGG(55, "MONSTER_EGG"), + SMITHING_TABLE(0, ""), + SMOKER(0, "1.14", "FURNACE"), + SMOOTH_QUARTZ(0, "1.13"), + SMOOTH_QUARTZ_SLAB(7, "STEP"), + SMOOTH_QUARTZ_STAIRS(0, ""), + SMOOTH_RED_SANDSTONE(2, "RED_SANDSTONE"), + SMOOTH_RED_SANDSTONE_SLAB(0, "STONE_SLAB2"), + SMOOTH_RED_SANDSTONE_STAIRS(0, ""), + 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, ""), + 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, ""), + SPRUCE_LEAVES(1, "LEAVES"), + SPRUCE_LOG(1, "LOG"), + SPRUCE_PLANKS(1, "WOOD"), + SPRUCE_PRESSURE_PLATE(0, "WOOD_PLATE"), + SPRUCE_SAPLING(1, "SAPLING"), + SPRUCE_SIGN(0, "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_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"), + 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, ""), + STRAY_SPAWN_EGG(6, "MONSTER_EGG"), + STRING(0, ""), + STRIPPED_ACACIA_LOG(0, "LOG_2"), + STRIPPED_ACACIA_WOOD(0, "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_JUNGLE_LOG(3, "LOG"), + STRIPPED_JUNGLE_WOOD(3, "LOG"), + STRIPPED_OAK_LOG(0, "LOG"), + STRIPPED_OAK_WOOD(0, "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"), + 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"), + TRADER_LLAMA_SPAWN_EGG(103, "1.14", "MONSTER_EGG"), + TRAPPED_CHEST(0, ""), + TRIDENT(0, "1.13"), + TRIPWIRE(0, ""), + TRIPWIRE_HOOK(0, ""), + 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"), + 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, ""), + WET_SPONGE(1, "SPONGE"), + WHEAT(0, "CROPS"), + WHEAT_SEEDS(0, "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_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_TULIP(6, "RED_ROSE"), + WHITE_WALL_BANNER(15, "WALL_BANNER"), + WHITE_WOOL(0, "WOOL"), + WITCH_SPAWN_EGG(66, "MONSTER_EGG"), + WITHER_ROSE(0, "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, ""), + YELLOW_BANNER(11, "BANNER", "STANDING_BANNER"), + YELLOW_BED(4, "BED", "BED_BLOCK"), + YELLOW_CARPET(4, "CARPET"), + YELLOW_CONCRETE(4, "CONCRETE"), + 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_STAINED_GLASS(4, "STAINED_GLASS"), + YELLOW_STAINED_GLASS_PANE(4, "THIN_GLASS", "STAINED_GLASS_PANE"), + YELLOW_TERRACOTTA(4, "HARD_CLAY", "STAINED_CLAY"), + YELLOW_WALL_BANNER(11, "WALL_BANNER"), + YELLOW_WOOL(4, "WOOL"), + ZOMBIE_HEAD(2, "SKULL", "SKULL_ITEM"), + ZOMBIE_HORSE_SPAWN_EGG(29, "MONSTER_EGG"), + ZOMBIE_PIGMAN_SPAWN_EGG(57, "MONSTER_EGG"), + ZOMBIE_SPAWN_EGG(54, "MONSTER_EGG"), + ZOMBIE_VILLAGER_SPAWN_EGG(27, "MONSTER_EGG"), + ZOMBIE_WALL_HEAD(2, "SKULL", "SKULL_ITEM"); + + + /** + * 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}. + */ + public static final String[] DAMAGEABLE = { + "HELMET", "CHESTPLATE", "LEGGINGS", "BOOTS", + "SWORD", "AXE", "PICKAXE", "SHOVEL", "HOE", + "ELYTRA", "TRIDENT", "HORSE_ARMOR", "BARDING", + "SHEARS", "FLINT_AND_STEEL", "BOW", "FISHING_ROD", + "CARROT_ON_A_STICK", "CARROT_STICK" + }; + /** + * A list of duplicated items in 1.13 and 1.12 with different purpose. + * Values are the new material names. + * Duplicates are only checked by keys not values. + * Checked with {@link String#equals} + */ + 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; + private final String[] legacy; + + Materials(int data, String... legacy) { + this.data = (byte) data; + 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); + } + + public static String[] collectCurrent() { + Material[] values = Material.values(); + return Arrays.stream(values).map(Enum::name).toArray(String[]::new); + } + + /** + * Checks if the version is 1.13 (Aquatic Update) or higher. + * + * @return true if 1.13 or higher. + */ + public static boolean isNewVersion() { + if (isNewVersion != null) { + return isNewVersion; + } + return isNewVersion = isVersionOrHigher(MinecraftVersion.VERSION_1_13); + } + + public static boolean isOneEight() { + return getVersion() == MinecraftVersion.VERSION_1_8; + } + + /** + * Uses newly added materials to minecraft to detect the server version. + * + * @return the current server version. + */ + public static MinecraftVersion getVersion() { + if (version != null) { + return version; + } + return version = valueOfVersion(Bukkit.getVersion()); + } + + /** + * 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. + * + * @see #matchMaterials(String, byte) + */ + private static Materials requestOldMaterials(String name, byte data) { + Materials cached = CACHED_SEARCH.get(name + "," + data); + + if (cached != null) { + return cached; + } + 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. + * + * @param name name of the material + * @return true if Materials enum has this material. + */ + public static boolean contains(String name) { + String formatted = format(name); + return Arrays.stream(Materials.VALUES).anyMatch(mat -> mat.name().equals(formatted)); + } + + /** + * @see #matchMaterials(String, byte) + */ + public static Materials matchMaterials(Material material) { + return matchMaterials(material.name()); + } + + /** + * @see #matchMaterials(String, byte) + */ + 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. + return matchMaterials(name, (byte) -1); + } + + /** + * Matches the argument string and its data with a Materials. + * + * @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.) + */ + public static Materials matchMaterials(String name, byte data) { + Validate.notEmpty(name, "Material name cannot be null or empty"); + 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); + } + + /** + * Gets the Materials based on the Material's ID and data. + * You should avoid using this for performance reasons. + * + * @param id the ID (Magic value) of the material. + * @param data the data of the material. + * @return some Materials, or null. + */ + public static Materials matchMaterials(int id, byte data) { + // Looping through Material.values() will take longer. + return Arrays.stream(Materials.VALUES).filter(mat -> mat.getId() == id && mat.data == data).findFirst().orElse(null); + } + + /** + * This method is temporary. Do not use this. + * 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. + */ + private static Materials requestDuplicatedMaterials(String name, byte data) { + Materials mat = requestOldMaterials(name, data); + return mat == null ? null : mat.name().endsWith("S") ? valueOf(name) : mat; + } + + /** + * Attempts to build the string like an enum name. + * + * @param name the material name to modify. + * @return a Material enum name. + */ + private static String format(String name) { + return name.toUpperCase().replace("MINECRAFT:", "").replace('-', '_').replaceAll("\\s+", "_").replaceAll("\\W", ""); + } + + /** + * Parses the material name if the legacy name has a version attached to it. + * + * @param name the material name to parse. + * @return the material name with the version removed. + */ + private static String parseLegacyVersionMaterialName(String name) { + if (!name.contains("/")) { + return name; + } + return name.substring(0, name.indexOf('/')); + } + + /** + * Checks if the version argument is the same 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. + */ + 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; + } + + /** + * Converts the material's name to a string with the first letter uppercase. + * + * @return a converted string. + */ + public static String toWord(Material material) { + return material.name().charAt(0) + material.name().substring(1).toLowerCase(); + } + + /** + * Compares two major versions. The current server version and the given version. + * + * @param version the version to check. + * @return true if is the same as the current version or higher. + */ + public static boolean isVersionOrHigher(String version) { + int currentVer = Integer.parseInt(getExactMajorVersion(Bukkit.getVersion()).replace(".", "")); + int versionNumber = Integer.parseInt(version.replace(".", "")); + + return currentVer >= versionNumber; + } + + /** + * 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. + */ + public static String getExactMajorVersion(String version) { + // getBukkitVersion() + if (version.contains("SNAPSHOT") || version.contains("-R")) { + 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(".")); + } + return version; + } + + /** + * Parses the string arugment to a version. + * Supports {@link Bukkit#getVersion()}, {@link Bukkit#getBukkitVersion()} and normal formats such as "1.14" + * + * @param version the server version. + * @return the Minecraft version represented by the string. + */ + 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; + } + + /** + * Checks if the material can be damaged from {@link #DAMAGEABLE}. + * + * @param name the name of the material. + * @return true of the material can be damaged. + */ + public static boolean isDamageable(String name) { + return Arrays.stream(DAMAGEABLE).anyMatch(name::contains); + } + + public static boolean isDuplicated(String name) { + String formatted = format(name); + return DUPLICATED.entrySet().stream().anyMatch(x -> x.getKey().name().equals(formatted)); + } + + /** + * 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. + */ + @SuppressWarnings("deprecation") + public int getId() { + return this.isNew() ? -1 : this.parseMaterial().getId(); + } + + public boolean isDuplicated() { + return DUPLICATED.containsKey(this); + } + + /** + * Checks if the given string matches any of this material's legacy material names. + * + * @param name the name to check + * @return true if it's one of the legacy names. + */ + public boolean matchAnyLegacy(String name) { + String formatted = format(name); + return Arrays.asList(this.legacy).contains(formatted); + } + + /** + * @return true if the item can be damaged. + * @see #isDamageable(String) + */ + 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() + * or {@link ItemStack#getDurability()} if not damageable. + * + * @return data of this material. + */ + public int getData() { + return this.data; + } + + /** + * Parses the Materials as an {@link ItemStack}. + * + * @return an ItemStack with the same material (and data if in older versions.) + */ + public ItemStack parseItem() { + return parseItem(false); + } + + /** + * Parses the Materials as an {@link ItemStack}. + * + * @param suggest if true {@link #parseMaterial(boolean)} + * @return an ItemStack with the same material (and data if in older versions.) + */ + @SuppressWarnings("deprecation") + public ItemStack parseItem(boolean suggest) { + Material material = this.parseMaterial(suggest); + return isNewVersion() ? new ItemStack(material) : new ItemStack(material, 1, this.data); + } + + /** + * Parses the Materials as a {@link Material}. + * + * @return the Material related to this Materials based on the server version. + */ + public Material parseMaterial() { + return parseMaterial(false); + } + + /** + * Parses the Materials as a {@link Material}. + * + * @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. + * @see #matchMaterials(String, byte) + */ + public Material parseMaterial(boolean suggest) { + Material newMat = Material.getMaterial(this.name()); + + // 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; + } + return requestOldMaterial(suggest); + } + + /** + * Parses from old material names and can accept suggestions. + * + * @param suggest Accept suggestions for newly added blocks + * @return A parsed Material suitable for this minecraft version. + */ + 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)); + + 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; + } + } + return null; + } + + /** + * Checks if an item is similar to the material and its data (if in 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.) + */ + @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; + } + + /** + * Get the suggested material names that can be used instead of this material. + * + * @return a list of suggested material names. + */ + public String[] getSuggestions() { + if (!this.legacy[0].contains(".")) { + return new String[0]; + } + return Arrays.stream(this.legacy).filter(mat -> !mat.contains(".")).toArray(String[]::new); + } + + /** + * Checks if this material is supported in the current version. + * It'll check both the newest matetrial name and for legacy names. + * + * @return true if the material exists in {@link Material} list. + */ + public boolean isSupported() { + return Arrays.stream(Material.values()).anyMatch(mat -> mat.name().equals(this.name()) || this.matchAnyLegacy(mat.name())); + } + + /** + * Gets the added version if the material is newly added after the 1.13 Aquatic Update and higher. + * + * @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. + */ + public boolean isNew() { + return this.legacy[0].contains("."); + } + + /** + * 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} + * + * @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. + */ + public enum MinecraftVersion { + /** + * Bountiful Update + */ + VERSION_1_8, + /** + * Combat Update (Pitiful Update?) + */ + VERSION_1_9, + /** + * Aquatic Update + */ + VERSION_1_13, + /** + * Village Pillage Update + */ + VERSION_1_14, + /** + * 1.7 or below. + * Using {@link #getVersionIfNew()} it means 1.12 or below. + */ + UNKNOWN; + + public static final MinecraftVersion[] VALUES = MinecraftVersion.values(); + } +} \ No newline at end of file diff --git a/src/main/scala/io/izzel/taboolib/util/lite/Vectors.java b/src/main/scala/io/izzel/taboolib/util/lite/Vectors.java new file mode 100644 index 0000000..c1e0b67 --- /dev/null +++ b/src/main/scala/io/izzel/taboolib/util/lite/Vectors.java @@ -0,0 +1,86 @@ +package io.izzel.taboolib.util.lite; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.stream.IntStream; + +/** + * @Author 坏黑 + * @Since 2019-07-20 13:42 + */ +public class Vectors { + + public static Item itemDrop(Player player, ItemStack itemStack, double bulletSpread, double radius) { + Location location = player.getLocation().add(0.0D, 1.5D, 0.0D); + Item item = player.getWorld().dropItem(location, itemStack); + double yaw = Math.toRadians((double)(-player.getLocation().getYaw() - 90.0F)); + double pitch = Math.toRadians((double)(-player.getLocation().getPitch())); + double x; + double y; + double z; + if (bulletSpread > 0.0D) { + double[] spread = new double[]{1.0D, 1.0D, 1.0D}; + IntStream.range(0, 3).forEach((t) -> { + spread[t] = (Numbers.getRandom().nextDouble() - Numbers.getRandom().nextDouble()) * bulletSpread * 0.1D; + }); + x = Math.cos(pitch) * Math.cos(yaw) + spread[0]; + y = Math.sin(pitch) + spread[1]; + z = -Math.sin(yaw) * Math.cos(pitch) + spread[2]; + } else { + x = Math.cos(pitch) * Math.cos(yaw); + y = Math.sin(pitch); + z = -Math.sin(yaw) * Math.cos(pitch); + } + + Vector dirVel = new Vector(x, y, z); + item.setVelocity(dirVel.normalize().multiply(radius)); + return item; + } + + public static void entityPush(Entity entity, Location to, double velocity) { + Location from = entity.getLocation(); + Vector test = to.clone().subtract(from).toVector(); + double elevation = test.getY(); + Double launchAngle = calculateLaunchAngle(from, to, velocity, elevation, 20.0D); + double distance = Math.sqrt(Math.pow(test.getX(), 2.0D) + Math.pow(test.getZ(), 2.0D)); + if (distance != 0.0D) { + if (launchAngle == null) { + launchAngle = Math.atan((40.0D * elevation + Math.pow(velocity, 2.0D)) / (40.0D * elevation + 2.0D * Math.pow(velocity, 2.0D))); + } + double hangTime = calculateHangTime(launchAngle, velocity, elevation, 20.0D); + test.setY(Math.tan(launchAngle) * distance); + test = normalizeVector(test); + Vector noise = Vector.getRandom(); + noise = noise.multiply(0.1D); + test.add(noise); + velocity = velocity + 1.188D * Math.pow(hangTime, 2.0D) + (Numbers.getRandom().nextDouble() - 0.8D) / 2.0D; + test = test.multiply(velocity / 20.0D); + entity.setVelocity(test); + } + } + + private static double calculateHangTime(double launchAngle, double v, double elev, double g) { + double a = v * Math.sin(launchAngle); + double b = -2.0D * g * elev; + return Math.pow(a, 2.0D) + b < 0.0D ? 0.0D : (a + Math.sqrt(Math.pow(a, 2.0D) + b)) / g; + } + + private static Vector normalizeVector(Vector victor) { + double mag = Math.sqrt(Math.pow(victor.getX(), 2.0D) + Math.pow(victor.getY(), 2.0D) + Math.pow(victor.getZ(), 2.0D)); + return mag != 0.0D ? victor.multiply(1.0D / mag) : victor.multiply(0); + } + + private static Double calculateLaunchAngle(Location from, Location to, double v, double elevation, double g) { + Vector vector = from.clone().subtract(to).toVector(); + double distance = Math.sqrt(Math.pow(vector.getX(), 2.0D) + Math.pow(vector.getZ(), 2.0D)); + double v2 = Math.pow(v, 2.0D); + double v4 = Math.pow(v, 4.0D); + double check = g * (g * Math.pow(distance, 2.0D) + 2.0D * elevation * v2); + return v4 < check ? null : Math.atan((v2 - Math.sqrt(v4 - check)) / (g * distance)); + } +}