From 6862b90569836451cdd3e4bfac2de1df8341df97 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Sat, 24 Jan 2015 17:11:02 -0700 Subject: [PATCH] title support for spigot protocol hack --- .../plot/titles/DefaultTitle.java | 14 +- .../plot/titles/HackTitle.java | 24 + .../plot/titles/HackTitleManager.java | 490 ++++++++++++++++++ .../plot/unused/Title.java | 413 --------------- 4 files changed, 524 insertions(+), 417 deletions(-) create mode 100644 PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitle.java create mode 100644 PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitleManager.java delete mode 100644 PlotSquared/src/main/java/com/intellectualcrafters/plot/unused/Title.java diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/DefaultTitle.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/DefaultTitle.java index 38b91cbd4..4050a947f 100644 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/DefaultTitle.java +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/DefaultTitle.java @@ -6,9 +6,15 @@ import org.bukkit.entity.Player; public class DefaultTitle extends AbstractTitle { @Override public void sendTitle(Player player, String head, String sub, ChatColor head_color, ChatColor sub_color) { - DefaultTitleManager title = new DefaultTitleManager(head,sub,1, 2, 1); - title.setTitleColor(head_color); - title.setSubtitleColor(sub_color); - title.send(player); + try { + DefaultTitleManager title = new DefaultTitleManager(head,sub,1, 2, 1); + title.setTitleColor(head_color); + title.setSubtitleColor(sub_color); + title.send(player); + } + catch (Throwable e) { + AbstractTitle.TITLE_CLASS = new HackTitle(); + AbstractTitle.TITLE_CLASS.sendTitle(player, head, sub, head_color, sub_color); + } } } diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitle.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitle.java new file mode 100644 index 000000000..b348c37dc --- /dev/null +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitle.java @@ -0,0 +1,24 @@ +package com.intellectualcrafters.plot.titles; + +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +import com.intellectualcrafters.plot.PlotMain; +import com.intellectualcrafters.plot.config.Settings; + +public class HackTitle extends AbstractTitle { + @Override + public void sendTitle(Player player, String head, String sub, ChatColor head_color, ChatColor sub_color) { + try { + HackTitleManager title = new HackTitleManager(head,sub,1, 2, 1); + title.setTitleColor(head_color); + title.setSubtitleColor(sub_color); + title.send(player); + } + catch (Throwable e) { + PlotMain.sendConsoleSenderMessage("&cYour server version does not support titles!"); + Settings.TITLES = false; + AbstractTitle.TITLE_CLASS = null; + } + } +} diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitleManager.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitleManager.java new file mode 100644 index 000000000..84e39fe5c --- /dev/null +++ b/PlotSquared/src/main/java/com/intellectualcrafters/plot/titles/HackTitleManager.java @@ -0,0 +1,490 @@ +package com.intellectualcrafters.plot.titles; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; + +/** + * Minecraft 1.8 Title + * + * @version 1.0.4 + * @author Maxim Van de Wynckel + */ +public class HackTitleManager { + /* Title packet */ + private Class packetTitle; + /* Title packet actions ENUM */ + private Class packetActions; + /* Chat serializer */ + private Class nmsChatSerializer; + /* Title text and color */ + private String title = ""; + private ChatColor titleColor = ChatColor.WHITE; + /* Subtitle text and color */ + private String subtitle = ""; + private ChatColor subtitleColor = ChatColor.WHITE; + /* Title timings */ + private int fadeInTime = -1; + private int stayTime = -1; + private int fadeOutTime = -1; + private boolean ticks = false; + + private static final Map, Class> CORRESPONDING_TYPES = new HashMap, Class>(); + + /** + * Create a new 1.8 title + * + * @param title + * Title + */ + public HackTitleManager(String title) { + this.title = title; + loadClasses(); + } + + /** + * Create a new 1.8 title + * + * @param title + * Title text + * @param subtitle + * Subtitle text + */ + public HackTitleManager(String title, String subtitle) { + this.title = title; + this.subtitle = subtitle; + loadClasses(); + } + + /** + * Copy 1.8 title + * + * @param title + * Title + */ + public HackTitleManager(HackTitleManager title) { + // Copy title + this.title = title.title; + this.subtitle = title.subtitle; + this.titleColor = title.titleColor; + this.subtitleColor = title.subtitleColor; + this.fadeInTime = title.fadeInTime; + this.fadeOutTime = title.fadeOutTime; + this.stayTime = title.stayTime; + this.ticks = title.ticks; + loadClasses(); + } + + /** + * Create a new 1.8 title + * + * @param title + * Title text + * @param subtitle + * Subtitle text + * @param fadeInTime + * Fade in time + * @param stayTime + * Stay on screen time + * @param fadeOutTime + * Fade out time + */ + public HackTitleManager(String title, String subtitle, int fadeInTime, int stayTime, + int fadeOutTime) { + this.title = title; + this.subtitle = subtitle; + this.fadeInTime = fadeInTime; + this.stayTime = stayTime; + this.fadeOutTime = fadeOutTime; + loadClasses(); + } + + /** + * Load spigot and NMS classes + */ + private void loadClasses() { + packetTitle = getClass("org.spigotmc.ProtocolInjector$PacketTitle"); + packetActions = getClass("org.spigotmc.ProtocolInjector$PacketTitle$Action"); + nmsChatSerializer = getNMSClass("ChatSerializer"); + } + + /** + * Set title text + * + * @param title + * Title + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * Get title text + * + * @return Title text + */ + public String getTitle() { + return this.title; + } + + /** + * Set subtitle text + * + * @param subtitle + * Subtitle text + */ + public void setSubtitle(String subtitle) { + this.subtitle = subtitle; + } + + /** + * Get subtitle text + * + * @return Subtitle text + */ + public String getSubtitle() { + return this.subtitle; + } + + /** + * Set the title color + * + * @param color + * Chat color + */ + public void setTitleColor(ChatColor color) { + this.titleColor = color; + } + + /** + * Set the subtitle color + * + * @param color + * Chat color + */ + public void setSubtitleColor(ChatColor color) { + this.subtitleColor = color; + } + + /** + * Set title fade in time + * + * @param time + * Time + */ + public void setFadeInTime(int time) { + this.fadeInTime = time; + } + + /** + * Set title fade out time + * + * @param time + * Time + */ + public void setFadeOutTime(int time) { + this.fadeOutTime = time; + } + + /** + * Set title stay time + * + * @param time + * Time + */ + public void setStayTime(int time) { + this.stayTime = time; + } + + /** + * Set timings to ticks + */ + public void setTimingsToTicks() { + ticks = true; + } + + /** + * Set timings to seconds + */ + public void setTimingsToSeconds() { + ticks = false; + } + + /** + * Send the title to a player + * + * @param player + * Player + */ + public void send(Player player) { + if (getProtocolVersion(player) >= 47 && isSpigot() + && packetTitle != null) { + // First reset previous settings + resetTitle(player); + try { + // Send timings first + Object handle = getHandle(player); + Object connection = getField(handle.getClass(), + "playerConnection").get(handle); + Object[] actions = packetActions.getEnumConstants(); + Method sendPacket = getMethod(connection.getClass(), + "sendPacket"); + Object packet = packetTitle.getConstructor(packetActions, + Integer.TYPE, Integer.TYPE, Integer.TYPE).newInstance( + actions[2], fadeInTime * (ticks ? 1 : 20), + stayTime * (ticks ? 1 : 20), + fadeOutTime * (ticks ? 1 : 20)); + // Send if set + if (fadeInTime != -1 && fadeOutTime != -1 && stayTime != -1) + sendPacket.invoke(connection, packet); + + // Send title + Object serialized = getMethod(nmsChatSerializer, "a", + String.class).invoke( + null, + "{text:\"" + + ChatColor.translateAlternateColorCodes('&', + title) + "\",color:" + + titleColor.name().toLowerCase() + "}"); + packet = packetTitle.getConstructor(packetActions, + getNMSClass("IChatBaseComponent")).newInstance( + actions[0], serialized); + sendPacket.invoke(connection, packet); + if (subtitle != "") { + // Send subtitle if present + serialized = getMethod(nmsChatSerializer, "a", String.class) + .invoke(null, + "{text:\"" + + ChatColor + .translateAlternateColorCodes( + '&', subtitle) + + "\",color:" + + subtitleColor.name() + .toLowerCase() + "}"); + packet = packetTitle.getConstructor(packetActions, + getNMSClass("IChatBaseComponent")).newInstance( + actions[1], serialized); + sendPacket.invoke(connection, packet); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * Broadcast the title to all players + */ + public void broadcast() { + for (Player p : Bukkit.getOnlinePlayers()) { + send(p); + } + } + + /** + * Clear the title + * + * @param player + * Player + */ + public void clearTitle(Player player) { + if (getProtocolVersion(player) >= 47 && isSpigot()) { + try { + // Send timings first + Object handle = getHandle(player); + Object connection = getField(handle.getClass(), + "playerConnection").get(handle); + Object[] actions = packetActions.getEnumConstants(); + Method sendPacket = getMethod(connection.getClass(), + "sendPacket"); + Object packet = packetTitle.getConstructor(packetActions) + .newInstance(actions[3]); + sendPacket.invoke(connection, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * Reset the title settings + * + * @param player + * Player + */ + public void resetTitle(Player player) { + if (getProtocolVersion(player) >= 47 && isSpigot()) { + try { + // Send timings first + Object handle = getHandle(player); + Object connection = getField(handle.getClass(), + "playerConnection").get(handle); + Object[] actions = packetActions.getEnumConstants(); + Method sendPacket = getMethod(connection.getClass(), + "sendPacket"); + Object packet = packetTitle.getConstructor(packetActions) + .newInstance(actions[4]); + sendPacket.invoke(connection, packet); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + /** + * Get the protocol version of the player + * + * @param player + * Player + * @return Protocol version + */ + private int getProtocolVersion(Player player) { + int version = 0; + try { + Object handle = getHandle(player); + Object connection = getField(handle.getClass(), "playerConnection") + .get(handle); + Object networkManager = getValue("networkManager", connection); + version = (Integer) getMethod("getVersion", + networkManager.getClass()).invoke(networkManager); + + return version; + } catch (Exception ex) { + ex.printStackTrace(); + } + return version; + } + + /** + * Check if running spigot + * + * @return Spigot + */ + private boolean isSpigot() { + return Bukkit.getVersion().contains("Spigot"); + } + + /** + * Get class by url + * + * @param namespace + * Namespace url + * @return Class + */ + private Class getClass(String namespace) { + try { + return Class.forName(namespace); + } catch (Exception e) { + + } + return null; + } + + private Field getField(String name, Class clazz) throws Exception { + return clazz.getDeclaredField(name); + } + + private Object getValue(String name, Object obj) throws Exception { + Field f = getField(name, obj.getClass()); + f.setAccessible(true); + return f.get(obj); + } + + private Class getPrimitiveType(Class clazz) { + return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES + .get(clazz) : clazz; + } + + private Class[] toPrimitiveTypeArray(Class[] classes) { + int a = classes != null ? classes.length : 0; + Class[] types = new Class[a]; + for (int i = 0; i < a; i++) + types[i] = getPrimitiveType(classes[i]); + return types; + } + + private static boolean equalsTypeArray(Class[] a, Class[] o) { + if (a.length != o.length) + return false; + for (int i = 0; i < a.length; i++) + if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i])) + return false; + return true; + } + + private Object getHandle(Object obj) { + try { + return getMethod("getHandle", obj.getClass()).invoke(obj); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private Method getMethod(String name, Class clazz, + Class... paramTypes) { + Class[] t = toPrimitiveTypeArray(paramTypes); + for (Method m : clazz.getMethods()) { + Class[] types = toPrimitiveTypeArray(m.getParameterTypes()); + if (m.getName().equals(name) && equalsTypeArray(types, t)) + return m; + } + return null; + } + + private String getVersion() { + String name = Bukkit.getServer().getClass().getPackage().getName(); + String version = name.substring(name.lastIndexOf('.') + 1) + "."; + return version; + } + + private Class getNMSClass(String className) { + String fullName = "net.minecraft.server." + getVersion() + className; + Class clazz = null; + try { + clazz = Class.forName(fullName); + } catch (Exception e) { + e.printStackTrace(); + } + return clazz; + } + + private Field getField(Class clazz, String name) { + try { + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + return field; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + private Method getMethod(Class clazz, String name, Class... args) { + for (Method m : clazz.getMethods()) + if (m.getName().equals(name) + && (args.length == 0 || ClassListEqual(args, + m.getParameterTypes()))) { + m.setAccessible(true); + return m; + } + return null; + } + + private boolean ClassListEqual(Class[] l1, Class[] l2) { + boolean equal = true; + if (l1.length != l2.length) + return false; + for (int i = 0; i < l1.length; i++) + if (l1[i] != l2[i]) { + equal = false; + break; + } + return equal; + } +} \ No newline at end of file diff --git a/PlotSquared/src/main/java/com/intellectualcrafters/plot/unused/Title.java b/PlotSquared/src/main/java/com/intellectualcrafters/plot/unused/Title.java deleted file mode 100644 index 233ed792c..000000000 --- a/PlotSquared/src/main/java/com/intellectualcrafters/plot/unused/Title.java +++ /dev/null @@ -1,413 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////////////////////////// -// PlotSquared - A plot manager and world generator for the Bukkit API / -// Copyright (c) 2014 IntellectualSites/IntellectualCrafters / -// / -// This program is free software; you can redistribute it and/or modify / -// it under the terms of the GNU General Public License as published by / -// the Free Software Foundation; either version 3 of the License, or / -// (at your option) any later version. / -// / -// This program is distributed in the hope that it will be useful, / -// but WITHOUT ANY WARRANTY; without even the implied warranty of / -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the / -// GNU General Public License for more details. / -// / -// You should have received a copy of the GNU General Public License / -// along with this program; if not, write to the Free Software Foundation, / -// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA / -// / -// You can contact us via: support@intellectualsites.com / -//////////////////////////////////////////////////////////////////////////////////////////////////// - -package com.intellectualcrafters.plot.unused; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; - -/** - * Minecraft 1.8 Title - * - * @author Maxim Van de Wynckel - * @version 1.0.3 - */ -public class Title { - private static final Map, Class> CORRESPONDING_TYPES; - - static { - CORRESPONDING_TYPES = new HashMap<>(); - } - - /* Title packet */ - private Class packetTitle; - /* Title packet actions ENUM */ - private Class packetActions; - /* Chat serializer */ - private Class nmsChatSerializer; - /* Title text and color */ - private String title; - private ChatColor titleColor = ChatColor.WHITE; - /* Subtitle text and color */ - private String subtitle = ""; - private ChatColor subtitleColor = ChatColor.WHITE; - /* Title timings */ - private int fadeInTime = -1; - private int stayTime = -1; - private int fadeOutTime = -1; - private boolean ticks = false; - - /** - * Create a new 1.8 title - * - * @param title Title - */ - public Title(final String title) { - this.title = title; - loadClasses(); - } - - /** - * Create a new 1.8 title - * - * @param title Title text - * @param subtitle Subtitle text - */ - public Title(final String title, final String subtitle) { - this.title = ""; - this.title = title; - this.subtitle = subtitle; - loadClasses(); - } - - /** - * Create a new 1.8 title - * - * @param title Title text - * @param subtitle Subtitle text - * @param fadeInTime Fade in time - * @param stayTime Stay on screen time - * @param fadeOutTime Fade out time - */ - public Title(final String title, final String subtitle, final int fadeInTime, final int stayTime, final int fadeOutTime) { - this.title = ""; - this.title = title; - this.subtitle = subtitle; - this.fadeInTime = fadeInTime; - this.stayTime = stayTime; - this.fadeOutTime = fadeOutTime; - loadClasses(); - } - - private static boolean equalsTypeArray(final Class[] a, final Class[] o) { - if (a.length != o.length) { - return false; - } - for (int i = 0; i < a.length; i++) { - if (!a[i].equals(o[i]) && !a[i].isAssignableFrom(o[i])) { - return false; - } - } - return true; - } - - /** - * Load spigot and NMS classes - */ - private void loadClasses() { - this.packetTitle = getClass("org.spigotmc.ProtocolInjector$PacketTitle"); - this.packetActions = getClass("org.spigotmc.ProtocolInjector$PacketTitle$Action"); - this.nmsChatSerializer = getNMSClass("ChatSerializer"); - } - - /** - * Set the title color - * - * @param color Chat color - */ - public void setTitleColor(final ChatColor color) { - this.titleColor = color; - } - - /** - * Set the subtitle color - * - * @param color Chat color - */ - public void setSubtitleColor(final ChatColor color) { - this.subtitleColor = color; - } - - /** - * Set title fade in time - * - * @param time Time - */ - public void setFadeInTime(final int time) { - this.fadeInTime = time; - } - - /** - * Set title fade out time - * - * @param time Time - */ - public void setFadeOutTime(final int time) { - this.fadeOutTime = time; - } - - /** - * Set title stay time - * - * @param time Time - */ - public void setStayTime(final int time) { - this.stayTime = time; - } - - /** - * Set timings to ticks - */ - public void setTimingsToTicks() { - this.ticks = true; - } - - /** - * Set timings to seconds - */ - public void setTimingsToSeconds() { - this.ticks = false; - } - - /** - * Send the title to a player - * - * @param player Player - */ - public void send(final Player player) { - if ((getProtocolVersion(player) >= 47) && isSpigot() && (this.packetTitle != null)) { - // First reset previous settings - resetTitle(player); - try { - // Send timings first - final Object handle = getHandle(player); - final Object connection = getField(handle.getClass(), "playerConnection").get(handle); - final Object[] actions = this.packetActions.getEnumConstants(); - final Method sendPacket = getMethod(connection.getClass(), "sendPacket"); - Object packet = this.packetTitle.getConstructor(this.packetActions, Integer.TYPE, Integer.TYPE, Integer.TYPE).newInstance(actions[2], this.fadeInTime * (this.ticks ? 1 : 20), this.stayTime * (this.ticks ? 1 : 20), this.fadeOutTime * (this.ticks ? 1 : 20)); - // Send if set - if ((this.fadeInTime != -1) && (this.fadeOutTime != -1) && (this.stayTime != -1)) { - sendPacket.invoke(connection, packet); - } - - // Send title - Object serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null, "{text:\"" + ChatColor.translateAlternateColorCodes('&', this.title) + "\",color:" + this.titleColor.name().toLowerCase() + "}"); - packet = this.packetTitle.getConstructor(this.packetActions, getNMSClass("IChatBaseComponent")).newInstance(actions[0], serialized); - sendPacket.invoke(connection, packet); - if (!this.subtitle.equals("")) { - // Send subtitle if present - serialized = getMethod(this.nmsChatSerializer, "a", String.class).invoke(null, "{text:\"" + ChatColor.translateAlternateColorCodes('&', this.subtitle) + "\",color:" + this.subtitleColor.name().toLowerCase() + "}"); - packet = this.packetTitle.getConstructor(this.packetActions, getNMSClass("IChatBaseComponent")).newInstance(actions[1], serialized); - sendPacket.invoke(connection, packet); - } - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - - /** - * Broadcast the title to all players - */ - public void broadcast() { - for (final Player p : Bukkit.getOnlinePlayers()) { - send(p); - } - } - - /** - * Clear the title - * - * @param player Player - */ - public void clearTitle(final Player player) { - if ((getProtocolVersion(player) >= 47) && isSpigot()) { - try { - // Send timings first - final Object handle = getHandle(player); - final Object connection = getField(handle.getClass(), "playerConnection").get(handle); - final Object[] actions = this.packetActions.getEnumConstants(); - final Method sendPacket = getMethod(connection.getClass(), "sendPacket"); - final Object packet = this.packetTitle.getConstructor(this.packetActions).newInstance(actions[3]); - sendPacket.invoke(connection, packet); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - - /** - * Reset the title settings - * - * @param player Player - */ - public void resetTitle(final Player player) { - if ((getProtocolVersion(player) >= 47) && isSpigot()) { - try { - // Send timings first - final Object handle = getHandle(player); - final Object connection = getField(handle.getClass(), "playerConnection").get(handle); - final Object[] actions = this.packetActions.getEnumConstants(); - final Method sendPacket = getMethod(connection.getClass(), "sendPacket"); - final Object packet = this.packetTitle.getConstructor(this.packetActions).newInstance(actions[4]); - sendPacket.invoke(connection, packet); - } catch (final Exception e) { - e.printStackTrace(); - } - } - } - - /** - * Get the protocol version of the player - * - * @param player Player - * - * @return Protocol version - */ - private int getProtocolVersion(final Player player) { - int version = 0; - try { - final Object handle = getHandle(player); - final Object connection = getField(handle.getClass(), "playerConnection").get(handle); - final Object networkManager = getValue("networkManager", connection); - version = (Integer) getMethod("getVersion", networkManager.getClass()).invoke(networkManager); - - return version; - } catch (final Exception ex) { - // ex.printStackTrace(); <-- spammy console - } - return version; - } - - /** - * Check if running spigot - * - * @return Spigot - */ - private boolean isSpigot() { - return Bukkit.getVersion().contains("Spigot"); - } - - /** - * Get class by url - * - * @param namespace Namespace url - * - * @return Class - */ - private Class getClass(final String namespace) { - try { - return Class.forName(namespace); - } catch (final Exception e) { - return null; - } - } - - private Field getField(final String name, final Class clazz) throws Exception { - return clazz.getDeclaredField(name); - } - - private Object getValue(final String name, final Object obj) throws Exception { - final Field f = getField(name, obj.getClass()); - f.setAccessible(true); - return f.get(obj); - } - - private Class getPrimitiveType(final Class clazz) { - return CORRESPONDING_TYPES.containsKey(clazz) ? CORRESPONDING_TYPES.get(clazz) : clazz; - } - - private Class[] toPrimitiveTypeArray(final Class[] classes) { - final int a = classes != null ? classes.length : 0; - final Class[] types = new Class[a]; - for (int i = 0; i < a; i++) { - types[i] = getPrimitiveType(classes[i]); - } - return types; - } - - private Object getHandle(final Object obj) { - try { - return getMethod("getHandle", obj.getClass()).invoke(obj); - } catch (final Exception e) { - e.printStackTrace(); - return null; - } - } - - private Method getMethod(final String name, final Class clazz, final Class... paramTypes) { - final Class[] t = toPrimitiveTypeArray(paramTypes); - for (final Method m : clazz.getMethods()) { - final Class[] types = toPrimitiveTypeArray(m.getParameterTypes()); - if (m.getName().equals(name) && equalsTypeArray(types, t)) { - return m; - } - } - return null; - } - - private String getVersion() { - final String name = Bukkit.getServer().getClass().getPackage().getName(); - return name.substring(name.lastIndexOf('.') + 1) + "."; - } - - private Class getNMSClass(final String className) { - final String fullName = "net.minecraft.server." + getVersion() + className; - Class clazz = null; - try { - clazz = Class.forName(fullName); - } catch (final Exception e) { - e.printStackTrace(); - } - return clazz; - } - - private Field getField(final Class clazz, final String name) { - try { - final Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - return field; - } catch (final Exception e) { - e.printStackTrace(); - return null; - } - } - - private Method getMethod(final Class clazz, final String name, final Class... args) { - for (final Method m : clazz.getMethods()) { - if (m.getName().equals(name) && ((args.length == 0) || ClassListEqual(args, m.getParameterTypes()))) { - m.setAccessible(true); - return m; - } - } - return null; - } - - private boolean ClassListEqual(final Class[] l1, final Class[] l2) { - boolean equal = true; - if (l1.length != l2.length) { - return false; - } - for (int i = 0; i < l1.length; i++) { - if (l1[i] != l2[i]) { - equal = false; - break; - } - } - return equal; - } -}