diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/reflection/ReflectionBuilder.java b/plugin/src/main/java/lol/pyr/znpcsplus/reflection/ReflectionBuilder.java index 0476f96..c31b8ef 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/reflection/ReflectionBuilder.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/reflection/ReflectionBuilder.java @@ -19,6 +19,10 @@ public class ReflectionBuilder { private Class expectType; private boolean strict = true; + public ReflectionBuilder() { + this(""); + } + public ReflectionBuilder(Class clazz) { this(""); withClassName(clazz); @@ -40,6 +44,11 @@ public class ReflectionBuilder { return this; } + public ReflectionBuilder withRawClassName(String className) { + this.className.add(className); + return this; + } + public ReflectionBuilder withClassName(Class clazz) { if (clazz != null) className.add(clazz.getName()); return this; diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/reflection/Reflections.java b/plugin/src/main/java/lol/pyr/znpcsplus/reflection/Reflections.java index e47d8a2..5521938 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/reflection/Reflections.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/reflection/Reflections.java @@ -2,7 +2,6 @@ package lol.pyr.znpcsplus.reflection; import com.github.retrooper.packetevents.PacketEvents; import com.github.retrooper.packetevents.manager.server.ServerVersion; -import com.mojang.authlib.GameProfile; import lol.pyr.znpcsplus.reflection.types.FieldReflection; import lol.pyr.znpcsplus.util.FoliaUtil; import org.bukkit.Bukkit; @@ -11,6 +10,7 @@ import org.bukkit.entity.Entity; import org.bukkit.plugin.Plugin; import java.lang.reflect.Method; +import java.util.Collection; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -20,9 +20,14 @@ import java.util.function.Consumer; * uses to access inaccessible components of the server jar. */ public final class Reflections { - public static final Class ENTITY_CLASS = - new ReflectionBuilder(ReflectionPackage.ENTITY) - .withClassName("Entity") + + /* + * Game profile methods used for obtaining raw skin data of online players + */ + + public static final Class GAME_PROFILE_CLASS = + new ReflectionBuilder() + .withRawClassName("com.mojang.authlib.GameProfile") .toClassReflection().get(); public static final Class ENTITY_HUMAN_CLASS = @@ -31,18 +36,70 @@ public final class Reflections { .withClassName("EntityHuman") .toClassReflection().get(); + public static final ReflectionLazyLoader GET_PLAYER_HANDLE_METHOD = + new ReflectionBuilder(ReflectionPackage.BUKKIT) + .withClassName("entity.CraftPlayer") + .withClassName("entity.CraftHumanEntity") + .withMethodName("getHandle") + .withExpectResult(ENTITY_HUMAN_CLASS) + .toMethodReflection(); + public static final ReflectionLazyLoader GET_PROFILE_METHOD = new ReflectionBuilder(ReflectionPackage.ENTITY) .withClassName(ENTITY_HUMAN_CLASS) - .withExpectResult(GameProfile.class) + .withExpectResult(GAME_PROFILE_CLASS) .toMethodReflection(); - public static final ReflectionLazyLoader GET_HANDLE_PLAYER_METHOD = - new ReflectionBuilder(ReflectionPackage.BUKKIT) - .withClassName("entity.CraftPlayer").withClassName("entity.CraftHumanEntity") - .withMethodName("getHandle") + public static final Class PROPERTY_MAP_CLASS = + new ReflectionBuilder() + .withRawClassName("com.mojang.authlib.properties.PropertyMap") + .toClassReflection().get(); + + public static final ReflectionLazyLoader GET_PROPERTY_MAP_METHOD = + new ReflectionBuilder(GAME_PROFILE_CLASS) + .withMethodName("getProperties") + .withExpectResult(PROPERTY_MAP_CLASS) .toMethodReflection(); + public static final ReflectionLazyLoader PROPERTY_MAP_VALUES_METHOD = + new ReflectionBuilder() + .withClassName(PROPERTY_MAP_CLASS.getSuperclass()) + .withMethodName("values") + .withExpectResult(Collection.class) + .toMethodReflection(); + + public static final Class PROPERTY_CLASS = + new ReflectionBuilder() + .withRawClassName("com.mojang.authlib.properties.Property") + .toClassReflection().get(); + + public static final ReflectionLazyLoader PROPERTY_GET_NAME_METHOD = + new ReflectionBuilder(PROPERTY_CLASS) + .withMethodName("getName") + .withExpectResult(String.class) + .toMethodReflection(); + + public static final ReflectionLazyLoader PROPERTY_GET_VALUE_METHOD = + new ReflectionBuilder(PROPERTY_CLASS) + .withMethodName("getValue") + .withExpectResult(String.class) + .toMethodReflection(); + + public static final ReflectionLazyLoader PROPERTY_GET_SIGNATURE_METHOD = + new ReflectionBuilder(PROPERTY_CLASS) + .withMethodName("getSignature") + .withExpectResult(String.class) + .toMethodReflection(); + + /* + * These methods are used for reserving entity ids so regular Minecraft + * entity packets don't interfere with our packet-based entities + */ + + public static final Class ENTITY_CLASS = + new ReflectionBuilder(ReflectionPackage.ENTITY) + .withClassName("Entity") + .toClassReflection().get(); public static final FieldReflection.ValueModifier ENTITY_ID_MODIFIER = new ReflectionBuilder(ReflectionPackage.ENTITY) .withClassName(ENTITY_CLASS) @@ -62,6 +119,11 @@ public final class Reflections { .toFieldReflection() .toStaticValueLoader(AtomicInteger.class); + /* + * All of these folia methods need to be reflected because folia is strictly + * available on the newest java versions but we need to keep support for Java 8 + */ + public static final Class ASYNC_SCHEDULER_CLASS = new ReflectionBuilder("io.papermc.paper.threadedregions.scheduler") .withClassName("AsyncScheduler") diff --git a/plugin/src/main/java/lol/pyr/znpcsplus/skin/Skin.java b/plugin/src/main/java/lol/pyr/znpcsplus/skin/Skin.java index 90841ba..e86423f 100644 --- a/plugin/src/main/java/lol/pyr/znpcsplus/skin/Skin.java +++ b/plugin/src/main/java/lol/pyr/znpcsplus/skin/Skin.java @@ -4,13 +4,12 @@ import com.github.retrooper.packetevents.protocol.player.TextureProperty; import com.github.retrooper.packetevents.protocol.player.UserProfile; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import com.mojang.authlib.properties.PropertyMap; +import lol.pyr.znpcsplus.reflection.Reflections; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; public class Skin { private final long timestamp = System.currentTimeMillis(); @@ -21,18 +20,23 @@ public class Skin { properties.add(new TextureProperty("textures", texture, signature)); } - public Skin(TextureProperty... properties) { - this.properties = Arrays.asList(properties); - } - public Skin(Collection properties) { this.properties = new ArrayList<>(properties); } - public Skin(PropertyMap properties) { - this.properties = properties.values().stream() - .map(property -> new TextureProperty(property.getName(), property.getValue(), property.getSignature())) - .collect(Collectors.toList()); + public Skin(Object propertyMap) { + this.properties = new ArrayList<>(); + try { + Collection properties = (Collection) Reflections.PROPERTY_MAP_VALUES_METHOD.get().invoke(propertyMap); + for (Object property : properties) { + String name = (String) Reflections.PROPERTY_GET_NAME_METHOD.get().invoke(property); + String value = (String) Reflections.PROPERTY_GET_VALUE_METHOD.get().invoke(property); + String signature = (String) Reflections.PROPERTY_GET_SIGNATURE_METHOD.get().invoke(property); + this.properties.add(new TextureProperty(name, value, signature)); + } + } catch (IllegalAccessException | InvocationTargetException e) { + throw new RuntimeException(e); + } } public Skin(JsonObject obj) {