145 lines
6.4 KiB
Java
145 lines
6.4 KiB
Java
package eu.mikroskeem.utils.bukkit;
|
|
|
|
import eu.mikroskeem.shuriken.instrumentation.validate.ClassDescriptor;
|
|
import eu.mikroskeem.shuriken.instrumentation.validate.FieldDescriptor;
|
|
import eu.mikroskeem.shuriken.instrumentation.validate.Validate;
|
|
import eu.mikroskeem.shuriken.reflect.Reflect;
|
|
import eu.mikroskeem.shuriken.reflect.wrappers.ClassWrapper;
|
|
import eu.mikroskeem.shuriken.reflect.wrappers.FieldWrapper;
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
import org.bukkit.plugin.java.JavaPluginLoader;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
|
|
import static com.google.common.base.Preconditions.checkNotNull;
|
|
|
|
public class ServerUtils {
|
|
/**
|
|
* Get server's TPS
|
|
*
|
|
* Will use PaperSpigot's API if available, reflection otherwise
|
|
* @return double array of TPS (not rounded!), values are -1 if reflection failed
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
public static <C> double[] getTPS(){
|
|
Class<C> _t = (Class<C>)double[].class;
|
|
try {
|
|
return Reflect.wrapClass(Bukkit.class).invokeMethod("getTPS", double[].class);
|
|
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
|
|
try {
|
|
Optional<ClassWrapper<?>> minecraftServerClassOpt = Reflect.getClass(String.format(
|
|
"net.minecraft.server.%s.MinecraftServer", getNmsVersion()
|
|
));
|
|
if (minecraftServerClassOpt.isPresent()) {
|
|
ClassWrapper<?> minecraftServerClass = minecraftServerClassOpt.get();
|
|
minecraftServerClass.invokeMethod("getServer", minecraftServerClass.getWrappedClass());
|
|
Optional<FieldWrapper<C>> recentTpsOpt = minecraftServerClass.getField("recentTps", _t);
|
|
if(recentTpsOpt.isPresent())
|
|
return (double[]) recentTpsOpt.get().read();
|
|
}
|
|
}
|
|
catch (NoSuchMethodException|NoSuchFieldException|InvocationTargetException|IllegalAccessException ignored){}
|
|
}
|
|
return new double[]{-1, -1, -1};
|
|
}
|
|
|
|
/**
|
|
* Get plugin class loader. Useful when you want to add new classes on runtime
|
|
*
|
|
* @param plugin Plugin which will be used to get plugin ClassLoader
|
|
* @return Plugin ClassLoader
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
@Nullable
|
|
public static ClassLoader getPluginClassLoader(JavaPlugin plugin){
|
|
/*
|
|
* Note: CB/Spigot has PluginClassLoader package-private, PaperSpigot has public
|
|
* So *DO NOT* try to cast this ClassLoader to PluginClassLoader, if you aim to be
|
|
* compatible with other Bukkit-based servers
|
|
* I repeat, *DO NOT USE* PluginClassLoader!
|
|
*/
|
|
JavaPluginLoader pl = (JavaPluginLoader) plugin.getPluginLoader();
|
|
try {
|
|
Optional<FieldWrapper<Object>> loadersFieldOpt = Reflect
|
|
.wrapClass(pl.getClass())
|
|
.setClassInstance(pl)
|
|
.getField("loaders", Object.class);
|
|
if(loadersFieldOpt.isPresent()) {
|
|
FieldWrapper<Object> loadersField = loadersFieldOpt.get();
|
|
switch (ServerUtils.getNmsVersion()){
|
|
case "v1_8_R3":
|
|
case "v1_9_R1":
|
|
case "v1_9_R2":
|
|
Map<String, ClassLoader> loaderMap = (Map<String, ClassLoader>) loadersField.read();
|
|
return loaderMap.get(plugin.getName());
|
|
case "v1_10_R1":
|
|
case "v1_11_R1":
|
|
Optional<ClassWrapper<?>> pluginClassLoaderOpt = Reflect
|
|
.getClass("org.bukkit.plugin.java.PluginClassLoader");
|
|
if(pluginClassLoaderOpt.isPresent()){
|
|
List<ClassLoader> loaders = (List<ClassLoader>) loadersField.read();
|
|
return loaders.stream().filter(loader -> {
|
|
try {
|
|
String pluginName = Reflect.wrapInstance(loader)
|
|
.getField("plugin", JavaPlugin.class)
|
|
.get()
|
|
.read()
|
|
.getName();
|
|
return pluginName.equals(plugin.getName());
|
|
}
|
|
catch (NoSuchFieldException|IllegalAccessException|NullPointerException ignored){}
|
|
return false;
|
|
}).findFirst().orElse(null);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
catch (NoSuchFieldException|IllegalAccessException ignored){}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get PluginClassLoader classes map
|
|
* @param classLoader PluginClassLoader instance
|
|
* @return Classes map
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
@Nullable
|
|
public static Map<String, Class<?>> getClassesMap(ClassLoader classLoader){
|
|
Class<?> clClass = classLoader.getClass();
|
|
try {
|
|
ClassWrapper<?> pluginClassLoader = checkNotNull(Reflect
|
|
.getClass("org.bukkit.plugin.java.PluginClassLoader").orElse(null),
|
|
"Couldn't find org.bukkit.plugin.java.PluginClassLoader class")
|
|
.setClassInstance(classLoader);
|
|
Validate.checkFields(pluginClassLoader, FieldDescriptor.of("classes", Map.class));
|
|
Validate.checkClass(ClassDescriptor.ofWrapped(clClass, pluginClassLoader));
|
|
return (Map<String, Class<?>>) checkNotNull(pluginClassLoader.getField("classes", Map.class)
|
|
.orElse(null),
|
|
"Failed to get classes field").read();
|
|
} catch(NoSuchFieldException|IllegalAccessException|NullPointerException e){
|
|
e.printStackTrace();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get NMS version of current running server
|
|
* @return NMS version or 0 length string
|
|
*/
|
|
public static String getNmsVersion(){
|
|
try {
|
|
String bukkitPackageName = Bukkit.getServer().getClass().getPackage().getName();
|
|
return bukkitPackageName.substring(bukkitPackageName.lastIndexOf(".") + 1);
|
|
} catch (NullPointerException e){
|
|
return "";
|
|
}
|
|
}
|
|
}
|