Fixed broken reflection code

This commit is contained in:
FlorianMichael 2024-04-02 12:14:29 +02:00
parent 491cf1ae99
commit 5fb1033c56
No known key found for this signature in database
GPG Key ID: C2FB87E71C425126
5 changed files with 97 additions and 106 deletions

View File

@ -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") {

View File

@ -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);
}
}

View File

@ -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

View File

@ -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);
}
}
}

View File

@ -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]