From 910e7080ad9302d17a7eb65d93b0b47e5bded5c9 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Sat, 4 Jun 2022 00:12:36 +0200 Subject: [PATCH] support 1.18.2 (#41) --- .../legacysupport/injector/NMSReflection.java | 8 ++++- .../legacysupport/listener/SoundListener.java | 32 ++++++++++++------- .../reflection/MethodSignature.java | 31 ++++++++++++++++++ .../reflection/ReflectionAPI.java | 29 +++++++++++++++++ 4 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 src/main/java/de/gerrygames/viarewind/legacysupport/reflection/MethodSignature.java diff --git a/src/main/java/de/gerrygames/viarewind/legacysupport/injector/NMSReflection.java b/src/main/java/de/gerrygames/viarewind/legacysupport/injector/NMSReflection.java index 1fd204b..4c39a35 100644 --- a/src/main/java/de/gerrygames/viarewind/legacysupport/injector/NMSReflection.java +++ b/src/main/java/de/gerrygames/viarewind/legacysupport/injector/NMSReflection.java @@ -1,6 +1,8 @@ package de.gerrygames.viarewind.legacysupport.injector; import com.viaversion.viaversion.api.Via; +import de.gerrygames.viarewind.legacysupport.reflection.MethodSignature; +import de.gerrygames.viarewind.legacysupport.reflection.ReflectionAPI; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -120,7 +122,11 @@ public class NMSReflection { .orElseThrow(() -> new ReflectiveOperationException("Failed to find PlayerConnection field in EntityPlayer")); } Object playerConnection = playerConnectionField.get(nmsPlayer); - playerConnection.getClass().getMethod("sendPacket", getPacketClass()).invoke(playerConnection, packet); + ReflectionAPI.pickMethod( + playerConnection.getClass(), + new MethodSignature("sendPacket", getPacketClass()), + new MethodSignature("a", getPacketClass()) + ).invoke(playerConnection, packet); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/src/main/java/de/gerrygames/viarewind/legacysupport/listener/SoundListener.java b/src/main/java/de/gerrygames/viarewind/legacysupport/listener/SoundListener.java index d525c68..a3d77b6 100644 --- a/src/main/java/de/gerrygames/viarewind/legacysupport/listener/SoundListener.java +++ b/src/main/java/de/gerrygames/viarewind/legacysupport/listener/SoundListener.java @@ -3,6 +3,8 @@ package de.gerrygames.viarewind.legacysupport.listener; import com.viaversion.viaversion.api.Via; import de.gerrygames.viarewind.legacysupport.BukkitPlugin; import de.gerrygames.viarewind.legacysupport.injector.NMSReflection; +import de.gerrygames.viarewind.legacysupport.reflection.MethodSignature; +import de.gerrygames.viarewind.legacysupport.reflection.ReflectionAPI; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Sound; @@ -98,20 +100,26 @@ public class SoundListener implements Listener { if (blockPositionClass != null) { blockPosition = blockPositionClass.getConstructor(int.class, int.class, int.class).newInstance(block.getX(), block.getY(), block.getZ()); } - Object blockData = nmsWorld.getClass().getSuperclass().getMethod("getType", blockPositionClass).invoke(nmsWorld, blockPosition); - Method getBlock = blockData.getClass().getMethod("getBlock"); + Method getTypeMethod = ReflectionAPI.pickMethod( + nmsWorld.getClass(), + new MethodSignature("getType", blockPositionClass), + new MethodSignature("a_", blockPositionClass) // 1.18.2 + ); + Object blockData = getTypeMethod.invoke(nmsWorld, blockPosition); + Method getBlock = ReflectionAPI.pickMethod( + blockData.getClass(), + new MethodSignature("getBlock"), + new MethodSignature("b") // 1.18.2 + ); getBlock.setAccessible(true); Object nmsBlock = getBlock.invoke(blockData); - Method getStepSound; - try { - getStepSound = nmsBlock.getClass().getMethod("getStepSound", blockData.getClass()); - } catch (NoSuchMethodException ex) { - try { - getStepSound = nmsBlock.getClass().getMethod("getStepSound"); - } catch (NoSuchMethodException ex2) { - getStepSound = nmsBlock.getClass().getMethod("w"); - } - } + Method getStepSound = ReflectionAPI.pickMethod( + nmsBlock.getClass(), + new MethodSignature("m", blockData.getClass()), // 1.18.2 + new MethodSignature("w"), // 1.18? + new MethodSignature("getStepSound", blockData.getClass()), // 1.17 + new MethodSignature("getStepSound") // pre 1.17 + ); Object soundType; if (getStepSound.getParameterCount() == 0) { diff --git a/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/MethodSignature.java b/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/MethodSignature.java new file mode 100644 index 0000000..c85e3d0 --- /dev/null +++ b/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/MethodSignature.java @@ -0,0 +1,31 @@ +package de.gerrygames.viarewind.legacysupport.reflection; + +import java.util.Arrays; +import java.util.StringJoiner; + +public class MethodSignature { + + private final String name; + private final Class[] parameterTypes; + + public MethodSignature(String name, Class... parameterTypes) { + this.name = name; + this.parameterTypes = parameterTypes; + } + + public String name() { + return name; + } + + public Class[] parameterTypes() { + return parameterTypes; + } + + @Override + public String toString() { + return new StringJoiner(", ", MethodSignature.class.getSimpleName() + "[", "]") + .add("name='" + name + "'") + .add("parameterTypes=" + Arrays.toString(parameterTypes)) + .toString(); + } +} diff --git a/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/ReflectionAPI.java b/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/ReflectionAPI.java index 9017a1b..479cae3 100644 --- a/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/ReflectionAPI.java +++ b/src/main/java/de/gerrygames/viarewind/legacysupport/reflection/ReflectionAPI.java @@ -7,6 +7,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -23,6 +24,34 @@ public class ReflectionAPI { } } + public static Method pickMethod(Class holder, String... names) { + return pickMethod(holder, Arrays.stream(names).map(MethodSignature::new).toArray(MethodSignature[]::new)); + } + + /** + * Recursively searches for (declared) methods at a specific class and all it's superclasses + * @param holder The base class where to start searching + * @param signatures Possible method signatures consisting of method name and parameters + * @return The found {@link Method} or {@code null} + * @throws RuntimeException If no method was found + */ + public static Method pickMethod(Class holder, MethodSignature... signatures) { + Class depth = holder; + do { + for (MethodSignature signature : signatures) { + try { + Method method = depth.getDeclaredMethod(signature.name(), signature.parameterTypes()); + if (!method.isAccessible()) { + method.setAccessible(true); + } + return method; + } catch (NoSuchMethodException ignored) { + } + } + } while ((depth = depth.getSuperclass()) != null); + throw new RuntimeException("Failed to resolve method in " + holder + " using " + Arrays.toString(signatures)); + } + public static Field getField(Class clazz, String fieldname) { String key = clazz.getName() + ":" + fieldname; Field field = null;