Use the normal packet listener instead of an async listener.
Dieser Commit ist enthalten in:
Ursprung
6f02e79802
Commit
285952b14d
@ -7,6 +7,7 @@ import org.bukkit.plugin.Plugin;
|
|||||||
|
|
||||||
import com.comphenix.protocol.PacketStream;
|
import com.comphenix.protocol.PacketStream;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a filter manager for asynchronous packets.
|
* Represents a filter manager for asynchronous packets.
|
||||||
@ -36,7 +37,7 @@ public class AsyncFilterManager {
|
|||||||
this.mainThread = Thread.currentThread();
|
this.mainThread = Thread.currentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListenerToken registerAsyncHandler(Plugin plugin, AsyncListener listener) {
|
public ListenerToken registerAsyncHandler(Plugin plugin, PacketListener listener) {
|
||||||
ListenerToken token = new ListenerToken(plugin, mainThread, this, listener);
|
ListenerToken token = new ListenerToken(plugin, mainThread, this, listener);
|
||||||
|
|
||||||
processingQueue.addListener(token, listener.getSendingWhitelist());
|
processingQueue.addListener(token, listener.getSendingWhitelist());
|
||||||
@ -56,15 +57,33 @@ public class AsyncFilterManager {
|
|||||||
processingQueue.removeListener(listenerToken, listenerToken.getAsyncListener().getSendingWhitelist());
|
processingQueue.removeListener(listenerToken, listenerToken.getAsyncListener().getSendingWhitelist());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enqueueSyncPacket(PacketEvent syncPacket, int sendingDelta, long timeoutDelta) {
|
/**
|
||||||
AsyncPacket asyncPacket = new AsyncPacket(packetStream, syncPacket,
|
* Enqueue a packet for asynchronous processing.
|
||||||
currentSendingIndex.getAndIncrement() + sendingDelta,
|
* @param syncPacket - synchronous packet event.
|
||||||
System.currentTimeMillis(),
|
* @param asyncMarker - the asynchronous marker to use.
|
||||||
timeoutDelta);
|
*/
|
||||||
|
public void enqueueSyncPacket(PacketEvent syncPacket, AsyncPacket asyncMarker) {
|
||||||
|
PacketEvent newEvent = PacketEvent.fromSynchronous(syncPacket, asyncMarker);
|
||||||
|
|
||||||
// Start the process
|
// Start the process
|
||||||
sendingQueue.enqueue(asyncPacket);
|
sendingQueue.enqueue(newEvent);
|
||||||
processingQueue.enqueuePacket(asyncPacket);
|
processingQueue.enqueuePacket(newEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an async marker with the given sending priority delta and timeout delta.
|
||||||
|
* @param sendingDelta - how many packets we're willing to wait.
|
||||||
|
* @param timeoutDelta - how long (in ms) until the packet expire.
|
||||||
|
* @return An async marker.
|
||||||
|
*/
|
||||||
|
public AsyncPacket createAsyncMarker(long sendingDelta, long timeoutDelta) {
|
||||||
|
return createAsyncMarker(sendingDelta, timeoutDelta,
|
||||||
|
currentSendingIndex.incrementAndGet(), System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method
|
||||||
|
private AsyncPacket createAsyncMarker(long sendingDelta, long timeoutDelta, long sendingIndex, long currentTime) {
|
||||||
|
return new AsyncPacket(packetStream, sendingIndex, sendingDelta, System.currentTimeMillis(), timeoutDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PacketStream getPacketStream() {
|
public PacketStream getPacketStream() {
|
||||||
@ -83,9 +102,11 @@ public class AsyncFilterManager {
|
|||||||
return sendingQueue;
|
return sendingQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove listeners, close threads and transmit every delayed packet.
|
||||||
|
*/
|
||||||
public void cleanupAll() {
|
public void cleanupAll() {
|
||||||
// Remove all listeners
|
processingQueue.cleanupAll();
|
||||||
|
sendingQueue.cleanupAll();
|
||||||
// We don't necessarily remove packets, as this might be a part of a server reload
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package com.comphenix.protocol.async;
|
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
|
||||||
|
|
||||||
public interface AsyncListener {
|
|
||||||
public void onAsyncPacket(AsyncPacket packet);
|
|
||||||
|
|
||||||
public ListeningWhitelist getSendingWhitelist();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the plugin that created this async packet listener.
|
|
||||||
* @return The plugin, or NULL if not available.
|
|
||||||
*/
|
|
||||||
public Plugin getPlugin();
|
|
||||||
}
|
|
@ -1,5 +1,6 @@
|
|||||||
package com.comphenix.protocol.async;
|
package com.comphenix.protocol.async;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -15,12 +16,7 @@ import com.google.common.primitives.Longs;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
||||||
|
|
||||||
/**
|
|
||||||
* Signal an end to the packet processing.
|
|
||||||
*/
|
|
||||||
static final AsyncPacket INTERUPT_PACKET = new AsyncPacket();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generated by Eclipse.
|
* Generated by Eclipse.
|
||||||
*/
|
*/
|
||||||
@ -31,11 +27,6 @@ public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
|||||||
*/
|
*/
|
||||||
public static final int DEFAULT_TIMEOUT_DELTA = 60000;
|
public static final int DEFAULT_TIMEOUT_DELTA = 60000;
|
||||||
|
|
||||||
/**
|
|
||||||
* The original synchronized packet.
|
|
||||||
*/
|
|
||||||
private PacketEvent packetEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The packet stream responsible for transmitting the packet when it's done processing.
|
* The packet stream responsible for transmitting the packet when it's done processing.
|
||||||
*/
|
*/
|
||||||
@ -56,33 +47,16 @@ public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
|||||||
|
|
||||||
// Whether or not the packet has been processed by the listeners
|
// Whether or not the packet has been processed by the listeners
|
||||||
private volatile boolean processed;
|
private volatile boolean processed;
|
||||||
|
|
||||||
private AsyncPacket() {
|
|
||||||
// Used by the poision pill pattern
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine whether or not this is a signal for the async listener to interrupt processing.
|
|
||||||
* @return Interrupt packet processing.
|
|
||||||
*/
|
|
||||||
boolean isInteruptPacket() {
|
|
||||||
// This is only possble if we're dealing with the poision pill packet
|
|
||||||
return packetEvent == null || packetStream == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a container for asyncronous packets.
|
* Create a container for asyncronous packets.
|
||||||
* @param packetEvent - the synchronous packet event.
|
|
||||||
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
|
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
|
||||||
*/
|
*/
|
||||||
public AsyncPacket(PacketStream packetStream, PacketEvent packetEvent, long sendingIndex, long initialTime, long timeoutDelta) {
|
AsyncPacket(PacketStream packetStream, long sendingIndex, long sendingDelta, long initialTime, long timeoutDelta) {
|
||||||
if (packetEvent == null)
|
|
||||||
throw new IllegalArgumentException("packetEvent cannot be NULL");
|
|
||||||
if (packetStream == null)
|
if (packetStream == null)
|
||||||
throw new IllegalArgumentException("packetStream cannot be NULL");
|
throw new IllegalArgumentException("packetStream cannot be NULL");
|
||||||
|
|
||||||
this.packetStream = packetStream;
|
this.packetStream = packetStream;
|
||||||
this.packetEvent = packetEvent;
|
|
||||||
|
|
||||||
// Timeout
|
// Timeout
|
||||||
this.initialTime = initialTime;
|
this.initialTime = initialTime;
|
||||||
@ -137,22 +111,6 @@ public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
|||||||
this.newSendingIndex = newSendingIndex;
|
this.newSendingIndex = newSendingIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the original synchronous packet event.
|
|
||||||
* @return The original packet event.
|
|
||||||
*/
|
|
||||||
public PacketEvent getPacketEvent() {
|
|
||||||
return packetEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the packet ID of the underlying packet.
|
|
||||||
* @return Packet ID.
|
|
||||||
*/
|
|
||||||
public int getPacketID() {
|
|
||||||
return packetEvent.getPacketID();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the packet stream responsible for transmitting this packet.
|
* Retrieve the packet stream responsible for transmitting this packet.
|
||||||
* @return The packet stream.
|
* @return The packet stream.
|
||||||
@ -173,7 +131,7 @@ public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
|||||||
* Retrieve whether or not this packet has been processed by the async listeners.
|
* Retrieve whether or not this packet has been processed by the async listeners.
|
||||||
* @return TRUE if it has been processed, FALSE otherwise.
|
* @return TRUE if it has been processed, FALSE otherwise.
|
||||||
*/
|
*/
|
||||||
boolean isProcessed() {
|
public boolean isProcessed() {
|
||||||
return processed;
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,21 +147,9 @@ public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
|||||||
* Retrieve iterator for the next listener in line.
|
* Retrieve iterator for the next listener in line.
|
||||||
* @return Next async packet listener iterator.
|
* @return Next async packet listener iterator.
|
||||||
*/
|
*/
|
||||||
Iterator<PrioritizedListener<ListenerToken>> getListenerTraversal() {
|
public Iterator<PrioritizedListener<ListenerToken>> getListenerTraversal() {
|
||||||
return listenerTraversal;
|
return listenerTraversal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* We're done processing. Send the packet.
|
|
||||||
*/
|
|
||||||
void sendPacket() {
|
|
||||||
try {
|
|
||||||
// We only support server packets at this stage
|
|
||||||
packetStream.sendServerPacket(packetEvent.getPlayer(), packetEvent.getPacket(), false);
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the iterator for the next listener.
|
* Set the iterator for the next listener.
|
||||||
@ -212,7 +158,26 @@ public class AsyncPacket implements Serializable, Comparable<AsyncPacket> {
|
|||||||
void setListenerTraversal(Iterator<PrioritizedListener<ListenerToken>> listenerTraversal) {
|
void setListenerTraversal(Iterator<PrioritizedListener<ListenerToken>> listenerTraversal) {
|
||||||
this.listenerTraversal = listenerTraversal;
|
this.listenerTraversal = listenerTraversal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transmit a given packet to the current packet stream.
|
||||||
|
* @param event - the packet to send.
|
||||||
|
* @throws IOException If the packet couldn't be sent.
|
||||||
|
*/
|
||||||
|
public void sendPacket(PacketEvent event) throws IOException {
|
||||||
|
try {
|
||||||
|
if (event.isServerPacket()) {
|
||||||
|
packetStream.sendServerPacket(event.getPlayer(), event.getPacket(), false);
|
||||||
|
} else {
|
||||||
|
packetStream.recieveClientPacket(event.getPlayer(), event.getPacket(), false);
|
||||||
|
}
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new IOException("Cannot send packet", e);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new IOException("Cannot send packet", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(AsyncPacket o) {
|
public int compareTo(AsyncPacket o) {
|
||||||
if (o == null)
|
if (o == null)
|
||||||
|
@ -5,8 +5,16 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
public class ListenerToken {
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
|
|
||||||
|
class ListenerToken {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal an end to the packet processing.
|
||||||
|
*/
|
||||||
|
private static final PacketEvent INTERUPT_PACKET = new PacketEvent(new Object());
|
||||||
|
|
||||||
// Default queue capacity
|
// Default queue capacity
|
||||||
private static int DEFAULT_CAPACITY = 1024;
|
private static int DEFAULT_CAPACITY = 1024;
|
||||||
|
|
||||||
@ -14,7 +22,7 @@ public class ListenerToken {
|
|||||||
private volatile boolean cancelled;
|
private volatile boolean cancelled;
|
||||||
|
|
||||||
// The packet listener
|
// The packet listener
|
||||||
private AsyncListener listener;
|
private PacketListener listener;
|
||||||
|
|
||||||
// The original plugin
|
// The original plugin
|
||||||
private Plugin plugin;
|
private Plugin plugin;
|
||||||
@ -23,12 +31,12 @@ public class ListenerToken {
|
|||||||
private AsyncFilterManager filterManager;
|
private AsyncFilterManager filterManager;
|
||||||
|
|
||||||
// List of queued packets
|
// List of queued packets
|
||||||
private ArrayBlockingQueue<AsyncPacket> queuedPackets = new ArrayBlockingQueue<AsyncPacket>(DEFAULT_CAPACITY);
|
private ArrayBlockingQueue<PacketEvent> queuedPackets = new ArrayBlockingQueue<PacketEvent>(DEFAULT_CAPACITY);
|
||||||
|
|
||||||
// Minecraft main thread
|
// Minecraft main thread
|
||||||
private Thread mainThread;
|
private Thread mainThread;
|
||||||
|
|
||||||
public ListenerToken(Plugin plugin, Thread mainThread, AsyncFilterManager filterManager, AsyncListener listener) {
|
public ListenerToken(Plugin plugin, Thread mainThread, AsyncFilterManager filterManager, PacketListener listener) {
|
||||||
if (filterManager == null)
|
if (filterManager == null)
|
||||||
throw new IllegalArgumentException("filterManager cannot be NULL");
|
throw new IllegalArgumentException("filterManager cannot be NULL");
|
||||||
if (listener == null)
|
if (listener == null)
|
||||||
@ -44,7 +52,7 @@ public class ListenerToken {
|
|||||||
return cancelled;
|
return cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsyncListener getAsyncListener() {
|
public PacketListener getAsyncListener() {
|
||||||
return listener;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +65,7 @@ public class ListenerToken {
|
|||||||
|
|
||||||
// Poison Pill Shutdown
|
// Poison Pill Shutdown
|
||||||
queuedPackets.clear();
|
queuedPackets.clear();
|
||||||
queuedPackets.add(AsyncPacket.INTERUPT_PACKET);
|
queuedPackets.add(INTERUPT_PACKET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,7 +73,7 @@ public class ListenerToken {
|
|||||||
* @param packet - a packet for processing.
|
* @param packet - a packet for processing.
|
||||||
* @throws IllegalStateException If the underlying packet queue is full.
|
* @throws IllegalStateException If the underlying packet queue is full.
|
||||||
*/
|
*/
|
||||||
public void enqueuePacket(AsyncPacket packet) {
|
public void enqueuePacket(PacketEvent packet) {
|
||||||
if (packet == null)
|
if (packet == null)
|
||||||
throw new IllegalArgumentException("packet is NULL");
|
throw new IllegalArgumentException("packet is NULL");
|
||||||
|
|
||||||
@ -86,16 +94,21 @@ public class ListenerToken {
|
|||||||
try {
|
try {
|
||||||
mainLoop:
|
mainLoop:
|
||||||
while (!cancelled) {
|
while (!cancelled) {
|
||||||
AsyncPacket packet = queuedPackets.take();
|
PacketEvent packet = queuedPackets.take();
|
||||||
|
AsyncPacket marker = packet.getAsyncMarker();
|
||||||
|
|
||||||
// Handle cancel requests
|
// Handle cancel requests
|
||||||
if (packet == null || packet.isInteruptPacket()) {
|
if (packet == null || marker == null || !packet.isAsynchronous()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here's the core of the asynchronous processing
|
// Here's the core of the asynchronous processing
|
||||||
try {
|
try {
|
||||||
listener.onAsyncPacket(packet);
|
if (packet.isServerPacket())
|
||||||
|
listener.onPacketSending(packet);
|
||||||
|
else
|
||||||
|
listener.onPacketReceiving(packet);
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Minecraft doesn't want your Exception.
|
// Minecraft doesn't want your Exception.
|
||||||
filterManager.getLogger().log(Level.SEVERE,
|
filterManager.getLogger().log(Level.SEVERE,
|
||||||
@ -103,8 +116,8 @@ public class ListenerToken {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now, get the next non-cancelled listener
|
// Now, get the next non-cancelled listener
|
||||||
for (; packet.getListenerTraversal().hasNext(); ) {
|
for (; marker.getListenerTraversal().hasNext(); ) {
|
||||||
ListenerToken token = packet.getListenerTraversal().next().getListener();
|
ListenerToken token = marker.getListenerTraversal().next().getListener();
|
||||||
|
|
||||||
if (!token.isCancelled()) {
|
if (!token.isCancelled()) {
|
||||||
token.enqueuePacket(packet);
|
token.enqueuePacket(packet);
|
||||||
|
@ -6,6 +6,7 @@ import java.util.concurrent.ArrayBlockingQueue;
|
|||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
import com.comphenix.protocol.concurrency.AbstractConcurrentListenerMultimap;
|
import com.comphenix.protocol.concurrency.AbstractConcurrentListenerMultimap;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.injector.PrioritizedListener;
|
import com.comphenix.protocol.injector.PrioritizedListener;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,7 +33,7 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<ListenerT
|
|||||||
private Semaphore concurrentProcessing;
|
private Semaphore concurrentProcessing;
|
||||||
|
|
||||||
// Queued packets for being processed
|
// Queued packets for being processed
|
||||||
private ArrayBlockingQueue<AsyncPacket> processingQueue;
|
private ArrayBlockingQueue<PacketEvent> processingQueue;
|
||||||
|
|
||||||
// Packets for sending
|
// Packets for sending
|
||||||
private PacketSendingQueue sendingQueue;
|
private PacketSendingQueue sendingQueue;
|
||||||
@ -43,7 +44,7 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<ListenerT
|
|||||||
|
|
||||||
public PacketProcessingQueue(PacketSendingQueue sendingQueue, int queueLimit, int maximumConcurrency) {
|
public PacketProcessingQueue(PacketSendingQueue sendingQueue, int queueLimit, int maximumConcurrency) {
|
||||||
super();
|
super();
|
||||||
this.processingQueue = new ArrayBlockingQueue<AsyncPacket>(queueLimit);
|
this.processingQueue = new ArrayBlockingQueue<PacketEvent>(queueLimit);
|
||||||
this.maximumConcurrency = maximumConcurrency;
|
this.maximumConcurrency = maximumConcurrency;
|
||||||
this.concurrentProcessing = new Semaphore(maximumConcurrency);
|
this.concurrentProcessing = new Semaphore(maximumConcurrency);
|
||||||
this.sendingQueue = sendingQueue;
|
this.sendingQueue = sendingQueue;
|
||||||
@ -54,7 +55,7 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<ListenerT
|
|||||||
* @param packet - packet to process.
|
* @param packet - packet to process.
|
||||||
* @return TRUE if we sucessfully queued the packet, FALSE if the queue ran out if space.
|
* @return TRUE if we sucessfully queued the packet, FALSE if the queue ran out if space.
|
||||||
*/
|
*/
|
||||||
public boolean enqueuePacket(AsyncPacket packet) {
|
public boolean enqueuePacket(PacketEvent packet) {
|
||||||
try {
|
try {
|
||||||
processingQueue.add(packet);
|
processingQueue.add(packet);
|
||||||
|
|
||||||
@ -71,17 +72,18 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<ListenerT
|
|||||||
*/
|
*/
|
||||||
public void signalBeginProcessing() {
|
public void signalBeginProcessing() {
|
||||||
while (concurrentProcessing.tryAcquire()) {
|
while (concurrentProcessing.tryAcquire()) {
|
||||||
AsyncPacket packet = processingQueue.poll();
|
PacketEvent packet = processingQueue.poll();
|
||||||
|
|
||||||
// Any packet queued?
|
// Any packet queued?
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
Collection<PrioritizedListener<ListenerToken>> list = getListener(packet.getPacketID());
|
Collection<PrioritizedListener<ListenerToken>> list = getListener(packet.getPacketID());
|
||||||
|
AsyncPacket marker = packet.getAsyncMarker();
|
||||||
|
|
||||||
if (list != null) {
|
if (list != null) {
|
||||||
Iterator<PrioritizedListener<ListenerToken>> iterator = list.iterator();
|
Iterator<PrioritizedListener<ListenerToken>> iterator = list.iterator();
|
||||||
|
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
packet.setListenerTraversal(iterator);
|
marker.setListenerTraversal(iterator);
|
||||||
iterator.next().getListener().enqueuePacket(packet);
|
iterator.next().getListener().enqueuePacket(packet);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -113,7 +115,15 @@ class PacketProcessingQueue extends AbstractConcurrentListenerMultimap<ListenerT
|
|||||||
return maximumConcurrency;
|
return maximumConcurrency;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeListeners() {
|
public void cleanupAll() {
|
||||||
for (PrioritizedListener<ListenerToken> token : )
|
// Cancel all the threads and every listener
|
||||||
|
for (PrioritizedListener<ListenerToken> token : values()) {
|
||||||
|
if (token != null) {
|
||||||
|
token.getListener().cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the rest, just in case
|
||||||
|
clearListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,41 +1,85 @@
|
|||||||
package com.comphenix.protocol.async;
|
package com.comphenix.protocol.async;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.concurrent.PriorityBlockingQueue;
|
import java.util.concurrent.PriorityBlockingQueue;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents packets ready to be transmitted to a client.
|
* Represents packets ready to be transmitted to a client.
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class PacketSendingQueue {
|
class PacketSendingQueue {
|
||||||
|
|
||||||
private PriorityBlockingQueue<AsyncPacket> sendingQueue;
|
private PriorityBlockingQueue<PacketEvent> sendingQueue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enqueue a packet for sending.
|
* Enqueue a packet for sending.
|
||||||
* @param packet
|
* @param packet
|
||||||
*/
|
*/
|
||||||
public void enqueue(AsyncPacket packet) {
|
public void enqueue(PacketEvent packet) {
|
||||||
sendingQueue.add(packet);
|
sendingQueue.add(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when one of the packets have finished processing.
|
* Invoked when one of the packets have finished processing.
|
||||||
*/
|
*/
|
||||||
public synchronized void signalPacketUpdate(AsyncPacket packetUpdated) {
|
public synchronized void signalPacketUpdate(PacketEvent packetUpdated) {
|
||||||
|
|
||||||
// Mark this packet as finished
|
// Mark this packet as finished
|
||||||
packetUpdated.setProcessed(true);
|
packetUpdated.getAsyncMarker().setProcessed(true);
|
||||||
|
signalPacketUpdates();
|
||||||
// Transmit as many packets as we can
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send every packet, regardless of the processing state.
|
||||||
|
*/
|
||||||
|
public synchronized void forceSend() {
|
||||||
while (true) {
|
while (true) {
|
||||||
AsyncPacket current = sendingQueue.peek();
|
PacketEvent current = sendingQueue.poll();
|
||||||
|
|
||||||
if (current != null && current.isProcessed()) {
|
if (current != null) {
|
||||||
current.sendPacket();
|
// Just print the error
|
||||||
sendingQueue.poll();
|
try {
|
||||||
|
current.getAsyncMarker().sendPacket(current);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when potentially every packet is finished.
|
||||||
|
*/
|
||||||
|
private void signalPacketUpdates() {
|
||||||
|
// Transmit as many packets as we can
|
||||||
|
while (true) {
|
||||||
|
PacketEvent current = sendingQueue.peek();
|
||||||
|
|
||||||
|
if (current != null && current.getAsyncMarker().isProcessed()) {
|
||||||
|
// Just print the error
|
||||||
|
try {
|
||||||
|
current.getAsyncMarker().sendPacket(current);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendingQueue.poll();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// And we're done
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically transmits every delayed packet.
|
||||||
|
*/
|
||||||
|
public void cleanupAll() {
|
||||||
|
forceSend();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import java.util.concurrent.ConcurrentMap;
|
|||||||
|
|
||||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||||
import com.comphenix.protocol.injector.PrioritizedListener;
|
import com.comphenix.protocol.injector.PrioritizedListener;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A thread-safe implementation of a listener multimap.
|
* A thread-safe implementation of a listener multimap.
|
||||||
@ -103,4 +104,19 @@ public abstract class AbstractConcurrentListenerMultimap<TListener> {
|
|||||||
public Collection<PrioritizedListener<TListener>> getListener(int packetID) {
|
public Collection<PrioritizedListener<TListener>> getListener(int packetID) {
|
||||||
return listeners.get(packetID);
|
return listeners.get(packetID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every listener.
|
||||||
|
* @return Every listener.
|
||||||
|
*/
|
||||||
|
protected Iterable<PrioritizedListener<TListener>> values() {
|
||||||
|
return Iterables.concat(listeners.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all packet listeners.
|
||||||
|
*/
|
||||||
|
protected void clearListeners() {
|
||||||
|
listeners.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ 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.AsyncPacket;
|
||||||
|
|
||||||
public class PacketEvent extends EventObject implements Cancellable {
|
public class PacketEvent extends EventObject implements Cancellable {
|
||||||
/**
|
/**
|
||||||
* Automatically generated by Eclipse.
|
* Automatically generated by Eclipse.
|
||||||
@ -35,7 +37,10 @@ public class PacketEvent extends EventObject implements Cancellable {
|
|||||||
private PacketContainer packet;
|
private PacketContainer packet;
|
||||||
private boolean serverPacket;
|
private boolean serverPacket;
|
||||||
private boolean cancel;
|
private boolean cancel;
|
||||||
|
|
||||||
|
private AsyncPacket asyncMarker;
|
||||||
|
private boolean asynchronous;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use the static constructors to create instances of this event.
|
* Use the static constructors to create instances of this event.
|
||||||
* @param source - the event source.
|
* @param source - the event source.
|
||||||
@ -50,6 +55,15 @@ public class PacketEvent extends EventObject implements Cancellable {
|
|||||||
this.player = player;
|
this.player = player;
|
||||||
this.serverPacket = serverPacket;
|
this.serverPacket = serverPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PacketEvent(PacketEvent origial, AsyncPacket asyncMarker) {
|
||||||
|
super(origial.source);
|
||||||
|
this.packet = origial.packet;
|
||||||
|
this.player = origial.player;
|
||||||
|
this.serverPacket = origial.serverPacket;
|
||||||
|
this.asyncMarker = asyncMarker;
|
||||||
|
this.asynchronous = true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an event representing a client packet transmission.
|
* Creates an event representing a client packet transmission.
|
||||||
@ -73,6 +87,16 @@ public class PacketEvent extends EventObject implements Cancellable {
|
|||||||
return new PacketEvent(source, packet, recipient, true);
|
return new PacketEvent(source, packet, recipient, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an asynchronous packet event from a synchronous event and a async marker.
|
||||||
|
* @param event - the original synchronous event.
|
||||||
|
* @param marker - the asynchronous marker.
|
||||||
|
* @return The new packet event.
|
||||||
|
*/
|
||||||
|
public static PacketEvent fromSynchronous(PacketEvent event, AsyncPacket marker) {
|
||||||
|
return new PacketEvent(event, marker);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the packet that will be sent to the player.
|
* Retrieves the packet that will be sent to the player.
|
||||||
* @return Packet to send to the player.
|
* @return Packet to send to the player.
|
||||||
@ -129,6 +153,36 @@ public class PacketEvent extends EventObject implements Cancellable {
|
|||||||
return serverPacket;
|
return serverPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the asynchronous marker.
|
||||||
|
* <p>
|
||||||
|
* If the packet is synchronous, this marker will be used to schedule an asynchronous event. In this
|
||||||
|
* asynchronous event, the marker is used to correctly pass the packet around to the different threads.
|
||||||
|
* @return The current asynchronous marker.
|
||||||
|
*/
|
||||||
|
public AsyncPacket getAsyncMarker() {
|
||||||
|
return asyncMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the asynchronous marker.
|
||||||
|
* <p>
|
||||||
|
* If the marker is non-null at the end of an synchronous event processing, the packet will be scheduled
|
||||||
|
* to be processed asynchronously with the given settings.
|
||||||
|
* @param asyncMarker - the new asynchronous marker.
|
||||||
|
*/
|
||||||
|
public void setAsyncMarker(AsyncPacket asyncMarker) {
|
||||||
|
this.asyncMarker = asyncMarker;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the packet event has been executed asynchronously or not.
|
||||||
|
* @return TRUE if this packet event is asynchronous, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isAsynchronous() {
|
||||||
|
return asynchronous;
|
||||||
|
}
|
||||||
|
|
||||||
private void writeObject(ObjectOutputStream output) throws IOException {
|
private void writeObject(ObjectOutputStream output) throws IOException {
|
||||||
// Default serialization
|
// Default serialization
|
||||||
output.defaultWriteObject();
|
output.defaultWriteObject();
|
||||||
|
@ -668,10 +668,7 @@ public final class PacketFilterManager implements ProtocolManager {
|
|||||||
for (PlayerInjector injection : playerInjection.values()) {
|
for (PlayerInjector injection : playerInjection.values()) {
|
||||||
injection.cleanupAll();
|
injection.cleanupAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up async handlers
|
|
||||||
asyncFilterManager.cleanupAll();
|
|
||||||
|
|
||||||
// Remove packet handlers
|
// Remove packet handlers
|
||||||
if (packetInjector != null)
|
if (packetInjector != null)
|
||||||
packetInjector.cleanupAll();
|
packetInjector.cleanupAll();
|
||||||
@ -681,6 +678,9 @@ public final class PacketFilterManager implements ProtocolManager {
|
|||||||
playerInjection.clear();
|
playerInjection.clear();
|
||||||
connectionLookup.clear();
|
connectionLookup.clear();
|
||||||
hasClosed = true;
|
hasClosed = true;
|
||||||
|
|
||||||
|
// Clean up async handlers. We have to do this last.
|
||||||
|
asyncFilterManager.cleanupAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren