Rewrite to use Shuriken libraries

This commit is contained in:
Mark Vainomaa 2017-03-22 01:09:03 +02:00
parent a5131f534b
commit 230e0ffda7
4 changed files with 104 additions and 103 deletions

View File

@ -10,24 +10,25 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>bukkitutils</artifactId>
<version>1.7-SNAPSHOT</version>
<version>1.8-SNAPSHOT</version>
<repositories>
<repository>
<id>destroystokyo-repo</id>
<url>https://repo.destroystokyo.com/repository/maven-public//</url>
</repository>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>eu.mikroskeem</groupId>
<artifactId>reflect</artifactId>
<version>1.1-SNAPSHOT</version>
<artifactId>shuriken.reflect</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>eu.mikroskeem</groupId>
<artifactId>shuriken.instrumentation</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.destroystokyo.paper</groupId>
@ -35,22 +36,11 @@
<version>1.11.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.11.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
<version>1.16.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations-java5</artifactId>
<version>RELEASE</version>
</dependency>
</dependencies>
</project>

View File

@ -1,11 +1,11 @@
package eu.mikroskeem.utils.bukkit;
import eu.mikroskeem.utils.reflect.Reflect;
import eu.mikroskeem.shuriken.reflect.Reflect;
import eu.mikroskeem.shuriken.reflect.wrappers.ClassWrapper;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import static com.google.common.base.Preconditions.checkNotNull;
import static eu.mikroskeem.utils.bukkit.ServerUtils.getNmsVersion;
@ -19,20 +19,22 @@ public class PlayerUtils {
* @param player Player who ping to query
* @return Player's ping (-1 if reflection failed)
*/
public static int getNMSPing(@NotNull Player player){
@SuppressWarnings("unchecked")
public static <CraftPlayer, NMSPlayer> int getNMSPing(@NotNull Player player){
try {
String nmsVer = getNmsVersion();
Class<?> craftPlayerClass = checkNotNull(Reflect.getClass(
String.format("org.bukkit.craftbukkit.%s.entity.CraftPlayer", nmsVer)));
Class<?> craftEntityPlayerClass = checkNotNull(Reflect.getClass(
String.format("net.minecraft.server.%s.EntityPlayer", nmsVer)));
Method getHandle = checkNotNull(Reflect.getMethod(craftPlayerClass, "getHandle"));
Object handle = checkNotNull(Reflect.invokeMethod(getHandle, player));
Field pingField = checkNotNull(Reflect.getField(craftEntityPlayerClass, "ping"));
return (Integer) checkNotNull(Reflect.readField(pingField, handle));
ClassWrapper<CraftPlayer> craftPlayerClass = (ClassWrapper<CraftPlayer>) checkNotNull(Reflect.getClass(
String.format("org.bukkit.craftbukkit.%s.entity.CraftPlayer", nmsVer)).orElse(null))
.setClassInstance(player);
ClassWrapper<NMSPlayer> nmsEntityPlayerClass = (ClassWrapper<NMSPlayer>) checkNotNull(Reflect.getClass(
String.format("net.minecraft.server.%s.EntityPlayer", nmsVer)).orElse(null));
NMSPlayer nmsPlayer = craftPlayerClass
.invokeMethod("getHandle", nmsEntityPlayerClass.getWrappedClass());
nmsEntityPlayerClass.setClassInstance(nmsPlayer);
return checkNotNull(nmsEntityPlayerClass.getField("ping", int.class).orElse(null)).read();
}
catch (NullPointerException ignored){
catch (NullPointerException|NoSuchFieldException|NoSuchMethodException|
IllegalAccessException|InvocationTargetException ignored){}
return -1;
}
}
}

View File

@ -1,13 +1,17 @@
package eu.mikroskeem.utils.bukkit;
import eu.mikroskeem.utils.reflect.Reflect;
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.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@ -21,18 +25,25 @@ public class ServerUtils {
* Will use PaperSpigot's API if available, reflection otherwise
* @return double array of TPS (not rounded!), values are -1 if reflection failed
*/
public static double[] getTPS(){
if(Reflect.getMethod(Bukkit.class, "getTps") != null) {
return Bukkit.getTPS();
} else {
@SuppressWarnings("unchecked")
public static <C> double[] getTPS(){
Class<C> _t = (Class<C>)double[].class;
try {
Class<?> MinecraftServerClass = checkNotNull(Reflect.getClass(
String.format("net.minecraft.server.%s.MinecraftServer", getNmsVersion())));
Method getServer = checkNotNull(Reflect.getMethod(MinecraftServerClass, "getServer"));
Field recentTPS = checkNotNull(Reflect.getField(MinecraftServerClass, "recentTps"));
Object server = checkNotNull(Reflect.invokeMethod(getServer, null));
return (double[]) checkNotNull(Reflect.readField(recentTPS, server));
} catch (NullPointerException ignored){}
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};
}
@ -54,34 +65,42 @@ public class ServerUtils {
*/
JavaPluginLoader pl = (JavaPluginLoader) plugin.getPluginLoader();
try {
Field loadersField = checkNotNull(Reflect.getField(pl.getClass(), "loaders"));
switch (getNmsVersion()){
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":
try {
Map<String, ClassLoader> loaderMap = (Map<String, ClassLoader>)
checkNotNull(Reflect.readField(loadersField, pl));
Map<String, ClassLoader> loaderMap = (Map<String, ClassLoader>) loadersField.read();
return loaderMap.get(plugin.getName());
}
catch (NullPointerException ignored){}
break;
case "v1_10_R1":
case "v1_11_R1":
Class<?> pluginClassLoader = checkNotNull(Reflect.getClass(
"org.bukkit.plugin.java.PluginClassLoader"));
List<ClassLoader> loaders = (List<ClassLoader>)
checkNotNull(Reflect.readField(loadersField, pl));
Optional<ClassLoader> loader = loaders.stream()
.filter(l->{
Field f = checkNotNull(Reflect.getField(pluginClassLoader, "plugin"));
return checkNotNull(((JavaPlugin)Reflect.readField(f, l)))
.getName().equals(plugin.getName());
}).findFirst();
return loader.isPresent()?loader.get():null;
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 (NullPointerException ignored){}
}
catch (NoSuchFieldException|IllegalAccessException ignored){}
return null;
}
@ -89,27 +108,22 @@ public class ServerUtils {
* Get PluginClassLoader classes map
* @param classLoader PluginClassLoader instance
* @return Classes map
* @throws RuntimeException if ClassLoader doesn't extend PluginClassLoader
*/
@SuppressWarnings("unchecked")
@Nullable
public static Map<String, Class<?>> getClassesMap(ClassLoader classLoader){
Class<?> clClass = classLoader.getClass();
try {
Class<?> pluginClassLoader = checkNotNull(Reflect.getClass(
"org.bukkit.plugin.java.PluginClassLoader"),
"Couldn't find org.bukkit.plugin.java.PluginClassLoader class");
if(pluginClassLoader.isAssignableFrom(clClass)){
Field classesField = checkNotNull(Reflect.getField(clClass, "classes"),
"Failed to get classes field");
return (Map<String, Class<?>>) checkNotNull(Reflect.readField(classesField, classLoader));
} else {
throw new RuntimeException(
clClass.getName()
+ " does not extend "
+ pluginClassLoader.getName());
}
} catch(NullPointerException e){
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;

View File

@ -1,12 +1,13 @@
package eu.mikroskeem.utils.bukkit.fakeplugin;
import eu.mikroskeem.utils.reflect.Reflect;
import eu.mikroskeem.shuriken.reflect.Reflect;
import eu.mikroskeem.shuriken.reflect.simple.SimpleReflect;
import eu.mikroskeem.shuriken.reflect.wrappers.ClassWrapper;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.SimplePluginManager;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@ -25,23 +26,17 @@ public class FakePluginFactory {
@SuppressWarnings("unchecked")
public FakePluginFactory(Plugin parentPlugin){
this.plugin = parentPlugin;
Field lookupNamesField, pluginsField;
if(plugin.getServer().getPluginManager().getClass() != SimplePluginManager.class){
throw new RuntimeException("Server PluginManager is not SimplePluginManager");
}
isPaper = Reflect.getMethod(Bukkit.class, "getTPS") != null;
isPaper = SimpleReflect.getMethod(Bukkit.class, "getTPS", double[].class) != null;
try {
pluginsField = checkNotNull(Reflect.getField(
SimplePluginManager.class,
"plugins"));
lookupNamesField = checkNotNull(Reflect.getField(
SimplePluginManager.class,
"lookupNames"));
plugins = (List<Plugin>) checkNotNull(Reflect.readField(pluginsField,
plugin.getServer().getPluginManager()));
lookupNames = (Map<String, Plugin>) checkNotNull(Reflect.readField(lookupNamesField,
plugin.getServer().getPluginManager()));
} catch (NullPointerException e){
ClassWrapper<SimplePluginManager> spm = Reflect.wrapClass(SimplePluginManager.class)
.setClassInstance(plugin.getServer().getPluginManager());
plugins = (List<Plugin>) checkNotNull(spm.getField("plugins", List.class).orElse(null)).read();
lookupNames = (Map<String, Plugin>) checkNotNull(spm.getField("lookupNames", Map.class).orElse(null)).read();
} catch (Exception e){
e.printStackTrace();
throw new RuntimeException("Failed to get 'plugins' and 'lookupNames' field!");
}
}