-
-
Notifications
You must be signed in to change notification settings - Fork 261
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: improve packet listener tracking
fix: terminal packets breaking protocol getter on inbound packets
- Loading branch information
Showing
17 changed files
with
543 additions
and
582 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
171 changes: 68 additions & 103 deletions
171
src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
Large diffs are not rendered by default.
Oops, something went wrong.
77 changes: 77 additions & 0 deletions
77
src/main/java/com/comphenix/protocol/injector/collection/InboundPacketListenerSet.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.comphenix.protocol.injector.collection; | ||
|
||
import javax.annotation.Nullable; | ||
|
||
import com.comphenix.protocol.concurrent.PacketTypeListenerSet; | ||
import com.comphenix.protocol.error.ErrorReporter; | ||
import com.comphenix.protocol.events.ListenerPriority; | ||
import com.comphenix.protocol.events.ListeningWhitelist; | ||
import com.comphenix.protocol.events.PacketEvent; | ||
import com.comphenix.protocol.events.PacketListener; | ||
import com.comphenix.protocol.timing.TimedListenerManager; | ||
import com.comphenix.protocol.timing.TimedListenerManager.ListenerType; | ||
import com.comphenix.protocol.timing.TimedTracker; | ||
|
||
public class InboundPacketListenerSet extends PacketListenerSet { | ||
|
||
public InboundPacketListenerSet(PacketTypeListenerSet mainThreadPacketTypes, ErrorReporter errorReporter) { | ||
super(mainThreadPacketTypes, errorReporter); | ||
} | ||
|
||
@Override | ||
protected ListeningWhitelist getListeningWhitelist(PacketListener packetListener) { | ||
return packetListener.getReceivingWhitelist(); | ||
} | ||
|
||
/** | ||
* Invokes the given packet event for every registered listener of the given | ||
* priority. | ||
* | ||
* @param event - the packet event to invoke. | ||
* @param priorityFilter - the required priority for a listener to be invoked. | ||
*/ | ||
@Override | ||
public void invoke(PacketEvent event, @Nullable ListenerPriority priorityFilter) { | ||
Iterable<PacketListener> listeners = this.map.get(event.getPacketType()); | ||
|
||
TimedListenerManager timedManager = TimedListenerManager.getInstance(); | ||
if (timedManager.isTiming()) { | ||
for (PacketListener element : listeners) { | ||
if (priorityFilter == null || element.getReceivingWhitelist().getPriority() == priorityFilter) { | ||
TimedTracker tracker = timedManager.getTracker(element, ListenerType.SYNC_CLIENT_SIDE); | ||
long token = tracker.beginTracking(); | ||
|
||
// Measure and record the execution time | ||
invokeReceivingListener(event, element); | ||
tracker.endTracking(token, event.getPacketType()); | ||
} | ||
} | ||
} else { | ||
for (PacketListener element : listeners) { | ||
if (priorityFilter == null || element.getReceivingWhitelist().getPriority() == priorityFilter) { | ||
invokeReceivingListener(event, element); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Invoke a particular receiving listener. | ||
* | ||
* @param reporter - the error reporter. | ||
* @param event - the related packet event. | ||
* @param listener - the listener to invoke. | ||
*/ | ||
private void invokeReceivingListener(PacketEvent event, PacketListener listener) { | ||
try { | ||
event.setReadOnly(listener.getReceivingWhitelist().getPriority() == ListenerPriority.MONITOR); | ||
listener.onPacketReceiving(event); | ||
} catch (OutOfMemoryError | ThreadDeath e) { | ||
throw e; | ||
} catch (Throwable e) { | ||
// Minecraft doesn't want your Exception. | ||
errorReporter.reportMinimal(listener.getPlugin(), "onPacketReceiving(PacketEvent)", e, | ||
event.getPacket().getHandle()); | ||
} | ||
} | ||
} |
129 changes: 129 additions & 0 deletions
129
src/main/java/com/comphenix/protocol/injector/collection/OutboundPacketListenerSet.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
package com.comphenix.protocol.injector.collection; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.logging.Level; | ||
|
||
import javax.annotation.Nullable; | ||
|
||
import com.comphenix.protocol.PacketType; | ||
import com.comphenix.protocol.ProtocolLibrary; | ||
import com.comphenix.protocol.concurrent.PacketTypeListenerSet; | ||
import com.comphenix.protocol.error.ErrorReporter; | ||
import com.comphenix.protocol.events.ListenerPriority; | ||
import com.comphenix.protocol.events.ListeningWhitelist; | ||
import com.comphenix.protocol.events.PacketContainer; | ||
import com.comphenix.protocol.events.PacketEvent; | ||
import com.comphenix.protocol.events.PacketListener; | ||
import com.comphenix.protocol.timing.TimedListenerManager; | ||
import com.comphenix.protocol.timing.TimedListenerManager.ListenerType; | ||
import com.comphenix.protocol.timing.TimedTracker; | ||
|
||
public class OutboundPacketListenerSet extends PacketListenerSet { | ||
|
||
public OutboundPacketListenerSet(PacketTypeListenerSet mainThreadPacketTypes, ErrorReporter errorReporter) { | ||
super(mainThreadPacketTypes, errorReporter); | ||
} | ||
|
||
@Override | ||
protected ListeningWhitelist getListeningWhitelist(PacketListener packetListener) { | ||
return packetListener.getSendingWhitelist(); | ||
} | ||
|
||
/** | ||
* Invokes the given packet event for every registered listener of the given | ||
* priority. | ||
* | ||
* @param event - the packet event to invoke. | ||
* @param priorityFilter - the priority for a listener to be invoked. If null is | ||
* provided, every registered listener will be invoked | ||
*/ | ||
@Override | ||
public void invoke(PacketEvent event, @Nullable ListenerPriority priorityFilter) { | ||
invokeUnpackedPacketSending(event, priorityFilter); | ||
if (event.getPacketType() == PacketType.Play.Server.BUNDLE && !event.isCancelled()) { | ||
// unpack the bundle and invoke for each packet in the bundle | ||
Iterable<PacketContainer> packets = event.getPacket().getPacketBundles().read(0); | ||
List<PacketContainer> outPackets = new ArrayList<>(); | ||
for (PacketContainer subPacket : packets) { | ||
if (subPacket == null) { | ||
ProtocolLibrary.getPlugin().getLogger().log(Level.WARNING, | ||
"Failed to invoke packet event " | ||
+ (priorityFilter == null ? "" : ("with priority " + priorityFilter)) | ||
+ " in bundle because bundle contains null packet: " + packets, | ||
new Throwable()); | ||
continue; | ||
} | ||
PacketEvent subPacketEvent = PacketEvent.fromServer(this, subPacket, event.getNetworkMarker(), | ||
event.getPlayer()); | ||
invokeUnpackedPacketSending(subPacketEvent, priorityFilter); | ||
|
||
if (!subPacketEvent.isCancelled()) { | ||
// if the packet event has been cancelled, the packet will be removed from the | ||
// bundle | ||
PacketContainer packet = subPacketEvent.getPacket(); | ||
if (packet == null) { | ||
ProtocolLibrary.getPlugin().getLogger().log(Level.WARNING, | ||
"null packet container returned for " + subPacketEvent, new Throwable()); | ||
} else if (packet.getHandle() == null) { | ||
ProtocolLibrary.getPlugin().getLogger().log(Level.WARNING, | ||
"null packet handle returned for " + subPacketEvent, new Throwable()); | ||
} else { | ||
outPackets.add(packet); | ||
} | ||
} | ||
} | ||
|
||
if (packets.iterator().hasNext()) { | ||
event.getPacket().getPacketBundles().write(0, outPackets); | ||
} else { | ||
// cancel entire packet if each individual packet has been cancelled | ||
event.setCancelled(true); | ||
} | ||
} | ||
} | ||
|
||
private void invokeUnpackedPacketSending(PacketEvent event, @Nullable ListenerPriority priorityFilter) { | ||
Iterable<PacketListener> listeners = this.map.get(event.getPacketType()); | ||
|
||
TimedListenerManager timedManager = TimedListenerManager.getInstance(); | ||
if (timedManager.isTiming()) { | ||
for (PacketListener element : listeners) { | ||
if (priorityFilter == null || element.getSendingWhitelist().getPriority() == priorityFilter) { | ||
TimedTracker tracker = timedManager.getTracker(element, ListenerType.SYNC_SERVER_SIDE); | ||
long token = tracker.beginTracking(); | ||
|
||
// Measure and record the execution time | ||
invokeSendingListener(event, element); | ||
tracker.endTracking(token, event.getPacketType()); | ||
} | ||
} | ||
} else { | ||
for (PacketListener element : listeners) { | ||
if (priorityFilter == null || element.getSendingWhitelist().getPriority() == priorityFilter) { | ||
invokeSendingListener(event, element); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Invoke a particular sending listener. | ||
* | ||
* @param reporter - the error reporter. | ||
* @param event - the related packet event. | ||
* @param listener - the listener to invoke. | ||
*/ | ||
private void invokeSendingListener(PacketEvent event, PacketListener listener) { | ||
try { | ||
event.setReadOnly(listener.getSendingWhitelist().getPriority() == ListenerPriority.MONITOR); | ||
listener.onPacketSending(event); | ||
} catch (OutOfMemoryError | ThreadDeath e) { | ||
throw e; | ||
} catch (Throwable e) { | ||
// Minecraft doesn't want your Exception. | ||
errorReporter.reportMinimal(listener.getPlugin(), "onPacketSending(PacketEvent)", e, | ||
event.getPacket().getHandle()); | ||
} | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
src/main/java/com/comphenix/protocol/injector/collection/PacketListenerSet.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package com.comphenix.protocol.injector.collection; | ||
|
||
import java.util.Set; | ||
|
||
import javax.annotation.Nullable; | ||
|
||
import com.comphenix.protocol.PacketType; | ||
import com.comphenix.protocol.PacketType.Sender; | ||
import com.comphenix.protocol.concurrent.PacketTypeListenerSet; | ||
import com.comphenix.protocol.concurrent.PacketTypeMultiMap; | ||
import com.comphenix.protocol.error.ErrorReporter; | ||
import com.comphenix.protocol.error.Report; | ||
import com.comphenix.protocol.error.ReportType; | ||
import com.comphenix.protocol.events.ListenerOptions; | ||
import com.comphenix.protocol.events.ListenerPriority; | ||
import com.comphenix.protocol.events.ListeningWhitelist; | ||
import com.comphenix.protocol.events.PacketAdapter; | ||
import com.comphenix.protocol.events.PacketEvent; | ||
import com.comphenix.protocol.events.PacketListener; | ||
import com.comphenix.protocol.injector.packet.PacketRegistry; | ||
import com.google.common.collect.ImmutableSet; | ||
|
||
public abstract class PacketListenerSet { | ||
|
||
private static final ReportType UNSUPPORTED_PACKET = new ReportType( | ||
"Plugin %s tried to register listener for unknown packet %s [direction: from %s]"); | ||
|
||
protected final PacketTypeMultiMap<PacketListener> map = new PacketTypeMultiMap<>(); | ||
|
||
protected final PacketTypeListenerSet mainThreadPacketTypes; | ||
protected final ErrorReporter errorReporter; | ||
|
||
public PacketListenerSet(PacketTypeListenerSet mainThreadPacketTypes, ErrorReporter errorReporter) { | ||
this.mainThreadPacketTypes = mainThreadPacketTypes; | ||
this.errorReporter = errorReporter; | ||
} | ||
|
||
protected abstract ListeningWhitelist getListeningWhitelist(PacketListener packetListener); | ||
|
||
public void addListener(PacketListener packetListener) { | ||
ListeningWhitelist listeningWhitelist = getListeningWhitelist(packetListener); | ||
this.map.put(listeningWhitelist, packetListener); | ||
|
||
Set<ListenerOptions> options = listeningWhitelist.getOptions(); | ||
for (PacketType packetType : listeningWhitelist.getTypes()) { | ||
if (!packetType.isAsyncForced() && !options.contains(ListenerOptions.ASYNC)) { | ||
this.mainThreadPacketTypes.add(packetType, packetListener); | ||
} | ||
|
||
Set<PacketType> supportedPacketTypes = (packetType.getSender() == Sender.SERVER) | ||
? PacketRegistry.getServerPacketTypes() | ||
: PacketRegistry.getClientPacketTypes(); | ||
|
||
if (!supportedPacketTypes.contains(packetType)) { | ||
this.errorReporter.reportWarning(this, Report.newBuilder(UNSUPPORTED_PACKET) | ||
.messageParam(PacketAdapter.getPluginName(packetListener), packetType, packetType.getSender()) | ||
.build()); | ||
} | ||
} | ||
} | ||
|
||
public void removeListener(PacketListener packetListener) { | ||
ListeningWhitelist listeningWhitelist = getListeningWhitelist(packetListener); | ||
this.map.remove(listeningWhitelist, packetListener); | ||
|
||
for (PacketType packetType : listeningWhitelist.getTypes()) { | ||
this.mainThreadPacketTypes.remove(packetType, packetListener); | ||
} | ||
} | ||
|
||
public final boolean containsPacketType(PacketType packetType) { | ||
return this.map.contains(packetType); | ||
} | ||
|
||
public final ImmutableSet<PacketType> getPacketTypes() { | ||
return this.map.getPacketTypes(); | ||
} | ||
|
||
public void invoke(PacketEvent event) { | ||
this.invoke(event, null); | ||
} | ||
|
||
public abstract void invoke(PacketEvent event, @Nullable ListenerPriority priorityFilter); | ||
|
||
public void clear() { | ||
this.map.clear(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.