/*
* Copyright (C) 2013-2016 Gonçalo Baltazar <me@goncalomb.com>
*
* This file is part of NBTEditor.
*
* NBTEditor 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.
*
* NBTEditor 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 NBTEditor. If not, see <http://www.gnu.org/licenses/>.
*/
package com.goncalomb.bukkit.mylib.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.SimpleCommandMap;
public final class BukkitReflect {
private final static class CachedPackage {
private String _packageName;
private HashMap<String, Class<?>> _cache = new HashMap<String, Class<?>>();
public CachedPackage(String packageName) {
_packageName = packageName;
}
public Class<?> getClass(String className) {
Class <?> clazz = _cache.get(className);
if (clazz == null) {
try {
clazz = this.getClass().getClassLoader().loadClass(_packageName + "." + className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot find class " + _packageName + "." + className + ".", e);
}
_cache.put(className, clazz);
}
return clazz;
}
}
private static boolean _isPrepared = false;
private static CachedPackage _craftBukkitPackage;
private static CachedPackage _minecraftPackage;
private static Method _getCommandMap;
private static HashMap<Material, String> _materialNames = new HashMap<Material, String>();
public static void prepareReflection() {
if (!_isPrepared) {
Class<?> craftServerClass = Bukkit.getServer().getClass();
_craftBukkitPackage = new CachedPackage(craftServerClass.getPackage().getName());
try {
Method getHandle = craftServerClass.getMethod("getHandle");
_minecraftPackage = new CachedPackage(getHandle.getReturnType().getPackage().getName());
_getCommandMap = craftServerClass.getMethod("getCommandMap");
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot find the required methods on the server class.", e);
}
_isPrepared = true;
try {
Class<?> mc_Item = getMinecraftClass("Item");
Field mc_Item_REGISTRY = mc_Item.getField("REGISTRY");
Method mc_Item_getById = mc_Item.getMethod("getById", int.class);
Method mc_RegistryMaterials_b = mc_Item_REGISTRY.getType().getMethod("b", Object.class);
Object the_REGISTRY = mc_Item_REGISTRY.get(null);
for (Material material : Material.values()) {
Object item = mc_Item_getById.invoke(null, material.getId());
if (item != null) {
_materialNames.put(material, mc_RegistryMaterials_b.invoke(the_REGISTRY, item).toString());
}
}
} catch (Exception e) {
throw new RuntimeException("Error while preparing Material names.", e);
}
}
}
private BukkitReflect() { }
public static Class<?> getCraftBukkitClass(String className) {
prepareReflection();
return _craftBukkitPackage.getClass(className);
}
public static Class<?> getMinecraftClass(String className) {
prepareReflection();
return _minecraftPackage.getClass(className);
}
public static SimpleCommandMap getCommandMap() {
prepareReflection();
return (SimpleCommandMap) invokeMethod(Bukkit.getServer(), _getCommandMap);
}
public static String getMaterialName(Material material) {
prepareReflection();
return _materialNames.get(material);
}
// Other helper methods...
static Object invokeMethod(Object object, Method method, Object... args) {
try {
return method.invoke(object, args);
} catch (Exception e) {
throw new RuntimeException("Error while invoking " + method.getName() + ".", e);
}
}
static Object getFieldValue(Object object, Field field) {
try {
return field.get(object);
} catch (Exception e) {
throw new RuntimeException("Error while getting field value " + field.getName() + " of class " + field.getDeclaringClass().getName() + ".", e);
}
}
static void setFieldValue(Object object, Field field, Object value) {
try {
field.set(object, value);
} catch (Exception e) {
throw new RuntimeException("Error while setting field value " + field.getName() + " of class " + field.getDeclaringClass().getName() + ".", e);
}
}
static Object newInstance(Class<?> clazz) {
try {
return clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("Error creating instance of " + clazz.getName() + ".", e);
}
}
static Object newInstance(Constructor<?> contructor, Object... initargs) {
try {
return contructor.newInstance(initargs);
} catch (Exception e) {
throw new RuntimeException("Error creating instance of " + contructor.getDeclaringClass().getName() + ".", e);
}
}
}