From 04b03ce06d39a49b8412cff55d8d0ffb7c0c78e9 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Mon, 22 Aug 2022 12:57:45 +0200 Subject: [PATCH 1/6] Fix TinyProtocol null player issues --- .../src/de/steamwar/core/ChatWrapper19.java | 8 - .../src/de/steamwar/core/ChatWrapper8.java | 8 - .../comphenix/tinyprotocol/TinyProtocol.java | 466 +++++------------- .../src/de/steamwar/core/ChatWrapper.java | 1 - .../de/steamwar/techhider/ProtocolUtils.java | 2 +- 5 files changed, 111 insertions(+), 374 deletions(-) diff --git a/SpigotCore_19/src/de/steamwar/core/ChatWrapper19.java b/SpigotCore_19/src/de/steamwar/core/ChatWrapper19.java index 8be810b..f9c1202 100644 --- a/SpigotCore_19/src/de/steamwar/core/ChatWrapper19.java +++ b/SpigotCore_19/src/de/steamwar/core/ChatWrapper19.java @@ -19,8 +19,6 @@ package de.steamwar.core; -import com.comphenix.tinyprotocol.Reflection; -import com.comphenix.tinyprotocol.TinyProtocol; import net.minecraft.network.chat.IChatMutableComponent; import net.minecraft.network.chat.contents.LiteralContents; @@ -29,10 +27,4 @@ public class ChatWrapper19 implements ChatWrapper { public Object stringToChatComponent(String text) { return IChatMutableComponent.a(new LiteralContents(text)); } - - private static final Reflection.FieldAccessor getName = Reflection.getField(TinyProtocol.PACKET_LOGIN_IN_START, String.class, 0); - @Override - public String getNameByLoginPacket(Object packet) { - return getName.get(packet); - } } diff --git a/SpigotCore_8/src/de/steamwar/core/ChatWrapper8.java b/SpigotCore_8/src/de/steamwar/core/ChatWrapper8.java index 7d02dfd..68b8e07 100644 --- a/SpigotCore_8/src/de/steamwar/core/ChatWrapper8.java +++ b/SpigotCore_8/src/de/steamwar/core/ChatWrapper8.java @@ -20,8 +20,6 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.Reflection; -import com.comphenix.tinyprotocol.TinyProtocol; -import com.mojang.authlib.GameProfile; public class ChatWrapper8 implements ChatWrapper { @@ -30,10 +28,4 @@ public class ChatWrapper8 implements ChatWrapper { public Object stringToChatComponent(String text) { return chatComponentConstructor.invoke(text); } - - private static final Reflection.FieldAccessor getGameProfile = Reflection.getField(TinyProtocol.PACKET_LOGIN_IN_START, GameProfile.class, 0); - @Override - public String getNameByLoginPacket(Object packet) { - return getGameProfile.get(packet).getName(); - } } diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java index 82a4afb..caf68fa 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java @@ -2,252 +2,70 @@ package com.comphenix.tinyprotocol; import com.comphenix.tinyprotocol.Reflection.FieldAccessor; import com.comphenix.tinyprotocol.Reflection.MethodInvoker; -import com.google.common.collect.Lists; -import com.google.common.collect.MapMaker; -import de.steamwar.core.ChatWrapper; import de.steamwar.core.Core; -import io.netty.channel.*; -import org.bukkit.Bukkit; +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelPromise; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitRunnable; import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.logging.Level; -/** - * Represents a very tiny alternative to ProtocolLib. - *

- * It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)! - * - * @author Kristian - */ -public class TinyProtocol { - private static final AtomicInteger ID = new AtomicInteger(0); - - // Used in order to lookup a channel - 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); - - // Looking up ServerConnection - private static final Class minecraftServerClass = Reflection.getUntypedClass("{nms.server}.MinecraftServer"); - private static final Class serverConnectionClass = Reflection.getUntypedClass("{nms.server.network}.ServerConnection"); - private static final FieldAccessor getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0); - private static final FieldAccessor getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0); - private static final FieldAccessor getNetworkMarkers = Reflection.getField(serverConnectionClass, Collection.class, 1); - - // Packets we have to intercept - public static final Class PACKET_LOGIN_IN_START = Reflection.getClass("{nms.network.protocol.login}.PacketLoginInStart"); - - // Speedup channel lookup - private final Map channelLookup = new MapMaker().weakValues().makeMap(); - private final Listener listener; - - // Channels that have already been removed - private final Set uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().makeMap()); - - // List of network markers - private Collection networkManagers; - - // Injected channel handlers - private final List serverChannels = Lists.newArrayList(); - private ChannelInboundHandlerAdapter serverChannelHandler; - private ChannelInitializer beginInitProtocol; - private ChannelInitializer endInitProtocol; - - // Current handler name - private final String handlerName; - private volatile boolean closed; - private final Plugin plugin; - - private final Map, List>> packetFilters = new HashMap<>(); - - @Deprecated - private PacketFilter inFilter = (player, channel, packet) -> packet; - - @Deprecated - private PacketFilter outFilter = (player, channel, packet) -> packet; - +public class TinyProtocol implements Listener { public static final TinyProtocol instance = new TinyProtocol(Core.getInstance()); + private static int id = 0; public static void init() { //enforce init } - public TinyProtocol(final Plugin plugin) { + private final Plugin plugin; + private final String handlerName; + private boolean closed; + + private final Map, List>> packetFilters = new HashMap<>(); + private final Map playerInterceptors = new HashMap<>(); + + private TinyProtocol(final Plugin plugin) { this.plugin = plugin; // Compute handler name - this.handlerName = "tiny-" + plugin.getName() + "-" + ID.incrementAndGet(); + this.handlerName = "tiny-" + plugin.getName() + "-" + ++id; // Prepare existing players - listener = new Listener() { + plugin.getServer().getPluginManager().registerEvents(this, plugin); - @EventHandler(priority = EventPriority.LOWEST) - public void onPlayerLogin(PlayerLoginEvent e) { - injectPlayerOnLogin( - e.getPlayer(), - () -> Bukkit.getScheduler().runTask(plugin, () -> injectPlayerOnLogin( - e.getPlayer(), - () -> Bukkit.getScheduler().runTaskLater(plugin, () -> injectPlayerOnLogin( - e.getPlayer(), - () -> { - //Give up - } - ), 1) - )) - ); - } - - @EventHandler - public void onPluginDisable(PluginDisableEvent e) { - if (e.getPlugin().equals(plugin)) { - close(); - } - } - }; - plugin.getServer().getPluginManager().registerEvents(listener, plugin); - - try { - registerChannelHandler(); - registerPlayers(plugin); - } catch (IllegalArgumentException ex) { - // Damn you, late bind - plugin.getLogger().info("[TinyProtocol] Delaying server channel injection due to late bind."); - - new BukkitRunnable() { - @Override - public void run() { - registerChannelHandler(); - registerPlayers(plugin); - plugin.getLogger().info("[TinyProtocol] Late bind injection successful."); - } - }.runTask(plugin); - } - } - - private void injectPlayerOnLogin(Player player, Runnable errorHandler) { - if (closed) - return; - - try { - Channel channel = getChannel(player); - - // Don't inject players that have been explicitly uninjected - if (!uninjectedChannels.contains(channel)) { - injectPlayer(player); - } - } catch (NullPointerException ex) { - errorHandler.run(); - } - } - - private void createServerChannelHandler() { - // Handle connected channels - endInitProtocol = new ChannelInitializer() { - - @Override - protected void initChannel(Channel channel) throws Exception { - try { - // This can take a while, so we need to stop the main thread from interfering - synchronized (networkManagers) { - // Stop injecting channels - if (!closed) { - channel.eventLoop().submit(() -> injectChannelInternal(channel)); - } - } - } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e); - } - } - - }; - - // This is executed before Minecraft's channel handler - beginInitProtocol = new ChannelInitializer() { - - @Override - protected void initChannel(Channel channel) throws Exception { - channel.pipeline().addLast(endInitProtocol); - } - - }; - - serverChannelHandler = new ChannelInboundHandlerAdapter() { - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - Channel channel = (Channel) msg; - - // Prepare to initialize ths channel - channel.pipeline().addFirst(beginInitProtocol); - ctx.fireChannelRead(msg); - } - - }; - } - - @SuppressWarnings("unchecked") - private void registerChannelHandler() { - Object mcServer = getMinecraftServer.get(Bukkit.getServer()); - Object serverConnection = getServerConnection.get(mcServer); - boolean looking = true; - - // We need to synchronize against this list - networkManagers = getNetworkMarkers.get(serverConnection); - createServerChannelHandler(); - - // Find the correct list, or implicitly throw an exception - for (int i = 0; looking; i++) { - List list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection); - - for (Object item : list) { - if (!(item instanceof ChannelFuture)) - break; - - // Channel future that contains the server connection - Channel serverChannel = ((ChannelFuture) item).channel(); - - serverChannels.add(serverChannel); - serverChannel.pipeline().addFirst(serverChannelHandler); - looking = false; - } - } - } - - private void unregisterChannelHandler() { - if (serverChannelHandler == null) - return; - - for (Channel serverChannel : serverChannels) { - final ChannelPipeline pipeline = serverChannel.pipeline(); - - // Remove channel handler - serverChannel.eventLoop().execute(() -> { - try { - pipeline.remove(serverChannelHandler); - } catch (NoSuchElementException e) { - // That's fine - } - }); - } - } - - private void registerPlayers(Plugin plugin) { for (Player player : plugin.getServer().getOnlinePlayers()) { - injectPlayer(player); + new PacketInterceptor(player); + } + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onPlayerLogin(PlayerLoginEvent e) { + if(closed) + return; + new PacketInterceptor(e.getPlayer()); + } + + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerDisconnect(PlayerQuitEvent e) { + getInterceptor(e.getPlayer()).ifPresent(PacketInterceptor::close); + } + + @EventHandler + public void onPluginDisable(PluginDisableEvent e) { + if (e.getPlugin().equals(plugin)) { + close(); } } @@ -259,158 +77,87 @@ public class TinyProtocol { packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter); } - public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) { - return filterPacket(outFilter, receiver, channel, packet); - } - - public Object onPacketInAsync(Player sender, Channel channel, Object packet) { - return filterPacket(inFilter, sender, channel, packet); - } - - private Object filterPacket(PacketFilter handler, Player player, Channel channel, Object packet) { - List> filters = packetFilters.getOrDefault(packet.getClass(), Collections.emptyList()); - - for(BiFunction filter : filters) { - packet = filter.apply(player, packet); - - if(packet == null) - return packet; - } - - return handler.onPacket(player, channel, packet); - } - - @Deprecated - public void setInFilter(PacketFilter filter) { - inFilter = filter; - } - - @Deprecated - public void setOutFilter(PacketFilter filter) { - outFilter = filter; - } - public void sendPacket(Player player, Object packet) { - sendPacket(getChannel(player), packet); - } - - public void sendPacket(Channel channel, Object packet) { - channel.pipeline().writeAndFlush(packet); + getInterceptor(player).ifPresent(i -> i.sendPacket(packet)); } public void receivePacket(Player player, Object packet) { - receivePacket(getChannel(player), packet); - } - - public void receivePacket(Channel channel, Object packet) { - channel.pipeline().context("encoder").fireChannelRead(packet); - } - - public void injectPlayer(Player player) { - injectChannelInternal(getChannel(player)).player = player; - } - - public void injectChannel(Channel channel) { - injectChannelInternal(channel); - } - - private PacketInterceptor injectChannelInternal(Channel channel) { - try { - PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName); - - // Inject our packet interceptor - if (interceptor == null) { - interceptor = new PacketInterceptor(); - if(!channel.isActive()) - return interceptor; - - channel.pipeline().addBefore("packet_handler", handlerName, interceptor); - uninjectedChannels.remove(channel); - } - - return interceptor; - } catch (IllegalArgumentException e) { - // Try again - return (PacketInterceptor) channel.pipeline().get(handlerName); - } - } - - public Channel getChannel(Player player) { - Channel channel = channelLookup.get(player.getName()); - - // Lookup channel again - if (channel == null) { - Object connection = getConnection.get(getPlayerHandle.invoke(player)); - Object manager = getManager.get(connection); - - channelLookup.put(player.getName(), channel = getChannel.get(manager)); - } - - return channel; - } - - public void uninjectPlayer(Player player) { - uninjectChannel(getChannel(player)); - } - - public void uninjectChannel(final Channel channel) { - // No need to guard against this if we're closing - if (!closed) { - uninjectedChannels.add(channel); - } - - // See ChannelInjector in ProtocolLib, line 590 - channel.eventLoop().execute(() -> { - try { - channel.pipeline().remove(handlerName); - } catch (NoSuchElementException e) { - // ignore - } - }); - } - - public boolean hasInjected(Player player) { - return hasInjected(getChannel(player)); - } - - public boolean hasInjected(Channel channel) { - return channel.pipeline().get(handlerName) != null; + getInterceptor(player).ifPresent(i -> i.receivePacket(packet)); } public final void close() { - if (!closed) { - closed = true; + if(closed) + return; + closed = true; - // Remove our handlers - for (Player player : plugin.getServer().getOnlinePlayers()) { - uninjectPlayer(player); - } + HandlerList.unregisterAll(this); - // Clean up Bukkit - HandlerList.unregisterAll(listener); - unregisterChannelHandler(); + for (Player player : plugin.getServer().getOnlinePlayers()) { + getInterceptor(player).ifPresent(PacketInterceptor::close); } } - @Deprecated - public interface PacketFilter { - Object onPacket(Player player, Channel channel, Object packet); + private Optional getInterceptor(Player player) { + synchronized (playerInterceptors) { + return Optional.ofNullable(playerInterceptors.get(player)); + } } + 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 final class PacketInterceptor extends ChannelDuplexHandler { - // Updated by the login event - public volatile Player player; + private final Player player; + private final Channel channel; + + private PacketInterceptor(Player player) { + this.player = player; + + Object connection = getConnection.get(getPlayerHandle.invoke(player)); + Object manager = getManager.get(connection); + channel = getChannel.get(manager); + + synchronized (playerInterceptors) { + playerInterceptors.put(player, this); + } + + channel.pipeline().addBefore("packet_handler", handlerName, this); + } + + private void sendPacket(Object packet) { + channel.pipeline().writeAndFlush(packet); + } + + private void receivePacket(Object packet) { + channel.pipeline().context("encoder").fireChannelRead(packet); + } + + private void close() { + if(channel.isActive()) { + channel.eventLoop().execute(() -> { + try { + channel.pipeline().remove(handlerName); + } catch (NoSuchElementException e) { + // ignore + } + }); + } + + synchronized (playerInterceptors) { + playerInterceptors.remove(player, this); + } + } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - // Intercept channel - final Channel channel = ctx.channel(); - handleLoginStart(channel, msg); - try { - msg = onPacketInAsync(player, channel, msg); + msg = filterPacket(player, msg); } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e); + plugin.getLogger().log(Level.SEVERE, "Error during incoming packet processing", e); } if (msg != null) { @@ -421,9 +168,9 @@ public class TinyProtocol { @Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { try { - msg = onPacketOutAsync(player, ctx.channel(), msg); + msg = filterPacket(player, msg); } catch (Exception e) { - plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e); + plugin.getLogger().log(Level.SEVERE, "Error during outgoing packet processing", e); } if (msg != null) { @@ -431,10 +178,17 @@ public class TinyProtocol { } } - private void handleLoginStart(Channel channel, Object packet) { - if (PACKET_LOGIN_IN_START.isInstance(packet)) { - channelLookup.put(ChatWrapper.impl.getNameByLoginPacket(packet), channel); + private Object filterPacket(Player player, Object packet) { + List> filters = packetFilters.getOrDefault(packet.getClass(), Collections.emptyList()); + + for(BiFunction filter : filters) { + packet = filter.apply(player, packet); + + if(packet == null) + break; } + + return packet; } } } diff --git a/SpigotCore_Main/src/de/steamwar/core/ChatWrapper.java b/SpigotCore_Main/src/de/steamwar/core/ChatWrapper.java index eeddd1c..2f4df8f 100644 --- a/SpigotCore_Main/src/de/steamwar/core/ChatWrapper.java +++ b/SpigotCore_Main/src/de/steamwar/core/ChatWrapper.java @@ -23,5 +23,4 @@ public interface ChatWrapper { ChatWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); Object stringToChatComponent(String text); - String getNameByLoginPacket(Object packet); } diff --git a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java index 1fc9e31..88a5cf9 100644 --- a/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java +++ b/SpigotCore_Main/src/de/steamwar/techhider/ProtocolUtils.java @@ -37,7 +37,7 @@ public class ProtocolUtils { private ProtocolUtils() {} public static void broadcastPacket(Object packet) { - Bukkit.getOnlinePlayers().stream().map(TinyProtocol.instance::getChannel).filter(TinyProtocol.instance::hasInjected).forEach(channel -> TinyProtocol.instance.sendPacket(channel, packet)); + Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet)); } public static BiFunction, Object> arrayCloneGenerator(Class elementClass) { From cbbafd7c092e5f779a908d4a633a88e70659197a Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 23 Aug 2022 12:47:53 +0200 Subject: [PATCH 2/6] Fix null connection issues --- .../comphenix/tinyprotocol/Reflection.java | 30 +++++++++++++++---- .../comphenix/tinyprotocol/TinyProtocol.java | 27 +++++++++-------- 2 files changed, 40 insertions(+), 17 deletions(-) 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); From b4a14ed5ec3c838a3b04b3032d3f8b2a1166da93 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 23 Aug 2022 12:52:20 +0200 Subject: [PATCH 3/6] Fix static final order --- .../com/comphenix/tinyprotocol/TinyProtocol.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java index 01ae7a3..c72429c 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java @@ -21,12 +21,6 @@ import java.util.function.BiFunction; import java.util.logging.Level; public class TinyProtocol implements Listener { - public static final TinyProtocol instance = new TinyProtocol(Core.getInstance()); - private static int id = 0; - - public static void init() { - //enforce init - } private static final Class craftServer = Reflection.getClass("{obc}.CraftServer"); private static final Class dedicatedPlayerList = Reflection.getClass("{nms.server.dedicated}.DedicatedPlayerList"); @@ -39,6 +33,13 @@ public class TinyProtocol implements Listener { private static final Class networkManager = Reflection.getClass("{nms.network}.NetworkManager"); private static final FieldAccessor getConnections = Reflection.getField(serverConnection, List.class, 0, networkManager); + public static final TinyProtocol instance = new TinyProtocol(Core.getInstance()); + private static int id = 0; + + public static void init() { + //enforce init + } + private final Plugin plugin; private final String handlerName; private final List connections; From c785603ace1ee684517891a6b3b4b1583d69fee5 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 23 Aug 2022 12:58:10 +0200 Subject: [PATCH 4/6] Fix generic type search --- SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java index 15aeeca..10d9155 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java @@ -189,7 +189,7 @@ public final class Reflection { return false; if(parameters.length > 0) { - Class[] arguments = (Class[]) ((ParameterizedType)field.getType().getGenericSuperclass()).getActualTypeArguments(); + Class[] arguments = (Class[]) ((ParameterizedType)field.getGenericType()).getActualTypeArguments(); for(int i = 0; i < parameters.length; i++) { if(arguments[i] != parameters[i]) From e84958309bbcfc8ff7a21da413615610c2a59f0d Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 23 Aug 2022 13:00:46 +0200 Subject: [PATCH 5/6] Fix generic type search --- .../src/com/comphenix/tinyprotocol/Reflection.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java index 10d9155..7348bcf 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java @@ -4,10 +4,7 @@ import de.steamwar.core.Core; import jdk.internal.misc.Unsafe; 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.lang.reflect.*; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -189,7 +186,7 @@ public final class Reflection { return false; if(parameters.length > 0) { - Class[] arguments = (Class[]) ((ParameterizedType)field.getGenericType()).getActualTypeArguments(); + Type[] arguments = ((ParameterizedType)field.getGenericType()).getActualTypeArguments(); for(int i = 0; i < parameters.length; i++) { if(arguments[i] != parameters[i]) From e66744ab5eab71c425d23a6f52dfd1abcbae736c Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 23 Aug 2022 13:08:38 +0200 Subject: [PATCH 6/6] Kick player on injection failure --- .../src/com/comphenix/tinyprotocol/TinyProtocol.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java index c72429c..b1bbb00 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/TinyProtocol.java @@ -123,7 +123,10 @@ public class TinyProtocol implements Listener { private PacketInterceptor(Player player) { this.player = player; - 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()))); + channel = getChannel.get(connections.stream().filter(connection -> player.getUniqueId().equals(getUUID.get(connection))).findAny().orElseThrow(() -> { + player.kickPlayer("An injection failure happend."); + return new SecurityException("Could not find channel for player " + player.getName()); + })); synchronized (playerInterceptors) { playerInterceptors.put(player, this);