Archiviert
13
0

Add the ability to intercept the write method of packets.

This is done by constructing a proxy around the class after every
event handler has been invoked, intercepting the write method. Each 
PacketOutputHandler registered by the packet event listeners is 
invoked in turn, modifying a byte array of the data that will be 
written to the network stream.

The byte array is initially filled with the serialized version of the 
packet in the packet event.
Dieser Commit ist enthalten in:
Kristian S. Stangeland 2013-07-17 03:52:27 +02:00
Ursprung 6fe7fe46f3
Commit 051a4eda87
26 geänderte Dateien mit 661 neuen und 71 gelöschten Zeilen

Datei anzeigen

@ -22,6 +22,7 @@ import java.lang.reflect.InvocationTargetException;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.events.ListenerPriority; import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
/** /**
@ -30,7 +31,6 @@ import com.comphenix.protocol.events.PacketContainer;
* @author Kristian * @author Kristian
*/ */
public interface PacketStream { public interface PacketStream {
/** /**
* Send a packet to the given player. * Send a packet to the given player.
* @param reciever - the reciever. * @param reciever - the reciever.
@ -50,6 +50,18 @@ public interface PacketStream {
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters)
throws InvocationTargetException; throws InvocationTargetException;
/**
* Send a packet to the given player.
* @param reciever - the reciever.
* @param packet - packet to send.
* @param marker - the network marker to use.
* @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
* @throws InvocationTargetException - if an error occured when sending the packet.
*/
public void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters)
throws InvocationTargetException;
/** /**
* Simulate recieving a certain packet from a given player. * Simulate recieving a certain packet from a given player.
* @param sender - the sender. * @param sender - the sender.
@ -70,4 +82,16 @@ public interface PacketStream {
*/ */
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
throws IllegalAccessException, InvocationTargetException; throws IllegalAccessException, InvocationTargetException;
/**
* Simulate recieving a certain packet from a given player.
* @param sender - the sender.
* @param packet - the packet that was sent.
* @param marker - the network marker to use.
* @param filters - whether or not to invoke any packet filters below {@link ListenerPriority#MONITOR}.
* @throws InvocationTargetException If the reflection machinery failed.
* @throws IllegalAccessException If the underlying method caused an error.
*/
public void recieveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters)
throws IllegalAccessException, InvocationTargetException;
} }

Datei anzeigen

@ -381,9 +381,9 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
void sendPacket(PacketEvent event) throws IOException { void sendPacket(PacketEvent event) throws IOException {
try { try {
if (event.isServerPacket()) { if (event.isServerPacket()) {
packetStream.sendServerPacket(event.getPlayer(), event.getPacket(), false); packetStream.sendServerPacket(event.getPlayer(), event.getPacket(), event.getNetworkMarker(), false);
} else { } else {
packetStream.recieveClientPacket(event.getPlayer(), event.getPacket(), false); packetStream.recieveClientPacket(event.getPlayer(), event.getPacket(), event.getNetworkMarker(), false);
} }
transmitted = true; transmitted = true;

Datei anzeigen

@ -0,0 +1,13 @@
package com.comphenix.protocol.events;
/**
* Represents additional options a listener may require.
*
* @author Kristian
*/
public enum ListenerOptions {
/**
* Retrieve the serialized client packet as it appears on the network stream.
*/
INTERCEPT_INPUT_BUFFER,
}

Datei anzeigen

@ -17,6 +17,9 @@
package com.comphenix.protocol.events; package com.comphenix.protocol.events;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set; import java.util.Set;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
@ -38,6 +41,7 @@ public class ListeningWhitelist {
private ListenerPriority priority; private ListenerPriority priority;
private Set<Integer> whitelist; private Set<Integer> whitelist;
private GamePhase gamePhase; private GamePhase gamePhase;
private Set<ListenerOptions> options = EnumSet.noneOf(ListenerOptions.class);
/** /**
* Creates a packet whitelist for a given priority with a set of packet IDs. * Creates a packet whitelist for a given priority with a set of packet IDs.
@ -83,6 +87,19 @@ public class ListeningWhitelist {
this.gamePhase = gamePhase; this.gamePhase = gamePhase;
} }
/**
* Creates a packet whitelist for a given priority with a set of packet IDs and options.
* @param priority - the listener priority.
* @param whitelist - list of packet IDs to observe/enable.
* @param gamePhase - which game phase to receieve notifications on.
*/
public ListeningWhitelist(ListenerPriority priority, Integer[] whitelist, GamePhase gamePhase, ListenerOptions... options) {
this.priority = priority;
this.whitelist = Sets.newHashSet(whitelist);
this.gamePhase = gamePhase;
this.options.addAll(Arrays.asList(options));
}
/** /**
* Whether or not this whitelist has any enabled packets. * Whether or not this whitelist has any enabled packets.
* @return TRUE if there are any packets, FALSE otherwise. * @return TRUE if there are any packets, FALSE otherwise.
@ -115,9 +132,17 @@ public class ListeningWhitelist {
return gamePhase; return gamePhase;
} }
/**
* Retrieve every special option associated with this whitelist.
* @return Every special option.
*/
public Set<ListenerOptions> getOptions() {
return Collections.unmodifiableSet(options);
}
@Override @Override
public int hashCode(){ public int hashCode(){
return Objects.hashCode(priority, whitelist, gamePhase); return Objects.hashCode(priority, whitelist, gamePhase, options);
} }
/** /**
@ -156,7 +181,9 @@ public class ListeningWhitelist {
if(obj instanceof ListeningWhitelist){ if(obj instanceof ListeningWhitelist){
final ListeningWhitelist other = (ListeningWhitelist) obj; final ListeningWhitelist other = (ListeningWhitelist) obj;
return Objects.equal(priority, other.priority) return Objects.equal(priority, other.priority)
&& Objects.equal(whitelist, other.whitelist); && Objects.equal(whitelist, other.whitelist)
&& Objects.equal(gamePhase, other.gamePhase)
&& Objects.equal(options, other.options);
} else{ } else{
return false; return false;
} }
@ -169,6 +196,9 @@ public class ListeningWhitelist {
else else
return Objects.toStringHelper(this) return Objects.toStringHelper(this)
.add("priority", priority) .add("priority", priority)
.add("packets", whitelist).toString(); .add("packets", whitelist)
.add("gamephase", gamePhase)
.add("options", options).
toString();
} }
} }

Datei anzeigen

@ -0,0 +1,133 @@
package com.comphenix.protocol.events;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.PriorityQueue;
import javax.annotation.Nonnull;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Ints;
public class NetworkMarker {
// Custom network handler
private PriorityQueue<PacketOutputHandler> outputHandlers;
// The input buffer
private ByteBuffer inputBuffer;
private ConnectionSide side;
/**
* Construct a new network marker.
* <p>
* The input buffer is only non-null for client-side packets.
* @param side - whether or not this marker belongs to a client or server packet.
* @param inputBuffer - the read serialized packet data.
*/
public NetworkMarker(@Nonnull ConnectionSide side, byte[] inputBuffer) {
this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
if (inputBuffer != null) {
this.inputBuffer = ByteBuffer.wrap(inputBuffer);
}
}
/**
* Retrieve whether or not this marker belongs to a client or a server side packet.
* @return The side the parent packet belongs to.
*/
public ConnectionSide getSide() {
return side;
}
/**
* Retrieve the serialized packet data (excluding the header) from the network input stream.
* <p>
* The returned buffer is read-only. If the parent event is a server side packet this
* method throws {@link IllegalStateException}.
* <p>
* It returns NULL if the packet was transmitted by a plugin locally.
* @return A byte buffer containing the raw packet data read from the network.
*/
public ByteBuffer getInputBuffer() {
if (side.isForServer())
throw new IllegalStateException("Server-side packets have no input buffer.");
return inputBuffer != null ? inputBuffer.asReadOnlyBuffer() : null;
}
/**
* Enqueue the given output handler for managing how the current packet will be written to the network stream.
* <p>
* Note that output handlers are not serialized, as most consumers will probably implement them using anonymous classes.
* It is not safe to serialize anonymous classes, as their name depend on the order in which they are declared in the parent class.
* <p>
* This can only be invoked on server side packet events.
* @param handler - the handler that will take part in serializing the packet.
* @return TRUE if it was added, FALSE if it has already been added.
*/
public boolean addOutputHandler(@Nonnull PacketOutputHandler handler) {
checkServerSide();
Preconditions.checkNotNull(handler, "handler cannot be NULL.");
// Lazy initialization - it's imperative that we save space and time here
if (outputHandlers == null) {
outputHandlers = new PriorityQueue<PacketOutputHandler>(10, new Comparator<PacketOutputHandler>() {
@Override
public int compare(PacketOutputHandler o1, PacketOutputHandler o2) {
return Ints.compare(o1.getPriority().getSlot(), o2.getPriority().getSlot());
}
});
}
return outputHandlers.add(handler);
}
/**
* Remove a given output handler from the serialization queue.
* <p>
* This can only be invoked on server side packet events.
* @param handler - the handler to remove.
* @return TRUE if the handler was removed, FALSE otherwise.
*/
public boolean removeOutputHandler(@Nonnull PacketOutputHandler handler) {
checkServerSide();
Preconditions.checkNotNull(handler, "handler cannot be NULL.");
if (outputHandlers != null) {
return outputHandlers.remove(handler);
}
return false;
}
/**
* Retrieve every registered output handler in no particular order.
* @return Every registered output handler.
*/
@Nonnull
public Collection<PacketOutputHandler> getOutputHandlers() {
if (outputHandlers != null) {
return outputHandlers;
} else {
return Collections.emptyList();
}
}
/**
* Ensure that the packet event is server side.
*/
private void checkServerSide() {
if (side.isForClient()) {
throw new IllegalStateException("Must be a server side packet.");
}
}
/**
* Determine if the given marker has any output handlers.
* @param marker - the marker to check.
* @return TRUE if it does, FALSE otherwise.
*/
public static boolean hasOutputHandlers(NetworkMarker marker) {
return marker != null && !marker.getOutputHandlers().isEmpty();
}
}

Datei anzeigen

@ -22,11 +22,11 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.EventObject; import java.util.EventObject;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable; import org.bukkit.event.Cancellable;
import com.comphenix.protocol.async.AsyncMarker; import com.comphenix.protocol.async.AsyncMarker;
import com.google.common.base.Preconditions;
public class PacketEvent extends EventObject implements Cancellable { public class PacketEvent extends EventObject implements Cancellable {
/** /**
@ -44,6 +44,9 @@ public class PacketEvent extends EventObject implements Cancellable {
private AsyncMarker asyncMarker; private AsyncMarker asyncMarker;
private boolean asynchronous; private boolean asynchronous;
// Network input and output handlers
private NetworkMarker networkMarker;
// Whether or not a packet event is read only // Whether or not a packet event is read only
private boolean readOnly; private boolean readOnly;
@ -56,9 +59,14 @@ public class PacketEvent extends EventObject implements Cancellable {
} }
private PacketEvent(Object source, PacketContainer packet, Player player, boolean serverPacket) { private PacketEvent(Object source, PacketContainer packet, Player player, boolean serverPacket) {
this(source, packet, null, player, serverPacket);
}
private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket) {
super(source); super(source);
this.packet = packet; this.packet = packet;
this.playerReference = new WeakReference<Player>(player); this.playerReference = new WeakReference<Player>(player);
this.networkMarker = marker;
this.serverPacket = serverPacket; this.serverPacket = serverPacket;
} }
@ -83,6 +91,18 @@ public class PacketEvent extends EventObject implements Cancellable {
return new PacketEvent(source, packet, client, false); return new PacketEvent(source, packet, client, false);
} }
/**
* Creates an event representing a client packet transmission.
* @param source - the event source.
* @param packet - the packet.
* @param marker - the network marker.
* @param client - the client that sent the packet.
* @return The event.
*/
public static PacketEvent fromClient(Object source, PacketContainer packet, NetworkMarker marker, Player client) {
return new PacketEvent(source, packet, marker, client, false);
}
/** /**
* Creates an event representing a server packet transmission. * Creates an event representing a server packet transmission.
* @param source - the event source. * @param source - the event source.
@ -94,6 +114,18 @@ public class PacketEvent extends EventObject implements Cancellable {
return new PacketEvent(source, packet, recipient, true); return new PacketEvent(source, packet, recipient, true);
} }
/**
* Creates an event representing a server packet transmission.
* @param source - the event source.
* @param packet - the packet.
* @param marker - the network marker.
* @param recipient - the client that will receieve the packet.
* @return The event.
*/
public static PacketEvent fromServer(Object source, PacketContainer packet, NetworkMarker marker, Player recipient) {
return new PacketEvent(source, packet, marker, recipient, true);
}
/** /**
* Create an asynchronous packet event from a synchronous event and a async marker. * Create an asynchronous packet event from a synchronous event and a async marker.
* @param event - the original synchronous event. * @param event - the original synchronous event.
@ -138,6 +170,35 @@ public class PacketEvent extends EventObject implements Cancellable {
return cancel; return cancel;
} }
/**
* Retrieve the object responsible for managing the serialized input and output of a packet.
* <p>
* Note that the serialized input data is only available for client-side packets, and the output handlers
* can only be applied to server-side packets.
* @return The network manager.
*/
public NetworkMarker getNetworkMarker() {
if (networkMarker == null) {
if (isServerPacket()) {
networkMarker = new NetworkMarker(
serverPacket ? ConnectionSide.SERVER_SIDE : ConnectionSide.CLIENT_SIDE, null);
} else {
throw new IllegalStateException("Add the option ListenerOptions.INTERCEPT_INPUT_BUFFER to your listener.");
}
}
return networkMarker;
}
/**
* Update the network manager.
* <p>
* This method is internal - do not call.
* @param networkMarker - the new network manager.
*/
public void setNetworkMarker(NetworkMarker networkMarker) {
this.networkMarker = Preconditions.checkNotNull(networkMarker, "marker cannot be NULL");
}
/** /**
* Sets whether or not the packet should be cancelled. Uncancelling is possible. * Sets whether or not the packet should be cancelled. Uncancelling is possible.
* <p> * <p>

Datei anzeigen

@ -0,0 +1,35 @@
package com.comphenix.protocol.events;
import org.bukkit.plugin.Plugin;
/**
* Represents a custom packet serializer onto the network stream.
*
* @author Kristian
*/
public interface PacketOutputHandler {
/**
* Retrieve the priority that decides the order each network handler is allowed to manipulate the output buffer.
* <p>
* Higher priority is executed before lower.
* @return The handler priority.
*/
public ListenerPriority getPriority();
/**
* The plugin that owns this output handler.
* @return The owner plugin.
*/
public Plugin getPlugin();
/**
* Invoked when a given packet is to be written to the output stream.
* <p>
* Note that the buffer is initially filled with the output from the default write method. This excludes
* the packet ID header.
* @param event - the packet that will be outputted.
* @param buffer - the data that is currently scheduled to be outputted.
* @return The modified byte array to write. NULL is not permitted.
*/
public byte[] handle(PacketEvent event, byte[] buffer);
}

Datei anzeigen

@ -19,6 +19,7 @@ import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.ConnectionSide; import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
@ -49,12 +50,15 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
private static class QueuedPacket { private static class QueuedPacket {
private final Player player; private final Player player;
private final PacketContainer packet; private final PacketContainer packet;
private final NetworkMarker marker;
private final boolean filtered; private final boolean filtered;
private final ConnectionSide side; private final ConnectionSide side;
public QueuedPacket(Player player, PacketContainer packet, boolean filtered, ConnectionSide side) { public QueuedPacket(Player player, PacketContainer packet, NetworkMarker marker, boolean filtered, ConnectionSide side) {
this.player = player; this.player = player;
this.packet = packet; this.packet = packet;
this.marker = marker;
this.filtered = filtered; this.filtered = filtered;
this.side = side; this.side = side;
} }
@ -83,6 +87,14 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
return side; return side;
} }
/**
* Retrieve the associated network marker used to serialize packets on the network stream.
* @return The associated marker.
*/
public NetworkMarker getMarker() {
return marker;
}
/** /**
* Determine if the packet should be intercepted by packet listeners. * Determine if the packet should be intercepted by packet listeners.
* @return TRUE if it should, FALSE otherwise. * @return TRUE if it should, FALSE otherwise.
@ -162,10 +174,10 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
// Attempt to send it now // Attempt to send it now
switch (packet.getSide()) { switch (packet.getSide()) {
case CLIENT_SIDE: case CLIENT_SIDE:
delegate.recieveClientPacket(packet.getPlayer(), packet.getPacket(), packet.isFiltered()); delegate.recieveClientPacket(packet.getPlayer(), packet.getPacket(), packet.getMarker(), packet.isFiltered());
break; break;
case SERVER_SIDE: case SERVER_SIDE:
delegate.sendServerPacket(packet.getPlayer(), packet.getPacket(), packet.isFiltered()); delegate.sendServerPacket(packet.getPlayer(), packet.getPacket(), packet.getMarker(), packet.isFiltered());
break; break;
default: default:
@ -197,29 +209,39 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
@Override @Override
public void sendServerPacket(Player reciever, PacketContainer packet) throws InvocationTargetException { public void sendServerPacket(Player reciever, PacketContainer packet) throws InvocationTargetException {
sendServerPacket(reciever, packet, true); sendServerPacket(reciever, packet, null, true);
} }
@Override @Override
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException { public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException {
sendServerPacket(reciever, packet, null, filters);
}
@Override
public void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
if (delegate != null) { if (delegate != null) {
delegate.sendServerPacket(reciever, packet, filters); delegate.sendServerPacket(reciever, packet, marker, filters);
} else { } else {
queuedPackets.add(new QueuedPacket(reciever, packet, filters, ConnectionSide.SERVER_SIDE)); queuedPackets.add(new QueuedPacket(reciever, packet, marker, filters, ConnectionSide.SERVER_SIDE));
} }
} }
@Override @Override
public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException { public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException {
recieveClientPacket(sender, packet, true); recieveClientPacket(sender, packet, null, true);
} }
@Override @Override
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException { public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException {
recieveClientPacket(sender, packet, null, filters);
}
@Override
public void recieveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters) throws IllegalAccessException, InvocationTargetException {
if (delegate != null) { if (delegate != null) {
delegate.recieveClientPacket(sender, packet, filters); delegate.recieveClientPacket(sender, packet, marker, filters);
} else { } else {
queuedPackets.add(new QueuedPacket(sender, packet, filters, ConnectionSide.CLIENT_SIDE)); queuedPackets.add(new QueuedPacket(sender, packet, marker, filters, ConnectionSide.CLIENT_SIDE));
} }
} }

Datei anzeigen

@ -142,7 +142,6 @@ public class PacketConstructor {
* @throws RuntimeException Minecraft threw an exception. * @throws RuntimeException Minecraft threw an exception.
*/ */
public PacketContainer createPacket(Object... values) throws FieldAccessException { public PacketContainer createPacket(Object... values) throws FieldAccessException {
try { try {
// Convert types // Convert types
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {

Datei anzeigen

@ -550,11 +550,16 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
@Override @Override
public void sendServerPacket(Player reciever, PacketContainer packet) throws InvocationTargetException { public void sendServerPacket(Player reciever, PacketContainer packet) throws InvocationTargetException {
sendServerPacket(reciever, packet, true); sendServerPacket(reciever, packet, null, true);
} }
@Override @Override
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException { public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException {
sendServerPacket(reciever, packet, null, true);
}
@Override
public void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
if (reciever == null) if (reciever == null)
throw new IllegalArgumentException("reciever cannot be NULL."); throw new IllegalArgumentException("reciever cannot be NULL.");
if (packet == null) if (packet == null)
@ -565,22 +570,27 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
// Inform the MONITOR packets // Inform the MONITOR packets
if (!filters) { if (!filters) {
sendingListeners.invokePacketSending( PacketEvent event = PacketEvent.fromServer(this, packet, marker, reciever);
reporter,
PacketEvent.fromServer(this, packet, reciever),
ListenerPriority.MONITOR);
}
playerInjection.sendServerPacket(reciever, packet, filters); sendingListeners.invokePacketSending(
reporter, event, ListenerPriority.MONITOR);
marker = event.getNetworkMarker();
}
playerInjection.sendServerPacket(reciever, packet, marker, filters);
} }
@Override @Override
public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException { public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException {
recieveClientPacket(sender, packet, true); recieveClientPacket(sender, packet, null, true);
} }
@Override @Override
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException { public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException {
recieveClientPacket(sender, packet, null, true);
}
@Override
public void recieveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters) throws IllegalAccessException, InvocationTargetException {
if (sender == null) if (sender == null)
throw new IllegalArgumentException("sender cannot be NULL."); throw new IllegalArgumentException("sender cannot be NULL.");
if (packet == null) if (packet == null)
@ -606,7 +616,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
// Let the monitors know though // Let the monitors know though
recievedListeners.invokePacketSending( recievedListeners.invokePacketSending(
reporter, reporter,
PacketEvent.fromClient(this, packet, sender), PacketEvent.fromClient(this, packet, marker, sender),
ListenerPriority.MONITOR); ListenerPriority.MONITOR);
} }

Datei anzeigen

@ -0,0 +1,92 @@
package com.comphenix.protocol.injector.packet;
import java.io.DataOutput;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.NoOp;
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.PacketEvent;
import com.comphenix.protocol.reflect.MethodInfo;
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import com.comphenix.protocol.utility.MinecraftReflection;
/**
* Retrieve a packet instance that has its write method intercepted.
* @author Kristian
*/
public class InterceptWritePacket {
public static final ReportType REPORT_CANNOT_FIND_WRITE_PACKET_METHOD = new ReportType("Cannot find write packet method in %s.");
public static final ReportType REPORT_CANNOT_CONSTRUCT_WRITE_PROXY = new ReportType("Cannot construct write proxy packet %s.");
/**
* Matches the readPacketData(DataInputStream) method in Packet.
*/
private static FuzzyMethodContract WRITE_PACKET = FuzzyMethodContract.newBuilder().
returnTypeVoid().
parameterDerivedOf(DataOutput.class).
parameterCount(1).
build();
private ClassLoader classLoader;
private ErrorReporter reporter;
private CallbackFilter filter;
private boolean writePacketIntercepted;
public InterceptWritePacket(ClassLoader classLoader, ErrorReporter reporter) {
this.classLoader = classLoader;
this.reporter = reporter;
}
/**
* Construct a new instance of the proxy object.
* @return New instance of proxy.
*/
public Object constructProxy(Object proxyObject, PacketEvent event, NetworkMarker marker) {
// Construct the proxy object
Enhancer ex = new Enhancer();
// Initialize the shared filter
if (filter == null) {
filter = new CallbackFilter() {
@Override
public int accept(Method method) {
// Skip methods defined in Object
if (WRITE_PACKET.isMatch(MethodInfo.fromMethod(method), null)) {
return 1;
} else {
return 0;
}
}
};
}
// Subclass the generic packet class
ex.setSuperclass(MinecraftReflection.getPacketClass());
ex.setCallbackFilter(filter);
ex.setClassLoader(classLoader);
ex.setCallbacks(new Callback[] {
NoOp.INSTANCE,
new WritePacketModifier(reporter, proxyObject, event, marker)
});
Object proxy = ex.create();
if (proxy != null) {
// Check that we found the read method
if (!writePacketIntercepted) {
reporter.reportWarning(this,
Report.newBuilder(REPORT_CANNOT_FIND_WRITE_PACKET_METHOD).
messageParam(MinecraftReflection.getPacketClass()));
}
}
return proxy;
}
}

Datei anzeigen

@ -137,7 +137,7 @@ class ProxyPacketInjector implements PacketInjector {
/** /**
* Matches the readPacketData(DataInputStream) method in Packet. * Matches the readPacketData(DataInputStream) method in Packet.
*/ */
private static FuzzyMethodContract readPacket = FuzzyMethodContract.newBuilder(). private static FuzzyMethodContract READ_PACKET = FuzzyMethodContract.newBuilder().
returnTypeVoid(). returnTypeVoid().
parameterDerivedOf(DataInput.class). parameterDerivedOf(DataInput.class).
parameterCount(1). parameterCount(1).
@ -240,7 +240,7 @@ class ProxyPacketInjector implements PacketInjector {
// Skip methods defined in Object // Skip methods defined in Object
if (method.getDeclaringClass().equals(Object.class)) { if (method.getDeclaringClass().equals(Object.class)) {
return 0; return 0;
} else if (readPacket.isMatch(MethodInfo.fromMethod(method), null)) { } else if (READ_PACKET.isMatch(MethodInfo.fromMethod(method), null)) {
readPacketIntercepted = true; readPacketIntercepted = true;
return 1; return 1;
} else { } else {

Datei anzeigen

@ -0,0 +1,124 @@
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.injector.packet;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.lang.reflect.Method;
import java.util.PriorityQueue;
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.PacketEvent;
import com.comphenix.protocol.events.PacketOutputHandler;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class WritePacketModifier implements MethodInterceptor {
public static final ReportType REPORT_CANNOT_WRITE_SERVER_PACKET = new ReportType("Cannot write server packet.");
// Report errors
private final ErrorReporter reporter;
// Marker that contains custom writers
private final Object proxyObject;
private final PacketEvent event;
private final NetworkMarker marker;
public WritePacketModifier(ErrorReporter reporter, Object proxyObject, PacketEvent event, NetworkMarker marker) {
this.proxyObject = proxyObject;
this.event = event;
this.marker = marker;
this.reporter = reporter;
}
@Override
public Object intercept(Object thisObj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
PriorityQueue<PacketOutputHandler> handlers = (PriorityQueue<PacketOutputHandler>) marker.getOutputHandlers();
// If every output handler has been removed - ignore everything
if (!handlers.isEmpty()) {
try {
DataOutput output = (DataOutput) args[0];
// First - we need the initial buffer
ByteArrayOutputStream outputBufferStream = new ByteArrayOutputStream();
proxy.invokeSuper(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(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);
}
}
// Write that output to the network stream
output.write(outputBuffer);
} catch (Throwable e) {
// Minecraft cannot handle this error
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_WRITE_SERVER_PACKET).callerParam(args[0]).error(e)
);
}
}
// Default to the super method
return proxy.invokeSuper(proxyObject, args);
}
/**
* Retrieve the proxied Minecraft object.
* @return The proxied object.
*/
public Object getProxyObject() {
return proxyObject;
}
/**
* Retrieve the associated packet event.
* @return The packet event.
*/
public PacketEvent getEvent() {
return event;
}
/**
* Retrieve the network marker that is in use.
* @return The network marker.
*/
public NetworkMarker getMarker() {
return marker;
}
}

Datei anzeigen

@ -86,7 +86,7 @@ class InjectedArrayList extends ArrayList<Object> {
super.add(result); super.add(result);
} else { } else {
// We'll use the FakePacket marker instead of preventing the filters // We'll use the FakePacket marker instead of preventing the filters
injector.sendServerPacket(createNegativePacket(packet), true); injector.sendServerPacket(createNegativePacket(packet), null, true);
} }
// Collection.add contract // Collection.add contract

Datei anzeigen

@ -31,6 +31,7 @@ import com.comphenix.protocol.Packets;
import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
@ -76,14 +77,10 @@ class NetworkFieldInjector extends PlayerInjector {
// Determine if we're listening // Determine if we're listening
private IntegerSet sendingFilters; private IntegerSet sendingFilters;
// Used to construct proxy objects
private ClassLoader classLoader;
public NetworkFieldInjector(ClassLoader classLoader, ErrorReporter reporter, Player player, public NetworkFieldInjector(ClassLoader classLoader, ErrorReporter reporter, Player player,
ListenerInvoker manager, IntegerSet sendingFilters) throws IllegalAccessException { ListenerInvoker manager, IntegerSet sendingFilters) throws IllegalAccessException {
super(reporter, player, manager); super(classLoader, reporter, player, manager);
this.classLoader = classLoader;
this.sendingFilters = sendingFilters; this.sendingFilters = sendingFilters;
} }
@ -105,12 +102,15 @@ class NetworkFieldInjector extends PlayerInjector {
} }
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException {
if (networkManager != null) { if (networkManager != null) {
try { try {
if (!filtered) { if (!filtered) {
ignoredPackets.add(packet); ignoredPackets.add(packet);
} }
if (marker != null) {
queuedMarkers.put(packet, marker);
}
// Note that invocation target exception is a wrapper for a checked exception // Note that invocation target exception is a wrapper for a checked exception
queueMethod.invoke(networkManager, packet); queueMethod.invoke(networkManager, packet);
@ -146,7 +146,6 @@ class NetworkFieldInjector extends PlayerInjector {
@Override @Override
public void injectManager() { public void injectManager() {
if (networkManager != null) { if (networkManager != null) {
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")

Datei anzeigen

@ -35,6 +35,7 @@ import com.comphenix.protocol.Packets;
import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.ListeningWhitelist; import com.comphenix.protocol.events.ListeningWhitelist;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
@ -51,9 +52,6 @@ public class NetworkObjectInjector extends PlayerInjector {
// Determine if we're listening // Determine if we're listening
private IntegerSet sendingFilters; private IntegerSet sendingFilters;
// Used to construct proxy objects
private ClassLoader classLoader;
// After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.), // After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.),
// CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue. // CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue.
// Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets // Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets
@ -79,9 +77,8 @@ public class NetworkObjectInjector extends PlayerInjector {
*/ */
public NetworkObjectInjector(ClassLoader classLoader, ErrorReporter reporter, Player player, public NetworkObjectInjector(ClassLoader classLoader, ErrorReporter reporter, Player player,
ListenerInvoker invoker, IntegerSet sendingFilters) throws IllegalAccessException { ListenerInvoker invoker, IntegerSet sendingFilters) throws IllegalAccessException {
super(reporter, player, invoker); super(classLoader, reporter, player, invoker);
this.sendingFilters = sendingFilters; this.sendingFilters = sendingFilters;
this.classLoader = classLoader;
} }
@Override @Override
@ -103,11 +100,15 @@ public class NetworkObjectInjector extends PlayerInjector {
} }
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException {
Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue(); Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue();
if (networkDelegate != null) { if (networkDelegate != null) {
try { try {
if (marker != null) {
queuedMarkers.put(packet, marker);
}
// Note that invocation target exception is a wrapper for a checked exception // Note that invocation target exception is a wrapper for a checked exception
queueMethod.invoke(networkDelegate, packet); queueMethod.invoke(networkDelegate, packet);

Datei anzeigen

@ -30,6 +30,7 @@ import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
@ -64,9 +65,6 @@ class NetworkServerInjector extends PlayerInjector {
// Determine if we're listening // Determine if we're listening
private IntegerSet sendingFilters; private IntegerSet sendingFilters;
// Used to create proxy objects
private ClassLoader classLoader;
// Whether or not the player has disconnected // Whether or not the player has disconnected
private boolean hasDisconnected; private boolean hasDisconnected;
@ -78,8 +76,7 @@ class NetworkServerInjector extends PlayerInjector {
ListenerInvoker invoker, IntegerSet sendingFilters, ListenerInvoker invoker, IntegerSet sendingFilters,
InjectedServerConnection serverInjection) throws IllegalAccessException { InjectedServerConnection serverInjection) throws IllegalAccessException {
super(reporter, player, invoker); super(classLoader, reporter, player, invoker);
this.classLoader = classLoader;
this.sendingFilters = sendingFilters; this.sendingFilters = sendingFilters;
this.serverInjection = serverInjection; this.serverInjection = serverInjection;
} }
@ -90,11 +87,15 @@ class NetworkServerInjector extends PlayerInjector {
} }
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException { public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException {
Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue(); Object serverDelegate = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
if (serverDelegate != null) { if (serverDelegate != null) {
try { try {
if (marker != null) {
queuedMarkers.put(packet, marker);
}
// Note that invocation target exception is a wrapper for a checked exception // Note that invocation target exception is a wrapper for a checked exception
MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet); MinecraftMethods.getSendPacketMethod().invoke(serverDelegate, packet);
@ -112,7 +113,6 @@ class NetworkServerInjector extends PlayerInjector {
@Override @Override
public void injectManager() { public void injectManager() {
if (serverHandlerRef == null) if (serverHandlerRef == null)
throw new IllegalStateException("Cannot find server handler."); throw new IllegalStateException("Cannot find server handler.");
// Don't inject twice // Don't inject twice

Datei anzeigen

@ -6,6 +6,7 @@ import java.net.InetSocketAddress;
import java.util.Set; import java.util.Set;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
@ -113,10 +114,11 @@ public interface PlayerInjectionHandler {
* Send the given packet to the given reciever. * Send the given packet to the given reciever.
* @param reciever - the player receiver. * @param reciever - the player receiver.
* @param packet - the packet to send. * @param packet - the packet to send.
* @param marker
* @param filters - whether or not to invoke the packet filters. * @param filters - whether or not to invoke the packet filters.
* @throws InvocationTargetException If an error occured during sending. * @throws InvocationTargetException If an error occured during sending.
*/ */
public abstract void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) public abstract void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters)
throws InvocationTargetException; throws InvocationTargetException;
/** /**

Datei anzeigen

@ -24,6 +24,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Map;
import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.Factory;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -32,6 +33,7 @@ import com.comphenix.protocol.Packets;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
@ -39,6 +41,7 @@ import com.comphenix.protocol.injector.BukkitUnwrapper;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks; import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.packet.InterceptWritePacket;
import com.comphenix.protocol.injector.server.SocketInjector; import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.reflect.FieldUtils; import com.comphenix.protocol.reflect.FieldUtils;
import com.comphenix.protocol.reflect.FuzzyReflection; import com.comphenix.protocol.reflect.FuzzyReflection;
@ -46,6 +49,7 @@ import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.reflect.VolatileField; import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion; import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.collect.MapMaker;
public abstract class PlayerInjector implements SocketInjector { public abstract class PlayerInjector implements SocketInjector {
// Disconnect method related reports // Disconnect method related reports
@ -120,6 +124,13 @@ public abstract class PlayerInjector implements SocketInjector {
// Handle errors // Handle errors
protected ErrorReporter reporter; protected ErrorReporter reporter;
// Used to construct proxy objects
protected ClassLoader classLoader;
// Previous markers
protected Map<Object, NetworkMarker> queuedMarkers = new MapMaker().weakKeys().makeMap();
protected InterceptWritePacket writePacketInterceptor;
// Whether or not the injector has been cleaned // Whether or not the injector has been cleaned
private boolean clean; private boolean clean;
@ -127,10 +138,14 @@ public abstract class PlayerInjector implements SocketInjector {
boolean updateOnLogin; boolean updateOnLogin;
Player updatedPlayer; Player updatedPlayer;
public PlayerInjector(ErrorReporter reporter, Player player, ListenerInvoker invoker) throws IllegalAccessException { public PlayerInjector(ClassLoader classLoader, ErrorReporter reporter, Player player, ListenerInvoker invoker) throws IllegalAccessException {
this.classLoader = classLoader;
this.reporter = reporter; this.reporter = reporter;
this.player = player; this.player = player;
this.invoker = invoker; this.invoker = invoker;
// Intercept the write method
writePacketInterceptor = new InterceptWritePacket(classLoader, reporter);
} }
/** /**
@ -492,11 +507,12 @@ public abstract class PlayerInjector implements SocketInjector {
/** /**
* Send a packet to the client. * Send a packet to the client.
* @param packet - server packet to send. * @param packet - server packet to send.
* @param marker - the network marker.
* @param filtered - whether or not the packet will be filtered by our listeners. * @param filtered - whether or not the packet will be filtered by our listeners.
* @param InvocationTargetException If an error occured when sending the packet. * @param InvocationTargetException If an error occured when sending the packet.
*/ */
@Override @Override
public abstract void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException; public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException;
/** /**
* Inject a hook to catch packets sent to the current player. * Inject a hook to catch packets sent to the current player.
@ -582,9 +598,11 @@ public abstract class PlayerInjector implements SocketInjector {
// Make sure we're listening // Make sure we're listening
if (id != null && hasListener(id)) { if (id != null && hasListener(id)) {
NetworkMarker marker = queuedMarkers.remove(packet);
// A packet has been sent guys! // A packet has been sent guys!
PacketContainer container = new PacketContainer(id, packet); PacketContainer container = new PacketContainer(id, packet);
PacketEvent event = PacketEvent.fromServer(invoker, container, currentPlayer); PacketEvent event = PacketEvent.fromServer(invoker, container, marker, currentPlayer);
invoker.invokePacketSending(event); invoker.invokePacketSending(event);
// Cancelling is pretty simple. Just ignore the packet. // Cancelling is pretty simple. Just ignore the packet.
@ -592,7 +610,14 @@ public abstract class PlayerInjector implements SocketInjector {
return null; return null;
// Right, remember to replace the packet again // Right, remember to replace the packet again
return event.getPacket().getHandle(); Object result = event.getPacket().getHandle();
marker = event.getNetworkMarker();
// See if we need to proxy the write method
if (result != null && NetworkMarker.hasOutputHandlers(marker)) {
result = writePacketInterceptor.constructProxy(result, event, marker);
}
return result;
} }
} catch (Throwable e) { } catch (Throwable e) {

Datei anzeigen

@ -38,6 +38,7 @@ import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType; import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
@ -533,12 +534,12 @@ class ProxyPlayerInjectionHandler implements PlayerInjectionHandler {
* @throws InvocationTargetException If an error occured during sending. * @throws InvocationTargetException If an error occured during sending.
*/ */
@Override @Override
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException { public void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
SocketInjector injector = getInjector(reciever); SocketInjector injector = getInjector(reciever);
// Send the packet, or drop it completely // Send the packet, or drop it completely
if (injector != null) { if (injector != null) {
injector.sendServerPacket(packet.getHandle(), filters); injector.sendServerPacket(packet.getHandle(), marker, filters);
} else { } else {
throw new PlayerLoggedOutException(String.format( throw new PlayerLoggedOutException(String.format(
"Unable to send packet %s (%s): Player %s has logged out.", "Unable to send packet %s (%s): Player %s has logged out.",

Datei anzeigen

@ -9,6 +9,8 @@ import java.util.List;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.events.NetworkMarker;
public class BukkitSocketInjector implements SocketInjector { public class BukkitSocketInjector implements SocketInjector {
private Player player; private Player player;
@ -41,9 +43,9 @@ public class BukkitSocketInjector implements SocketInjector {
} }
@Override @Override
public void sendServerPacket(Object packet, boolean filtered) public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
throws InvocationTargetException { throws InvocationTargetException {
QueuedSendPacket command = new QueuedSendPacket(packet, filtered); QueuedSendPacket command = new QueuedSendPacket(packet, marker, filtered);
// Queue until we can find something better // Queue until we can find something better
syncronizedQueue.add(command); syncronizedQueue.add(command);
@ -65,7 +67,7 @@ public class BukkitSocketInjector implements SocketInjector {
try { try {
synchronized(syncronizedQueue) { synchronized(syncronizedQueue) {
for (QueuedSendPacket command : syncronizedQueue) { for (QueuedSendPacket command : syncronizedQueue) {
delegate.sendServerPacket(command.getPacket(), command.isFiltered()); delegate.sendServerPacket(command.getPacket(), command.getMarker(), command.isFiltered());
} }
syncronizedQueue.clear(); syncronizedQueue.clear();
} }

Datei anzeigen

@ -1,18 +1,30 @@
package com.comphenix.protocol.injector.server; package com.comphenix.protocol.injector.server;
import com.comphenix.protocol.events.NetworkMarker;
/** /**
* Represents a single send packet command. * Represents a single send packet command.
* @author Kristian * @author Kristian
*/ */
class QueuedSendPacket { class QueuedSendPacket {
private final Object packet; private final Object packet;
private final NetworkMarker marker;
private final boolean filtered; private final boolean filtered;
public QueuedSendPacket(Object packet, boolean filtered) { public QueuedSendPacket(Object packet, NetworkMarker marker, boolean filtered) {
this.packet = packet; this.packet = packet;
this.marker = marker;
this.filtered = filtered; this.filtered = filtered;
} }
/**
* Retrieve the network marker.
* @return Marker.
*/
public NetworkMarker getMarker() {
return marker;
}
/** /**
* Retrieve the underlying packet that will be sent. * Retrieve the underlying packet that will be sent.
* @return The underlying packet. * @return The underlying packet.

Datei anzeigen

@ -6,6 +6,8 @@ import java.net.SocketAddress;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.events.NetworkMarker;
/** /**
* Represents an injector that only gives access to a player's socket. * Represents an injector that only gives access to a player's socket.
* *
@ -36,10 +38,11 @@ public interface SocketInjector {
/** /**
* Send a packet to the client. * Send a packet to the client.
* @param packet - server packet to send. * @param packet - server packet to send.
* @param marker - the network marker.
* @param filtered - whether or not the packet will be filtered by our listeners. * @param filtered - whether or not the packet will be filtered by our listeners.
* @param InvocationTargetException If an error occured when sending the packet. * @param InvocationTargetException If an error occured when sending the packet.
*/ */
public abstract void sendServerPacket(Object packet, boolean filtered) public abstract void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered)
throws InvocationTargetException; throws InvocationTargetException;
/** /**

Datei anzeigen

@ -191,7 +191,7 @@ public class TemporaryPlayerFactory {
* @throws FieldAccessException If we were unable to construct the message packet. * @throws FieldAccessException If we were unable to construct the message packet.
*/ */
private Object sendMessage(SocketInjector injector, String message) throws InvocationTargetException, FieldAccessException { private Object sendMessage(SocketInjector injector, String message) throws InvocationTargetException, FieldAccessException {
injector.sendServerPacket(chatPacket.createPacket(message).getHandle(), false); injector.sendServerPacket(chatPacket.createPacket(message).getHandle(), null, false);
return null; return null;
} }
} }

Datei anzeigen

@ -7,6 +7,7 @@ import java.util.Set;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.comphenix.protocol.concurrency.IntegerSet; import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener; import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.GamePhase; import com.comphenix.protocol.injector.GamePhase;
@ -69,8 +70,8 @@ class DummyPlayerHandler implements PlayerInjectionHandler {
} }
@Override @Override
public void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException { public void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
injector.sendServerPacket(reciever, packet, filters); injector.sendServerPacket(reciever, packet, marker, filters);
} }
@Override @Override

Datei anzeigen

@ -24,6 +24,7 @@ import com.comphenix.protocol.concurrency.IntegerSet;
import com.comphenix.protocol.error.DelegatedErrorReporter; import com.comphenix.protocol.error.DelegatedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter; import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report; import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent; import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.ListenerInvoker; import com.comphenix.protocol.injector.ListenerInvoker;
@ -460,15 +461,15 @@ public class SpigotPacketInjector implements SpigotPacketListener {
}, CLEANUP_DELAY); }, CLEANUP_DELAY);
} }
} }
/** /**
* Invoked when a plugin wants to sent a packet. * Invoked when a plugin wants to sent a packet.
* @param reciever - the packet receiver. * @param reciever - the packet receiver.
* @param packet - the packet to transmit. * @param packet - the packet to transmit.
* @param marker - the network marker object.
* @param filters - whether or not to invoke the packet listeners. * @param filters - whether or not to invoke the packet listeners.
* @throws InvocationTargetException If anything went wrong. * @throws InvocationTargetException If anything went wrong.
*/ */
void sendServerPacket(Player reciever, PacketContainer packet, boolean filters) throws InvocationTargetException { void sendServerPacket(Player reciever, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
NetworkObjectInjector networkObject = getInjector(reciever); NetworkObjectInjector networkObject = getInjector(reciever);
// If TRUE, process this packet like any other // If TRUE, process this packet like any other
@ -478,7 +479,7 @@ public class SpigotPacketInjector implements SpigotPacketListener {
ignoredPackets.add(packet.getHandle()); ignoredPackets.add(packet.getHandle());
if (networkObject != null) if (networkObject != null)
networkObject.sendServerPacket(packet.getHandle(), filters); networkObject.sendServerPacket(packet.getHandle(), marker, filters);
else else
throw new PlayerLoggedOutException("Player " + reciever + " has logged out"); throw new PlayerLoggedOutException("Player " + reciever + " has logged out");
} }