diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java index f1138fc..15aeeca 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java @@ -7,6 +7,7 @@ import org.bukkit.Bukkit; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -135,15 +136,16 @@ public final class Reflection { return getField(getClass(className), fieldType, index); } - // Common method - private static FieldAccessor getField(Class target, String name, Class fieldType, int index) { + public static FieldAccessor getField(Class target, Class fieldType, int index, Class... parameters) { + return getField(target, null, fieldType, index, parameters); + } + + private static FieldAccessor getField(Class target, String name, Class fieldType, int index, Class... parameters) { for (final Field field : target.getDeclaredFields()) { - if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) { + if(matching(field, name, fieldType, parameters) && index-- <= 0) { field.setAccessible(true); - // A function for retrieving a specific field value return new FieldAccessor() { - @Override @SuppressWarnings("unchecked") public T get(Object target) { @@ -179,6 +181,24 @@ public final class Reflection { throw new IllegalArgumentException("Cannot find field with type " + fieldType); } + private static boolean matching(Field field, String name, Class fieldType, Class... parameters) { + if(name != null && !field.getName().equals(name)) + return false; + + if(!fieldType.isAssignableFrom(field.getType())) + return false; + + if(parameters.length > 0) { + Class[] arguments = (Class[]) ((ParameterizedType)field.getType().getGenericSuperclass()).getActualTypeArguments(); + + for(int i = 0; i < parameters.length; i++) { + if(arguments[i] != parameters[i]) + return false; + } + } + return true; + } + /** * Search for the first publicly and privately defined method of the given name and parameter count. * diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java index caf68fa..01ae7a3 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java @@ -1,7 +1,6 @@ package com.comphenix.tinyprotocol; import com.comphenix.tinyprotocol.Reflection.FieldAccessor; -import com.comphenix.tinyprotocol.Reflection.MethodInvoker; import de.steamwar.core.Core; import io.netty.channel.Channel; import io.netty.channel.ChannelDuplexHandler; @@ -29,8 +28,20 @@ public class TinyProtocol implements Listener { //enforce init } + private static final Class craftServer = Reflection.getClass("{obc}.CraftServer"); + private static final Class dedicatedPlayerList = Reflection.getClass("{nms.server.dedicated}.DedicatedPlayerList"); + private static final FieldAccessor getPlayerList = Reflection.getField(craftServer, dedicatedPlayerList, 0); + private static final Class playerList = Reflection.getClass("{nms.server.players}.PlayerList"); + private static final Class minecraftServer = Reflection.getClass("{nms.server}.MinecraftServer"); + private static final FieldAccessor getMinecraftServer = Reflection.getField(playerList, minecraftServer, 0); + private static final Class serverConnection = Reflection.getClass("{nms.server.network}.ServerConnection"); + private static final FieldAccessor getServerConnection = Reflection.getField(minecraftServer, serverConnection, 0); + private static final Class networkManager = Reflection.getClass("{nms.network}.NetworkManager"); + private static final FieldAccessor getConnections = Reflection.getField(serverConnection, List.class, 0, networkManager); + private final Plugin plugin; private final String handlerName; + private final List connections; private boolean closed; private final Map, List>> packetFilters = new HashMap<>(); @@ -38,11 +49,9 @@ public class TinyProtocol implements Listener { private TinyProtocol(final Plugin plugin) { this.plugin = plugin; - - // Compute handler name this.handlerName = "tiny-" + plugin.getName() + "-" + ++id; + this.connections = getConnections.get(getServerConnection.get(getMinecraftServer.get(getPlayerList.get(plugin.getServer())))); - // Prepare existing players plugin.getServer().getPluginManager().registerEvents(this, plugin); for (Player player : plugin.getServer().getOnlinePlayers()) { @@ -103,12 +112,8 @@ public class TinyProtocol implements Listener { } } - private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle"); - private static final Class playerConnection = Reflection.getUntypedClass("{nms.server.network}.PlayerConnection"); - private static final FieldAccessor getConnection = Reflection.getField("{nms.server.level}.EntityPlayer", playerConnection, 0); - private static final Class networkManager = Reflection.getUntypedClass("{nms.network}.NetworkManager"); - private static final FieldAccessor getManager = Reflection.getField(playerConnection, networkManager, 0); private static final FieldAccessor getChannel = Reflection.getField(networkManager, Channel.class, 0); + private static final FieldAccessor getUUID = Reflection.getField(networkManager, UUID.class, 0); private final class PacketInterceptor extends ChannelDuplexHandler { private final Player player; @@ -117,9 +122,7 @@ public class TinyProtocol implements Listener { private PacketInterceptor(Player player) { this.player = player; - Object connection = getConnection.get(getPlayerHandle.invoke(player)); - Object manager = getManager.get(connection); - channel = getChannel.get(manager); + channel = getChannel.get(connections.stream().filter(connection -> player.getUniqueId().equals(getUUID.get(connection))).findAny().orElseThrow(() -> new SecurityException("Could not find channel for player " + player.getName()))); synchronized (playerInterceptors) { playerInterceptors.put(player, this);