package com.comphenix.protocol.events; import javax.annotation.Nonnull; import java.util.*; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolManager; import com.google.common.base.Preconditions; import org.bukkit.entity.Player; /** * Marker containing the serialized packet data seen from the network, or output handlers that will serialize the * current packet. * * @author Kristian */ public class NetworkMarker { // The input data private final PacketType type; private final ConnectionSide side; // Post-processing of the packet private Set postListeners; private Deque scheduledPackets; /** * Construct a new network marker. *

* The input buffer is only non-null for client-side packets. * * @param side - which side this marker belongs to. * @param type - packet type */ public NetworkMarker(@Nonnull ConnectionSide side, PacketType type) { this.side = Preconditions.checkNotNull(side, "side cannot be NULL."); this.type = type; } /** * Determine if the given marker has any post listeners. * * @param marker - the marker to check. * @return TRUE if it does, FALSE otherwise. */ public static boolean hasPostListeners(NetworkMarker marker) { return marker != null && !marker.getPostListeners().isEmpty(); } /** * Retrieve the network marker of a particular event without creating it. *

* This is an internal method that should not be used by API users. * * @param event - the event. * @return The network marker. */ public static NetworkMarker getNetworkMarker(PacketEvent event) { return event.networkMarker; } /** * Retrieve the scheduled packets of a particular network marker without constructing the list. *

* 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 Deque readScheduledPackets(NetworkMarker marker) { return marker.scheduledPackets; } /** * 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 this.side; } public PacketType getType() { return this.type; } /** * Add a listener that is invoked after a packet has been successfully sent to the client, or received by the server. *

* Received packets are not guarenteed to have been fully processed, but packets passed to {@link * ProtocolManager#receiveClientPacket(Player, PacketContainer)} will be processed after the current packet event. *

* Note that post listeners will be executed asynchronously off the main thread. They are not executed in any defined * order. * * @param listener - the listener that will be invoked. * @return TRUE if it was added. */ public boolean addPostListener(PacketPostListener listener) { if (this.postListeners == null) { this.postListeners = new HashSet<>(); } return this.postListeners.add(listener); } /** * Remove the first instance of the given listener. * * @param listener - listener to remove. * @return TRUE if it was removed, FALSE otherwise. */ public boolean removePostListener(PacketPostListener listener) { if (this.postListeners != null) { return this.postListeners.remove(listener); } return false; } /** * Retrieve an immutable view of all the listeners that will be invoked once the packet has been sent or received. * * @return Every post packet listener. Never NULL. */ public Set getPostListeners() { return this.postListeners != null ? this.postListeners : Collections.emptySet(); } /** * Retrieve a modifiable queue of packets that will be schedule (in-order) when the current packet has been * successfully transmitted. * * @return the queue of packets to schedule after this packet, in order. */ public Deque getScheduledPackets() { if (this.scheduledPackets == null) { this.scheduledPackets = new LinkedList<>(); } return this.scheduledPackets; } /** * Ensure that the packet event is server side. */ private void checkServerSide() { if (this.side.isForClient()) { throw new IllegalStateException("Must be a server side packet."); } } }