Added 1.13.2 support, made backwards premium

This commit is contained in:
libraryaddict
2020-02-13 19:47:02 +13:00
parent 7fdbea1185
commit 1fcefbcdcc
49 changed files with 1114 additions and 539 deletions

View File

@@ -2,11 +2,14 @@ package me.libraryaddict.disguise.utilities.reflection;
import org.bukkit.entity.Entity;
import java.io.File;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.util.ArrayList;
@@ -20,27 +23,36 @@ import java.util.jar.JarFile;
// Code for this taken and slightly modified from
// https://github.com/ddopson/java-class-enumerator
public class ClassGetter {
private class TestPrem {
String user = "%%__USER__%%";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
private @interface PremInfo {
String user();
}
public static ArrayList<Class<?>> getClassesForPackage(String pkgname) {
return getClassesForPackage(Entity.class, pkgname);
}
public static ArrayList<Class<?>> getClassesForPackage(Class runFrom, String pkgname) {
ArrayList<Class<?>> classes = new ArrayList<>();
// String relPath = pkgname.replace('.', '/');
// Get a File object for the package
CodeSource src = Entity.class.getProtectionDomain().getCodeSource();
CodeSource src = runFrom.getProtectionDomain().getCodeSource();
if (src != null) {
URL resource = src.getLocation();
resource.getPath();
processJarfile(resource, pkgname, classes);
if (resource.getPath().endsWith(".jar")) {
processJarfile(resource, pkgname, classes);
} else {
for (File f : new File(resource.getPath() + "/" + pkgname.replace(".", "/")).listFiles()) {
if (!f.getName().endsWith(".class")) {
continue;
}
try {
classes.add(Class.forName(pkgname + "." + f.getName().replace(".class", "")));
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
return classes;
@@ -58,7 +70,6 @@ public class ClassGetter {
}
}
@PremInfo(user = "%%__USER__%%")
private static void processJarfile(URL resource, String pkgname, ArrayList<Class<?>> classes) {
try {
String relPath = pkgname.replace('.', '/');

View File

@@ -0,0 +1,79 @@
package me.libraryaddict.disguise.utilities.reflection;
import me.libraryaddict.disguise.disguisetypes.FlagWatcher;
import me.libraryaddict.disguise.disguisetypes.watchers.MushroomCowWatcher;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* Created by libraryaddict on 13/02/2020.
*/
public class CompileMethods {
public static void main(String[] args) {
ArrayList<Class<?>> classes = ClassGetter
.getClassesForPackage(FlagWatcher.class, "me.libraryaddict.disguise.disguisetypes.watchers");
classes.add(FlagWatcher.class);
classes.add(MushroomCowWatcher.class);
ArrayList<String> methods = new ArrayList<>();
for (Class c : classes) {
for (Method method : c.getMethods()) {
if (method.getParameterTypes().length != 1) {
continue;
} else if (method.getName().startsWith("get")) {
continue;
} else if (method.isAnnotationPresent(Deprecated.class) &&
!method.isAnnotationPresent(NmsRemovedIn.class)) {
continue;
} else if (!method.getReturnType().equals(Void.TYPE)) {
continue;
} else if (method.getName().equals("removePotionEffect")) {
continue;
} else if (!FlagWatcher.class.isAssignableFrom(method.getDeclaringClass())) {
continue;
}
int added = -1;
int removed = -1;
if (method.isAnnotationPresent(NmsAddedIn.class)) {
added = method.getAnnotation(NmsAddedIn.class).val().ordinal();
} else if (method.getDeclaringClass().isAnnotationPresent(NmsAddedIn.class)) {
added = method.getDeclaringClass().getAnnotation(NmsAddedIn.class).val().ordinal();
}
if (method.isAnnotationPresent(NmsRemovedIn.class)) {
removed = method.getAnnotation(NmsRemovedIn.class).val().ordinal();
} else if (method.getDeclaringClass().isAnnotationPresent(NmsRemovedIn.class)) {
removed = method.getDeclaringClass().getAnnotation(NmsRemovedIn.class).val().ordinal();
}
Class<?> param = method.getParameterTypes()[0];
String s = ((added >= 0 || removed >= 0) ? added + ":" + removed + ":" : "") +
method.getDeclaringClass().getSimpleName() + ":" + method.getName() + ":" +
param.getName();
if (methods.contains(s)) {
continue;
}
methods.add(s);
}
}
File methodsFile = new File("target/classes/methods.txt");
try (PrintWriter writer = new PrintWriter(methodsFile, "UTF-8")) {
writer.write(StringUtils.join(methods, "\n"));
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@@ -0,0 +1,133 @@
package me.libraryaddict.disguise.utilities.reflection;
import me.libraryaddict.disguise.LibsDisguises;
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
import me.libraryaddict.disguise.disguisetypes.FlagWatcher;
import org.apache.commons.lang.ClassUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;
/**
* Created by libraryaddict on 13/02/2020.
*/
public class DisguiseMethods {
private HashMap<Class<? extends FlagWatcher>, List<Method>> watcherMethods = new HashMap<>();
public ArrayList<Method> getMethods(Class c) {
ArrayList<Method> methods = new ArrayList<>();
if (watcherMethods.containsKey(c)) {
methods.addAll(watcherMethods.get(c));
}
if (c != FlagWatcher.class) {
methods.addAll(getMethods(c.getSuperclass()));
}
return methods;
}
public DisguiseMethods() {
try (InputStream stream = LibsDisguises.getInstance().getResource("methods.txt")) {
List<String> lines = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)).lines()
.collect(Collectors.toList());
HashMap<String, Class<? extends FlagWatcher>> classes = new HashMap<>();
classes.put(FlagWatcher.class.getSimpleName(), FlagWatcher.class);
for (DisguiseType t : DisguiseType.values()) {
if (t.getWatcherClass() == null) {
continue;
}
Class c = t.getWatcherClass();
while (!classes.containsKey(c.getSimpleName())) {
classes.put(c.getSimpleName(), c);
c = ReflectionManager.getSuperClass(c);
}
}
for (String line : lines) {
String[] split = line.split(":");
if (split.length > 3) {
int added = Integer.parseInt(split[0]);
int removed = Integer.parseInt(split[1]);
if (added >= 0 && added > ReflectionManager.getVersion().ordinal()) {
continue;
} else if (removed >= 0 && removed <= ReflectionManager.getVersion().ordinal()) {
continue;
}
}
Class<? extends FlagWatcher> watcher = classes.get(split[split.length - 3]);
if (watcher == null) {
continue;
}
String paramName = split[split.length - 1];
Class param;
if (!paramName.contains(".")) {
param = parseType(paramName);
} else {
param = Class.forName(paramName);
}
Method method = watcher.getMethod(split[split.length - 2], param);
watcherMethods.computeIfAbsent(watcher, (a) -> new ArrayList<>()).add(method);
}
}
catch (IOException | ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* Return the java {@link java.lang.Class} object with the specified class name.
* <p>
* This is an "extended" {@link java.lang.Class#forName(java.lang.String) } operation.
* <p>
* + It is able to return Class objects for primitive types
* + Classes in name space `java.lang` do not need the fully qualified name
* + It does not throw a checked Exception
*
* @param className The class name, never `null`
* @throws IllegalArgumentException if no class can be loaded
*/
private Class<?> parseType(final String className) {
switch (className) {
case "boolean":
return boolean.class;
case "byte":
return byte.class;
case "short":
return short.class;
case "int":
return int.class;
case "long":
return long.class;
case "float":
return float.class;
case "double":
return double.class;
case "char":
return char.class;
case "[I":
return int[].class;
default:
throw new IllegalArgumentException("Class not found: " + className);
}
}
}

View File

@@ -7,6 +7,6 @@ import java.lang.annotation.RetentionPolicy;
* Created by libraryaddict on 6/02/2020.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NmsAdded {
NmsVersion added();
public @interface NmsAddedIn {
NmsVersion val();
}

View File

@@ -7,6 +7,6 @@ import java.lang.annotation.RetentionPolicy;
* Created by libraryaddict on 6/02/2020.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NmsRemoved {
NmsVersion removed();
public @interface NmsRemovedIn {
NmsVersion val();
}

View File

@@ -4,6 +4,14 @@ package me.libraryaddict.disguise.utilities.reflection;
* Created by libraryaddict on 6/02/2020.
*/
public enum NmsVersion {
v1_13,
v1_14,
v1_15
v1_15;
/**
* If this nms version isn't newer than the running version
*/
public boolean isSupported() {
return ReflectionManager.getVersion().ordinal() >= ordinal();
}
}

View File

@@ -18,7 +18,7 @@ import org.apache.commons.lang.StringUtils;
import org.bukkit.*;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.craftbukkit.libs.org.apache.commons.io.IOUtils;
import org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.bukkit.entity.*;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
@@ -26,15 +26,19 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.util.Vector;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.*;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
public class ReflectionManager {
private static String bukkitVersion;
@@ -43,18 +47,20 @@ public class ReflectionManager {
private static Constructor<?> boundingBoxConstructor;
private static Method setBoundingBoxMethod;
private static Field pingField;
public static Field entityCountField;
private static Field entityCountField;
private static Field chunkMapField;
private static Field chunkProviderField;
private static Field entityTrackerField;
private static Field trackedEntitiesField;
@NmsRemovedIn(val = NmsVersion.v1_14)
private static Method ihmGet;
@NmsRemovedIn(val = NmsVersion.v1_14)
private static Field trackerField;
@NmsRemovedIn(val = NmsVersion.v1_14)
private static Field entitiesField;
@Getter
private static NmsVersion version;
public static boolean isSupported(NmsVersion version) {
return getVersion().ordinal() >= version.ordinal();
}
public static void init() {
try {
Object entity = createEntityInstance(DisguiseType.COW, "Cow");
@@ -88,10 +94,16 @@ public class ReflectionManager {
pingField = getNmsField("EntityPlayer", "ping");
chunkProviderField = getNmsField("World", "chunkProvider");
chunkMapField = getNmsField("ChunkProviderServer", "playerChunkMap");
trackedEntitiesField = getNmsField("PlayerChunkMap", "trackedEntities");
entityTrackerField = getNmsField("PlayerChunkMap$EntityTracker", "trackerEntry");
if (NmsVersion.v1_14.isSupported()) {
chunkProviderField = getNmsField("World", "chunkProvider");
chunkMapField = getNmsField("ChunkProviderServer", "playerChunkMap");
trackedEntitiesField = getNmsField("PlayerChunkMap", "trackedEntities");
entityTrackerField = getNmsField("PlayerChunkMap$EntityTracker", "trackerEntry");
} else {
trackerField = getNmsField("WorldServer", "tracker");
entitiesField = getNmsField("EntityTracker", "trackedEntities");
ihmGet = getNmsMethod("IntHashMap", "get", int.class);
}
boundingBoxConstructor = getNmsConstructor("AxisAlignedBB", double.class, double.class, double.class,
double.class, double.class, double.class);
@@ -104,19 +116,19 @@ public class ReflectionManager {
}
public static boolean isSupported(AccessibleObject obj) {
if (obj.isAnnotationPresent(NmsAdded.class)) {
NmsAdded added = obj.getAnnotation(NmsAdded.class);
if (obj.isAnnotationPresent(NmsAddedIn.class)) {
NmsAddedIn added = obj.getAnnotation(NmsAddedIn.class);
// If it was added after/on this version
if (!isSupported(added.added())) {
// If it was added after this version
if (!added.val().isSupported()) {
return false;
}
}
if (obj.isAnnotationPresent(NmsRemoved.class)) {
NmsRemoved removed = obj.getAnnotation(NmsRemoved.class);
if (obj.isAnnotationPresent(NmsRemovedIn.class)) {
NmsRemovedIn removed = obj.getAnnotation(NmsRemovedIn.class);
if (isSupported(removed.removed())) {
if (removed.val().isSupported()) {
return false;
}
}
@@ -152,7 +164,8 @@ public class ReflectionManager {
public static YamlConfiguration getPluginYaml(ClassLoader loader) {
try (InputStream stream = loader.getResourceAsStream("plugin.yml")) {
YamlConfiguration config = new YamlConfiguration();
config.loadFromString(IOUtils.toString(stream, "UTF-8"));
config.loadFromString(new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)).lines()
.collect(Collectors.joining("\n")));
return config;
}
@@ -169,17 +182,21 @@ public class ReflectionManager {
public static int getNewEntityId(boolean increment) {
try {
AtomicInteger entityCount = (AtomicInteger) entityCountField.get(null);
int id;
Number entityCount = (Number) entityCountField.get(null);
if (increment) {
id = entityCount.getAndIncrement();
} else {
id = entityCount.get();
if (NmsVersion.v1_14.isSupported()) {
return ((AtomicInteger) entityCount).getAndIncrement();
} else {
int id = entityCount.intValue();
entityCountField.set(null, id + 1);
return id;
}
}
return id;
return entityCount.intValue();
}
catch (IllegalAccessException e) {
e.printStackTrace();
@@ -194,34 +211,44 @@ public class ReflectionManager {
Object entityObject;
Object world = getWorldServer(Bukkit.getWorlds().get(0));
switch (entityName) {
case "Player":
Object minecraftServer = getNmsMethod("MinecraftServer", "getServer").invoke(null);
if (entityName.equals("Player")) {
Object minecraftServer = getNmsMethod("MinecraftServer", "getServer").invoke(null);
Object playerinteractmanager = getNmsClass("PlayerInteractManager")
.getDeclaredConstructor(getNmsClass("WorldServer")).newInstance(world);
Object playerinteractmanager = getNmsClass("PlayerInteractManager")
.getDeclaredConstructor(getNmsClass(NmsVersion.v1_14.isSupported() ? "WorldServer" : "World"))
.newInstance(world);
WrappedGameProfile gameProfile = getGameProfile(new UUID(0, 0), "Steve");
WrappedGameProfile gameProfile = getGameProfile(new UUID(0, 0), "Steve");
entityObject = entityClass
.getDeclaredConstructor(getNmsClass("MinecraftServer"), getNmsClass("WorldServer"),
gameProfile.getHandleType(), playerinteractmanager.getClass())
.newInstance(minecraftServer, world, gameProfile.getHandle(), playerinteractmanager);
break;
case "EnderPearl":
entityObject = entityClass.getDeclaredConstructor(getNmsClass("World"), getNmsClass("EntityLiving"))
.newInstance(world, createEntityInstance(DisguiseType.COW, "Cow"));
break;
case "FishingHook":
entityObject = entityClass
.getDeclaredConstructor(getNmsClass("MinecraftServer"), getNmsClass("WorldServer"),
gameProfile.getHandleType(), playerinteractmanager.getClass())
.newInstance(minecraftServer, world, gameProfile.getHandle(), playerinteractmanager);
} else if (entityName.equals("EnderPearl")) {
entityObject = entityClass.getDeclaredConstructor(getNmsClass("World"), getNmsClass("EntityLiving"))
.newInstance(world, createEntityInstance(DisguiseType.COW, "Cow"));
} else if (entityName.equals("FishingHook")) {
if (NmsVersion.v1_14.isSupported()) {
entityObject = entityClass
.getDeclaredConstructor(getNmsClass("EntityHuman"), getNmsClass("World"), int.class,
int.class)
.newInstance(createEntityInstance(DisguiseType.PLAYER, "Player"), world, 0, 0);
break;
default:
} else {
entityObject = entityClass.getDeclaredConstructor(getNmsClass("World"), getNmsClass("EntityHuman"))
.newInstance(world, createEntityInstance(DisguiseType.PLAYER, "Player"));
}
} else if (!NmsVersion.v1_14.isSupported() && entityName.equals("Potion")) {
entityObject = entityClass
.getDeclaredConstructor(getNmsClass("World"), Double.TYPE, Double.TYPE, Double.TYPE,
getNmsClass("ItemStack"))
.newInstance(world, 0d, 0d, 0d, getNmsItem(new ItemStack(Material.SPLASH_POTION)));
} else {
if (NmsVersion.v1_14.isSupported()) {
entityObject = entityClass.getDeclaredConstructor(getNmsClass("EntityTypes"), getNmsClass("World"))
.newInstance(getEntityType(disguiseType.getEntityType()), world);
break;
} else {
entityObject = entityClass.getDeclaredConstructor(getNmsClass("World")).newInstance(world);
}
}
return entityObject;
@@ -395,17 +422,25 @@ public class ReflectionManager {
public static Object getEntityTrackerEntry(Entity target) throws Exception {
Object world = getWorldServer(target.getWorld());
Object chunkProvider = chunkProviderField.get(world);
Object chunkMap = chunkMapField.get(chunkProvider);
Map trackedEntities = (Map) trackedEntitiesField.get(chunkMap);
Object entityTracker = trackedEntities.get(target.getEntityId());
if (NmsVersion.v1_14.isSupported()) {
Object chunkProvider = chunkProviderField.get(world);
Object chunkMap = chunkMapField.get(chunkProvider);
Map trackedEntities = (Map) trackedEntitiesField.get(chunkMap);
if (entityTracker == null) {
return null;
Object entityTracker = trackedEntities.get(target.getEntityId());
if (entityTracker == null) {
return null;
}
return entityTrackerField.get(entityTracker);
}
return entityTrackerField.get(entityTracker);
Object tracker = trackerField.get(world);
Object trackedEntities = entitiesField.get(tracker);
return ihmGet.invoke(trackedEntities, target.getEntityId());
}
public static Object getMinecraftServer() {
@@ -675,13 +710,21 @@ public class ReflectionManager {
public static float[] getSize(Entity entity) {
try {
Object size = getNmsField("Entity", "size").get(getNmsEntity(entity));
if (NmsVersion.v1_14.isSupported()) {
Object size = getNmsField("Entity", "size").get(getNmsEntity(entity));
//float length = getNmsField("EntitySize", "length").getFloat(size);
float width = getNmsField("EntitySize", "width").getFloat(size);
float height = getNmsField("Entity", "headHeight").getFloat(getNmsEntity(entity));
//float length = getNmsField("EntitySize", "length").getFloat(size);
float width = getNmsField("EntitySize", "width").getFloat(size);
float height = getNmsField("Entity", "headHeight").getFloat(getNmsEntity(entity));
return new float[]{width, height};
return new float[]{width, height};
} else {
// float length = getNmsField("Entity", "length").getFloat(getNmsEntity(entity));
float width = getNmsField("Entity", "width").getFloat(getNmsEntity(entity));
float height = (Float) getNmsMethod("Entity", "getHeadHeight").invoke(getNmsEntity(entity));
return new float[]{width, height};
}
}
catch (Exception ex) {
ex.printStackTrace();
@@ -1045,6 +1088,30 @@ public class ReflectionManager {
return null;
}
public static boolean isAssignableFrom(Class toCheck, Class checkAgainst) {
if (!NmsVersion.v1_14.isSupported() && toCheck != checkAgainst) {
if (toCheck == OcelotWatcher.class) {
toCheck = TameableWatcher.class;
}
}
return checkAgainst.isAssignableFrom(toCheck);
}
public static Class getSuperClass(Class cl) {
if (cl == FlagWatcher.class) {
return null;
}
if (!NmsVersion.v1_14.isSupported()) {
if (cl == OcelotWatcher.class) {
return TameableWatcher.class;
}
}
return cl.getSuperclass();
}
public static Object getVillagerProfession(Villager.Profession profession) {
try {
Object villagerProfession = getNmsField("IRegistry", "VILLAGER_PROFESSION").get(null);
@@ -1124,10 +1191,14 @@ public class ReflectionManager {
public static Object getEntityType(EntityType entityType) {
try {
Method entityTypes = getNmsMethod("EntityTypes", "a", String.class);
Object val = entityTypes.invoke(null,
entityType.getName() == null ? entityType.name().toLowerCase() : entityType.getName());
Optional<Object> entityObj = (Optional<Object>) entityTypes.invoke(null, entityType.getName());
if (NmsVersion.v1_14.isSupported()) {
return ((Optional<Object>) val).orElse(null);
}
return entityObj.orElse(null);
return val;
}
catch (Exception e) {
e.printStackTrace();
@@ -1513,6 +1584,7 @@ public class ReflectionManager {
DisguiseUtilities.getLogger()
.severe("Value: " + watch.getRawValue() + " (" + watch.getRawValue().getClass() + ") (" +
nmsEntity.getClass() + ") & " + disguiseType.getWatcherClass().getSimpleName());
continue;
}