diff --git a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnterConfigurationEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnterConfigurationEvent.java index f0148ef5ac..05d6c2af02 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnterConfigurationEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnterConfigurationEvent.java @@ -15,7 +15,9 @@ /** * This event is executed when a player is about to enter the configuration state. * It is not called for the initial configuration of a player after login. - *

Velocity will wait for this event before asking the client to enter configuration state.

+ *

Velocity will wait for this event before asking the client to enter configuration state. + * However due to backend server being unable to keep the connection alive during state changes, + * Velocity will only wait for a maximum of 5 seconds.

* * @param player The player who is about to enter configuration state. * @param server The server that wants to reconfigure the player. diff --git a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishConfigurationEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishConfigurationEvent.java index 6b924d445f..50df5a8abe 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishConfigurationEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishConfigurationEvent.java @@ -15,9 +15,9 @@ /** * This event is executed when a player is about to finish the configuration state. *

Velocity will wait for this event before asking the client to finish the configuration state. - * However due to backend server being unable to keep the connection alive for more than 15 seconds, + * However due to backend server being unable to keep the connection alive during state changes, * Velocity will only wait for a maximum of 5 seconds. If you need to hold a player in configuration - * state it is recommended to use the {@link PlayerConfigurationEvent}.

+ * state, use the {@link PlayerConfigurationEvent}.

* * @param player The player who is about to finish the configuration phase. * @param server The server that has (re-)configured the player. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java index 008eaaba5b..7d232b09f8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientConfigSessionHandler.java @@ -244,14 +244,14 @@ public CompletableFuture handleBackendFinishUpdate(VelocityServerConnectio smc.write(brandPacket); } - callConfigurationEvent().thenRun(() -> { - server.getEventManager().fire(new PlayerFinishConfigurationEvent(player, serverConn)) - .completeOnTimeout(null, 5, TimeUnit.SECONDS).thenRunAsync(() -> { - player.getConnection().write(FinishedUpdatePacket.INSTANCE); - player.getConnection().getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.PLAY); - server.getEventManager().fireAndForget(new PlayerFinishedConfigurationEvent(player, serverConn)); - }, player.getConnection().eventLoop()); - }).exceptionally(ex -> { + callConfigurationEvent().thenCompose(v -> { + return server.getEventManager().fire(new PlayerFinishConfigurationEvent(player, serverConn)) + .completeOnTimeout(null, 5, TimeUnit.SECONDS); + }).thenRunAsync(() -> { + player.getConnection().write(FinishedUpdatePacket.INSTANCE); + player.getConnection().getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.PLAY); + server.getEventManager().fireAndForget(new PlayerFinishedConfigurationEvent(player, serverConn)); + }, player.getConnection().eventLoop()).exceptionally(ex -> { logger.error("Error finishing configuration state:", ex); return null; }); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java index b855b54c93..11f6b52982 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ConnectedPlayer.java @@ -1274,15 +1274,16 @@ private boolean sendKeepAliveToBackend(final @Nullable VelocityServerConnection * Switches the connection to the client into config state. */ public void switchToConfigState() { - server.getEventManager().fire(new PlayerEnterConfigurationEvent(this, getConnectionInFlightOrConnectedServer())).thenRunAsync(() -> { - connection.write(StartUpdatePacket.INSTANCE); - connection.getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.CONFIG); - // Make sure we don't send any play packets to the player after update start - connection.addPlayPacketQueueHandler(); - }, connection.eventLoop()).exceptionally((ex) -> { - logger.error("Error switching player connection to config state", ex); - return null; - }); + server.getEventManager().fire(new PlayerEnterConfigurationEvent(this, getConnectionInFlightOrConnectedServer())) + .completeOnTimeout(null, 5, TimeUnit.SECONDS).thenRunAsync(() -> { + connection.write(StartUpdatePacket.INSTANCE); + connection.getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.CONFIG); + // Make sure we don't send any play packets to the player after update start + connection.addPlayPacketQueueHandler(); + }, connection.eventLoop()).exceptionally((ex) -> { + logger.error("Error switching player connection to config state", ex); + return null; + }); } /**