fix: change state before processing packet for state boundary packets

Fixes an issue where disconnects during the first phase of login would write a DisconnectPacket instead of LoginDisconnectPacket because the state was not yet updated to be login from handshake.
This commit is contained in:
mworzala 2024-10-31 07:52:14 -04:00 committed by Matt Worzala
parent 03856ccc21
commit 685dd152b7
3 changed files with 14 additions and 9 deletions

View File

@ -2106,7 +2106,8 @@ public class Player extends LivingEntity implements CommandSender, HoverEventSou
public void interpretPacketQueue() {
final PacketListenerManager manager = MinecraftServer.getPacketListenerManager();
// This method is NOT thread-safe
this.packets.drain(packet -> manager.processClientPacket(packet, playerConnection), ServerFlag.PLAYER_PACKET_PER_TICK);
this.packets.drain(packet -> manager.processClientPacket(packet, playerConnection,
getPlayerConnection().getConnectionState()), ServerFlag.PLAYER_PACKET_PER_TICK);
}
/**

View File

@ -107,8 +107,7 @@ public final class PacketListenerManager {
* @param connection the connection of the player who sent the packet
* @param <T> the packet type
*/
public <T extends ClientPacket> void processClientPacket(@NotNull T packet, @NotNull PlayerConnection connection) {
final ConnectionState state = connection.getConnectionState();
public <T extends ClientPacket> void processClientPacket(@NotNull T packet, @NotNull PlayerConnection connection, @NotNull ConnectionState state) {
final Class clazz = packet.getClass();
PacketPrePlayListenerConsumer<T> packetListenerConsumer = listeners[state.ordinal()].get(clazz);

View File

@ -136,10 +136,20 @@ public class PlayerSocketConnection extends PlayerConnection {
case PacketReading.Result.Success<ClientPacket> success -> {
for (PacketReading.ParsedPacket<ClientPacket> parsedPacket : success.packets()) {
final ClientPacket packet = parsedPacket.packet();
// Update connection state 'as we receive' the packet, aka before we send any responses
// from processing. This is important for disconnection during start of handshake.
final ConnectionState currState = getConnectionState();
final ConnectionState nextState = parsedPacket.nextState();
if (nextState != currState) {
setConnectionState(nextState);
}
try {
final boolean processImmediately = IMMEDIATE_PROCESS_PACKETS.contains(packet.getClass());
if (processImmediately) {
MinecraftServer.getPacketListenerManager().processClientPacket(packet, this);
// Interpret the packet using the connection state we received it.
MinecraftServer.getPacketListenerManager().processClientPacket(packet, this, currState);
} else {
// To be processed during the next player tick
final Player player = getPlayer();
@ -149,11 +159,6 @@ 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();