package cx.sfy.LagAssist.packets; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.command.CommandMap; import org.bukkit.command.PluginCommand; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; import org.bukkit.map.MapView; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.SimplePluginManager; import org.bukkit.scoreboard.Scoreboard; import org.json.simple.JSONObject; import cx.sfy.LagAssist.Main; import cx.sfy.LagAssist.utils.V1_8; import cx.sfy.LagAssist.utils.VersionMgr; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.ComponentBuilder; public class Reflection { private static Map, Field[]> cached = new HashMap, Field[]>(); private static String version = ServerPackage.getServerVersion(); public static enum Classes { CraftWorld(), CraftBlock(), CraftPlayer(), Material(), MapMeta(), WorldServer(), ChunkProviderServer(), PacketPlayOutTitle(), IChatBaseComponent(), World(); private Class type; public Class getType() { return type; } } public static enum Methods { setMapId(), getMapId(), getPlayerHandle(), getBlockType(), getChunkProviderServer(), chunkExists(), getIChatBaseComponent(), setViewDistance(); private Method mthd; public Method getMethod() { return mthd; } } public static void Enabler() { // PUTTING CLASSES IN ENUM. Classes.CraftWorld.type = getClass("{cb}.CraftWorld"); Classes.World.type = getClass("{b}.World"); Classes.CraftBlock.type = getClass("{cb}.block.CraftBlock"); Classes.CraftPlayer.type = getClass("{cb}.entity.CraftPlayer"); Classes.Material.type = getClass("{b}.Material"); Classes.MapMeta.type = getClass("{b}.inventory.meta.MapMeta"); Classes.WorldServer.type = getClass("{nms}.WorldServer"); Classes.ChunkProviderServer.type = getClass("{nms}.ChunkProviderServer"); Classes.IChatBaseComponent.type = getClass("{nms}.IChatBaseComponent"); Classes.PacketPlayOutTitle.type = getClass("{nms}.PacketPlayOutTitle"); // PUTTING METHODS IN ENUM. Methods.setMapId.mthd = getMethod(Classes.MapMeta.getType(), "setMapId", int.class); Methods.getMapId.mthd = getMethod(Classes.MapMeta.getType(), "getMapId"); Methods.getPlayerHandle.mthd = getMethod(Classes.CraftPlayer.getType(), "getHandle"); Methods.getBlockType.mthd = getMethod(Classes.CraftBlock.getType(), "getType"); Methods.getChunkProviderServer.mthd = getMethod(Classes.WorldServer.getType(), "getChunkProviderServer"); Methods.getIChatBaseComponent.mthd = getMethod(Classes.IChatBaseComponent.getType(), "a", String.class); Methods.chunkExists.mthd = getMethod(Classes.ChunkProviderServer.getType(), VersionMgr.ChunkExistsName(), int.class, int.class); Methods.setViewDistance.mthd = getMethod(Classes.World.getType(), "setViewDistance", int.class); } @SuppressWarnings("deprecation") public static void sendAction(Player player, String s) { if (Bukkit.getVersion().contains("1.8")) { V1_8.sendActionbar(player, s); } else { player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new ComponentBuilder(s).create()); } } public void sendTitle(Player p, int fadein, int stay, int fadeout, String title, String subtitle) { try { Object enumTitle = Classes.PacketPlayOutTitle.getType().getDeclaredClasses()[0].getField("TITLE").get(null); Object enumSubtitle = Classes.PacketPlayOutTitle.getType().getDeclaredClasses()[0].getField("SUBTITLE") .get(null); Object titlebase = runMethod(null, Methods.getIChatBaseComponent.getMethod(), "{\"text\": \"" + title + "\"}"); Object subtitlebase = runMethod(null, Methods.getIChatBaseComponent.getMethod(), "{\"text\": \"" + subtitle + "\"}"); Class packetcls = Classes.PacketPlayOutTitle.getType(); Constructor constr = packetcls.getConstructor( Classes.PacketPlayOutTitle.getType().getDeclaredClasses()[0], Classes.IChatBaseComponent.getType(), int.class, int.class, int.class); Object packetTitle = constr.newInstance(enumTitle, titlebase, fadein, stay, fadeout); Object packetSubtitle = constr.newInstance(enumSubtitle, subtitlebase, fadein, stay, fadeout); sendPlayerPacket(p, packetTitle); sendPlayerPacket(p, packetSubtitle); } catch (Exception e) { e.printStackTrace(); } } public static MapView getMapView(int i) { Class buk = Bukkit.class; try { Method getMap = buk.getDeclaredMethod("getMap", VersionMgr.isNewMaterials() ? int.class : short.class); return (MapView) (VersionMgr.isNewMaterials() ? getMap.invoke(null, i) : getMap.invoke(null, (short) i)); } catch (Exception e) { e.printStackTrace(); return null; } } public static int getId(MapView view) { if (view == null) { return 0; } Class mv = MapView.class; try { Method getMap = mv.getDeclaredMethod("getId"); Object obj = getMap.invoke(view); if (obj instanceof Short) { return (short) obj; } else if (obj instanceof Integer) { return (int) obj; } } catch (Exception e) { e.printStackTrace(); } return 0; } @SuppressWarnings("unchecked") static JSONObject convert(String text) { JSONObject json = new JSONObject(); json.put("text", text); return json; } public static Class getClass(String classname) { try { String path = classname.replace("{nms}", "net.minecraft.server." + version) .replace("{nm}", "net.minecraft." + version).replace("{cb}", "org.bukkit.craftbukkit." + version) .replace("{b}", "org.bukkit"); return Class.forName(path); } catch (Exception e) { e.printStackTrace(); return null; } } public static Object getCraftWorld(World w) { Class crwclass = Classes.CraftWorld.getType(); System.out.println(crwclass.getName()); Object craftworld = crwclass.cast(w); return craftworld; } public static Object getWorldServer(Object craftWorld) { try { return getFieldValue(craftWorld, "world"); } catch (Exception e) { e.printStackTrace(); } return null; } public static Object getChunkProvider(Object worldServer) { try { return runMethod(worldServer, Methods.getChunkProviderServer.getMethod()); } catch (Exception e) { e.printStackTrace(); } return null; } public static boolean isChunkExistent(Object chunkProvider, int x, int z) { try { return (boolean) runMethod(chunkProvider, Methods.chunkExists.getMethod(), x, z); } catch (Exception e) { e.printStackTrace(); } // NOTE: ASSUMING TRUE IN ORDER TO IGNORE IF EXCEPTION POPS UP. return true; } public static boolean isTile(Block b) { return !b.getState().getClass().getSimpleName().toLowerCase().contains("craftblockstate"); } public static Entity getEntity(Location l) { try { Collection ents = l.getWorld().getNearbyEntities(l, 1, 1, 1); for (Entity ent : ents) { return ent; } } catch (Exception e) { return null; } return null; } public static void setmapId(ItemStack s, int id) { MapMeta mapm = (MapMeta) s.getItemMeta(); try { runMethod(mapm, Methods.setMapId.getMethod(), id); } catch (Exception e) { e.printStackTrace(); } s.setItemMeta(mapm); } public static int getMapId(ItemStack s) { MapMeta mapm = (MapMeta) s.getItemMeta(); try { return (int) runMethod(mapm, Methods.getMapId.getMethod()); } catch (Exception e) { e.printStackTrace(); } return 0; } public static Object getNmsPlayer(Player p) { if (p == null) { return null; } Method getHandle; try { getHandle = p.getClass().getMethod("getHandle"); return getHandle.invoke(p); } catch (Exception e) { e.printStackTrace(); return null; } } public static Object getNmsScoreboard(Scoreboard s) throws Exception { Method getHandle = s.getClass().getMethod("getHandle"); return getHandle.invoke(s); } public static String getObjectSerialized(Object obj) { YamlConfiguration conf = new YamlConfiguration(); Class cls = obj.getClass(); String loc = cls.getSimpleName(); createObjectSerialized(conf, loc, obj, 0); return conf.saveToString(); } public static void createObjectSerialized(YamlConfiguration conf, String loc, Object obj, int recursiveness) { Class cls = obj.getClass(); if (!cached.containsKey(cls)) { cached.put(cls, cls.getDeclaredFields()); } for (Field fl : cached.get(cls)) { fl.setAccessible(true); Object newobj = getFieldValue(fl, obj); if (newobj == null) { continue; } String name = fl.getName(); String type = newobj.getClass().getSimpleName(); String newloc = loc + "." + type + "." + name; if (isSimple(newobj) || recursiveness > 1) { conf.set(newloc, convertToString(newobj)); continue; } createObjectSerialized(conf, newloc, newobj, recursiveness + 1); } } // public static long getObjectSize(Object obj, int recursiveness) { // if (obj == null) { // return 0; // } // // // if (obj instanceof Serializable) { // return getSerializedSize((Serializable) obj); // } // // Class cls = obj.getClass(); // // long size = 0; // // if (!cached.containsKey(cls)) { // cached.put(cls, cls.getDeclaredFields()); // } // // for (Field fl : cached.get(cls)) { // fl.setAccessible(true); // Object nobj = getFieldValue(fl, obj); // size+=getObjectSize(nobj, recursiveness+1); // } // // return size; // } // // private static long getSerializedSize(Serializable obj) { // // try { // ByteArrayOutputStream bos = new ByteArrayOutputStream(); // ObjectOutputStream oos = new ObjectOutputStream(bos); // oos.writeObject(obj); // oos.flush(); // byte[] data = bos.toByteArray(); // // return data.length; // } catch (Exception e) { // return 0; // } // } public static Object getFieldValue(Object instance, String fieldName) throws Exception { Field field = instance.getClass().getDeclaredField(fieldName); field.setAccessible(true); return field.get(instance); } @SuppressWarnings("unchecked") public static T getFieldValue(Field field, Object obj) { try { return (T) field.get(obj); } catch (Exception e) { e.printStackTrace(); return null; } } public static Field getField(Class clazz, String fieldName) throws Exception { Field field = clazz.getDeclaredField(fieldName); field.setAccessible(true); return field; } public static Method getMethod(Class clazz, String methodName, Class... resl) { Method method; try { method = clazz.getDeclaredMethod(methodName, resl); method.setAccessible(true); return method; } catch (Exception e) { return null; } } public static Object runMethod(Object obj, Method m, Object... resl) throws Exception { return m.invoke(obj, resl); } public static Object runMethod(Object obj, String name, Object... resl) throws Exception { Class[] classes = new Class[resl.length]; for (int i = 0; i < resl.length; i++) { classes[i] = resl[i].getClass(); } return getMethod(obj.getClass(), name, classes).invoke(obj, resl); } public static void setValue(Object instance, String field, Object value) { try { Field f = instance.getClass().getDeclaredField(field); f.setAccessible(true); f.set(instance, value); } catch (Throwable t) { t.printStackTrace(); } } public static void sendAllPacket(Object packet) throws Exception { for (Player p : Bukkit.getOnlinePlayers()) { Object nmsPlayer = getNmsPlayer(p); Object connection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer); connection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(connection, packet); } } public static int getPing(Player p) { try { Object entityPlayer = Methods.getPlayerHandle.getMethod().invoke(p); return (int) getFieldValue(entityPlayer, "ping"); } catch (Exception e) { return -1; } } public static void sendListPacket(List players, Object packet) { try { for (String name : players) { Object nmsPlayer = getNmsPlayer(Bukkit.getPlayer(name)); Object connection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer); connection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(connection, packet); } } catch (Exception e) { e.printStackTrace(); } } public static void sendPlayerPacket(Player p, Object packet) throws Exception { Object nmsPlayer = getNmsPlayer(p); Object connection = nmsPlayer.getClass().getField("playerConnection").get(nmsPlayer); connection.getClass().getMethod("sendPacket", getClass("{nms}.Packet")).invoke(connection, packet); } public static PluginCommand getCommand(String name, Plugin plugin) { PluginCommand command = null; try { Constructor c = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class); c.setAccessible(true); command = c.newInstance(name, plugin); } catch (Exception e) { e.printStackTrace(); } return command; } public static CommandMap getCommandMap() { CommandMap commandMap = null; try { if (Bukkit.getPluginManager() instanceof SimplePluginManager) { Field f = SimplePluginManager.class.getDeclaredField("commandMap"); f.setAccessible(true); commandMap = (CommandMap) f.get(Bukkit.getPluginManager()); } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return commandMap; } private static String convertToString(Object obj) { Class cls = obj.getClass(); if (cls.isArray()) { String stg = ""; int length = Array.getLength(obj); for (int i = 0; i < length; i++) { stg += convertToString(Array.get(obj, i)); } return stg; } return obj.toString(); } private static boolean isSimple(Object obj) { Class cls = obj.getClass(); if (cls.isPrimitive()) { return true; } if (cls.isEnum()) { return true; } if (cls == Integer.class) { return true; } if (cls == Boolean.class) { return true; } if (cls == String.class) { return true; } if (cls == Character.class) { return true; } if (cls == Byte.class) { return true; } if (cls == Short.class) { return true; } if (cls == Float.class) { return true; } if (cls == Double.class) { return true; } if (cls == Long.class) { return true; } return false; } public static void setViewDistance(World w, int amount) { try { runMethod(w, Methods.setViewDistance.mthd, amount); Main.sendDebug("Succesfully set view distance at " + amount + " in world " + w.getName(), 1); } catch (Exception e) { Main.sendDebug("Exception at setViewDistance (" + w.getName() + ", " + amount + ")", 1); } } }