13
0
geforkt von Mirrors/Velocity

Update Velocity (might fix Command problems) and fix PluginMessages... #4

Zusammengeführt
Lixfel hat 32 Commits von fix-pluginmessages nach master 2024-08-20 08:14:12 +02:00 zusammengeführt
10 geänderte Dateien mit 173 neuen und 95 gelöschten Zeilen
Nur Änderungen aus Commit 6073f698e2 werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -0,0 +1,26 @@
/*
* Copyright (C) 2024 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.event.player.configuration;
import com.velocitypowered.api.event.annotation.AwaitingEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import org.jetbrains.annotations.NotNull;
/**
* This event is executed when a player entered the configuration state and can be configured by Velocity.
* <p>Velocity will wait for this event before continuing/ending the configuration state.</p>
*
* @param player The player who can be configured.
* @param server The server that is currently configuring the player.
* @since 3.3.0
* @sinceMinecraft 1.20.2
*/
@AwaitingEvent
public record PlayerConfigurationEvent(@NotNull Player player, ServerConnection server) {
}

Datei anzeigen

@ -7,21 +7,23 @@
package com.velocitypowered.api.event.player.configuration; package com.velocitypowered.api.event.player.configuration;
import com.velocitypowered.api.network.ProtocolState; import com.velocitypowered.api.event.annotation.AwaitingEvent;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* This event is executed when a player with version 1.20.2 or higher enters the configuration phase. * This event is executed when a player is about to enter the configuration state.
* <p>From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed, * It is <b>not</b> called for the initial configuration of a player after login.
* the {@linkplain Player#getProtocolState()} method is guaranteed * <p>Velocity will wait for this event before asking the client to enter configuration state.
* to return {@link ProtocolState#CONFIGURATION}.</p> * 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.</p>
* *
* @param player The player that has entered the configuration phase. * @param player The player who is about to enter configuration state.
* @param server The server that will now (re-)configure the player. * @param server The server that wants to reconfigure the player.
* @since 3.3.0 * @since 3.3.0
* @sinceMinecraft 1.20.2 * @sinceMinecraft 1.20.2
*/ */
@AwaitingEvent
public record PlayerEnterConfigurationEvent(@NotNull Player player, ServerConnection server) { public record PlayerEnterConfigurationEvent(@NotNull Player player, ServerConnection server) {
} }

Datei anzeigen

@ -0,0 +1,27 @@
/*
* Copyright (C) 2024 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/
package com.velocitypowered.api.event.player.configuration;
import com.velocitypowered.api.network.ProtocolState;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection;
import org.jetbrains.annotations.NotNull;
/**
* This event is executed when a player has entered the configuration state.
* <p>From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed,
* the {@linkplain Player#getProtocolState()} method is guaranteed
* to return {@link ProtocolState#CONFIGURATION}.</p>
*
* @param player The player who has entered the configuration state.
* @param server The server that will now (re-)configure the player.
* @since 3.3.0
* @sinceMinecraft 1.20.2
*/
public record PlayerEnteredConfigurationEvent(@NotNull Player player, ServerConnection server) {
}

Datei anzeigen

@ -13,11 +13,14 @@ import com.velocitypowered.api.proxy.ServerConnection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* This event is executed when the player is about to finish the Configuration state. * This event is executed when a player is about to finish the configuration state.
* <p>Velocity will wait for this event to finish the configuration phase on the client.</p> * <p>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 during state changes,
* Velocity will only wait for a maximum of 5 seconds. If you need to hold a player in configuration
* state, use the {@link PlayerConfigurationEvent}.</p>
* *
* @param player The player who is about to complete the configuration phase. * @param player The player who is about to finish the configuration phase.
* @param server The server that is currently (re-)configuring the player. * @param server The server that has (re-)configured the player.
* @since 3.3.0 * @since 3.3.0
* @sinceMinecraft 1.20.2 * @sinceMinecraft 1.20.2
*/ */

Datei anzeigen

@ -13,11 +13,11 @@ import com.velocitypowered.api.proxy.ServerConnection;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* Event executed when a player of version 1.20.2 or higher finishes the Configuration state. * This event is executed when a player has finished the configuration state.
* <p>From this moment on, the {@link Player#getProtocolState()} method * <p>From this moment on, the {@link Player#getProtocolState()} method
* will return {@link ProtocolState#PLAY}.</p> * will return {@link ProtocolState#PLAY}.</p>
* *
* @param player The player who has completed the Configuration state * @param player The player who has finished the configuration state.
* @param server The server that has (re-)configured the player. * @param server The server that has (re-)configured the player.
* @since 3.3.0 * @since 3.3.0
* @sinceMinecraft 1.20.2 * @sinceMinecraft 1.20.2

Datei anzeigen

@ -19,6 +19,7 @@ package com.velocitypowered.proxy.connection.backend;
import com.velocitypowered.api.event.player.CookieRequestEvent; import com.velocitypowered.api.event.player.CookieRequestEvent;
import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent; import com.velocitypowered.api.event.player.ServerLoginPluginMessageEvent;
import com.velocitypowered.api.event.player.configuration.PlayerEnteredConfigurationEvent;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
@ -142,10 +143,8 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(ServerLoginSuccessPacket packet) { public boolean handle(ServerLoginSuccessPacket packet) {
if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN if (server.getConfiguration().getPlayerInfoForwardingMode() == PlayerInfoForwarding.MODERN && !informationForwarded) {
&& !informationForwarded) { resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE, serverConn.getServer()));
resultFuture.complete(ConnectionRequestResults.forDisconnect(MODERN_IP_FORWARDING_FAILURE,
serverConn.getServer()));
serverConn.disconnect(); serverConn.disconnect();
return true; return true;
} }
@ -156,12 +155,10 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
// Move into the PLAY phase. // Move into the PLAY phase.
MinecraftConnection smc = serverConn.ensureConnected(); MinecraftConnection smc = serverConn.ensureConnected();
if (smc.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) { if (smc.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
smc.setActiveSessionHandler(StateRegistry.PLAY, smc.setActiveSessionHandler(StateRegistry.PLAY, new TransitionSessionHandler(server, serverConn, resultFuture));
new TransitionSessionHandler(server, serverConn, resultFuture));
} else { } else {
smc.write(new LoginAcknowledgedPacket()); smc.write(new LoginAcknowledgedPacket());
smc.setActiveSessionHandler(StateRegistry.CONFIG, smc.setActiveSessionHandler(StateRegistry.CONFIG, new ConfigSessionHandler(server, serverConn, resultFuture));
new ConfigSessionHandler(server, serverConn, resultFuture));
ConnectedPlayer player = serverConn.getPlayer(); ConnectedPlayer player = serverConn.getPlayer();
if (player.getClientSettingsPacket() != null) { if (player.getClientSettingsPacket() != null) {
smc.write(player.getClientSettingsPacket()); smc.write(player.getClientSettingsPacket());
@ -169,6 +166,9 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) { if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) {
smc.setAutoReading(false); smc.setAutoReading(false);
clientPlaySessionHandler.doSwitch().thenAcceptAsync((unused) -> smc.setAutoReading(true), smc.eventLoop()); clientPlaySessionHandler.doSwitch().thenAcceptAsync((unused) -> smc.setAutoReading(true), smc.eventLoop());
} else {
// Initial login - the player is already in configuration state.
server.getEventManager().fireAndForget(new PlayerEnteredConfigurationEvent(player, serverConn));
} }
} }

Datei anzeigen

@ -178,14 +178,14 @@ public class AuthSessionHandler implements MinecraftSessionHandler {
inbound.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_data")); inbound.disconnect(Component.translatable("multiplayer.disconnect.invalid_player_data"));
} else { } else {
loginState = State.ACKNOWLEDGED; loginState = State.ACKNOWLEDGED;
mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, mcConnection.setActiveSessionHandler(StateRegistry.CONFIG, new ClientConfigSessionHandler(server, connectedPlayer));
new ClientConfigSessionHandler(server, connectedPlayer));
server.getEventManager().fire(new PostLoginEvent(connectedPlayer)) server.getEventManager().fire(new PostLoginEvent(connectedPlayer)).thenCompose(ignored -> {
.thenCompose((ignored) -> connectToInitialServer(connectedPlayer)).exceptionally((ex) -> { return connectToInitialServer(connectedPlayer);
logger.error("Exception while connecting {} to initial server", connectedPlayer, ex); }).exceptionally((ex) -> {
return null; logger.error("Exception while connecting {} to initial server", connectedPlayer, ex);
}); return null;
});
} }
return true; return true;
} }
@ -224,8 +224,7 @@ public class AuthSessionHandler implements MinecraftSessionHandler {
player.disconnect0(reason.get(), true); player.disconnect0(reason.get(), true);
} else { } else {
if (!server.registerConnection(player)) { if (!server.registerConnection(player)) {
player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), player.disconnect0(Component.translatable("velocity.error.already-connected-proxy"), true);
true);
return; return;
} }
@ -238,13 +237,13 @@ public class AuthSessionHandler implements MinecraftSessionHandler {
loginState = State.SUCCESS_SENT; loginState = State.SUCCESS_SENT;
if (inbound.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) { if (inbound.getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
loginState = State.ACKNOWLEDGED; loginState = State.ACKNOWLEDGED;
mcConnection.setActiveSessionHandler(StateRegistry.PLAY, mcConnection.setActiveSessionHandler(StateRegistry.PLAY, new InitialConnectSessionHandler(player, server));
new InitialConnectSessionHandler(player, server)); server.getEventManager().fire(new PostLoginEvent(player)).thenCompose((ignored) -> {
server.getEventManager().fire(new PostLoginEvent(player)) return connectToInitialServer(player);
.thenCompose((ignored) -> connectToInitialServer(player)).exceptionally((ex) -> { }).exceptionally((ex) -> {
logger.error("Exception while connecting {} to initial server", player, ex); logger.error("Exception while connecting {} to initial server", player, ex);
return null; return null;
}); });
} }
} }
}, mcConnection.eventLoop()).exceptionally((ex) -> { }, mcConnection.eventLoop()).exceptionally((ex) -> {

Datei anzeigen

@ -19,6 +19,7 @@ package com.velocitypowered.proxy.connection.client;
import com.velocitypowered.api.event.player.CookieReceiveEvent; import com.velocitypowered.api.event.player.CookieReceiveEvent;
import com.velocitypowered.api.event.player.PlayerClientBrandEvent; import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
import com.velocitypowered.api.event.player.configuration.PlayerConfigurationEvent;
import com.velocitypowered.api.event.player.configuration.PlayerFinishConfigurationEvent; import com.velocitypowered.api.event.player.configuration.PlayerFinishConfigurationEvent;
import com.velocitypowered.api.event.player.configuration.PlayerFinishedConfigurationEvent; import com.velocitypowered.api.event.player.configuration.PlayerFinishedConfigurationEvent;
import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.VelocityServer;
@ -48,8 +49,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Handles the client config stage. * Handles the client config stage.
@ -61,6 +60,7 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
private final ConnectedPlayer player; private final ConnectedPlayer player;
private String brandChannel = null; private String brandChannel = null;
private CompletableFuture<?> configurationFuture;
private CompletableFuture<Void> configSwitchFuture; private CompletableFuture<Void> configSwitchFuture;
/** /**
@ -81,11 +81,7 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(final KeepAlivePacket packet) { public boolean handle(final KeepAlivePacket packet) {
final VelocityServerConnection serverConnection = player.getConnectedServer(); player.forwardKeepAlive(packet);
if (!this.sendKeepAliveToBackend(serverConnection, packet)) {
final VelocityServerConnection connectionInFlight = player.getConnectionInFlight();
this.sendKeepAliveToBackend(connectionInFlight, packet);
}
return true; return true;
} }
@ -106,8 +102,7 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(FinishedUpdatePacket packet) { public boolean handle(FinishedUpdatePacket packet) {
player.getConnection() player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, new ClientPlaySessionHandler(server, player));
.setActiveSessionHandler(StateRegistry.PLAY, new ClientPlaySessionHandler(server, player));
configSwitchFuture.complete(null); configSwitchFuture.complete(null);
return true; return true;
@ -141,12 +136,14 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(KnownPacksPacket packet) { public boolean handle(KnownPacksPacket packet) {
if (player.getConnectionInFlight() != null) { callConfigurationEvent().thenRun(() -> {
player.getConnectionInFlight().ensureConnected().write(packet); player.getConnectionInFlightOrConnectedServer().ensureConnected().write(packet);
return true; }).exceptionally(ex -> {
} logger.error("Error forwarding known packs response to backend:", ex);
return null;
});
return false; return true;
} }
@Override @Override
@ -209,26 +206,25 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
@Override @Override
public void exception(Throwable throwable) { public void exception(Throwable throwable) {
player.disconnect( player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED));
Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED));
} }
private boolean sendKeepAliveToBackend( /**
final @Nullable VelocityServerConnection serverConnection, * Calls the {@link PlayerConfigurationEvent}.
final @NotNull KeepAlivePacket packet * For 1.20.5+ backends this is done when the client responds to
) { * the known packs request. The response is delayed until the event
if (serverConnection != null) { * has been called.
final Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId()); * For 1.20.2-1.20.4 servers this is done when the client acknowledges
if (sentTime != null) { * the end of the configuration.
final MinecraftConnection smc = serverConnection.getConnection(); * This is handled differently because for 1.20.5+ servers can't keep
if (smc != null) { * their connection alive between states and older servers don't have
player.setPing(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sentTime)); * the known packs transaction.
smc.write(packet); */
return true; private CompletableFuture<?> callConfigurationEvent() {
} if (configurationFuture != null) {
} return configurationFuture;
} }
return false; return configurationFuture = server.getEventManager().fire(new PlayerConfigurationEvent(player, player.getConnectionInFlightOrConnectedServer()));
} }
/** /**
@ -248,11 +244,17 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler {
smc.write(brandPacket); smc.write(brandPacket);
} }
server.getEventManager().fire(new PlayerFinishConfigurationEvent(player, serverConn)).thenAcceptAsync(event -> { callConfigurationEvent().thenCompose(v -> {
return server.getEventManager().fire(new PlayerFinishConfigurationEvent(player, serverConn))
.completeOnTimeout(null, 5, TimeUnit.SECONDS);
}).thenRunAsync(() -> {
player.getConnection().write(FinishedUpdatePacket.INSTANCE); player.getConnection().write(FinishedUpdatePacket.INSTANCE);
player.getConnection().getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.PLAY); player.getConnection().getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.PLAY);
server.getEventManager().fireAndForget(new PlayerFinishedConfigurationEvent(player, serverConn)); server.getEventManager().fireAndForget(new PlayerFinishedConfigurationEvent(player, serverConn));
}, player.getConnection().eventLoop()); }, player.getConnection().eventLoop()).exceptionally(ex -> {
logger.error("Error finishing configuration state:", ex);
return null;
});
return configSwitchFuture; return configSwitchFuture;
} }

Datei anzeigen

@ -27,7 +27,7 @@ import com.velocitypowered.api.event.player.CookieReceiveEvent;
import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent; import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent;
import com.velocitypowered.api.event.player.PlayerClientBrandEvent; import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
import com.velocitypowered.api.event.player.TabCompleteEvent; import com.velocitypowered.api.event.player.TabCompleteEvent;
import com.velocitypowered.api.event.player.configuration.PlayerEnterConfigurationEvent; import com.velocitypowered.api.event.player.configuration.PlayerEnteredConfigurationEvent;
import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier; import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier; import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
@ -86,7 +86,6 @@ import java.util.Queue;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
@ -178,17 +177,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
@Override @Override
public boolean handle(KeepAlivePacket packet) { public boolean handle(KeepAlivePacket packet) {
final VelocityServerConnection serverConnection = player.getConnectedServer(); player.forwardKeepAlive(packet);
if (serverConnection != null) {
final Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId());
if (sentTime != null) {
final MinecraftConnection smc = serverConnection.getConnection();
if (smc != null) {
player.setPing(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sentTime));
smc.write(packet);
}
}
}
return true; return true;
} }
@ -408,7 +397,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
// Complete client switch // Complete client switch
player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG); player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG);
VelocityServerConnection serverConnection = player.getConnectedServer(); VelocityServerConnection serverConnection = player.getConnectedServer();
server.getEventManager().fireAndForget(new PlayerEnterConfigurationEvent(player, serverConnection)); server.getEventManager().fireAndForget(new PlayerEnteredConfigurationEvent(player, serverConnection));
if (serverConnection != null) { if (serverConnection != null) {
MinecraftConnection smc = serverConnection.ensureConnected(); MinecraftConnection smc = serverConnection.ensureConnected();
CompletableFuture.runAsync(() -> { CompletableFuture.runAsync(() -> {

Datei anzeigen

@ -111,6 +111,7 @@ import java.util.UUID;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException; import java.util.concurrent.CompletionException;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import net.kyori.adventure.audience.MessageType; import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.bossbar.BossBar; import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.identity.Identity; import net.kyori.adventure.identity.Identity;
@ -634,6 +635,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
return connectionInFlight; return connectionInFlight;
} }
public VelocityServerConnection getConnectionInFlightOrConnectedServer() {
return connectionInFlight != null ? connectionInFlight : connectedServer;
}
public void resetInFlightConnection() { public void resetInFlightConnection() {
connectionInFlight = null; connectionInFlight = null;
} }
@ -1239,21 +1244,46 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
} }
} }
/**
* Forwards the keep alive packet to the backend server it belongs to.
* This is either the connection in flight or the connected server.
*/
public boolean forwardKeepAlive(final KeepAlivePacket packet) {
if (!this.sendKeepAliveToBackend(connectedServer, packet)) {
return this.sendKeepAliveToBackend(connectionInFlight, packet);
}
return false;
}
private boolean sendKeepAliveToBackend(final @Nullable VelocityServerConnection serverConnection, final @NotNull KeepAlivePacket packet) {
if (serverConnection != null) {
final Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId());
if (sentTime != null) {
final MinecraftConnection smc = serverConnection.getConnection();
if (smc != null) {
setPing(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sentTime));
smc.write(packet);
return true;
}
}
}
return false;
}
/** /**
* Switches the connection to the client into config state. * Switches the connection to the client into config state.
*/ */
public void switchToConfigState() { public void switchToConfigState() {
CompletableFuture.runAsync(() -> { server.getEventManager().fire(new PlayerEnterConfigurationEvent(this, getConnectionInFlightOrConnectedServer()))
connection.write(StartUpdatePacket.INSTANCE); .completeOnTimeout(null, 5, TimeUnit.SECONDS).thenRunAsync(() -> {
connection.getChannel().pipeline() connection.write(StartUpdatePacket.INSTANCE);
.get(MinecraftEncoder.class).setState(StateRegistry.CONFIG); connection.getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.CONFIG);
// Make sure we don't send any play packets to the player after update start // Make sure we don't send any play packets to the player after update start
connection.addPlayPacketQueueHandler(); connection.addPlayPacketQueueHandler();
server.getEventManager().fireAndForget(new PlayerEnterConfigurationEvent(this, connectionInFlight)); }, connection.eventLoop()).exceptionally((ex) -> {
}, connection.eventLoop()).exceptionally((ex) -> { logger.error("Error switching player connection to config state", ex);
logger.error("Error switching player connection to config state", ex); return null;
return null; });
});
} }
/** /**