Archiviert
13
0

Added support for "post packet events".

NetworkMarker now contains a list of post listeners that are invoked 
(in no particular order) when a packet has been serialize and sent
to a player, OR, when it has been enqueued for processing by the 
server.

This works for both 1.7.2+ (Netty) and 1.6.4 and earlier, though the
1.6.4 version has a good deal more overhead.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2014-04-25 02:55:17 +02:00
Ursprung 5185442f35
Commit f7c4fd4ec9
12 geänderte Dateien mit 356 neuen und 51 gelöschten Zeilen

Datei anzeigen

@ -7,15 +7,18 @@ import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.PriorityQueue;
import javax.annotation.Nonnull;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.utility.ByteBufferInputStream;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.StreamSerializer;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
/**
@ -48,6 +51,8 @@ public abstract class NetworkMarker {
// Custom network handler
private PriorityQueue<PacketOutputHandler> outputHandlers;
// Sent listeners
private List<PacketPostListener> postListeners;
// The input buffer
private ByteBuffer inputBuffer;
@ -151,7 +156,6 @@ public abstract class NetworkMarker {
* <p>
* The data is exactly the same as in {@link #getInputBuffer()}.
* @see #getInputBuffer()
* @param excludeHeader - whether or not to exclude the packet ID header.
* @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
*/
public DataInputStream getInputStream() {
@ -252,6 +256,45 @@ public abstract class NetworkMarker {
}
}
/**
* Add a listener that is invoked after a packet has been successfully sent to the client, or received
* by the server.
* <p>
* Received packets are not guarenteed to have been fully processed, but packets passed
* to {@link ProtocolManager#recieveClientPacket(Player, PacketContainer)} will be processed after the
* current packet event.
* <p>
* Note that post listeners will be executed asynchronously off the main thread. They are not executed
* in any defined order.
* @param listener - the listener that will be invoked.
* @return TRUE if it was added.
*/
public boolean addPostListener(PacketPostListener listener) {
if (postListeners == null)
postListeners = Lists.newArrayList();
return postListeners.add(listener);
}
/**
* Remove the first instance of the given listener.
* @param listener - listener to remove.
* @return TRUE if it was removed, FALSE otherwise.
*/
public boolean removePostListener(PacketPostListener listener) {
if (postListeners != null) {
return postListeners.remove(listener);
}
return false;
}
/**
* Retrieve an immutable view of all the listeners that will be invoked once the packet has been sent or received.
* @return Every post packet listener. Never NULL.
*/
public List<PacketPostListener> getPostListeners() {
return postListeners != null ? Collections.unmodifiableList(postListeners) : Collections.<PacketPostListener>emptyList();
}
/**
* Ensure that the packet event is server side.
*/
@ -304,6 +347,15 @@ public abstract class NetworkMarker {
return marker != null && !marker.getOutputHandlers().isEmpty();
}
/**
* Determine if the given marker has any post listeners.
* @param marker - the marker to check.
* @return TRUE if it does, FALSE otherwise.
*/
public static boolean hasPostListeners(NetworkMarker marker) {
return marker != null && !marker.getPostListeners().isEmpty();
}
/**
* Retrieve the byte buffer stored in the given marker.
* @param marker - the marker.

Datei anzeigen

@ -70,6 +70,7 @@ public class PacketEvent extends EventObject implements Cancellable {
// Whether or not a packet event is read only
private boolean readOnly;
private boolean filtered;
/**
* Use the static constructors to create instances of this event.
@ -77,18 +78,20 @@ public class PacketEvent extends EventObject implements Cancellable {
*/
public PacketEvent(Object source) {
super(source);
this.filtered = true;
}
private PacketEvent(Object source, PacketContainer packet, Player player, boolean serverPacket) {
this(source, packet, null, player, serverPacket);
this(source, packet, null, player, serverPacket, true);
}
private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket) {
private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket, boolean filtered) {
super(source);
this.packet = packet;
this.playerReference = new WeakReference<Player>(player);
this.networkMarker = marker;
this.serverPacket = serverPacket;
this.filtered = filtered;
}
private PacketEvent(PacketEvent origial, AsyncMarker asyncMarker) {
@ -97,6 +100,7 @@ public class PacketEvent extends EventObject implements Cancellable {
this.playerReference = origial.playerReference;
this.cancel = origial.cancel;
this.serverPacket = origial.serverPacket;
this.filtered = origial.filtered;
this.asyncMarker = asyncMarker;
this.asynchronous = true;
}
@ -121,7 +125,22 @@ public class PacketEvent extends EventObject implements Cancellable {
* @return The event.
*/
public static PacketEvent fromClient(Object source, PacketContainer packet, NetworkMarker marker, Player client) {
return new PacketEvent(source, packet, marker, client, false);
return new PacketEvent(source, packet, marker, client, false, true);
}
/**
* Creates an event representing a client packet transmission.
* <p>
* If <i>filtered</i> is FALSE, then this event is only processed by packet monitors.
* @param source - the event source.
* @param packet - the packet.
* @param marker - the network marker.
* @param client - the client that sent the packet.
* @param filtered - whether or not this packet event is processed by every packet listener.
* @return The event.
*/
public static PacketEvent fromClient(Object source, PacketContainer packet, NetworkMarker marker, Player client, boolean filtered) {
return new PacketEvent(source, packet, marker, client, false, filtered);
}
/**
@ -144,7 +163,22 @@ public class PacketEvent extends EventObject implements Cancellable {
* @return The event.
*/
public static PacketEvent fromServer(Object source, PacketContainer packet, NetworkMarker marker, Player recipient) {
return new PacketEvent(source, packet, marker, recipient, true);
return new PacketEvent(source, packet, marker, recipient, true, true);
}
/**
* Creates an event representing a server packet transmission.
* <p>
* If <i>filtered</i> is FALSE, then this event is only processed by packet monitors.
* @param source - the event source.
* @param packet - the packet.
* @param marker - the network marker.
* @param recipient - the client that will receieve the packet.
* @param filtered - whether or not this packet event is processed by every packet listener.
* @return The event.
*/
public static PacketEvent fromServer(Object source, PacketContainer packet, NetworkMarker marker, Player recipient, boolean filtered) {
return new PacketEvent(source, packet, marker, recipient, true, filtered);
}
/**
@ -286,6 +320,16 @@ public class PacketEvent extends EventObject implements Cancellable {
return playerReference.get();
}
/**
* Determine if this packet is filtered by every packet listener.
* <p>
* If not, it will only be intercepted by monitor packets.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isFiltered() {
return filtered;
}
/**
* Whether or not this packet was created by the server.
* <p>

Datei anzeigen

@ -20,7 +20,7 @@ package com.comphenix.protocol.events;
import org.bukkit.plugin.Plugin;
/**
* Represents a listener that receives notifications when packets are sent or received.
* Represents a listener that receives notifications when packets are sending or being received.
* <p>
* Use {@link PacketAdapter} for a simple wrapper around this interface.
* @author Kristian

Datei anzeigen

@ -4,7 +4,6 @@ import org.bukkit.plugin.Plugin;
/**
* Represents an adapter version of the output handler interface.
*
* @author Kristian
*/
public abstract class PacketOutputAdapter implements PacketOutputHandler {

Datei anzeigen

@ -0,0 +1,22 @@
package com.comphenix.protocol.events;
import org.bukkit.plugin.Plugin;
import com.google.common.base.Preconditions;
/**
* Represents an adapter version of a post listener.
* @author Kristian
*/
public abstract class PacketPostAdapter implements PacketPostListener {
private Plugin plugin;
public PacketPostAdapter(Plugin plugin) {
this.plugin = Preconditions.checkNotNull(plugin, "plugin cannot be NULL");
}
@Override
public Plugin getPlugin() {
return plugin;
}
}

Datei anzeigen

@ -0,0 +1,23 @@
package com.comphenix.protocol.events;
import org.bukkit.plugin.Plugin;
/**
* Represents a packet listener that is invoked after a packet has been sent or received.
* @author Kristian
*/
public interface PacketPostListener {
/**
* Retrieve the plugin this listener belongs to.
* @return The assoicated plugin.
*/
public Plugin getPlugin();
/**
* Invoked after a packet has been sent or received.
* <p>
* Note that this is invoked asynchronously.
* @param event - the packet event.
*/
public void onPostEvent(PacketEvent event);
}

Datei anzeigen

@ -0,0 +1,83 @@
package com.comphenix.protocol.injector;
import java.util.PriorityQueue;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketOutputHandler;
import com.comphenix.protocol.events.PacketPostListener;
/**
* Represents a processor for network markers.
* @author Kristian
*/
public class NetworkProcessor {
private ErrorReporter reporter;
/**
* Construct a new network processor.
* @param reporter - the reporter.
*/
public NetworkProcessor(ErrorReporter reporter) {
this.reporter = reporter;
}
/**
* Process the serialized packet byte array with the given network marker.
* @param event - current packet event.
* @param marker - the network marker.
* @param input - the input array.
* @return The output array.
*/
public byte[] processOutput(PacketEvent event, NetworkMarker marker, final byte[] input) {
// Bit of a hack - but we need the performance
PriorityQueue<PacketOutputHandler> handlers = (PriorityQueue<PacketOutputHandler>)
marker.getOutputHandlers();
byte[] output = input;
// Let each handler prepare the actual output
while (!handlers.isEmpty()) {
PacketOutputHandler handler = handlers.poll();
try {
byte[] changed = handler.handle(event, output);
// Don't break just because a plugin returned NULL
if (changed != null) {
output = changed;
} else {
throw new IllegalStateException("Handler cannot return a NULL array.");
}
} catch (OutOfMemoryError e) {
throw e;
} catch (ThreadDeath e) {
throw e;
} catch (Throwable e) {
reporter.reportMinimal(handler.getPlugin(), "PacketOutputHandler.handle()", e);
}
}
return output;
}
/**
* Invoke the post listeners, if any.
* @param marker - the network marker, or NULL.
*/
public void invokePostListeners(PacketEvent event, NetworkMarker marker) {
if (NetworkMarker.hasPostListeners(marker)) {
// Invoke every sent listener
for (PacketPostListener listener : marker.getPostListeners()) {
try {
listener.onPostEvent(event);
} catch (OutOfMemoryError e) {
throw e;
} catch (ThreadDeath e) {
throw e;
} catch (Throwable e) {
reporter.reportMinimal(listener.getPlugin(), "SentListener.run()", e);
}
}
}
}
}

Datei anzeigen

@ -782,7 +782,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
// Inform the MONITOR packets
if (!filters) {
PacketEvent event = PacketEvent.fromServer(this, packet, marker, receiver);
PacketEvent event = PacketEvent.fromServer(this, packet, marker, receiver, false);
sendingListeners.invokePacketSending(
reporter, event, ListenerPriority.MONITOR);
@ -832,7 +832,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
// Let the monitors know though
recievedListeners.invokePacketSending(
reporter,
PacketEvent.fromClient(this, packet, marker, sender),
PacketEvent.fromClient(this, packet, marker, sender, false),
ListenerPriority.MONITOR);
}

Datei anzeigen

@ -3,7 +3,10 @@ package com.comphenix.protocol.injector.netty;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.ListIterator;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
@ -13,6 +16,9 @@ import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelHandler;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelInboundHandler;
import net.minecraft.util.io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.util.io.netty.channel.ChannelPromise;
import net.minecraft.util.io.netty.channel.socket.SocketChannel;
import net.minecraft.util.io.netty.handler.codec.ByteToMessageDecoder;
import net.minecraft.util.io.netty.handler.codec.MessageToByteEncoder;
@ -31,7 +37,7 @@ import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketOutputHandler;
import com.comphenix.protocol.injector.NetworkProcessor;
import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
@ -94,6 +100,11 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
*/
private PacketEvent currentEvent;
/**
* A packet event that should be processed by the write method.
*/
private PacketEvent finalEvent;
/**
* A flag set by the main thread to indiciate that a packet should not be processed.
*/
@ -107,12 +118,17 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
private ByteToMessageDecoder vanillaDecoder;
private MessageToByteEncoder<Object> vanillaEncoder;
// Our extra handler
// Our extra handlers
private MessageToByteEncoder<Object> protocolEncoder;
private ChannelInboundHandler finishHandler;
private Deque<PacketEvent> finishQueue = new ArrayDeque<PacketEvent>();
// The channel listener
private ChannelListener channelListener;
// Processing network markers
private NetworkProcessor processor;
// Closed
private boolean injected;
private boolean closed;
@ -131,6 +147,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
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");
this.processor = new NetworkProcessor(ProtocolLibrary.getErrorReporter());
// Get the channel field
this.channelField = new VolatileField(
@ -178,10 +195,27 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception {
ChannelInjector.this.encode(ctx, packet, output);
}
@Override
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
super.write(ctx, packet, promise);
ChannelInjector.this.finalWrite(ctx, packet, promise);
}
};
// Intercept recieved packets
finishHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Execute context first
ctx.fireChannelRead(msg);
ChannelInjector.this.finishRead(ctx, msg);
}
};
// Insert our handlers - note that we effectively replace the vanilla encoder/decoder
originalChannel.pipeline().addBefore("decoder", "protocol_lib_decoder", this);
originalChannel.pipeline().addBefore("protocol_lib_decoder", "protocol_lib_finish", finishHandler);
originalChannel.pipeline().addAfter("encoder", "protocol_lib_encoder", protocolEncoder);
// Intercept all write methods
@ -250,7 +284,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
return true;
}
}
/**
* Process a given message on the packet listeners.
* @param message - the message/packet.
@ -286,10 +320,10 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
* @throws Exception If anything went wrong.
*/
protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception {
NetworkMarker marker = null;
PacketEvent event = currentEvent;
try {
PacketEvent event = currentEvent;
NetworkMarker marker = null;
// Skip every kind of non-filtered packet
if (!scheduleProcessPackets.get()) {
return;
@ -323,15 +357,16 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) {
ByteBuf packetBuffer = ctx.alloc().buffer();
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, packetBuffer);
byte[] data = getBytes(packetBuffer);
for (PacketOutputHandler handler : marker.getOutputHandlers()) {
data = handler.handle(event, data);
}
// Let each handler prepare the actual output
byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer));
// Write the result
output.writeBytes(data);
packet = null;
// Sent listeners?
finalEvent = event;
return;
}
} catch (Exception e) {
@ -341,10 +376,29 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Attempt to handle the packet nevertheless
if (packet != null) {
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, output);
finalEvent = event;
}
}
}
/**
* Invoked when a packet has been written to the channel.
* @param ctx - current context.
* @param packet - the packet that has been written.
* @param promise - a promise.
*/
protected void finalWrite(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) {
PacketEvent event = finalEvent;
if (event != null) {
// Necessary to prevent infinite loops
finalEvent = null;
currentEvent = null;
processor.invokePostListeners(event, NetworkMarker.getNetworkMarker(event));
}
}
private void scheduleMainThread(final Object packetCopy) {
// Don't use BukkitExecutors for this - it has a bit of overhead
Bukkit.getScheduler().scheduleSyncDelayedTask(factory.getPlugin(), new Runnable() {
@ -360,9 +414,12 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
byteBuffer.markReaderIndex();
DECODE_BUFFER.invoke(vanillaDecoder, ctx, byteBuffer, packets);
try {
if (packets.size() > 0) {
Object input = packets.get(0);
try {
// Reset queue
finishQueue.clear();
for (ListIterator<Object> it = packets.listIterator(); it.hasNext(); ) {
Object input = it.next();
Class<?> packetClass = input.getClass();
NetworkMarker marker = null;
@ -377,10 +434,14 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Handle packet changes
if (output != null) {
if (output.isCancelled())
packets.clear();
else if (output.getPacket().getHandle() != input)
packets.set(0, output.getPacket().getHandle());
if (output.isCancelled()) {
it.remove();
continue;
} else if (output.getPacket().getHandle() != input) {
it.set(output.getPacket().getHandle());
}
finishQueue.addLast(output);
}
}
} catch (Exception e) {
@ -389,6 +450,24 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
}
}
/**
* Invoked after our decoder.
* @param ctx - current context.
* @param msg - the current packet.
*/
protected void finishRead(ChannelHandlerContext ctx, Object msg) {
// Assume same order
PacketEvent event = finishQueue.pollFirst();
if (event != null) {
NetworkMarker marker = NetworkMarker.getNetworkMarker(event);
if (marker != null) {
processor.invokePostListeners(event, marker);
}
}
}
/**
* Invoked when we may need to handle the login packet.
* @param packetClass - the packet class.
@ -608,6 +687,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
@Override
public Object call() throws Exception {
originalChannel.pipeline().remove(ChannelInjector.this);
originalChannel.pipeline().remove(finishHandler);
originalChannel.pipeline().remove(protocolEncoder);
return null;
}

Datei anzeigen

@ -28,8 +28,10 @@ import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.NetworkProcessor;
import com.google.common.collect.MapMaker;
import net.sf.cglib.proxy.MethodInterceptor;
@ -47,6 +49,7 @@ class ReadPacketModifier implements MethodInterceptor {
// Report errors
private ErrorReporter reporter;
private NetworkProcessor processor;
// If this is a read packet data method
private boolean isReadPacketDataMethod;
@ -58,6 +61,7 @@ class ReadPacketModifier implements MethodInterceptor {
this.packetID = packetID;
this.packetInjector = packetInjector;
this.reporter = reporter;
this.processor = new NetworkProcessor(reporter);
this.isReadPacketDataMethod = isReadPacketDataMethod;
}
@ -152,9 +156,14 @@ class ReadPacketModifier implements MethodInterceptor {
if (event.isCancelled()) {
override.put(thisObj, CANCEL_MARKER);
return returnValue;
} else if (!objectEquals(thisObj, result)) {
override.put(thisObj, result);
}
// This is fine - received packets are enqueued in any case
NetworkMarker marker = NetworkMarker.getNetworkMarker(event);
processor.invokePostListeners(event, marker);
}
} catch (OutOfMemoryError e) {

Datei anzeigen

@ -30,6 +30,7 @@ import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketOutputHandler;
import com.comphenix.protocol.injector.NetworkProcessor;
import com.google.common.collect.MapMaker;
import net.sf.cglib.proxy.MethodInterceptor;
@ -55,12 +56,14 @@ public class WritePacketModifier implements MethodInterceptor {
// Report errors
private final ErrorReporter reporter;
private final NetworkProcessor processor;
// Whether or not this represents the write method
private boolean isWriteMethod;
public WritePacketModifier(ErrorReporter reporter, boolean isWriteMethod) {
this.reporter = reporter;
this.processor = new NetworkProcessor(reporter);
this.isWriteMethod = isWriteMethod;
}
@ -85,39 +88,24 @@ public class WritePacketModifier implements MethodInterceptor {
}
if (isWriteMethod) {
PriorityQueue<PacketOutputHandler> handlers = (PriorityQueue<PacketOutputHandler>)
information.marker.getOutputHandlers();
// If every output handler has been removed - ignore everything
if (!handlers.isEmpty()) {
if (!information.marker.getOutputHandlers().isEmpty()) {
try {
DataOutput output = (DataOutput) args[0];
// First - we need the initial buffer
ByteArrayOutputStream outputBufferStream = new ByteArrayOutputStream();
proxy.invoke(information.proxyObject, new Object[] { new DataOutputStream(outputBufferStream) });
byte[] outputBuffer = outputBufferStream.toByteArray();
// Let each handler prepare the actual output
while (!handlers.isEmpty()) {
PacketOutputHandler handler = handlers.poll();
try {
byte[] changed = handler.handle(information.event, outputBuffer);
// Don't break just because a plugin returned NULL
if (changed != null) {
outputBuffer = changed;
} else {
throw new IllegalStateException("Handler cannot return a NULL array.");
}
} catch (Exception e) {
reporter.reportMinimal(handler.getPlugin(), "PacketOutputHandler.handle()", e);
}
}
byte[] outputBuffer = processor.processOutput(information.event, information.marker,
outputBufferStream.toByteArray());
// Write that output to the network stream
output.write(outputBuffer);
// We're done
processor.invokePostListeners(information.event, information.marker);
return null;
} catch (OutOfMemoryError e) {
@ -131,6 +119,11 @@ public class WritePacketModifier implements MethodInterceptor {
);
}
}
// Invoke this write method first
proxy.invoke(information.proxyObject, args);
processor.invokePostListeners(information.event, information.marker);
return null;
}
// Default to the super method

Datei anzeigen

@ -636,7 +636,7 @@ public abstract class PlayerInjector implements SocketInjector {
marker = NetworkMarker.getNetworkMarker(event);
// See if we need to proxy the write method
if (result != null && NetworkMarker.hasOutputHandlers(marker)) {
if (result != null && (NetworkMarker.hasOutputHandlers(marker) || NetworkMarker.hasPostListeners(marker))) {
result = writePacketInterceptor.constructProxy(result, event, marker);
}
return result;