Fixed disconnecting players in the middle of a backend server reconfiguration (#1669)

This commit is contained in:
Adrian
2025-10-19 09:43:40 -05:00
committed by GitHub
parent 67b988e6d2
commit 02cf349075
3 changed files with 21 additions and 16 deletions

View File

@@ -257,7 +257,13 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
@Override
public boolean handle(DisconnectPacket packet) {
serverConn.disconnect();
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
// If the player receives a DisconnectPacket without a connection to a server in progress,
// it means that the backend server has kicked the player during reconfiguration
if (serverConn.getPlayer().getConnectionInFlight() != null) {
resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
} else {
serverConn.getPlayer().handleConnectionException(serverConn.getServer(), packet, true);
}
return true;
}

View File

@@ -165,7 +165,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
}
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) {
smc.setAutoReading(false);
clientPlaySessionHandler.doSwitch().thenAcceptAsync((unused) -> smc.setAutoReading(true), smc.eventLoop());
clientPlaySessionHandler.doSwitch().thenRunAsync(() -> smc.setAutoReading(true), smc.eventLoop());
} else {
// Initial login - the player is already in configuration state.
server.getEventManager().fireAndForget(new PlayerEnteredConfigurationEvent(player, serverConn));

View File

@@ -817,9 +817,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
createConnectionRequest(res.getServer(), previousConnection).connect()
.whenCompleteAsync((status, throwable) -> {
if (throwable != null) {
handleConnectionException(
status != null ? status.getAttemptedConnection() : res.getServer(), throwable,
true);
handleConnectionException(res.getServer(), throwable, true);
return;
}
@@ -1497,7 +1495,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
VelocityServerConnection con =
new VelocityServerConnection(vrs, previousServer, ConnectedPlayer.this, server);
connectionInFlight = con;
return con.connect().whenCompleteAsync((result, exception) -> this.resetIfInFlightIs(con),
return con.connect().whenCompleteAsync((result, exception) -> {
if (result != null && !result.isSuccessful() && !result.isSafe()) {
handleConnectionException(result.getAttemptedConnection(),
// The only way for the reason to be null is if the result is safe
DisconnectPacket.create(result.getReasonComponent().orElseThrow(),
getProtocolVersion(), connection.getState()), false);
}
this.resetIfInFlightIs(con);
},
connection.eventLoop());
}, connection.eventLoop());
});
@@ -1511,22 +1518,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
@Override
public CompletableFuture<Result> connect() {
return this.internalConnect().whenCompleteAsync((status, throwable) -> {
if (status != null && !status.isSuccessful()) {
if (!status.isSafe()) {
handleConnectionException(status.getAttemptedConnection(), throwable, false);
}
}
}, connection.eventLoop()).thenApply(x -> x);
return this.internalConnect().thenApply(x -> x);
}
@Override
public CompletableFuture<Boolean> connectWithIndication() {
return internalConnect().whenCompleteAsync((status, throwable) -> {
if (throwable != null) {
// TODO: The exception handling from this is not very good. Find a better way.
handleConnectionException(status != null ? status.getAttemptedConnection() : toConnect,
throwable, true);
handleConnectionException(toConnect, throwable, true);
return;
}