From 5fb1033c56c4b3f19d5808583342ca4a2920ed20 Mon Sep 17 00:00:00 2001 From: FlorianMichael <60033407+FlorianMichael@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:14:29 +0200 Subject: [PATCH] Fixed broken reflection code --- build.gradle | 2 +- .../legacysupport/injector/NMSReflection.java | 37 +++--- .../legacysupport/listener/SoundListener.java | 122 ++++++++++-------- .../reflection/ReflectionAPI.java | 38 ++---- src/main/resources/plugin.yml | 4 +- 5 files changed, 97 insertions(+), 106 deletions(-) diff --git a/build.gradle b/build.gradle index b11c9c5..de0d56e 100644 --- a/build.gradle +++ b/build.gradle @@ -91,7 +91,7 @@ hangarPublish { changelog.set(changelogContent) apiKey.set(System.getenv("HANGAR_TOKEN")) platforms { - paper { + PAPER { jar.set(tasks.jar.archiveFile) platformVersions.set([property('mcVersionRange') as String]) dependencies.hangar("ViaVersion") { diff --git a/src/main/java/com/viaversion/viarewind/legacysupport/injector/NMSReflection.java b/src/main/java/com/viaversion/viarewind/legacysupport/injector/NMSReflection.java index 1eee743..5882279 100644 --- a/src/main/java/com/viaversion/viarewind/legacysupport/injector/NMSReflection.java +++ b/src/main/java/com/viaversion/viarewind/legacysupport/injector/NMSReflection.java @@ -18,13 +18,12 @@ package com.viaversion.viarewind.legacysupport.injector; -import com.viaversion.viarewind.legacysupport.reflection.MethodSignature; -import com.viaversion.viarewind.legacysupport.reflection.ReflectionAPI; import com.viaversion.viaversion.api.Via; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Arrays; public class NMSReflection { @@ -119,22 +118,24 @@ public class NMSReflection { return Class.forName("net.minecraft.server." + getVersion() + "." + name); } - public static void sendPacket(Player player, Object packet) { - try { - Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player); - if (playerConnectionField == null) { - playerConnectionField = Arrays.stream(nmsPlayer.getClass().getFields()) - .filter(field -> field.getType() == getPlayerConnectionClass()).findFirst() - .orElseThrow(() -> new ReflectiveOperationException("Failed to find PlayerConnection field in EntityPlayer")); - } - Object playerConnection = playerConnectionField.get(nmsPlayer); - ReflectionAPI.pickMethod( - playerConnection.getClass(), - new MethodSignature("sendPacket", getPacketClass()), - new MethodSignature("a", getPacketClass()) - ).invoke(playerConnection, packet); - } catch (Exception ex) { - ex.printStackTrace(); + public static void sendPacket(Player player, Object packet) throws ReflectiveOperationException { + Object nmsPlayer = player.getClass().getMethod("getHandle").invoke(player); + if (playerConnectionField == null) { + playerConnectionField = Arrays.stream(nmsPlayer.getClass().getFields()) + .filter(field -> field.getType() == getPlayerConnectionClass()).findFirst() + .orElseThrow(() -> new ReflectiveOperationException("Failed to find PlayerConnection field in EntityPlayer")); } + Object playerConnection = playerConnectionField.get(nmsPlayer); + Method sendPacket; + try { // TODO find better way + sendPacket = playerConnection.getClass().getDeclaredMethod("sendPacket", getPacketClass()); + } catch (Exception e) { + try { + sendPacket = playerConnection.getClass().getDeclaredMethod("a", getPacketClass()); + } catch (Exception e2) { + throw new ReflectiveOperationException("Failed to find sendPacket method in PlayerConnection"); + } + } + sendPacket.invoke(playerConnection, packet); } } diff --git a/src/main/java/com/viaversion/viarewind/legacysupport/listener/SoundListener.java b/src/main/java/com/viaversion/viarewind/legacysupport/listener/SoundListener.java index ad4298c..3c114b4 100644 --- a/src/main/java/com/viaversion/viarewind/legacysupport/listener/SoundListener.java +++ b/src/main/java/com/viaversion/viarewind/legacysupport/listener/SoundListener.java @@ -40,6 +40,7 @@ import org.bukkit.event.player.PlayerExpChangeEvent; import org.bukkit.event.player.PlayerPickupItemEvent; import java.lang.reflect.Method; +import java.util.logging.Level; @SuppressWarnings("unchecked") public class SoundListener implements Listener { @@ -88,7 +89,11 @@ public class SoundListener implements Listener { if (Via.getAPI().getServerVersion().lowestSupportedVersion() >= ProtocolVersion.v1_17.getVersion()) { player.playSound(e.getBlockPlaced().getLocation(), e.getBlock().getBlockData().getSoundGroup().getPlaceSound(), 1.0f, 0.8f); } else { - playBlockPlaceSoundNMS(player, e.getBlock()); + try { + playBlockPlaceSoundNMS(player, e.getBlock()); + } catch (Exception exception) { + Via.getPlatform().getLogger().log(Level.SEVERE, "Could not play block place sound.", exception); + } } } @@ -123,67 +128,70 @@ public class SoundListener implements Listener { // 1.8.8 -> 1.16.5 - private static void playBlockPlaceSoundNMS(Player player, Block block) { - try { - World world = block.getWorld(); - Object nmsWorld = world.getClass().getMethod("getHandle").invoke(world); - Class blockPositionClass = NMSReflection.getBlockPositionClass(); - Object blockPosition = null; + private static void playBlockPlaceSoundNMS(Player player, Block block) throws Exception { + World world = block.getWorld(); + Object nmsWorld = world.getClass().getMethod("getHandle").invoke(world); + Class blockPositionClass = NMSReflection.getBlockPositionClass(); + Object blockPosition = null; - if (blockPositionClass != null) - blockPosition = blockPositionClass.getConstructor(int.class, int.class, int.class).newInstance(block.getX(), block.getY(), block.getZ()); + if (blockPositionClass != null) + blockPosition = blockPositionClass.getConstructor(int.class, int.class, int.class).newInstance(block.getX(), block.getY(), block.getZ()); - Method getTypeMethod = nmsWorld.getClass().getMethod("getType", blockPositionClass); - getTypeMethod.setAccessible(true); + Method getTypeMethod = nmsWorld.getClass().getMethod("getType", blockPositionClass); + getTypeMethod.setAccessible(true); - Object blockData = getTypeMethod.invoke(nmsWorld, blockPosition); - Method getBlock = blockData.getClass().getMethod("getBlock"); - getBlock.setAccessible(true); + Object blockData = getTypeMethod.invoke(nmsWorld, blockPosition); + Method getBlock = blockData.getClass().getMethod("getBlock"); + getBlock.setAccessible(true); - Object nmsBlock = getBlock.invoke(blockData); - Method getStepSound = ReflectionAPI.pickMethod( - nmsBlock.getClass(), - new MethodSignature("w"), // 1.9 -> 1.10 - new MethodSignature("getStepSound", blockData.getClass()), // 1.14 -> 1.16 - new MethodSignature("getStepSound") // 1.11 -> 1.12 - ); - getStepSound.setAccessible(true); - - Object soundType; - if (getStepSound.getParameterCount() == 0) { - soundType = getStepSound.invoke(nmsBlock); // 1.9 -> 1.13 - } else { - soundType = getStepSound.invoke(nmsBlock, blockData); // 1.14 -> 1.16.5 - } - - Method soundEffectMethod; - Method volumeMethod; - Method pitchMethod; - - try { - // 1.16.5 - soundEffectMethod = soundType.getClass().getMethod("getPlaceSound"); - volumeMethod = soundType.getClass().getMethod("getVolume"); - pitchMethod = soundType.getClass().getMethod("getPitch"); - } catch (NoSuchMethodException ex) { - // 1.9 -> 1.16.4 - soundEffectMethod = soundType.getClass().getMethod("e"); - volumeMethod = soundType.getClass().getMethod("a"); - pitchMethod = soundType.getClass().getMethod("b"); - } - - Object soundEffect = soundEffectMethod.invoke(soundType); - float volume = (float) volumeMethod.invoke(soundType); - float pitch = (float) pitchMethod.invoke(soundType); - Object soundCategory = Enum.valueOf(NMSReflection.getSoundCategoryClass(), "BLOCKS"); - - volume = (volume + 1.0f) / 2.0f; - pitch *= 0.8; - - playSound(player, soundEffect, soundCategory, block.getX() + 0.5, block.getY() + 0.5, block.getZ() + 0.5, volume, pitch); - } catch (Exception ex) { - ex.printStackTrace(); + Object nmsBlock = getBlock.invoke(blockData); + Method getStepSound; + final int serverProtocol = Via.getAPI().getServerVersion().lowestSupportedVersion(); + if (serverProtocol > ProtocolVersion.v1_8.getVersion() && serverProtocol < ProtocolVersion.v1_12.getVersion()) { + getStepSound = ReflectionAPI.findRecursiveMethodOrNull(nmsBlock.getClass(), "w"); + } else if (serverProtocol > ProtocolVersion.v1_10.getVersion() && serverProtocol < ProtocolVersion.v1_13.getVersion()) { + getStepSound = ReflectionAPI.findRecursiveMethodOrNull(nmsBlock.getClass(), "getStepSound"); + } else { // 1.14 - 1.16.5 + getStepSound = ReflectionAPI.findRecursiveMethodOrNull(nmsBlock.getClass(), "getStepSound", blockData.getClass()); } + if (getStepSound == null) { + Via.getPlatform().getLogger().severe("Could not find getStepSound method in " + nmsBlock.getClass().getName()); + return; + } + + getStepSound.setAccessible(true); + Object soundType; + if (getStepSound.getParameterCount() == 0) { + soundType = getStepSound.invoke(nmsBlock); // 1.9 - 1.13 + } else { + soundType = getStepSound.invoke(nmsBlock, blockData); // 1.14 - 1.16.5 + } + + Method soundEffectMethod; + Method volumeMethod; + Method pitchMethod; + + try { + // 1.16.5 + soundEffectMethod = soundType.getClass().getMethod("getPlaceSound"); + volumeMethod = soundType.getClass().getMethod("getVolume"); + pitchMethod = soundType.getClass().getMethod("getPitch"); + } catch (NoSuchMethodException ex) { + // 1.9 -> 1.16.4 + soundEffectMethod = soundType.getClass().getMethod("e"); + volumeMethod = soundType.getClass().getMethod("a"); + pitchMethod = soundType.getClass().getMethod("b"); + } + + Object soundEffect = soundEffectMethod.invoke(soundType); + float volume = (float) volumeMethod.invoke(soundType); + float pitch = (float) pitchMethod.invoke(soundType); + Object soundCategory = Enum.valueOf(NMSReflection.getSoundCategoryClass(), "BLOCKS"); + + volume = (volume + 1.0f) / 2.0f; + pitch *= 0.8; + + playSound(player, soundEffect, soundCategory, block.getX() + 0.5, block.getY() + 0.5, block.getZ() + 0.5, volume, pitch); } // 1.8.8 -> 1.16.5 diff --git a/src/main/java/com/viaversion/viarewind/legacysupport/reflection/ReflectionAPI.java b/src/main/java/com/viaversion/viarewind/legacysupport/reflection/ReflectionAPI.java index b7919e3..a5e4b2d 100644 --- a/src/main/java/com/viaversion/viarewind/legacysupport/reflection/ReflectionAPI.java +++ b/src/main/java/com/viaversion/viarewind/legacysupport/reflection/ReflectionAPI.java @@ -38,34 +38,6 @@ public class ReflectionAPI { } } - /** - * 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 (signature.returnType() != null && !Objects.equals(method.getReturnType(), signature.returnType())) { - continue; - } - 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; @@ -128,4 +100,14 @@ public class ReflectionAPI { ex.printStackTrace(); } } + + public static Method findRecursiveMethodOrNull(Class clazz, String methodName, Class... parameterTypes) { + try { + return clazz.getDeclaredMethod(methodName, parameterTypes); + } catch (NoSuchMethodException ex) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) return null; + return findRecursiveMethodOrNull(superClass, methodName, parameterTypes); + } + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8cc189a..d93af5c 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ version: ${version} main: com.viaversion.viarewind.legacysupport.BukkitPlugin api-version: 1.13 -authors: [Gerrygames] +authors: [FlorianMichael/EnZaXD, Gerrygames] website: https://github.com/ViaVersion/ViaRewind-Legacy-Support -depend: [ViaVersion] +depend: [ViaRewind]