diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java index c4add014..2d29bc19 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -951,7 +951,6 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok } private void onPlayerLogin(PlayerLoginEvent event) { - System.out.println("Address: " + event.getAddress()); playerInjection.updatePlayer(event.getPlayer()); } diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java index 7322029a..5a5c4bab 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelInjector.java @@ -22,7 +22,6 @@ import net.minecraft.util.io.netty.util.concurrent.GenericFutureListener; import net.minecraft.util.io.netty.util.internal.TypeParameterMatcher; import net.sf.cglib.proxy.Factory; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import com.comphenix.protocol.PacketType; @@ -35,7 +34,6 @@ import com.comphenix.protocol.events.NetworkMarker; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketOutputHandler; import com.comphenix.protocol.injector.server.SocketInjector; -import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.reflect.accessors.Accessors; @@ -46,19 +44,15 @@ import com.comphenix.protocol.utility.MinecraftMethods; import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.base.Preconditions; import com.google.common.collect.MapMaker; -import com.google.common.collect.Maps; /** * Represents a channel injector. * @author Kristian */ -class ChannelInjector extends ByteToMessageDecoder { +class ChannelInjector extends ByteToMessageDecoder implements Injector { public static final ReportType REPORT_CANNOT_INTERCEPT_SERVER_PACKET = new ReportType("Unable to intercept a written server packet."); public static final ReportType REPORT_CANNOT_INTERCEPT_CLIENT_PACKET = new ReportType("Unable to intercept a read client packet."); - private static final ConcurrentMap PLAYER_LOOKUP = Maps.newConcurrentMap(); - private static final ConcurrentMap NAME_LOOKUP = new MapMaker().weakValues().makeMap(); - // The login packet private static Class PACKET_LOGIN_CLIENT = null; private static FieldAccessor LOGIN_GAME_PROFILE = null; @@ -71,6 +65,9 @@ class ChannelInjector extends ByteToMessageDecoder { // For retrieving the protocol private static FieldAccessor PROTOCOL_ACCESSOR; + // The factory that created this injector + private InjectionFactory factory; + // The player, or temporary player private Player player; private Player updated; @@ -112,117 +109,29 @@ class ChannelInjector extends ByteToMessageDecoder { * @param player - the current player, or temporary player. * @param networkManager - its network manager. * @param channel - its channel. + * @param channelListener - a listener. + * @param factory - the factory that created this injector */ - private ChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener) { + public ChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener, InjectionFactory factory) { this.player = Preconditions.checkNotNull(player, "player cannot be NULL"); this.networkManager = Preconditions.checkNotNull(networkManager, "networkMananger cannot be NULL"); this.originalChannel = Preconditions.checkNotNull(channel, "channel cannot be NULL"); this.channelListener = Preconditions.checkNotNull(channelListener, "channelListener cannot be NULL"); - + this.factory = Preconditions.checkNotNull(factory, "factory cannot be NULL"); + // Get the channel field this.channelField = new VolatileField( FuzzyReflection.fromObject(networkManager, true). getFieldByType("channel", Channel.class), networkManager, true); } - - /** - * Construct or retrieve a channel injector from an existing Bukkit player. - * @param player - the existing Bukkit player. - * @param channelListener - the listener. - * @return A new injector, or an existing injector associated with this player. - */ - public static ChannelInjector fromPlayer(Player player, ChannelListener listener) { - ChannelInjector injector = PLAYER_LOOKUP.get(player); - // Find a temporary injector as well - if (injector == null) - injector = getTemporaryInjector(player); - if (injector != null) - return injector; - - Object networkManager = MinecraftFields.getNetworkManager(player); - - // Must be a temporary Bukkit player - if (networkManager == null) - return fromName(player.getName(), player); - - Channel channel = FuzzyReflection.getFieldValue(networkManager, Channel.class, true); - - // See if a channel has already been created - injector = (ChannelInjector) findChannelHandler(channel, ChannelInjector.class); - - if (injector != null) { - // Update the player instance - injector.player = player; - } else { - injector = new ChannelInjector(player, networkManager, channel, listener); - } - // Cache injector and return - NAME_LOOKUP.put(player.getName(), injector); - PLAYER_LOOKUP.put(player, injector); - return injector; - } - - /** - * Retrieve the associated channel injector. - * @param player - the temporary player, or normal Bukkit player. - * @return The associated injector, or NULL if this is a Bukkit player. - */ - private static ChannelInjector getTemporaryInjector(Player player) { - SocketInjector injector = TemporaryPlayerFactory.getInjectorFromPlayer(player); - - if (injector != null) { - return ((ChannelSocketInjector) injector).getChannelInjector(); - } - return null; - } - - /** - * Retrieve a cached injector from a name. - * @param address - the name. - * @return The cached injector. - * @throws IllegalArgumentException If we cannot find the corresponding injector. - */ - private static ChannelInjector fromName(String name, Player player) { - ChannelInjector injector = NAME_LOOKUP.get(name); - - // We can only retrieve cached injectors - if (injector != null) { - // Update instance - injector.updated = player; - return injector; - } - throw new IllegalArgumentException("Cannot inject temporary Bukkit player."); - } - - /** - * Construct a new channel injector for the given channel. - * @param channel - the channel. - * @param playerFactory - a temporary player creator. - * @param channelListener - the listener. - * @param loader - the current (plugin) class loader. - * @return The channel injector. - */ - public static ChannelInjector fromChannel(Channel channel, ChannelListener listener, TemporaryPlayerFactory playerFactory) { - Object networkManager = findNetworkManager(channel); - Player temporaryPlayer = playerFactory.createTemporaryPlayer(Bukkit.getServer()); - ChannelInjector injector = new ChannelInjector(temporaryPlayer, networkManager, channel, listener); - - // Initialize temporary player - TemporaryPlayerFactory.setInjectorInPlayer(temporaryPlayer, new ChannelSocketInjector(injector)); - return injector; - } - - /** - * Inject the current channel. - *

- * Note that only active channels can be injected. - * @return TRUE if we injected the channel, false if we could not inject or it was already injected. - */ + @Override @SuppressWarnings("unchecked") public boolean inject() { synchronized (networkManager) { + if (closed) + return false; if (originalChannel instanceof Factory) return false; if (!originalChannel.isActive()) @@ -230,9 +139,6 @@ class ChannelInjector extends ByteToMessageDecoder { // Don't inject the same channel twice if (findChannelHandler(originalChannel, ChannelInjector.class) != null) { - // Invalidate cache - if (player != null) - PLAYER_LOOKUP.remove(player); return false; } @@ -303,30 +209,7 @@ class ChannelInjector extends ByteToMessageDecoder { } ENCODER_TYPE_MATCHER.set(encoder, TypeParameterMatcher.get(MinecraftReflection.getPacketClass())); } - - /** - * Close the current injector. - */ - public void close() { - if (!closed) { - closed = true; - - if (injected) { - channelField.revertValue(); - - try { - originalChannel.pipeline().remove(this); - originalChannel.pipeline().remove(protocolEncoder); - } catch (NoSuchElementException e) { - // Ignore it - the player has logged out - } - // Clear cache - NAME_LOOKUP.remove(player.getName()); - PLAYER_LOOKUP.remove(player); - } - } - } - + /** * Encode a packet to a byte buffer, taking over for the standard Minecraft encoder. * @param ctx - the current context. @@ -441,7 +324,7 @@ class ChannelInjector extends ByteToMessageDecoder { GameProfile profile = (GameProfile) LOGIN_GAME_PROFILE.get(packet); // Save the channel injector - NAME_LOOKUP.put(profile.getName(), this); + factory.cacheInjector(profile.getName(), this); } } @@ -485,13 +368,8 @@ class ChannelInjector extends ByteToMessageDecoder { } } } - - /** - * Send a packet to a player's client. - * @param packet - the packet to send. - * @param marker - the network marker. - * @param filtered - whether or not the packet is filtered. - */ + + @Override public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) { saveMarker(packet, marker); processedPackets.remove(packet); @@ -522,12 +400,7 @@ class ChannelInjector extends ByteToMessageDecoder { } } - /** - * Recieve a packet on the server. - * @param packet - the (NMS) packet to send. - * @param marker - the network marker. - * @param filtered - whether or not the packet is filtered. - */ + @Override public void recieveClientPacket(Object packet, NetworkMarker marker, boolean filtered) { saveMarker(packet, marker); processedPackets.remove(packet); @@ -545,10 +418,7 @@ class ChannelInjector extends ByteToMessageDecoder { } } - /** - * Retrieve the current protocol state. - * @return The current protocol. - */ + @Override public Protocol getCurrentProtocol() { if (PROTOCOL_ACCESSOR == null) { PROTOCOL_ACCESSOR = Accessors.getFieldAccessor( @@ -568,96 +438,57 @@ class ChannelInjector extends ByteToMessageDecoder { return playerConnection; } - /** - * Undo the ignore status of a packet. - * @param packet - the packet. - * @return TRUE if the ignore status was undone, FALSE otherwise. - */ + @Override public boolean unignorePacket(Object packet) { return ignoredPackets.remove(packet); } - /** - * Ignore the given packet. - * @param packet - the packet to ignore. - * @return TRUE if it was ignored, FALSE if it already is ignored. - */ + @Override public boolean ignorePacket(Object packet) { return ignoredPackets.add(packet); } - /** - * Retrieve the network marker associated with a given packet. - * @param packet - the packet. - * @return The network marker. - */ + @Override public NetworkMarker getMarker(Object packet) { return packetMarker.get(packet); } - /** - * Associate a given network marker with a specific packet. - * @param packet - the NMS packet. - * @param marker - the associated marker. - */ + @Override public void saveMarker(Object packet, NetworkMarker marker) { if (marker != null) { packetMarker.put(packet, marker); } } - /** - * Associate a given network marker with a packet event. - * @param marker - the marker. - * @param event - the packet event - */ + @Override public void saveEvent(NetworkMarker marker, PacketEvent event) { if (marker != null) { markerEvent.put(marker, event); } } - - /** - * Find the network manager in a channel's pipeline. - * @param channel - the channel. - * @return The network manager. - */ - private static Object findNetworkManager(Channel channel) { - // Find the network manager - Object networkManager = findChannelHandler(channel, MinecraftReflection.getNetworkManagerClass()); - - if (networkManager != null) - return networkManager; - throw new IllegalArgumentException("Unable to find NetworkManager in " + channel); - } - - /** - * Find the first channel handler that is assignable to a given type. - * @param channel - the channel. - * @param clazz - the type. - * @return The first handler, or NULL. - */ - private static ChannelHandler findChannelHandler(Channel channel, Class clazz) { - for (Entry entry : channel.pipeline()) { - if (clazz.isAssignableFrom(entry.getValue().getClass())) { - return entry.getValue(); - } - } - return null; - } - - /** - * Retrieve the current player or temporary player associated with the injector. - * @return The current player. - */ + + @Override public Player getPlayer() { return player; } /** - * Determine if the channel has already been injected. - * @return TRUE if it has, FALSE otherwise. + * Set the player instance. + * @param player - current instance. */ + public void setPlayer(Player player) { + this.player = player; + } + + /** + * Set the updated player instance. + * @param updated - updated instance. + */ + public void setUpdatedPlayer(Player updated) { + this.updated = updated; + } + + @Override public boolean isInjected() { return injected; } @@ -666,10 +497,46 @@ class ChannelInjector extends ByteToMessageDecoder { * Determine if this channel has been closed and cleaned up. * @return TRUE if it has, FALSE otherwise. */ + @Override public boolean isClosed() { return closed; } + @Override + public void close() { + if (!closed) { + closed = true; + + if (injected) { + channelField.revertValue(); + + try { + originalChannel.pipeline().remove(this); + originalChannel.pipeline().remove(protocolEncoder); + } catch (NoSuchElementException e) { + // Ignore it - the player has logged out + } + // Clear cache + factory.invalidate(player); + } + } + } + + /** + * Find the first channel handler that is assignable to a given type. + * @param channel - the channel. + * @param clazz - the type. + * @return The first handler, or NULL. + */ + public static ChannelHandler findChannelHandler(Channel channel, Class clazz) { + for (Entry entry : channel.pipeline()) { + if (clazz.isAssignableFrom(entry.getValue().getClass())) { + return entry.getValue(); + } + } + return null; + } + /** * Represents a socket injector that foreards to the current channel injector. * @author Kristian diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java index a8e38a61..15f6ae5d 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ChannelListener.java @@ -3,6 +3,7 @@ package com.comphenix.protocol.injector.netty; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.events.NetworkMarker; + /** * Represents a listener for received or sent packets. * @author Kristian @@ -17,7 +18,7 @@ interface ChannelListener { * @param marker - the associated network marker, if any. * @return The new packet, if it should be changed, or NULL to cancel. */ - public Object onPacketSending(ChannelInjector injector, Object packet, NetworkMarker marker); + public Object onPacketSending(Injector injector, Object packet, NetworkMarker marker); /** * Invoked when a packet is being received from a client. @@ -28,7 +29,7 @@ interface ChannelListener { * @param marker - the associated network marker, if any. * @return The new packet, if it should be changed, or NULL to cancel. */ - public Object onPacketReceiving(ChannelInjector injector, Object packet, NetworkMarker marker); + public Object onPacketReceiving(Injector injector, Object packet, NetworkMarker marker); /** * Determine if there is a packet listener for the given packet. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java new file mode 100644 index 00000000..d6918d79 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/ClosedInjector.java @@ -0,0 +1,99 @@ +package com.comphenix.protocol.injector.netty; + +import org.bukkit.entity.Player; + +import com.comphenix.protocol.PacketType.Protocol; +import com.comphenix.protocol.events.NetworkMarker; +import com.comphenix.protocol.events.PacketEvent; + + +/** + * Represents a closed injector. + * @author Kristian + */ +class ClosedInjector implements Injector { + private Player player; + + /** + * Construct a new injector that is always closed. + * @param player - the associated player. + */ + public ClosedInjector(Player player) { + this.player = player; + } + + @Override + public boolean inject() { + return false; + } + + @Override + public void close() { + // Do nothing + } + + @Override + public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) { + // Do nothing + } + + @Override + public void recieveClientPacket(Object packet, NetworkMarker marker, boolean filtered) { + // Do nothing + } + + @Override + public Protocol getCurrentProtocol() { + return Protocol.HANDSHAKING; + } + + @Override + public boolean unignorePacket(Object packet) { + return false; + } + + @Override + public boolean ignorePacket(Object packet) { + return false; + } + + @Override + public NetworkMarker getMarker(Object packet) { + return null; + } + + @Override + public void saveMarker(Object packet, NetworkMarker marker) { + // Do nothing + } + + @Override + public void saveEvent(NetworkMarker marker, PacketEvent event) { + // Do nothing + } + + @Override + public void setUpdatedPlayer(Player player) { + // Do nothing + } + + @Override + public Player getPlayer() { + return player; + } + + @Override + public void setPlayer(Player player) { + this.player = player; + } + + @Override + public boolean isInjected() { + return false; + } + + @Override + public boolean isClosed() { + return true; + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/InjectionFactory.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/InjectionFactory.java new file mode 100644 index 00000000..9af27a61 --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/InjectionFactory.java @@ -0,0 +1,202 @@ +package com.comphenix.protocol.injector.netty; + +import java.util.concurrent.ConcurrentMap; + +import javax.annotation.Nonnull; +import net.minecraft.util.io.netty.channel.Channel; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import com.comphenix.protocol.injector.netty.ChannelInjector.ChannelSocketInjector; +import com.comphenix.protocol.injector.server.SocketInjector; +import com.comphenix.protocol.injector.server.TemporaryPlayerFactory; +import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.utility.MinecraftFields; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.google.common.collect.MapMaker; +import com.google.common.collect.Maps; + +/** + * Represents an injector factory. + *

+ * Note that the factory will return {@link ClosedInjector} when the factory is closed. + * @author Kristian + */ +class InjectionFactory { + private final ConcurrentMap playerLookup = Maps.newConcurrentMap(); + private final ConcurrentMap nameLookup = new MapMaker().weakValues().makeMap(); + + // Whether or not the factory is closed + private boolean closed; + + /** + * Construct or retrieve a channel injector from an existing Bukkit player. + * @param player - the existing Bukkit player. + * @param channelListener - the listener. + * @return A new injector, an existing injector associated with this player, or a closed injector. + */ + @Nonnull + public Injector fromPlayer(Player player, ChannelListener listener) { + if (closed) + return new ClosedInjector(player); + Injector injector = playerLookup.get(player); + + // Find a temporary injector as well + if (injector == null) + injector = getTemporaryInjector(player); + if (injector != null) + return injector; + + Object networkManager = MinecraftFields.getNetworkManager(player); + + // Must be a temporary Bukkit player + if (networkManager == null) { + return fromName(player.getName(), player); + } + Channel channel = FuzzyReflection.getFieldValue(networkManager, Channel.class, true); + + // See if a channel has already been created + injector = (ChannelInjector) ChannelInjector.findChannelHandler(channel, ChannelInjector.class); + + if (injector != null) { + // Update the player instance + playerLookup.remove(injector.getPlayer()); + injector.setPlayer(player); + } else { + injector = new ChannelInjector(player, networkManager, channel, listener, this); + } + + // Cache injector and return + cacheInjector(player, injector); + return injector; + } + + /** + * Retrieve a cached injector from a name. + *

+ * The injector may be NULL if the plugin has been reloaded during a player login. + * @param address - the name. + * @return The cached injector, or a closed injector if it could not be found. + */ + public Injector fromName(String name, Player player) { + if (closed) + return new ClosedInjector(player); + Injector injector = nameLookup.get(name); + + // We can only retrieve cached injectors + if (injector != null) { + // Update instance + injector.setUpdatedPlayer(player); + return injector; + } + return new ClosedInjector(player); + } + + /** + * Construct a new channel injector for the given channel. + * @param channel - the channel. + * @param playerFactory - a temporary player creator. + * @param channelListener - the listener. + * @param loader - the current (plugin) class loader. + * @return The channel injector, or a closed injector. + */ + @Nonnull + public Injector fromChannel(Channel channel, ChannelListener listener, TemporaryPlayerFactory playerFactory) { + if (closed) + return new ClosedInjector(null); + + Object networkManager = findNetworkManager(channel); + Player temporaryPlayer = playerFactory.createTemporaryPlayer(Bukkit.getServer()); + ChannelInjector injector = new ChannelInjector(temporaryPlayer, networkManager, channel, listener, this); + + // Initialize temporary player + TemporaryPlayerFactory.setInjectorInPlayer(temporaryPlayer, new ChannelSocketInjector(injector)); + return injector; + } + + /** + * Invalidate a cached injector. + * @param player - the associated player. + * @return The cached injector, or NULL if nothing was cached. + */ + public Injector invalidate(Player player) { + Injector injector = playerLookup.remove(player); + + nameLookup.remove(player.getName()); + return injector; + } + + /** + * Cache an injector by player. + * @param player - the player. + * @param injector - the injector to cache. + * @return The previously cached injector. + */ + public Injector cacheInjector(Player player, Injector injector) { + nameLookup.put(player.getName(), injector); + return playerLookup.put(player, injector); + } + + /** + * Cache an injector by name alone. + * @param name - the name to lookup. + * @param injector - the injector. + * @return The cached injector. + */ + public Injector cacheInjector(String name, Injector injector) { + return nameLookup.put(name, injector); + } + + /** + * Retrieve the associated channel injector. + * @param player - the temporary player, or normal Bukkit player. + * @return The associated injector, or NULL if this is a Bukkit player. + */ + private ChannelInjector getTemporaryInjector(Player player) { + SocketInjector injector = TemporaryPlayerFactory.getInjectorFromPlayer(player); + + if (injector != null) { + return ((ChannelSocketInjector) injector).getChannelInjector(); + } + return null; + } + + /** + * Find the network manager in a channel's pipeline. + * @param channel - the channel. + * @return The network manager. + */ + private Object findNetworkManager(Channel channel) { + // Find the network manager + Object networkManager = ChannelInjector.findChannelHandler(channel, MinecraftReflection.getNetworkManagerClass()); + + if (networkManager != null) + return networkManager; + throw new IllegalArgumentException("Unable to find NetworkManager in " + channel); + } + + /** + * Determine if the factory is closed. + *

+ * If it is, all new injectors will be closed by default. + * @return TRUE if it is closed, FALSE otherwise. + */ + public boolean isClosed() { + return closed; + } + + /** + * Close all injectors created by this factory, and cease the creation of new injections. + */ + public synchronized void close() { + if (!closed) { + closed = true; + + // Close everything + for (Injector injector : playerLookup.values()) + injector.close(); + for (Injector injector : nameLookup.values()) + injector.close(); + } + } +} diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java new file mode 100644 index 00000000..bcfee64f --- /dev/null +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/Injector.java @@ -0,0 +1,115 @@ +package com.comphenix.protocol.injector.netty; + +import org.bukkit.entity.Player; + +import com.comphenix.protocol.PacketType.Protocol; +import com.comphenix.protocol.events.NetworkMarker; +import com.comphenix.protocol.events.PacketEvent; + +/** + * Represents an injected client connection. + * @author Kristian + */ +interface Injector { + /** + * Inject the current channel. + *

+ * Note that only active channels can be injected. + * @return TRUE if we injected the channel, false if we could not inject or it was already injected. + */ + public abstract boolean inject(); + + /** + * Close the current injector. + */ + public abstract void close(); + + /** + * Send a packet to a player's client. + * @param packet - the packet to send. + * @param marker - the network marker. + * @param filtered - whether or not the packet is filtered. + */ + public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered); + + /** + * Recieve a packet on the server. + * @param packet - the (NMS) packet to send. + * @param marker - the network marker. + * @param filtered - whether or not the packet is filtered. + */ + public abstract void recieveClientPacket(Object packet, NetworkMarker marker, boolean filtered); + + /** + * Retrieve the current protocol state. + * @return The current protocol. + */ + public abstract Protocol getCurrentProtocol(); + + /** + * Undo the ignore status of a packet. + * @param packet - the packet. + * @return TRUE if the ignore status was undone, FALSE otherwise. + */ + public abstract boolean unignorePacket(Object packet); + + /** + * Ignore the given packet. + * @param packet - the packet to ignore. + * @return TRUE if it was ignored, FALSE if it already is ignored. + */ + public abstract boolean ignorePacket(Object packet); + + /** + * Retrieve the network marker associated with a given packet. + * @param packet - the packet. + * @return The network marker. + */ + public abstract NetworkMarker getMarker(Object packet); + + /** + * Associate a given network marker with a specific packet. + * @param packet - the NMS packet. + * @param marker - the associated marker. + */ + public abstract void saveMarker(Object packet, NetworkMarker marker); + + /** + * Associate a given network marker with a packet event. + * @param marker - the marker. + * @param event - the packet event + */ + public abstract void saveEvent(NetworkMarker marker, PacketEvent event); + + /** + * Retrieve the current player or temporary player associated with the injector. + * @return The current player. + */ + public abstract Player getPlayer(); + + /** + * Set the current player instance. + * @param player - the current player. + */ + public abstract void setPlayer(Player player); + + /** + * Determine if the channel has already been injected. + * @return TRUE if it has, FALSE otherwise. + */ + public abstract boolean isInjected(); + + /** + * Determine if this channel has been closed and cleaned up. + * @return TRUE if it has, FALSE otherwise. + */ + public abstract boolean isClosed(); + + /** + * Set the updated player instance. + *

+ * This will not replace the current instance, but it will allow PacketEvent to provide additional player information. + * @param player - the more up-to-date player. + */ + public abstract void setUpdatedPlayer(Player player); +} \ No newline at end of file diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java index 57f8f5fc..a8d4ccf9 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/netty/NettyProtocolInjector.java @@ -7,7 +7,6 @@ import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.util.List; import java.util.Set; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import net.minecraft.util.io.netty.channel.Channel; @@ -23,11 +22,7 @@ import com.comphenix.protocol.concurrency.PacketTypeSet; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.ReportType; -import com.comphenix.protocol.events.ConnectionSide; -import com.comphenix.protocol.events.ListenerOptions; -import com.comphenix.protocol.events.NetworkMarker; -import com.comphenix.protocol.events.PacketContainer; -import com.comphenix.protocol.events.PacketEvent; +import com.comphenix.protocol.events.*; import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.packet.PacketInjector; import com.comphenix.protocol.injector.packet.PacketRegistry; @@ -40,6 +35,7 @@ import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.utility.MinecraftReflection; import com.google.common.collect.Lists; + public class NettyProtocolInjector implements ChannelListener { public static final ReportType REPORT_CANNOT_INJECT_INCOMING_CHANNEL = new ReportType("Unable to to inject incoming channel %s."); @@ -50,6 +46,9 @@ public class NettyProtocolInjector implements ChannelListener { private TemporaryPlayerFactory playerFactory = new TemporaryPlayerFactory(); private List bootstrapFields = Lists.newArrayList(); + // The channel injector factory + private InjectionFactory injectionFactory = new InjectionFactory(); + // List of network managers private volatile List networkManagers; @@ -92,15 +91,9 @@ public class NettyProtocolInjector implements ChannelListener { @Override protected void initChannel(Channel channel) throws Exception { try { - // Check and see if the injector has closed - synchronized (this) { - if (closed) - return; - } - // This can take a while, so we need to stop the main thread from interfering synchronized (networkManagers) { - ChannelInjector.fromChannel(channel, NettyProtocolInjector.this, playerFactory).inject(); + injectionFactory.fromChannel(channel, NettyProtocolInjector.this, playerFactory).inject(); } } catch (Exception e) { reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_INJECT_INCOMING_CHANNEL). @@ -167,7 +160,7 @@ public class NettyProtocolInjector implements ChannelListener { * @param player */ public void injectPlayer(Player player) { - ChannelInjector.fromPlayer(player, this).inject(); + injectionFactory.fromPlayer(player, this).inject(); } private List getBootstrapFields(Object serverConnection) { @@ -203,16 +196,13 @@ public class NettyProtocolInjector implements ChannelListener { } field.revertValue(); } - // Uninject all the players - for (Player player : Bukkit.getServer().getOnlinePlayers()) { - ChannelInjector.fromPlayer(player, this).close(); - } + injectionFactory.close(); } } @Override - public Object onPacketSending(ChannelInjector injector, Object packet, NetworkMarker marker) { + public Object onPacketSending(Injector injector, Object packet, NetworkMarker marker) { Class clazz = packet.getClass(); if (sendingFilters.contains(clazz)) { @@ -235,7 +225,7 @@ public class NettyProtocolInjector implements ChannelListener { } @Override - public Object onPacketReceiving(ChannelInjector injector, Object packet, NetworkMarker marker) { + public Object onPacketReceiving(Injector injector, Object packet, NetworkMarker marker) { Class clazz = packet.getClass(); if (reveivedFilters.contains(clazz)) { @@ -295,12 +285,12 @@ public class NettyProtocolInjector implements ChannelListener { @Override public void updatePlayer(Player player) { - ChannelInjector.fromPlayer(player, listener).inject(); + injectionFactory.fromPlayer(player, listener).inject(); } @Override public void injectPlayer(Player player, ConflictStrategy strategy) { - ChannelInjector.fromPlayer(player, listener).inject(); + injectionFactory.fromPlayer(player, listener).inject(); } @Override @@ -324,19 +314,19 @@ public class NettyProtocolInjector implements ChannelListener { @Override public boolean uninjectPlayer(Player player) { - ChannelInjector.fromPlayer(player, listener).close(); + injectionFactory.fromPlayer(player, listener).close(); return true; } @Override public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException { - ChannelInjector.fromPlayer(receiver, listener). + injectionFactory.fromPlayer(receiver, listener). sendServerPacket(packet.getHandle(), marker, filters); } @Override public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException { - ChannelInjector.fromPlayer(player, listener). + injectionFactory.fromPlayer(player, listener). recieveClientPacket(mcPacket, null, true); } @@ -348,7 +338,7 @@ public class NettyProtocolInjector implements ChannelListener { @Override public void handleDisconnect(Player player) { - ChannelInjector.fromPlayer(player, listener).close(); + injectionFactory.fromPlayer(player, listener).close(); } }; } @@ -363,7 +353,7 @@ public class NettyProtocolInjector implements ChannelListener { @Override public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) { NetworkMarker marker = buffered != null ? new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, buffered) : null; - ChannelInjector.fromPlayer(client, NettyProtocolInjector.this). + injectionFactory.fromPlayer(client, NettyProtocolInjector.this). saveMarker(packet.getHandle(), marker); return packetReceived(packet, client, marker); }