Remove Reflection from TinyProtocol

This commit is contained in:
2026-05-16 11:36:09 +02:00
parent be233c65fe
commit 5a57b5f799
@@ -20,11 +20,13 @@
package com.comphenix.tinyprotocol; package com.comphenix.tinyprotocol;
import com.google.common.collect.MapMaker; import com.google.common.collect.MapMaker;
import com.mojang.authlib.GameProfile;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import de.steamwar.Reflection.Field;
import io.netty.channel.*; import io.netty.channel.*;
import org.bukkit.Bukkit; import net.minecraft.network.Connection;
import net.minecraft.network.protocol.login.ServerboundHelloPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerConnectionListener;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@@ -49,27 +51,6 @@ import java.util.logging.Level;
public abstract class TinyProtocol { public abstract class TinyProtocol {
private static final AtomicInteger ID = new AtomicInteger(0); private static final AtomicInteger ID = new AtomicInteger(0);
// Required Minecraft classes
private static final Class<?> entityPlayerClass = Reflection.getClass("{nms}.EntityPlayer", "net.minecraft.server.level.EntityPlayer");
private static final Class<?> playerConnectionClass = Reflection.getClass("{nms}.PlayerConnection", "net.minecraft.server.network.PlayerConnection");
private static final Class<?> networkManagerClass = Reflection.getClass("{nms}.NetworkManager", "net.minecraft.network.NetworkManager");
// Used in order to lookup a channel
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
private static final FieldAccessor<?> getConnection = Reflection.getField(entityPlayerClass, null, playerConnectionClass);
private static final FieldAccessor<?> getManager = Reflection.getField(playerConnectionClass, null, networkManagerClass);
private static final FieldAccessor<Channel> getChannel = Reflection.getField(networkManagerClass, Channel.class, 0);
// Looking up ServerConnection
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer", "net.minecraft.server.MinecraftServer");
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection", "net.minecraft.server.network.ServerConnection");
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
// Packets we have to intercept
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getClass("{nms}.PacketLoginInStart", "net.minecraft.network.protocol.login.PacketLoginInStart");
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
// Speedup channel lookup // Speedup channel lookup
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap(); private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
private Listener listener; private Listener listener;
@@ -78,7 +59,7 @@ public abstract class TinyProtocol {
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap()); private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
// List of network markers // List of network markers
private List<Object> networkManagers; private List<Connection> networkManagers;
// Injected channel handlers // Injected channel handlers
private List<Channel> serverChannels = new ArrayList<>(); private List<Channel> serverChannels = new ArrayList<>();
@@ -204,34 +185,18 @@ public abstract class TinyProtocol {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void registerChannelHandler() { private void registerChannelHandler() {
Object mcServer = getMinecraftServer.get(Bukkit.getServer()); ServerConnectionListener serverConnection = MinecraftServer.getServer().getConnection();
Object serverConnection = getServerConnection.get(mcServer); networkManagers = serverConnection.getConnections();
boolean looking = true;
try {
Field field = Reflection.getParameterizedField(serverConnectionClass, List.class, networkManagerClass);
field.setAccessible(true);
networkManagers = (List<Object>) field.get(serverConnection);
} catch (Exception ex) {
plugin.getLogger().info("Encountered an exception checking list fields" + ex);
MethodInvoker method = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
networkManagers = (List<Object>) method.invoke(null, serverConnection);
}
if (networkManagers == null) {
throw new IllegalArgumentException("Failed to obtain list of network managers");
}
// We need to synchronize against this list // We need to synchronize against this list
createServerChannelHandler(); createServerChannelHandler();
// Find the correct list, or implicitly throw an exception // Find the correct list, or implicitly throw an exception
boolean looking = true;
for (int i = 0; looking; i++) { for (int i = 0; looking; i++) {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) { for (Object item : list) {
if (!ChannelFuture.class.isInstance(item)) if (!(item instanceof ChannelFuture))
break; break;
// Channel future that contains the server connection // Channel future that contains the server connection
@@ -416,10 +381,8 @@ public abstract class TinyProtocol {
// Lookup channel again // Lookup channel again
if (channel == null) { if (channel == null) {
Object connection = getConnection.get(getPlayerHandle.invoke(player)); Channel playerChannel = ((CraftPlayer) player).getHandle().connection.connection.channel;
Object manager = getManager.get(connection); channelLookup.put(player.getName(), channel = playerChannel);
channelLookup.put(player.getName(), channel = getChannel.get(manager));
} }
return channel; return channel;
@@ -536,9 +499,8 @@ public abstract class TinyProtocol {
} }
private void handleLoginStart(Channel channel, Object packet) { private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) { if (packet instanceof ServerboundHelloPacket(String name, UUID packetId)) {
GameProfile profile = getGameProfile.get(packet); channelLookup.put(name, channel);
channelLookup.put(profile.getName(), channel);
} }
} }
} }