diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java
index f0d86d1a..c5a30c4c 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/ProtocolManager.java
@@ -72,6 +72,24 @@ public interface ProtocolManager extends PacketStream {
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
throws IllegalAccessException, InvocationTargetException;
+ /**
+ * Broadcast a given packet to every connected player on the server.
+ * @param packet - the packet to broadcast.
+ * @throws FieldAccessException If we were unable to send the packet due to reflection problems.
+ */
+ public void broadcastServerPacket(PacketContainer packet);
+
+ /**
+ * Broadcast a packet to every player that is recieving information about a given entity.
+ *
+ * This is usually every player in the same world within an observable distance. If the entity is a
+ * player, its naturally excluded.
+ * @param packet - the packet to broadcast.
+ * @param tracker - the entity tracker.
+ * @throws FieldAccessException If we were unable to send the packet due to reflection problems.
+ */
+ public void broadcastServerPacket(PacketContainer packet, Entity tracker);
+
/**
* Retrieves a list of every registered packet listener.
* @return Every registered packet listener.
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java
index f4d6dba4..07ad0396 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/DelayedPacketManager.java
@@ -29,7 +29,6 @@ import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
@@ -42,74 +41,12 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
// Registering packet IDs that are not supported
public static final ReportType REPORT_CANNOT_SEND_QUEUED_PACKET = new ReportType("Cannot send queued packet %s.");
public static final ReportType REPORT_CANNOT_REGISTER_QUEUED_LISTENER = new ReportType("Cannot register queued listener %s.");
-
- /**
- * Represents a packet that will be transmitted later.
- * @author Kristian
- *
- */
- private static class QueuedPacket {
- private final Player player;
- private final PacketContainer packet;
- private final NetworkMarker marker;
-
- private final boolean filtered;
- private final ConnectionSide side;
-
- public QueuedPacket(Player player, PacketContainer packet, NetworkMarker marker, boolean filtered, ConnectionSide side) {
- this.player = player;
- this.packet = packet;
- this.marker = marker;
- this.filtered = filtered;
- this.side = side;
- }
-
- /**
- * Retrieve the packet that will be transmitted or receieved.
- * @return The packet.
- */
- public PacketContainer getPacket() {
- return packet;
- }
-
- /**
- * Retrieve the player that will send or recieve the packet.
- * @return The source.
- */
- public Player getPlayer() {
- return player;
- }
-
- /**
- * Retrieve whether or not the packet will the sent or received.
- * @return The connection side.
- */
- public ConnectionSide getSide() {
- 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.
- * @return TRUE if it should, FALSE otherwise.
- */
- public boolean isFiltered() {
- return filtered;
- }
- }
private volatile InternalManager delegate;
- // Packet listeners that will be registered
- private final Set queuedListeners = Sets.newSetFromMap(Maps.newConcurrentMap());
- private final List queuedPackets = Collections.synchronizedList(Lists.newArrayList());
+ // Queued actions
+ private final List queuedActions = Collections.synchronizedList(Lists.newArrayList());
+ private final List queuedListeners = Collections.synchronizedList(Lists.newArrayList());
private AsynchronousManager asyncManager;
private ErrorReporter reporter;
@@ -170,46 +107,75 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
delegate.registerEvents(queuedManager, queuedPlugin);
}
- for (PacketListener listener : queuedListeners) {
- try {
- delegate.addPacketListener(listener);
- } catch (IllegalArgumentException e) {
- // Inform about this plugin error
- reporter.reportWarning(this,
- Report.newBuilder(REPORT_CANNOT_REGISTER_QUEUED_LISTENER).
- callerParam(delegate).messageParam(listener).error(e));
+ // Add any pending listeners
+ synchronized (queuedListeners) {
+ for (PacketListener listener : queuedListeners) {
+ try {
+ delegate.addPacketListener(listener);
+ } catch (IllegalArgumentException e) {
+ // Inform about this plugin error
+ reporter.reportWarning(this,
+ Report.newBuilder(REPORT_CANNOT_REGISTER_QUEUED_LISTENER).
+ callerParam(delegate).messageParam(listener).error(e));
+ }
}
}
- synchronized (queuedPackets) {
- for (QueuedPacket packet : queuedPackets) {
- try {
- // Attempt to send it now
- switch (packet.getSide()) {
- case CLIENT_SIDE:
- delegate.recieveClientPacket(packet.getPlayer(), packet.getPacket(), packet.getMarker(), packet.isFiltered());
- break;
- case SERVER_SIDE:
- delegate.sendServerPacket(packet.getPlayer(), packet.getPacket(), packet.getMarker(), packet.isFiltered());
- break;
- default:
-
- }
- } catch (Exception e) {
- // Inform about this plugin error
- reporter.reportWarning(this,
- Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_PACKET).
- callerParam(delegate).messageParam(packet).error(e));
- }
+ // Execute any delayed actions
+ synchronized (queuedActions) {
+ for (Runnable action : queuedActions) {
+ action.run();
}
}
// Don't keep this around anymore
queuedListeners.clear();
- queuedPackets.clear();
+ queuedActions.clear();
}
}
+ private Runnable queuedAddPacket(final ConnectionSide side, final Player player, final PacketContainer packet,
+ final NetworkMarker marker, final boolean filtered) {
+
+ return new Runnable() {
+ @Override
+ public void run() {
+ try {
+ // Attempt to send it now
+ switch (side) {
+ case CLIENT_SIDE:
+ delegate.recieveClientPacket(player, packet, marker, filtered);
+ break;
+ case SERVER_SIDE:
+ delegate.sendServerPacket(player, packet, marker, filtered);
+ break;
+ default:
+ throw new IllegalArgumentException("side cannot be " + side);
+ }
+ } catch (Exception e) {
+ // Inform about this plugin error
+ reporter.reportWarning(this,
+ Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_PACKET).
+ callerParam(delegate).messageParam(packet).error(e));
+ }
+ }
+ };
+ }
+
+ private Runnable queuedBroadcastServerPacket(final PacketContainer packet, final Entity tracker) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ // Invoke the correct version
+ if (tracker != null) {
+ delegate.broadcastServerPacket(packet, tracker);
+ } else {
+ delegate.broadcastServerPacket(packet);
+ }
+ }
+ };
+ }
+
@Override
public void setPlayerHook(PlayerInjectHooks playerHook) {
this.hook = playerHook;
@@ -235,7 +201,7 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
if (delegate != null) {
delegate.sendServerPacket(reciever, packet, marker, filters);
} else {
- queuedPackets.add(new QueuedPacket(reciever, packet, marker, filters, ConnectionSide.SERVER_SIDE));
+ queuedActions.add(queuedAddPacket(ConnectionSide.SERVER_SIDE, reciever, packet, marker, filters));
}
}
@@ -254,9 +220,25 @@ public class DelayedPacketManager implements ProtocolManager, InternalManager {
if (delegate != null) {
delegate.recieveClientPacket(sender, packet, marker, filters);
} else {
- queuedPackets.add(new QueuedPacket(sender, packet, marker, filters, ConnectionSide.CLIENT_SIDE));
+ queuedActions.add(queuedAddPacket(ConnectionSide.CLIENT_SIDE, sender, packet, marker, filters));
}
}
+
+ @Override
+ public void broadcastServerPacket(PacketContainer packet, Entity tracker) {
+ if (delegate != null)
+ delegate.broadcastServerPacket(packet, tracker);
+ else
+ queuedActions.add(queuedBroadcastServerPacket(packet, tracker));
+ }
+
+ @Override
+ public void broadcastServerPacket(PacketContainer packet) {
+ if (delegate != null)
+ delegate.broadcastServerPacket(packet);
+ else
+ queuedActions.add(queuedBroadcastServerPacket(packet, null));
+ }
@Override
public ImmutableSet getPacketListeners() {
diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
index a43421e9..d31fb9ae 100644
--- a/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
+++ b/ProtocolLib/src/main/java/com/comphenix/protocol/injector/PacketFilterManager.java
@@ -19,6 +19,7 @@ package com.comphenix.protocol.injector;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -68,6 +69,7 @@ import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
@@ -617,6 +619,34 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
}
}
+ @Override
+ public void broadcastServerPacket(PacketContainer packet) {
+ Preconditions.checkNotNull(packet, "packet cannot be NULL.");
+ broadcastServerPacket(packet, Arrays.asList(server.getOnlinePlayers()));
+ }
+
+ @Override
+ public void broadcastServerPacket(PacketContainer packet, Entity tracker) {
+ Preconditions.checkNotNull(packet, "packet cannot be NULL.");
+ Preconditions.checkNotNull(tracker, "tracker cannot be NULL.");
+ broadcastServerPacket(packet, getEntityTrackers(tracker));
+ }
+
+ /**
+ * Broadcast a packet to a given iterable of players.
+ * @param packet - the packet to broadcast.
+ * @param players - the iterable of players.
+ */
+ private void broadcastServerPacket(PacketContainer packet, Iterable players) {
+ try {
+ for (Player player : players) {
+ sendServerPacket(player, packet);
+ }
+ } catch (InvocationTargetException e) {
+ throw new FieldAccessException("Unable to send server packet.", e);
+ }
+ }
+
@Override
public void sendServerPacket(Player reciever, PacketContainer packet) throws InvocationTargetException {
sendServerPacket(reciever, packet, null, true);