Add PlayerPacketOutEvent (#689)

This commit is contained in:
TheMode 2022-02-17 13:51:55 +01:00 committed by GitHub
parent be100fa5b8
commit 9b04e89552
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 62 additions and 207 deletions

View File

@ -1,8 +1,8 @@
package net.minestom.demo;
import net.kyori.adventure.text.Component;
import net.minestom.demo.generator.ChunkGeneratorDemo;
import net.minestom.demo.generator.NoiseTestGenerator;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.audience.Audiences;
import net.minestom.server.coordinate.Pos;
@ -17,10 +17,7 @@ import net.minestom.server.event.EventNode;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.PickupItemEvent;
import net.minestom.server.event.player.PlayerDeathEvent;
import net.minestom.server.event.player.PlayerDisconnectEvent;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;
import net.minestom.server.event.player.*;
import net.minestom.server.event.server.ServerTickMonitorEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
@ -114,6 +111,12 @@ public class PlayerInit {
})
.build();
player.getInventory().addItemStack(bundle);
})
.addListener(PlayerPacketOutEvent.class, event -> {
//System.out.println("out " + event.getPacket().getClass().getSimpleName());
})
.addListener(PlayerPacketEvent.class, event -> {
//System.out.println("in " + event.getPacket().getClass().getSimpleName());
});
static {

View File

@ -0,0 +1,33 @@
package net.minestom.server.event.player;
import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.PlayerEvent;
import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
/**
* Listen to outgoing packets asynchronously.
* <p>
* Currently, do not support viewable packets.
*/
@ApiStatus.Experimental
public class PlayerPacketOutEvent implements PlayerEvent {
private final Player player;
private final ServerPacket packet;
public PlayerPacketOutEvent(Player player, ServerPacket packet) {
this.player = player;
this.packet = packet;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
public @NotNull ServerPacket getPacket() {
return packet;
}
}

View File

@ -1,22 +0,0 @@
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.ClientPacket;
import org.jetbrains.annotations.NotNull;
/**
* Interface used to add a listener for incoming packets with {@link ConnectionManager#onPacketReceive(ClientPacketConsumer)}.
*/
@FunctionalInterface
public interface ClientPacketConsumer {
/**
* 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 ClientPacket packet);
}

View File

@ -1,37 +0,0 @@
package net.minestom.server.listener.manager;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import java.util.Collection;
/**
* Used to control the output of a packet in {@link ClientPacketConsumer#accept(Player, PacketController, ClientPacket)}
* and {@link ServerPacketConsumer#accept(Collection, PacketController, ServerPacket)}.
*/
public class PacketController {
private boolean cancel;
protected PacketController() {
}
/**
* Gets if the packet is cancelled.
*
* @return true if the packet will be cancelled, false otherwise
*/
public boolean isCancel() {
return cancel;
}
/**
* Used to cancel the packet.
*
* @param cancel true if the packet should be cancelled, false otherwise
*/
public void setCancel(boolean cancel) {
this.cancel = cancel;
}
}

View File

@ -6,16 +6,12 @@ import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerPacketEvent;
import net.minestom.server.listener.*;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.network.packet.client.play.*;
import net.minestom.server.network.packet.server.ServerPacket;
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;
@ -79,17 +75,6 @@ public final class PacketListenerManager {
LOGGER.warn("Packet " + clazz + " does not have any default listener! (The issue comes from Minestom)");
}
// TODO remove legacy
{
final PacketController packetController = new PacketController();
for (ClientPacketConsumer clientPacketConsumer : serverProcess.connection().getReceivePacketConsumers()) {
clientPacketConsumer.accept(player, packetController, packet);
}
if (packetController.isCancel())
return;
}
// Event
PlayerPacketEvent playerPacketEvent = new PlayerPacketEvent(player, packet);
EventDispatcher.call(playerPacketEvent);
@ -108,27 +93,6 @@ public final class PacketListenerManager {
}
}
/**
* Executes the consumers from {@link ConnectionManager#onPacketSend(ServerPacketConsumer)}.
*
* @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 boolean processServerPacket(@NotNull ServerPacket packet, @NotNull Collection<Player> players) {
final List<ServerPacketConsumer> consumers = serverProcess.connection().getSendPacketConsumers();
if (consumers.isEmpty()) {
return true;
}
final PacketController packetController = new PacketController();
for (ServerPacketConsumer serverPacketConsumer : consumers) {
serverPacketConsumer.accept(players, packetController, packet);
}
return !packetController.isCancel();
}
/**
* Sets the listener of a packet.
* <p>

View File

@ -1,25 +0,0 @@
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(ServerPacketConsumer)}.
*/
@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

@ -8,8 +8,6 @@ import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.AsyncPlayerPreLoginEvent;
import net.minestom.server.event.player.PlayerLoginEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.listener.manager.ClientPacketConsumer;
import net.minestom.server.listener.manager.ServerPacketConsumer;
import net.minestom.server.network.packet.server.login.LoginSuccessPacket;
import net.minestom.server.network.packet.server.play.DisconnectPacket;
import net.minestom.server.network.packet.server.play.KeepAlivePacket;
@ -25,7 +23,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Function;
@ -42,10 +39,6 @@ public final class ConnectionManager {
private final Set<Player> unmodifiablePlayers = Collections.unmodifiableSet(players);
private final Map<PlayerConnection, Player> connectionPlayerMap = new ConcurrentHashMap<>();
// All the consumers to call once a packet is received
private final List<ClientPacketConsumer> receiveClientPacketConsumers = new CopyOnWriteArrayList<>();
// All the consumers to call once a packet is sent
private final List<ServerPacketConsumer> sendClientPacketConsumers = new CopyOnWriteArrayList<>();
// The uuid provider once a player login
private volatile UuidProvider uuidProvider = (playerConnection, username) -> UUID.randomUUID();
// The player provider to have your own Player implementation
@ -126,56 +119,6 @@ public final class ConnectionManager {
return null;
}
/**
* Gets all the listeners which are called for each packet received.
*
* @return a list of packet's consumers
* @deprecated see {@link net.minestom.server.event.player.PlayerPacketEvent}
*/
@NotNull
@Deprecated
public List<ClientPacketConsumer> getReceivePacketConsumers() {
return receiveClientPacketConsumers;
}
/**
* Adds a consumer to call once a packet is received.
*
* @param clientPacketConsumer the packet consumer
* @deprecated listen to {@link net.minestom.server.event.player.PlayerPacketEvent}
*/
@Deprecated
public void onPacketReceive(@NotNull ClientPacketConsumer clientPacketConsumer) {
this.receiveClientPacketConsumers.add(clientPacketConsumer);
}
/**
* Gets all the listeners which are called for each packet sent.
*
* @return a list of packet's consumers
* @deprecated all packet listening methods will ultimately be removed.
* May or may not work depending on the packet.
* It is instead recommended to use a proxy, improving scalability and increasing server performance
*/
@NotNull
@Deprecated
public List<ServerPacketConsumer> getSendPacketConsumers() {
return sendClientPacketConsumers;
}
/**
* Adds a consumer to call once a packet is sent.
*
* @param serverPacketConsumer the packet consumer
* @deprecated all packet listening methods will ultimately be removed.
* May or may not work depending on the packet.
* It is instead recommended to use a proxy, improving scalability and increasing server performance
*/
@Deprecated
public void onPacketSend(@NotNull ServerPacketConsumer serverPacketConsumer) {
this.sendClientPacketConsumers.add(serverPacketConsumer);
}
/**
* Changes how {@link UUID} are attributed to players.
* <p>

View File

@ -18,7 +18,6 @@ public class FakePlayerConnection extends PlayerConnection {
public void sendPacket(@NotNull SendablePacket packet) {
FakePlayerController controller = getFakePlayer().getController();
final ServerPacket serverPacket = SendablePacket.extractServerPacket(packet);
if (!shouldSendPacket(serverPacket)) return;
controller.consumePacket(serverPacket);
}

View File

@ -5,18 +5,14 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
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.SendablePacket;
import net.minestom.server.network.packet.server.ServerPacket;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.net.SocketAddress;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@ -84,11 +80,8 @@ public abstract class PlayerConnection {
/**
* Serializes the packet and send it to the client.
* <p>
* Also responsible for executing {@link ConnectionManager#onPacketSend(ServerPacketConsumer)} consumers.
*
* @param packet the packet to send
* @see #shouldSendPacket(ServerPacket)
*/
public abstract void sendPacket(@NotNull SendablePacket packet);
@ -111,11 +104,6 @@ public abstract class PlayerConnection {
// Empty
}
protected boolean shouldSendPacket(@NotNull ServerPacket serverPacket) {
return player == null ||
PACKET_LISTENER_MANAGER.processServerPacket(serverPacket, Collections.singleton(player));
}
/**
* Gets the remote address of the client.
*

View File

@ -5,6 +5,8 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.adventure.MinestomAdventure;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.event.ListenerHandle;
import net.minestom.server.event.player.PlayerPacketOutEvent;
import net.minestom.server.extras.mojangAuth.MojangCrypt;
import net.minestom.server.network.ConnectionState;
import net.minestom.server.network.PacketProcessor;
@ -75,6 +77,8 @@ public class PlayerSocketConnection extends PlayerConnection {
private final AtomicReference<BinaryBuffer> tickBuffer = new AtomicReference<>(PooledBuffers.get());
private volatile BinaryBuffer cacheBuffer;
private final ListenerHandle<PlayerPacketOutEvent> outgoing = MinecraftServer.getGlobalEventHandler().getHandle(PlayerPacketOutEvent.class);
public PlayerSocketConnection(@NotNull Worker worker, @NotNull SocketChannel channel, SocketAddress remoteAddress) {
super();
this.worker = worker;
@ -346,12 +350,21 @@ public class PlayerSocketConnection extends PlayerConnection {
private void writePacketSync(SendablePacket packet, boolean compressed) {
if (!channel.isConnected()) return;
final Player player = getPlayer();
// Outgoing event
if (player != null && outgoing.hasListener()) {
final ServerPacket serverPacket = SendablePacket.extractServerPacket(packet);
outgoing.call(new PlayerPacketOutEvent(player, serverPacket));
}
// Write packet
if (packet instanceof ServerPacket serverPacket) {
writeServerPacketSync(serverPacket, compressed);
} else if (packet instanceof FramedPacket framedPacket) {
writeFramedPacketSync(framedPacket);
var buffer = framedPacket.body();
writeBufferSync0(buffer, 0, buffer.limit());
} else if (packet instanceof CachedPacket cachedPacket) {
writeBufferSync(cachedPacket.body());
var buffer = cachedPacket.body();
writeBufferSync0(buffer, buffer.position(), buffer.remaining());
} else if (packet instanceof LazyPacket lazyPacket) {
writeServerPacketSync(lazyPacket.packet(), compressed);
} else {
@ -360,7 +373,6 @@ public class PlayerSocketConnection extends PlayerConnection {
}
private void writeServerPacketSync(ServerPacket serverPacket, boolean compressed) {
if (!shouldSendPacket(serverPacket)) return;
final Player player = getPlayer();
if (player != null) {
if (MinestomAdventure.AUTOMATIC_COMPONENT_TRANSLATION && serverPacket instanceof ComponentHoldingServerPacket) {
@ -368,15 +380,17 @@ public class PlayerSocketConnection extends PlayerConnection {
GlobalTranslator.render(component, Objects.requireNonNullElseGet(player.getLocale(), MinestomAdventure::getDefaultLocale)));
}
}
writeBufferSync(PacketUtils.createFramedPacket(serverPacket, compressed));
var buffer = PacketUtils.createFramedPacket(serverPacket, compressed);
writeBufferSync0(buffer, 0, buffer.limit());
if (player == null) flushSync(); // Player is probably not logged yet
}
private void writeFramedPacketSync(FramedPacket framedPacket) {
writeBufferSync(framedPacket.body());
private void writeBufferSync(@NotNull ByteBuffer buffer, int index, int length) {
// TODO read buffer for outgoing event
writeBufferSync0(buffer, index, length);
}
private void writeBufferSync(@NotNull ByteBuffer buffer, int index, int length) {
private void writeBufferSync0(@NotNull ByteBuffer buffer, int index, int length) {
if (encrypted) { // Encryption support
ByteBuffer output = PooledBuffers.tempBuffer();
try {
@ -405,10 +419,6 @@ public class PlayerSocketConnection extends PlayerConnection {
}
}
private void writeBufferSync(@NotNull ByteBuffer buffer) {
writeBufferSync(buffer, buffer.position(), buffer.remaining());
}
public void flushSync() {
try {
if (!channel.isConnected()) throw new ClosedChannelException();

View File

@ -104,7 +104,6 @@ public final class PacketUtils {
public static void sendGroupedPacket(@NotNull Collection<Player> players, @NotNull ServerPacket packet,
@NotNull Predicate<Player> predicate) {
if (players.isEmpty()) return;
if (!MinecraftServer.getPacketListenerManager().processServerPacket(packet, players)) return;
// work out if the packet needs to be sent individually due to server-side translating
final SendablePacket sendablePacket = GROUPED_PACKET ? new CachedPacket(packet) : packet;
players.forEach(player -> {