package com.taiter.ce;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
/*
* This file is part of Custom Enchantments
* Copyright (C) Taiterio 2015
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
public class ReflectionHelper {
private static String cbVersion = "org.bukkit.craftbukkit.";
private static String nmsVersion = "net.minecraft.server.";
private static Constructor<?> effectPacketConstructor;
static {
String pkg = Bukkit.getServer().getClass().getPackage().getName();
String version = pkg.substring(pkg.lastIndexOf(".") + 1);
cbVersion += version + ".";
nmsVersion += version + ".";
//Grab all needed reflection methods/constructors
try {
effectPacketConstructor = getNMSClass("PacketPlayOutWorldParticles").getConstructor(getNMSClass("EnumParticle"), boolean.class, float.class, float.class, float.class, float.class,
float.class, float.class, float.class, int.class, int[].class);
} catch (NoSuchMethodException | SecurityException e) {
e.printStackTrace();
}
new EffectManager();
}
public static Constructor<?> getEffectPacketConstructor() {
return effectPacketConstructor;
}
public static Object loadEnumParticleValues() throws NoSuchMethodException, SecurityException {
return getNMSClass("EnumParticle").getEnumConstants();
}
public static Class<?> wrapperClassToPrimitive(Class<?> cl) {
if (cl == Boolean.class)
return boolean.class;
if (cl == Short.class)
return short.class;
if (cl == Byte.class)
return byte.class;
if (cl == Integer.class)
return int.class;
if (cl == Long.class)
return long.class;
if (cl == Float.class)
return float.class;
if (cl == Double.class)
return double.class;
if (cl == Character.class)
return char.class;
if (cl == Void.class)
return void.class;
return cl;
}
public static Class<?>[] toParamTypes(Object... params) {
Class<?>[] classes = new Class<?>[params.length];
for (int i = 0; i < params.length; i++)
classes[i] = wrapperClassToPrimitive(params[i].getClass());
return classes;
}
public static Object getEntityHandle(Entity e) {
return callMethod(e, "getHandle");
}
public static Object getWorldHandle(World w) {
return callMethod(w, "getHandle");
}
public static Object getPlayerConnection(Player p) {
return getPlayerConnection(getEntityHandle(p));
}
public static Object getPlayerConnection(Object handle) {
return getDeclaredField(handle, "playerConnection");
}
public static void sendPacket(Player p, Object packet) {
Object pc = getPlayerConnection(p);
try {
pc.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(pc, packet);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Object getPacket(String name, Object... params) {
return callDeclaredConstructor(getNMSClass(name), params);
}
public static void sendJsonMessage(Player p, String json) {
//Used for sending formatted text chat, unused for now
Object msg = callDeclaredMethod(getNMSClass("ChatSerializer"), "a", json);
sendPacket(p, getPacket("PacketPlayOutChat", msg, true));
}
public static Class<?> getClass(String name) {
try {
return Class.forName(name);
} catch (Exception e) {
return null;
}
}
public static Class<?> getNMSClass(String name) {
return getClass(nmsVersion + name);
}
public static Class<?> getCBClass(String name) {
return getClass(cbVersion + name);
}
public static Object callDeclaredMethod(Object object, String method) {
return callDeclaredMethod(object, method, new Object[0]);
}
public static Object callDeclaredMethod(Object object, String method, Object... params) {
try {
Method m = object.getClass().getDeclaredMethod(method, toParamTypes(params));
m.setAccessible(true);
return m.invoke(object, params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object callMethod(Object object, String method) {
return callMethod(object, method, new Object[0]);
}
public static Object callMethod(Object object, String method, Object... params) {
try {
Method m = object.getClass().getMethod(method, toParamTypes(params));
m.setAccessible(true);
return m.invoke(object, params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object callDeclaredConstructor(Class<?> clazz, Object... params) {
try {
Constructor<?> con = clazz.getDeclaredConstructor(toParamTypes(params));
con.setAccessible(true);
return con.newInstance(params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object callConstructor(Class<?> clazz, Object... params) {
try {
Constructor<?> con = clazz.getConstructor(toParamTypes(params));
con.setAccessible(true);
return con.newInstance(params);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object getDeclaredField(Object object, String field) {
try {
Field f = object.getClass().getDeclaredField(field);
f.setAccessible(true);
return f.get(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Object getField(Object object, String field) {
try {
Field f = object.getClass().getField(field);
f.setAccessible(true);
return f.get(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void setDeclaredField(Object object, String field, Object value) {
try {
Field f = object.getClass().getDeclaredField(field);
f.setAccessible(true);
f.set(object, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void setField(Object object, String field, Object value) {
try {
Field f = object.getClass().getField(field);
f.setAccessible(true);
f.set(object, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}