Minestom/src/main/java/net/minestom/server/network/PacketProcessor.java

138 lines
5.9 KiB
Java

package net.minestom.server.network;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.network.netty.packet.InboundPacket;
import net.minestom.server.network.packet.client.ClientPlayPacket;
import net.minestom.server.network.packet.client.ClientPreplayPacket;
import net.minestom.server.network.packet.client.handler.ClientLoginPacketsHandler;
import net.minestom.server.network.packet.client.handler.ClientPlayPacketsHandler;
import net.minestom.server.network.packet.client.handler.ClientStatusPacketsHandler;
import net.minestom.server.network.packet.client.handshake.HandshakePacket;
import net.minestom.server.network.player.NettyPlayerConnection;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.Readable;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Responsible for processing client packets.
* <p>
* You can retrieve the different packet handlers per state (status/login/play)
* from the {@link net.minestom.server.network.packet.client.handler.ClientPacketsHandler} class.
* <p>
* Packet handlers are cached here and can be retrieved with {@link #getStatusPacketsHandler()}, {@link #getLoginPacketsHandler()}
* and {@link #getPlayPacketsHandler()}. The one to use depend on the type of packet you need to retrieve (the packet id 0 does not have
* the same meaning as it is a login or play packet).
*/
public final class PacketProcessor {
private final static Logger LOGGER = LoggerFactory.getLogger(PacketProcessor.class);
// Protocols state
private final ClientStatusPacketsHandler statusPacketsHandler;
private final ClientLoginPacketsHandler loginPacketsHandler;
private final ClientPlayPacketsHandler playPacketsHandler;
public PacketProcessor() {
this.statusPacketsHandler = new ClientStatusPacketsHandler();
this.loginPacketsHandler = new ClientLoginPacketsHandler();
this.playPacketsHandler = new ClientPlayPacketsHandler();
}
public void process(@NotNull NettyPlayerConnection playerConnection, @NotNull InboundPacket packet) {
// Increment packet count (checked in PlayerConnection#update)
if (MinecraftServer.getRateLimit() > 0) {
playerConnection.getPacketCounter().incrementAndGet();
}
final int packetId = packet.getPacketId();
BinaryReader binaryReader = new BinaryReader(packet.getBody());
final ConnectionState connectionState = playerConnection.getConnectionState();
if (connectionState == ConnectionState.UNKNOWN) {
// Should be handshake packet
if (packetId == 0) {
HandshakePacket handshakePacket = new HandshakePacket();
safeRead(playerConnection, handshakePacket, binaryReader);
handshakePacket.process(playerConnection);
}
return;
}
switch (connectionState) {
case PLAY:
final Player player = playerConnection.getPlayer();
ClientPlayPacket playPacket = (ClientPlayPacket) playPacketsHandler.getPacketInstance(packetId);
safeRead(playerConnection, playPacket, binaryReader);
assert player != null;
player.addPacketToQueue(playPacket);
break;
case LOGIN:
final ClientPreplayPacket loginPacket = (ClientPreplayPacket) loginPacketsHandler.getPacketInstance(packetId);
safeRead(playerConnection, loginPacket, binaryReader);
loginPacket.process(playerConnection);
break;
case STATUS:
final ClientPreplayPacket statusPacket = (ClientPreplayPacket) statusPacketsHandler.getPacketInstance(packetId);
safeRead(playerConnection, statusPacket, binaryReader);
statusPacket.process(playerConnection);
break;
}
}
/**
* Gets the handler for client status packets.
*
* @return the status packets handler
* @see <a href="https://wiki.vg/Protocol#Status">Status packets</a>
*/
public @NotNull ClientStatusPacketsHandler getStatusPacketsHandler() {
return statusPacketsHandler;
}
/**
* Gets the handler for client login packets.
*
* @return the status login handler
* @see <a href="https://wiki.vg/Protocol#Login">Login packets</a>
*/
public @NotNull ClientLoginPacketsHandler getLoginPacketsHandler() {
return loginPacketsHandler;
}
/**
* Gets the handler for client play packets.
*
* @return the play packets handler
* @see <a href="https://wiki.vg/Protocol#Play">Play packets</a>
*/
public @NotNull ClientPlayPacketsHandler getPlayPacketsHandler() {
return playPacketsHandler;
}
/**
* Calls {@link Readable#read(BinaryReader)} and catch all the exceptions to be printed using the packet processor logger.
*
* @param connection the connection who sent the packet
* @param readable the readable interface
* @param reader the buffer containing the packet
*/
private void safeRead(@NotNull PlayerConnection connection, @NotNull Readable readable, @NotNull BinaryReader reader) {
final int readableBytes = reader.available();
// Check if there is anything to read
if (readableBytes == 0) {
return;
}
try {
readable.read(reader);
} catch (Exception e) {
final Player player = connection.getPlayer();
final String username = player != null ? player.getUsername() : "null";
LOGGER.warn("Connection {} ({}) sent an unexpected packet.",
connection.getRemoteAddress(),
username);
MinecraftServer.getExceptionManager().handleException(e);
}
}
}