mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-24 03:25:29 +01:00
Added the ability to schedule packets after an event has succeeded.
Also fixes post listeners and asynchronous packet listeners.
This commit is contained in:
parent
f7c4fd4ec9
commit
1ef602416d
@ -51,8 +51,10 @@ public abstract class NetworkMarker {
|
||||
|
||||
// Custom network handler
|
||||
private PriorityQueue<PacketOutputHandler> outputHandlers;
|
||||
// Sent listeners
|
||||
// Post listeners
|
||||
private List<PacketPostListener> postListeners;
|
||||
// Post packets
|
||||
private List<ScheduledPacket> scheduledPackets;
|
||||
|
||||
// The input buffer
|
||||
private ByteBuffer inputBuffer;
|
||||
@ -295,6 +297,18 @@ public abstract class NetworkMarker {
|
||||
return postListeners != null ? Collections.unmodifiableList(postListeners) : Collections.<PacketPostListener>emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of packets that will be schedule (in-order) when the current packet has been successfully transmitted.
|
||||
* <p>
|
||||
* This list is modifiable.
|
||||
* @return List of packets that will be scheduled.
|
||||
*/
|
||||
public List<ScheduledPacket> getScheduledPackets() {
|
||||
if (scheduledPackets == null)
|
||||
scheduledPackets = Lists.newArrayList();
|
||||
return scheduledPackets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the packet event is server side.
|
||||
*/
|
||||
@ -385,4 +399,15 @@ public abstract class NetworkMarker {
|
||||
public static NetworkMarker getNetworkMarker(PacketEvent event) {
|
||||
return event.networkMarker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the scheduled packets of a particular network marker without constructing the list.
|
||||
* <p>
|
||||
* This is an internal method that should not be used by API users.
|
||||
* @param marker - the marker.
|
||||
* @return The list, or NULL if not found or initialized.
|
||||
*/
|
||||
public static List<ScheduledPacket> readScheduledPackets(NetworkMarker marker) {
|
||||
return marker.scheduledPackets;
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,7 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
@ -206,6 +207,16 @@ public class PacketContainer implements Serializable {
|
||||
this.structureModifier = structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new packet container from a given handle.
|
||||
* @param packet - the NMS packet.
|
||||
* @return The packet container.
|
||||
*/
|
||||
public static PacketContainer fromPacket(Object packet) {
|
||||
PacketType type = PacketType.fromClass(packet.getClass());
|
||||
return new PacketContainer(type, packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* For serialization.
|
||||
*/
|
||||
|
@ -101,6 +101,7 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
this.cancel = origial.cancel;
|
||||
this.serverPacket = origial.serverPacket;
|
||||
this.filtered = origial.filtered;
|
||||
this.networkMarker = origial.networkMarker;
|
||||
this.asyncMarker = asyncMarker;
|
||||
this.asynchronous = true;
|
||||
}
|
||||
@ -401,6 +402,28 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
return asynchronous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule a packet for sending or receiving after the current packet event is successful.
|
||||
* <p>
|
||||
* The packet will be added to {@link NetworkMarker#getScheduledPackets()}.
|
||||
* @param scheduled - the packet to transmit or receive.
|
||||
*/
|
||||
public void schedule(ScheduledPacket scheduled) {
|
||||
getNetworkMarker().getScheduledPackets().add(scheduled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unschedule a specific packet.
|
||||
* @param scheduled - the scheduled packet.
|
||||
* @return TRUE if it was unscheduled, FALSE otherwise.
|
||||
*/
|
||||
public boolean unschedule(ScheduledPacket scheduled) {
|
||||
if (networkMarker != null) {
|
||||
return networkMarker.getScheduledPackets().remove(scheduled);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream output) throws IOException {
|
||||
// Default serialization
|
||||
output.defaultWriteObject();
|
||||
|
@ -0,0 +1,146 @@
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.PacketStream;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.google.common.base.Preconditions;import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Represents a packet that is scheduled for transmission at a later stage.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class ScheduledPacket {
|
||||
protected PacketContainer packet;
|
||||
protected Player target;
|
||||
protected boolean filtered;
|
||||
|
||||
/**
|
||||
* Construct a new scheduled packet.
|
||||
* <p>
|
||||
* Note that the sender is infered from the packet type.
|
||||
* @param packet - the packet.
|
||||
* @param target - the target player.
|
||||
* @param filtered - whether or not to
|
||||
*/
|
||||
public ScheduledPacket(PacketContainer packet, Player target, boolean filtered) {
|
||||
setPacket(packet);
|
||||
setTarget(target);
|
||||
setFiltered(filtered);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new scheduled packet that will not be processed by any packet listeners (except MONITOR).
|
||||
* @param packet - the packet.
|
||||
* @param target - the target player.
|
||||
* @return The scheduled packet.
|
||||
*/
|
||||
public static ScheduledPacket fromSilent(PacketContainer packet, Player target) {
|
||||
return new ScheduledPacket(packet, target, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new scheduled packet that will be processed by any packet listeners.
|
||||
* @param packet - the packet.
|
||||
* @param target - the target player.
|
||||
* @return The scheduled packet.
|
||||
*/
|
||||
public static ScheduledPacket fromFiltered(PacketContainer packet, Player target) {
|
||||
return new ScheduledPacket(packet, target, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the packet that will be sent or transmitted.
|
||||
* @return The sent or received packet.
|
||||
*/
|
||||
public PacketContainer getPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the packet that will be sent or transmitted.
|
||||
* @param packet - the new packet, cannot be NULL.
|
||||
*/
|
||||
public void setPacket(PacketContainer packet) {
|
||||
this.packet = Preconditions.checkNotNull(packet, "packet cannot be NULL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the target player.
|
||||
* @return The target player.
|
||||
*/
|
||||
public Player getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the target player.
|
||||
* @param target - the new target, cannot be NULL.
|
||||
*/
|
||||
public void setTarget(Player target) {
|
||||
this.target = Preconditions.checkNotNull(target, "target cannot be NULL");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this packet will be processed by any of the packet listeners.
|
||||
* @return TRUE if it will, FALSE otherwise.
|
||||
*/
|
||||
public boolean isFiltered() {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this packet will be processed by packet listeners (except MONITOR listeners).
|
||||
* @param filtered - TRUE if it should be processed by listeners, FALSE otherwise.
|
||||
*/
|
||||
public void setFiltered(boolean filtered) {
|
||||
this.filtered = filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the sender of this packet.
|
||||
* @return The sender.
|
||||
*/
|
||||
public Sender getSender() {
|
||||
return packet.getType().getSender();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the packet transmission or reception.
|
||||
*/
|
||||
public void schedule() {
|
||||
schedule(ProtocolLibrary.getProtocolManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule the packet transmission or reception.
|
||||
* @param stream - the packet stream.
|
||||
*/
|
||||
public void schedule(PacketStream stream) {
|
||||
Preconditions.checkNotNull(stream, "stream cannot be NULL");
|
||||
|
||||
try {
|
||||
if (getSender() == Sender.CLIENT) {
|
||||
stream.recieveClientPacket(getTarget(), getPacket(), isFiltered());
|
||||
} else {
|
||||
stream.sendServerPacket(getTarget(), getPacket(), isFiltered());
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("Cannot send packet " + this + " to " + stream);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Cannot send packet " + this + " to " + stream);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper(this)
|
||||
.add("packet", packet)
|
||||
.add("target", target)
|
||||
.add("filtered", filtered)
|
||||
.toString();
|
||||
}
|
||||
}
|
@ -1,12 +1,16 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
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;
|
||||
import com.comphenix.protocol.events.ScheduledPacket;
|
||||
|
||||
/**
|
||||
* Represents a processor for network markers.
|
||||
@ -61,10 +65,13 @@ public class NetworkProcessor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the post listeners, if any.
|
||||
* Invoke the post listeners and packet transmission, if any.
|
||||
* @param marker - the network marker, or NULL.
|
||||
*/
|
||||
public void invokePostListeners(PacketEvent event, NetworkMarker marker) {
|
||||
public void invokePostEvent(PacketEvent event, NetworkMarker marker) {
|
||||
if (marker == null)
|
||||
return;
|
||||
|
||||
if (NetworkMarker.hasPostListeners(marker)) {
|
||||
// Invoke every sent listener
|
||||
for (PacketPostListener listener : marker.getPostListeners()) {
|
||||
@ -79,5 +86,22 @@ public class NetworkProcessor {
|
||||
}
|
||||
}
|
||||
}
|
||||
sendScheduledPackets(marker);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send any scheduled packets.
|
||||
* @param marker - the network marker.
|
||||
*/
|
||||
private void sendScheduledPackets(NetworkMarker marker) {
|
||||
// Next, invoke post packet transmission
|
||||
List<ScheduledPacket> scheduled = NetworkMarker.readScheduledPackets(marker);
|
||||
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
|
||||
|
||||
if (scheduled != null) {
|
||||
for (ScheduledPacket packet : scheduled) {
|
||||
packet.schedule(manager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.events.ConnectionSide;
|
||||
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.comphenix.protocol.injector.server.SocketInjector;
|
||||
@ -261,12 +262,21 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
}
|
||||
|
||||
protected PacketEvent handleScheduled(Object instance, FieldAccessor accessor) {
|
||||
// See if we've been instructed not to process packets
|
||||
if (!scheduleProcessPackets.get())
|
||||
return BYPASSED_PACKET;
|
||||
|
||||
// Let the filters handle this packet
|
||||
Object original = accessor.get(instance);
|
||||
|
||||
// See if we've been instructed not to process packets
|
||||
if (!scheduleProcessPackets.get()) {
|
||||
NetworkMarker marker = getMarker(original);
|
||||
|
||||
if (marker != null) {
|
||||
PacketEvent result = new PacketEvent(ChannelInjector.class);
|
||||
result.setNetworkMarker(marker);
|
||||
return result;
|
||||
} else {
|
||||
return BYPASSED_PACKET;
|
||||
}
|
||||
}
|
||||
PacketEvent event = processSending(original);
|
||||
|
||||
if (event != null && !event.isCancelled()) {
|
||||
@ -291,7 +301,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
* @return The resulting message/packet.
|
||||
*/
|
||||
private PacketEvent processSending(Object message) {
|
||||
return channelListener.onPacketSending(ChannelInjector.this, message);
|
||||
return channelListener.onPacketSending(ChannelInjector.this, message, getMarker(message));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -395,7 +405,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
finalEvent = null;
|
||||
currentEvent = null;
|
||||
|
||||
processor.invokePostListeners(event, NetworkMarker.getNetworkMarker(event));
|
||||
processor.invokePostEvent(event, NetworkMarker.getNetworkMarker(event));
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,7 +473,7 @@ class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
NetworkMarker marker = NetworkMarker.getNetworkMarker(event);
|
||||
|
||||
if (marker != null) {
|
||||
processor.invokePostListeners(event, marker);
|
||||
processor.invokePostEvent(event, marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,10 @@ interface ChannelListener {
|
||||
* This is invoked on the main thread.
|
||||
* @param injector - the channel injector.
|
||||
* @param packet - the packet.
|
||||
* @param marker - the network marker.
|
||||
* @return The packet even that was passed to the listeners, with a possible packet change, or NULL.
|
||||
*/
|
||||
public PacketEvent onPacketSending(Injector injector, Object packet);
|
||||
public PacketEvent onPacketSending(Injector injector, Object packet, NetworkMarker marker);
|
||||
|
||||
/**
|
||||
* Invoked when a packet is being received from a client.
|
||||
|
@ -226,23 +226,23 @@ public class NettyProtocolInjector implements ChannelListener {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketEvent onPacketSending(Injector injector, Object packet) {
|
||||
@Override
|
||||
public PacketEvent onPacketSending(Injector injector, Object packet, NetworkMarker marker) {
|
||||
Class<?> clazz = packet.getClass();
|
||||
|
||||
if (sendingFilters.contains(clazz)) {
|
||||
if (sendingFilters.contains(clazz) || marker != null) {
|
||||
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
|
||||
return packetQueued(container, injector.getPlayer());
|
||||
return packetQueued(container, injector.getPlayer(), marker);
|
||||
}
|
||||
// Don't change anything
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketEvent onPacketReceiving(Injector injector, Object packet, NetworkMarker marker) {
|
||||
Class<?> clazz = packet.getClass();
|
||||
|
||||
if (reveivedFilters.contains(clazz)) {
|
||||
if (reveivedFilters.contains(clazz) || marker != null) {
|
||||
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
|
||||
return packetReceived(container, injector.getPlayer(), marker);
|
||||
}
|
||||
@ -261,8 +261,8 @@ public class NettyProtocolInjector implements ChannelListener {
|
||||
* @param receiver - the receiver of this packet.
|
||||
* @return The packet event that was used.
|
||||
*/
|
||||
private PacketEvent packetQueued(PacketContainer packet, Player receiver) {
|
||||
PacketEvent event = PacketEvent.fromServer(this, packet, receiver);
|
||||
private PacketEvent packetQueued(PacketContainer packet, Player receiver, NetworkMarker marker) {
|
||||
PacketEvent event = PacketEvent.fromServer(this, packet, marker, receiver);
|
||||
|
||||
invoker.invokePacketSending(event);
|
||||
return event;
|
||||
|
@ -163,7 +163,7 @@ class ReadPacketModifier implements MethodInterceptor {
|
||||
|
||||
// This is fine - received packets are enqueued in any case
|
||||
NetworkMarker marker = NetworkMarker.getNetworkMarker(event);
|
||||
processor.invokePostListeners(event, marker);
|
||||
processor.invokePostEvent(event, marker);
|
||||
}
|
||||
|
||||
} catch (OutOfMemoryError e) {
|
||||
|
@ -105,7 +105,7 @@ public class WritePacketModifier implements MethodInterceptor {
|
||||
output.write(outputBuffer);
|
||||
|
||||
// We're done
|
||||
processor.invokePostListeners(information.event, information.marker);
|
||||
processor.invokePostEvent(information.event, information.marker);
|
||||
return null;
|
||||
|
||||
} catch (OutOfMemoryError e) {
|
||||
@ -122,7 +122,7 @@ public class WritePacketModifier implements MethodInterceptor {
|
||||
|
||||
// Invoke this write method first
|
||||
proxy.invoke(information.proxyObject, args);
|
||||
processor.invokePostListeners(information.event, information.marker);
|
||||
processor.invokePostEvent(information.event, information.marker);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user