Server packet listener now takes a collection of player, for future network optimization

This commit is contained in:
themode 2020-11-20 03:47:29 +01:00
parent a0fccca1c6
commit 0739b57dd1
7 changed files with 67 additions and 41 deletions

View File

@ -339,7 +339,6 @@ public class Player extends LivingEntity implements CommandSender {
@Override
public void update(long time) {
// Network tick
this.playerConnection.update();

View File

@ -2,23 +2,21 @@ package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import org.jetbrains.annotations.NotNull;
/**
* Interface used to add a listener for incoming/outgoing packets with
* {@link ConnectionManager#onPacketReceive(PacketConsumer)} and {@link ConnectionManager#onPacketSend(PacketConsumer)}.
*
* @param <T> the packet type
* Interface used to add a listener for incoming packets with {@link ConnectionManager#onPacketReceive(ClientPacketConsumer)}.
*/
@FunctionalInterface
public interface PacketConsumer<T> {
public interface ClientPacketConsumer {
/**
* Called when a packet is received/sent from/to a client.
* Called when a packet is received from a client.
*
* @param player the player concerned by the packet
* @param packetController the packet controller, can be used to cancel the packet
* @param packet the packet
*/
void accept(@NotNull Player player, @NotNull PacketController packetController, @NotNull T packet);
void accept(@NotNull Player player, @NotNull PacketController packetController, @NotNull ClientPlayPacket packet);
}

View File

@ -1,9 +1,14 @@
package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import java.util.Collection;
/**
* Used to control the output of a packet in {@link PacketConsumer#accept(Player, PacketController, Object)}.
* Used to control the output of a packet in {@link ClientPacketConsumer#accept(Player, PacketController, ClientPlayPacket)}
* and {@link ServerPacketConsumer#accept(Collection, PacketController, ServerPacket)}.
*/
public class PacketController {

View File

@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -74,8 +75,8 @@ public final class PacketListenerManager {
}
final PacketController packetController = new PacketController();
for (PacketConsumer<ClientPlayPacket> packetConsumer : CONNECTION_MANAGER.getReceivePacketConsumers()) {
packetConsumer.accept(player, packetController, packet);
for (ClientPacketConsumer clientPacketConsumer : CONNECTION_MANAGER.getReceivePacketConsumers()) {
clientPacketConsumer.accept(player, packetController, packet);
}
if (packetController.isCancel())
@ -86,22 +87,21 @@ public final class PacketListenerManager {
}
/**
* Executes the consumers from {@link ConnectionManager#onPacketSend(PacketConsumer)}.
* Executes the consumers from {@link ConnectionManager#onPacketSend(ServerPacketConsumer)}.
*
* @param packet the packet to process
* @param player the player which should receive the packet
* @param <T> the packet type
* @param packet the packet to process
* @param players the players which should receive the packet
* @return true if the packet is not cancelled, false otherwise
*/
public <T extends ServerPacket> boolean processServerPacket(@NotNull T packet, @NotNull Player player) {
final List<PacketConsumer<ServerPacket>> consumers = CONNECTION_MANAGER.getSendPacketConsumers();
public boolean processServerPacket(@NotNull ServerPacket packet, @NotNull Collection<Player> players) {
final List<ServerPacketConsumer> consumers = CONNECTION_MANAGER.getSendPacketConsumers();
if (consumers.isEmpty()) {
return true;
}
final PacketController packetController = new PacketController();
for (PacketConsumer<ServerPacket> packetConsumer : consumers) {
packetConsumer.accept(player, packetController, packet);
for (ServerPacketConsumer serverPacketConsumer : consumers) {
serverPacketConsumer.accept(players, packetController, packet);
}
return !packetController.isCancel();

View File

@ -0,0 +1,27 @@
package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
/**
* Interface used to add a listener for outgoing packets with {@link ConnectionManager#onPacketSend(ServerPacket)}.
*
* @param <T> the packet type
*/
@FunctionalInterface
public interface ServerPacketConsumer {
/**
* Called when a packet is sent to a client.
*
* @param players the players who will receive the packet
* @param packetController the packet controller, can be used for cancelling
* @param packet the packet to send
*/
void accept(@NotNull Collection<Player> players, @NotNull PacketController packetController, @NotNull ServerPacket packet);
}

View File

@ -3,10 +3,9 @@ package net.minestom.server.network;
import net.minestom.server.chat.JsonMessage;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.fakeplayer.FakePlayer;
import net.minestom.server.listener.manager.PacketConsumer;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.listener.manager.ClientPacketConsumer;
import net.minestom.server.listener.manager.ServerPacketConsumer;
import net.minestom.server.network.packet.client.login.LoginStartPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.play.ChatMessagePacket;
import net.minestom.server.network.player.PlayerConnection;
@ -29,9 +28,9 @@ public final class ConnectionManager {
private final Map<PlayerConnection, Player> connectionPlayerMap = Collections.synchronizedMap(new HashMap<>());
// All the consumers to call once a packet is received
private final List<PacketConsumer<ClientPlayPacket>> receivePacketConsumers = new CopyOnWriteArrayList<>();
private final List<ClientPacketConsumer> receiveClientPacketConsumers = new CopyOnWriteArrayList<>();
// All the consumers to call once a packet is sent
private final List<PacketConsumer<ServerPacket>> sendPacketConsumers = new CopyOnWriteArrayList<>();
private final List<ServerPacketConsumer> sendClientPacketConsumers = new CopyOnWriteArrayList<>();
// The uuid provider once a player login
private UuidProvider uuidProvider;
// The player provider to have your own Player implementation
@ -148,17 +147,17 @@ public final class ConnectionManager {
* @return a list of packet's consumers
*/
@NotNull
public List<PacketConsumer<ClientPlayPacket>> getReceivePacketConsumers() {
return receivePacketConsumers;
public List<ClientPacketConsumer> getReceivePacketConsumers() {
return receiveClientPacketConsumers;
}
/**
* Adds a consumer to call once a packet is received.
*
* @param packetConsumer the packet consumer
* @param clientPacketConsumer the packet consumer
*/
public void onPacketReceive(@NotNull PacketConsumer<ClientPlayPacket> packetConsumer) {
this.receivePacketConsumers.add(packetConsumer);
public void onPacketReceive(@NotNull ClientPacketConsumer clientPacketConsumer) {
this.receiveClientPacketConsumers.add(clientPacketConsumer);
}
/**
@ -167,21 +166,17 @@ public final class ConnectionManager {
* @return a list of packet's consumers
*/
@NotNull
public List<PacketConsumer<ServerPacket>> getSendPacketConsumers() {
return Collections.unmodifiableList(sendPacketConsumers);
public List<ServerPacketConsumer> getSendPacketConsumers() {
return Collections.unmodifiableList(sendClientPacketConsumers);
}
/**
* Adds a consumer to call once a packet is sent.
* <p>
* Be aware that it is possible for the same packet instance to be used multiple time,
* changing the object fields could lead to issues.
* (consider canceling the packet instead and send your own)
*
* @param packetConsumer the packet consumer
* @param serverPacketConsumer the packet consumer
*/
public void onPacketSend(@NotNull PacketConsumer<ServerPacket> packetConsumer) {
this.sendPacketConsumers.add(packetConsumer);
public void onPacketSend(@NotNull ServerPacketConsumer serverPacketConsumer) {
this.sendClientPacketConsumers.add(serverPacketConsumer);
}
/**

View File

@ -4,8 +4,8 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.chat.ChatColor;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.entity.Player;
import net.minestom.server.listener.manager.PacketConsumer;
import net.minestom.server.listener.manager.PacketListenerManager;
import net.minestom.server.listener.manager.ServerPacketConsumer;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.packet.server.ServerPacket;
@ -15,6 +15,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.concurrent.atomic.AtomicInteger;
/**
@ -92,7 +93,7 @@ public abstract class PlayerConnection {
/**
* Serializes the packet and send it to the client.
* <p>
* Also responsible for executing {@link ConnectionManager#onPacketSend(PacketConsumer)} consumers.
* Also responsible for executing {@link ConnectionManager#onPacketSend(ServerPacketConsumer)} consumers.
*
* @param serverPacket the packet to send
* @see #shouldSendPacket(ServerPacket)
@ -100,7 +101,8 @@ public abstract class PlayerConnection {
public abstract void sendPacket(@NotNull ServerPacket serverPacket);
protected boolean shouldSendPacket(@NotNull ServerPacket serverPacket) {
return player == null || PACKET_LISTENER_MANAGER.processServerPacket(serverPacket, player);
return player == null ||
PACKET_LISTENER_MANAGER.processServerPacket(serverPacket, Collections.singleton(player));
}
/**