mirror of
https://github.com/Minestom/Minestom.git
synced 2025-02-09 08:51:38 +01:00
Handle connection state in reading
This commit is contained in:
parent
c092e7dd0b
commit
21b21005a2
@ -5,7 +5,6 @@ import net.minestom.server.event.EventDispatcher;
|
||||
import net.minestom.server.event.player.PlayerPacketEvent;
|
||||
import net.minestom.server.listener.*;
|
||||
import net.minestom.server.listener.common.*;
|
||||
import net.minestom.server.listener.preplay.ConfigListener;
|
||||
import net.minestom.server.listener.preplay.HandshakeListener;
|
||||
import net.minestom.server.listener.preplay.LoginListener;
|
||||
import net.minestom.server.listener.preplay.StatusListener;
|
||||
@ -56,8 +55,8 @@ public final class PacketListenerManager {
|
||||
setConfigurationListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
|
||||
setConfigurationListener(ClientPongPacket.class, (packet, player) -> {/* empty */});
|
||||
setConfigurationListener(ClientResourcePackStatusPacket.class, ResourcePackListener::listener);
|
||||
setConfigurationListener(ClientSelectKnownPacksPacket.class, ConfigListener::selectKnownPacks);
|
||||
setConfigurationListener(ClientFinishConfigurationPacket.class, ConfigListener::finishConfigListener);
|
||||
setConfigurationListener(ClientSelectKnownPacksPacket.class, LoginListener::selectKnownPacks);
|
||||
setConfigurationListener(ClientFinishConfigurationPacket.class, LoginListener::finishConfigListener);
|
||||
setListener(ConnectionState.CONFIGURATION, ClientCookieResponsePacket.class, CookieListener::handleCookieResponse);
|
||||
|
||||
setPlayListener(ClientKeepAlivePacket.class, KeepAliveListener::listener);
|
||||
|
@ -1,20 +0,0 @@
|
||||
package net.minestom.server.listener.preplay;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
|
||||
import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public final class ConfigListener {
|
||||
private static final ConnectionManager CONNECTION_MANAGER = MinecraftServer.getConnectionManager();
|
||||
|
||||
public static void selectKnownPacks(@NotNull ClientSelectKnownPacksPacket packet, @NotNull Player player) {
|
||||
player.getPlayerConnection().receiveKnownPacksResponse(packet.entries());
|
||||
}
|
||||
|
||||
public static void finishConfigListener(@NotNull ClientFinishConfigurationPacket packet, @NotNull Player player) {
|
||||
CONNECTION_MANAGER.transitionConfigToPlay(player);
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.extras.bungee.BungeeCordProxy;
|
||||
import net.minestom.server.network.ConnectionState;
|
||||
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
|
||||
import net.minestom.server.network.player.GameProfile;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
@ -40,9 +39,9 @@ public final class HandshakeListener {
|
||||
public static void listener(@NotNull ClientHandshakePacket packet, @NotNull PlayerConnection connection) {
|
||||
String address = packet.serverAddress();
|
||||
switch (packet.intent()) {
|
||||
case STATUS -> connection.setConnectionState(ConnectionState.STATUS);
|
||||
case STATUS -> {
|
||||
}
|
||||
case LOGIN -> {
|
||||
connection.setConnectionState(ConnectionState.LOGIN);
|
||||
if (packet.protocolVersion() != MinecraftServer.PROTOCOL_VERSION) {
|
||||
// Incorrect client version
|
||||
connection.kick(INVALID_VERSION_TEXT);
|
||||
@ -114,9 +113,8 @@ public final class HandshakeListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
case TRANSFER -> {
|
||||
throw new UnsupportedOperationException("Transfer intent is not supported in HandshakeListener");
|
||||
}
|
||||
case TRANSFER ->
|
||||
throw new UnsupportedOperationException("Transfer intent is not supported in HandshakeListener");
|
||||
default -> {
|
||||
// Unexpected error
|
||||
}
|
||||
|
@ -11,6 +11,8 @@ import net.minestom.server.extras.bungee.BungeeCordProxy;
|
||||
import net.minestom.server.extras.mojangAuth.MojangCrypt;
|
||||
import net.minestom.server.extras.velocity.VelocityProxy;
|
||||
import net.minestom.server.network.NetworkBuffer;
|
||||
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
|
||||
import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket;
|
||||
import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
|
||||
import net.minestom.server.network.packet.client.login.ClientLoginAcknowledgedPacket;
|
||||
import net.minestom.server.network.packet.client.login.ClientLoginPluginResponsePacket;
|
||||
@ -204,6 +206,14 @@ public final class LoginListener {
|
||||
executeConfig(player, false);
|
||||
}
|
||||
|
||||
public static void selectKnownPacks(@NotNull ClientSelectKnownPacksPacket packet, @NotNull Player player) {
|
||||
player.getPlayerConnection().receiveKnownPacksResponse(packet.entries());
|
||||
}
|
||||
|
||||
public static void finishConfigListener(@NotNull ClientFinishConfigurationPacket packet, @NotNull Player player) {
|
||||
MinecraftServer.getConnectionManager().transitionConfigToPlay(player);
|
||||
}
|
||||
|
||||
private static void enterConfig(PlayerConnection connection, GameProfile gameProfile) {
|
||||
gameProfile = MinecraftServer.getConnectionManager().transitionLoginToConfig(connection, gameProfile);
|
||||
if (connection instanceof PlayerSocketConnection socketConnection) {
|
||||
|
@ -222,13 +222,9 @@ public final class ConnectionManager {
|
||||
configurationPlayers.add(player);
|
||||
keepAlivePlayers.add(player);
|
||||
}
|
||||
|
||||
final PlayerConnection connection = player.getPlayerConnection();
|
||||
connection.setConnectionState(ConnectionState.CONFIGURATION);
|
||||
|
||||
player.sendPacket(PluginMessagePacket.brandPacket(MinecraftServer.getBrandName()));
|
||||
// Request known packs immediately, but don't wait for the response until required (sending registry data).
|
||||
final var knownPacksFuture = connection.requestKnownPacks(List.of(SelectKnownPacksPacket.MINECRAFT_CORE));
|
||||
final var knownPacksFuture = player.getPlayerConnection().requestKnownPacks(List.of(SelectKnownPacksPacket.MINECRAFT_CORE));
|
||||
|
||||
var event = new AsyncPlayerConfigurationEvent(player, isFirstConfig);
|
||||
EventDispatcher.call(event);
|
||||
@ -329,7 +325,6 @@ public final class ConnectionManager {
|
||||
public void updateWaitingPlayers() {
|
||||
this.waitingPlayers.drain(player -> {
|
||||
if (!player.isOnline()) return; // Player disconnected while in queued to join
|
||||
player.getPlayerConnection().setConnectionState(ConnectionState.PLAY);
|
||||
playPlayers.add(player);
|
||||
keepAlivePlayers.add(player);
|
||||
|
||||
|
@ -36,15 +36,16 @@ public final class PacketReading {
|
||||
* At least one packet was read.
|
||||
* The buffer may still contain half-read packets and should therefore be compacted for next read.
|
||||
*/
|
||||
record Success<T>(List<T> packets, ConnectionState newState) implements Result<T> {
|
||||
record Success<T>(List<ParsedPacket<T>> packets) implements Result<T> {
|
||||
public Success {
|
||||
if (packets.isEmpty()) {
|
||||
throw new IllegalArgumentException("Empty packets");
|
||||
}
|
||||
packets = List.copyOf(packets);
|
||||
}
|
||||
|
||||
public Success(T packet, ConnectionState newState) {
|
||||
this(List.of(packet), newState);
|
||||
public Success(ParsedPacket<T> packet) {
|
||||
this(List.of(packet));
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +68,9 @@ public final class PacketReading {
|
||||
}
|
||||
}
|
||||
|
||||
public record ParsedPacket<T>(ConnectionState nextState, T packet) {
|
||||
}
|
||||
|
||||
public static Result<ClientPacket> readClients(
|
||||
@NotNull NetworkBuffer buffer,
|
||||
@NotNull ConnectionState state,
|
||||
@ -90,7 +94,7 @@ public final class PacketReading {
|
||||
@NotNull BiFunction<T, ConnectionState, ConnectionState> stateUpdater,
|
||||
boolean compressed
|
||||
) throws DataFormatException {
|
||||
List<T> packets = new ArrayList<>();
|
||||
List<ParsedPacket<T>> packets = new ArrayList<>();
|
||||
readLoop:
|
||||
while (buffer.readableBytes() > 0) {
|
||||
final Result<T> result = readPacket(buffer, parser, state, stateUpdater, compressed);
|
||||
@ -98,18 +102,19 @@ public final class PacketReading {
|
||||
switch (result) {
|
||||
case Result.Success<T> success -> {
|
||||
assert success.packets().size() == 1;
|
||||
packets.add(success.packets().getFirst());
|
||||
state = success.newState();
|
||||
final ParsedPacket<T> parsedPacket = success.packets().getFirst();
|
||||
packets.add(parsedPacket);
|
||||
state = parsedPacket.nextState();
|
||||
}
|
||||
case Result.Empty<T> ignored -> {
|
||||
break readLoop;
|
||||
}
|
||||
case Result.Failure<T> failure -> {
|
||||
return packets.isEmpty() ? failure : new Result.Success<>(packets, state);
|
||||
return packets.isEmpty() ? failure : new Result.Success<>(packets);
|
||||
}
|
||||
}
|
||||
}
|
||||
return !packets.isEmpty() ? new Result.Success<>(packets, state) : EMPTY_CLIENT_PACKET;
|
||||
return !packets.isEmpty() ? new Result.Success<>(packets) : EMPTY_CLIENT_PACKET;
|
||||
}
|
||||
|
||||
public static Result<ClientPacket> readClient(
|
||||
@ -172,7 +177,7 @@ public final class PacketReading {
|
||||
final T packet = readFramedPacket(buffer, registry, compressed);
|
||||
final ConnectionState nextState = stateUpdater.apply(packet, state);
|
||||
buffer.index(readerEnd, writerEnd);
|
||||
return new Result.Success<>(packet, nextState);
|
||||
return new Result.Success<>(new ParsedPacket<>(nextState, packet));
|
||||
}
|
||||
|
||||
private static <T> T readFramedPacket(NetworkBuffer buffer,
|
||||
|
@ -18,6 +18,7 @@ import net.minestom.server.network.packet.client.ClientPacket;
|
||||
import net.minestom.server.network.packet.client.common.ClientCookieResponsePacket;
|
||||
import net.minestom.server.network.packet.client.common.ClientKeepAlivePacket;
|
||||
import net.minestom.server.network.packet.client.common.ClientPingRequestPacket;
|
||||
import net.minestom.server.network.packet.client.configuration.ClientFinishConfigurationPacket;
|
||||
import net.minestom.server.network.packet.client.configuration.ClientSelectKnownPacksPacket;
|
||||
import net.minestom.server.network.packet.client.handshake.ClientHandshakePacket;
|
||||
import net.minestom.server.network.packet.client.login.ClientEncryptionResponsePacket;
|
||||
@ -64,7 +65,8 @@ public class PlayerSocketConnection extends PlayerConnection {
|
||||
ClientLoginPluginResponsePacket.class,
|
||||
ClientSelectKnownPacksPacket.class, // Immediate answer to server request on config
|
||||
ClientConfigurationAckPacket.class, // Handle config state
|
||||
ClientLoginAcknowledgedPacket.class // Handle config state
|
||||
ClientLoginAcknowledgedPacket.class, // Handle config state
|
||||
ClientFinishConfigurationPacket.class // Enter play state
|
||||
);
|
||||
|
||||
private final SocketChannel channel;
|
||||
@ -116,12 +118,13 @@ public class PlayerSocketConnection extends PlayerConnection {
|
||||
|
||||
private void processPackets(NetworkBuffer readBuffer, PacketParser<ClientPacket> packetParser) {
|
||||
// Read all packets
|
||||
final ConnectionState startingState = getConnectionState();
|
||||
final PacketReading.Result<ClientPacket> result;
|
||||
try {
|
||||
result = PacketReading.readPackets(
|
||||
readBuffer,
|
||||
packetParser,
|
||||
getConnectionState(), PacketVanilla::nextClientState,
|
||||
startingState, PacketVanilla::nextClientState,
|
||||
compression()
|
||||
);
|
||||
} catch (DataFormatException e) {
|
||||
@ -131,7 +134,8 @@ public class PlayerSocketConnection extends PlayerConnection {
|
||||
}
|
||||
switch (result) {
|
||||
case PacketReading.Result.Success<ClientPacket> success -> {
|
||||
for (ClientPacket packet : success.packets()) {
|
||||
for (PacketReading.ParsedPacket<ClientPacket> parsedPacket : success.packets()) {
|
||||
final ClientPacket packet = parsedPacket.packet();
|
||||
try {
|
||||
final boolean processImmediately = IMMEDIATE_PROCESS_PACKETS.contains(packet.getClass());
|
||||
if (processImmediately) {
|
||||
@ -145,6 +149,11 @@ public class PlayerSocketConnection extends PlayerConnection {
|
||||
} catch (Exception e) {
|
||||
MinecraftServer.getExceptionManager().handleException(e);
|
||||
}
|
||||
// Update state to properly interpret next packet
|
||||
final ConnectionState nextState = parsedPacket.nextState();
|
||||
if (nextState != getConnectionState()) {
|
||||
setConnectionState(nextState);
|
||||
}
|
||||
}
|
||||
// Compact in case of incomplete read
|
||||
readBuffer.compact();
|
||||
|
@ -61,7 +61,7 @@ public class SendablePacketTest {
|
||||
return;
|
||||
}
|
||||
assertEquals(1, success.packets().size());
|
||||
var readPacket = success.packets().getFirst();
|
||||
ClientPacket readPacket = success.packets().getFirst().packet();
|
||||
assertEquals(packet, readPacket);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ public class SocketReadTest {
|
||||
if (!(readResult instanceof PacketReading.Result.Success<ClientPacket> success)) {
|
||||
throw new AssertionError("Expected a success result, got " + readResult);
|
||||
}
|
||||
var packets = success.packets();
|
||||
List<ClientPacket> packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList();
|
||||
assertEquals(List.of(packet), packets);
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ public class SocketReadTest {
|
||||
if (!(readResult instanceof PacketReading.Result.Success<ClientPacket> success)) {
|
||||
throw new AssertionError("Expected a success result, got " + readResult);
|
||||
}
|
||||
var packets = success.packets();
|
||||
List<ClientPacket> packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList();
|
||||
assertEquals(List.of(packet, packet), packets);
|
||||
}
|
||||
|
||||
@ -63,7 +63,7 @@ public class SocketReadTest {
|
||||
if (!(readResult instanceof PacketReading.Result.Success<ClientPacket> success)) {
|
||||
throw new AssertionError("Expected a success result, got " + readResult);
|
||||
}
|
||||
var packets = success.packets();
|
||||
List<ClientPacket> packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList();
|
||||
assertEquals(List.of(packet), packets);
|
||||
|
||||
readResult = PacketReading.readClients(buffer, ConnectionState.PLAY, compressed);
|
||||
@ -87,7 +87,7 @@ public class SocketReadTest {
|
||||
if (!(readResult instanceof PacketReading.Result.Success<ClientPacket> success)) {
|
||||
throw new AssertionError("Expected a success result, got " + readResult);
|
||||
}
|
||||
var packets = success.packets();
|
||||
List<ClientPacket> packets = success.packets().stream().map(PacketReading.ParsedPacket::packet).toList();
|
||||
assertEquals(1, buffer.readableBytes());
|
||||
|
||||
assertEquals(List.of(packet), packets);
|
||||
|
@ -46,7 +46,6 @@ final class TestConnectionImpl implements TestConnection {
|
||||
throw new IllegalStateException("Already connected");
|
||||
}
|
||||
|
||||
playerConnection.setConnectionState(ConnectionState.LOGIN);
|
||||
final GameProfile gameProfile = new GameProfile(UUID.randomUUID(), "RandName");
|
||||
var player = process.connection().createPlayer(playerConnection, gameProfile);
|
||||
player.eventNode().addListener(AsyncPlayerConfigurationEvent.class, event -> {
|
||||
@ -65,6 +64,7 @@ final class TestConnectionImpl implements TestConnection {
|
||||
future.complete(player);
|
||||
});
|
||||
future.join();
|
||||
playerConnection.setConnectionState(ConnectionState.PLAY);
|
||||
process.connection().updateWaitingPlayers();
|
||||
return player;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user