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 998d32cf..9765fc45 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java @@ -216,10 +216,19 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok // Use the correct injection type if (builder.isNettyEnabled()) { - spigotInjector = new SpigotPacketInjector(classLoader, reporter, this, server); + this.spigotInjector = new SpigotPacketInjector(classLoader, reporter, this, server); this.playerInjection = spigotInjector.getPlayerHandler(); this.packetInjector = spigotInjector.getPacketInjector(); + // Set real injector, in case we need it + spigotInjector.setProxyPacketInjector(PacketInjectorBuilder.newBuilder(). + invoker(this). + reporter(reporter). + classLoader(classLoader). + playerInjection(playerInjection). + buildInjector() + ); + } else { // Initialize standard injection mangers this.playerInjection = PlayerInjectorBuilder.newBuilder(). @@ -231,7 +240,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok injectionFilter(isInjectionNecessary). version(builder.getMinecraftVersion()). buildHandler(); - + this.packetInjector = PacketInjectorBuilder.newBuilder(). invoker(this). reporter(reporter). @@ -376,6 +385,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok } // Update it this.inputBufferedPackets = updated; + this.packetInjector.inputBuffersChanged(updated.toSet()); } /** diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java index 2603c2bb..12090aae 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/PacketInjector.java @@ -41,6 +41,12 @@ public interface PacketInjector { */ public abstract boolean hasPacketHandler(int packetID); + /** + * Invoked when input buffers have changed. + * @param set - the new set of packets that require the read buffer. + */ + public abstract void inputBuffersChanged(Set set); + /** * Retrieve every intercepted packet ID. * @return Every intercepted packet ID. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java index 25b38039..8ed3ea47 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/packet/ProxyPacketInjector.java @@ -164,7 +164,7 @@ class ProxyPacketInjector implements PacketInjector { // Determine if the read packet method was found private boolean readPacketIntercepted = false; - + public ProxyPacketInjector(ClassLoader classLoader, ListenerInvoker manager, PlayerInjectionHandler playerInjection, ErrorReporter reporter) throws FieldAccessException { @@ -206,6 +206,11 @@ class ProxyPacketInjector implements PacketInjector { } } + @Override + public void inputBuffersChanged(Set set) { + // No need to do anything + } + @Override @SuppressWarnings("rawtypes") public boolean addPacketHandler(int packetID) { @@ -321,6 +326,10 @@ class ProxyPacketInjector implements PacketInjector { // Called from the ReadPacketModified monitor public PacketEvent packetRecieved(PacketContainer packet, DataInputStream input, byte[] buffered) { + if (playerInjection.canRecievePackets()) { + return playerInjection.handlePacketRecieved(packet, input, buffered); + } + try { Player client = playerInjection.getPlayerByConnection(input); diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java index 4f4858dc..291d2e5d 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/PlayerInjectionHandler.java @@ -8,6 +8,7 @@ import org.bukkit.entity.Player; import com.comphenix.protocol.events.NetworkMarker; import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; @@ -159,6 +160,21 @@ public interface PlayerInjectionHandler { */ public abstract Set getSendingFilters(); + /** + * Whether or not this player injection handler can also recieve packets. + * @return TRUE if it can, FALSE otherwise. + */ + public abstract boolean canRecievePackets(); + + /** + * Invoked if this player injection handler can process recieved packets. + * @param packet - the recieved packet. + * @param input - the input stream. + * @param buffered - the buffered packet. + * @return The packet event. + */ + public abstract PacketEvent handlePacketRecieved(PacketContainer packet, DataInputStream input, byte[] buffered); + /** * Close any lingering proxy injections. */ diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java index f13a4440..0b2ea3c8 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/player/ProxyPlayerInjectionHandler.java @@ -41,6 +41,7 @@ import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.events.NetworkMarker; import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.ListenerInvoker; @@ -649,6 +650,16 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler { return null; } + @Override + public boolean canRecievePackets() { + return false; + } + + @Override + public PacketEvent handlePacketRecieved(PacketContainer packet, DataInputStream input, byte[] buffered) { + throw new UnsupportedOperationException("Proxy injection cannot handle recieved packets."); + } + /** * Determine if the given listeners are valid. * @param listeners - listeners to check. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java index 783e36ff..3b3c4f90 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPacketInjector.java @@ -4,10 +4,12 @@ import java.util.Set; import org.bukkit.entity.Player; +import com.comphenix.protocol.Packets; import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.injector.packet.PacketInjector; +import com.google.common.collect.Sets; /** * Dummy packet injector that simply delegates to its parent Spigot packet injector or receiving filters. @@ -17,6 +19,8 @@ import com.comphenix.protocol.injector.packet.PacketInjector; class DummyPacketInjector implements PacketInjector { private SpigotPacketInjector injector; private IntegerSet reveivedFilters; + + private IntegerSet lastBufferedPackets = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1); public DummyPacketInjector(SpigotPacketInjector injector, IntegerSet reveivedFilters) { this.injector = injector; @@ -27,6 +31,20 @@ class DummyPacketInjector implements PacketInjector { public void undoCancel(Integer id, Object packet) { // Do nothing yet } + + @Override + public void inputBuffersChanged(Set set) { + Set removed = Sets.difference(lastBufferedPackets.toSet(), set); + Set added = Sets.difference(set, lastBufferedPackets.toSet()); + + // Update the proxy packet injector + for (int packet : removed) { + injector.getProxyPacketInjector().removePacketHandler(packet); + } + for (int packet : added) { + injector.getProxyPacketInjector().addPacketHandler(packet); + } + } @Override public boolean addPacketHandler(int packetID) { @@ -52,7 +70,7 @@ class DummyPacketInjector implements PacketInjector { @Override public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) { - return injector.packetReceived(packet, client); + return injector.packetReceived(packet, client, buffered); } @Override diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java index af8e9f0e..554b1d75 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/DummyPlayerHandler.java @@ -9,6 +9,7 @@ import org.bukkit.entity.Player; import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.events.NetworkMarker; import com.comphenix.protocol.events.PacketContainer; +import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; @@ -95,6 +96,20 @@ class DummyPlayerHandler implements PlayerInjectionHandler { return PlayerInjectHooks.NETWORK_SERVER_OBJECT; } + @Override + public boolean canRecievePackets() { + return true; + } + + @Override + public PacketEvent handlePacketRecieved(PacketContainer packet, DataInputStream input, byte[] buffered) { + // Associate this buffered data + if (buffered != null) { + injector.saveBuffered(packet.getHandle(), buffered); + } + return null; + } + @Override public PlayerInjectHooks getPlayerHook() { // Pretend that we do diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java index 220c8c78..8b7a1eeb 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/spigot/SpigotPacketInjector.java @@ -4,6 +4,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collections; +import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; @@ -24,6 +25,7 @@ import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.error.DelegatedErrorReporter; import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.Report; +import com.comphenix.protocol.events.ConnectionSide; import com.comphenix.protocol.events.NetworkMarker; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; @@ -78,12 +80,18 @@ public class SpigotPacketInjector implements SpigotPacketListener { // Player to injector private ConcurrentMap playerInjector = Maps.newConcurrentMap(); + // For handling read buffered packet data + private Map readBufferedPackets = new MapMaker().weakKeys().makeMap(); + // Responsible for informing the PL packet listeners private ListenerInvoker invoker; private ErrorReporter reporter; private Server server; private ClassLoader classLoader; + // The proxy packet injector + private PacketInjector proxyPacketInjector; + /** * Create a new spigot injector. */ @@ -96,6 +104,30 @@ public class SpigotPacketInjector implements SpigotPacketListener { this.reveivedFilters = new IntegerSet(Packets.MAXIMUM_PACKET_ID + 1); } + /** + * Retrieve the underlying listener invoker. + * @return The invoker. + */ + public ListenerInvoker getInvoker() { + return invoker; + } + + /** + * Set the real proxy packet injector. + * @param proxyPacketInjector - the real injector. + */ + public void setProxyPacketInjector(PacketInjector proxyPacketInjector) { + this.proxyPacketInjector = proxyPacketInjector; + } + + /** + * Retrieve the real proxy packet injector. + * @return The real injector. + */ + public PacketInjector getProxyPacketInjector() { + return proxyPacketInjector; + } + /** * Retrieve the spigot packet listener class. * @return The listener class. @@ -343,6 +375,15 @@ public class SpigotPacketInjector implements SpigotPacketListener { return result; } + /** + * Save the buffered serialized input packet. + * @param handle - the associated packet. + * @param buffered - the buffere data to save. + */ + public void saveBuffered(Object handle, byte[] buffered) { + readBufferedPackets.put(handle, buffered); + } + @Override public Object packetReceived(Object networkManager, Object connection, Object packet) { Integer id = invoker.getPacketID(packet); @@ -355,7 +396,7 @@ public class SpigotPacketInjector implements SpigotPacketListener { Player sender = getInjector(networkManager, connection).getUpdatedPlayer(); PacketContainer container = new PacketContainer(id, packet); - PacketEvent event = packetReceived(container, sender); + PacketEvent event = packetReceived(container, sender, readBufferedPackets.get(packet)); if (!event.isCancelled()) return event.getPacket().getHandle(); @@ -408,8 +449,9 @@ public class SpigotPacketInjector implements SpigotPacketListener { * @param sender - the client packet. * @return The packet event that was used. */ - PacketEvent packetReceived(PacketContainer packet, Player sender) { - PacketEvent event = PacketEvent.fromClient(this, packet, sender); + PacketEvent packetReceived(PacketContainer packet, Player sender, byte[] buffered) { + NetworkMarker marker = buffered != null ? new NetworkMarker(ConnectionSide.CLIENT_SIDE, buffered) : null; + PacketEvent event = PacketEvent.fromClient(this, packet, marker, sender); invoker.invokePacketRecieving(event); return event;