Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Configuration State API #1261

Merged
merged 12 commits into from
Jun 16, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* 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.proxy.Player;
import org.jetbrains.annotations.NotNull;

// TODO: Protocol State API
/**
* This event is executed when a player with version 1.20.2 or higher enters the configuration phase.
* <p>From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed,
* the {@linkplain Player#protocolState()} method is guaranteed
* to return {@link ProtocolState#CONFIGURATION}.</p>
*
* @param player The player that has entered the configuration phase
* @since 3.3.0
*/
public record PlayerEnterConfigurationEvent(@NotNull Player player) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* 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 org.jetbrains.annotations.NotNull;

// TODO: Protocol State API
/**
* This event is executed when the player is about to finish the Configuration state.
4drian3d marked this conversation as resolved.
Show resolved Hide resolved
* <p>Velocity will wait for this event to finish the configuration phase on the client.</p>
*
* @param player The player who is about to complete the configuration phase
*/
4drian3d marked this conversation as resolved.
Show resolved Hide resolved
@AwaitingEvent
public record PlayerFinishConfigurationEvent(@NotNull Player player) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* 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.proxy.Player;

/**
* Event executed when a player of version 1.20.2 finishes the Configuration state.
4drian3d marked this conversation as resolved.
Show resolved Hide resolved
* <p>From this moment on, the {@link Player#protocolState()} method
* will return {@link ProtocolState#PLAY}.</p>
*
* @param player The player who has completed the Configuration state
*/
4drian3d marked this conversation as resolved.
Show resolved Hide resolved
public record PlayerFinishedConfigurationEvent(Player player) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
import com.velocitypowered.proxy.command.builtin.VelocityCommand;
import com.velocitypowered.proxy.config.VelocityConfiguration;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.util.ServerListPingHandler;
import com.velocitypowered.proxy.console.VelocityConsole;
import com.velocitypowered.proxy.crypto.EncryptionUtils;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,11 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
return;
}

if (msg instanceof MinecraftPacket) {
MinecraftPacket pkt = (MinecraftPacket) msg;
if (msg instanceof MinecraftPacket pkt) {
if (!pkt.handle(activeSessionHandler)) {
activeSessionHandler.handleGeneric((MinecraftPacket) msg);
}
} else if (msg instanceof HAProxyMessage) {
HAProxyMessage proxyMessage = (HAProxyMessage) msg;
} else if (msg instanceof HAProxyMessage proxyMessage) {
this.remoteAddress = new InetSocketAddress(proxyMessage.sourceAddress(),
proxyMessage.sourcePort());
} else if (msg instanceof ByteBuf) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.client.ClientPlaySessionHandler;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.ResourcePackHandler;
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.handler.ResourcePackHandler;
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.StateRegistry;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import io.netty.buffer.Unpooled;
import java.util.Optional;
import java.util.StringJoiner;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.ComponentSerializer;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
Expand Down Expand Up @@ -143,7 +142,7 @@ private void processPlayerList(ByteBufDataInput in) {
out.writeUTF("PlayerList");
out.writeUTF(info.getServerInfo().getName());

StringJoiner joiner = new StringJoiner(", ");
final StringJoiner joiner = new StringJoiner(", ");
for (Player online : info.getPlayersConnected()) {
joiner.add(online.getUsername());
}
Expand Down Expand Up @@ -187,10 +186,9 @@ private void processMessage0(ByteBufDataInput in,

Component messageComponent = serializer.deserialize(message);
if (target.equals("ALL")) {
proxy.sendMessage(Identity.nil(), messageComponent);
proxy.sendMessage(messageComponent);
} else {
proxy.getPlayer(target).ifPresent(player -> player.sendMessage(Identity.nil(),
messageComponent));
proxy.getPlayer(target).ifPresent(player -> player.sendMessage(messageComponent));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.connection.client.ClientConfigSessionHandler;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
import com.velocitypowered.proxy.connection.util.ConnectionRequestResults;
import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl;
Expand Down Expand Up @@ -171,15 +171,16 @@ public boolean handle(final ResourcePackRequestPacket packet) {

@Override
public boolean handle(FinishedUpdatePacket packet) {
MinecraftConnection smc = serverConn.ensureConnected();
ConnectedPlayer player = serverConn.getPlayer();
ClientConfigSessionHandler configHandler =
final MinecraftConnection smc = serverConn.ensureConnected();
final ConnectedPlayer player = serverConn.getPlayer();
final ClientConfigSessionHandler configHandler =
(ClientConfigSessionHandler) player.getConnection().getActiveSessionHandler();

smc.setAutoReading(false);
// Even when not auto reading messages are still decoded. Decode them with the correct state
smc.getChannel().pipeline().get(MinecraftDecoder.class).setState(StateRegistry.PLAY);
configHandler.handleBackendFinishUpdate(serverConn).thenAcceptAsync((unused) -> {
//noinspection DataFlowIssue
configHandler.handleBackendFinishUpdate(serverConn).thenRunAsync(() -> {
if (serverConn == player.getConnectedServer()) {
smc.setActiveSessionHandler(StateRegistry.PLAY);
player.sendPlayerListHeaderAndFooter(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,9 @@ public boolean handle(ServerLoginSuccessPacket packet) {
if (player.getClientSettingsPacket() != null) {
smc.write(player.getClientSettingsPacket());
}
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler) {
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) {
smc.setAutoReading(false);
((ClientPlaySessionHandler) player.getConnection()
.getActiveSessionHandler()).doSwitch().thenAcceptAsync((unused) -> {
smc.setAutoReading(true);
}, smc.eventLoop());
clientPlaySessionHandler.doSwitch().thenAcceptAsync((unused) -> smc.setAutoReading(true), smc.eventLoop());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
package com.velocitypowered.proxy.connection.client;

import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
import com.velocitypowered.api.event.player.configuration.PlayerFinishConfigurationEvent;
import com.velocitypowered.api.event.player.configuration.PlayerFinishedConfigurationEvent;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
Expand Down Expand Up @@ -208,10 +210,13 @@ public CompletableFuture<Void> handleBackendFinishUpdate(VelocityServerConnectio
smc.write(brandPacket);
}

player.getConnection().eventLoop().execute(() -> {
player.getConnection().write(FinishedUpdatePacket.INSTANCE);
player.getConnection().getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.PLAY);
});
server.getEventManager().fire(new PlayerFinishConfigurationEvent(player))
.thenAcceptAsync(event -> {
player.getConnection().write(FinishedUpdatePacket.INSTANCE);
player.getConnection().getChannel().pipeline()
.get(MinecraftEncoder.class).setState(StateRegistry.PLAY);
server.getEventManager().fireAndForget(new PlayerFinishedConfigurationEvent(player));
}, player.getConnection().eventLoop());

smc.write(FinishedUpdatePacket.INSTANCE);
smc.getChannel().pipeline().get(MinecraftEncoder.class).setState(StateRegistry.PLAY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent;
import com.velocitypowered.api.event.player.PlayerClientBrandEvent;
import com.velocitypowered.api.event.player.TabCompleteEvent;
import com.velocitypowered.api.event.player.configuration.PlayerEnterConfigurationEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.messages.ChannelIdentifier;
import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
Expand Down Expand Up @@ -402,6 +403,7 @@ public boolean handle(ResourcePackResponsePacket packet) {
public boolean handle(FinishedUpdatePacket packet) {
// Complete client switch
player.getConnection().setActiveSessionHandler(StateRegistry.CONFIG);
server.getEventManager().fireAndForget(new PlayerEnterConfigurationEvent(player));
VelocityServerConnection serverConnection = player.getConnectedServer();
if (serverConnection != null) {
MinecraftConnection smc = serverConnection.ensureConnected();
Expand Down Expand Up @@ -487,7 +489,7 @@ public void writabilityChanged() {
* @return a future that completes when the switch is complete
*/
public CompletableFuture<Void> doSwitch() {
VelocityServerConnection existingConnection = player.getConnectedServer();
final VelocityServerConnection existingConnection = player.getConnectedServer();

if (existingConnection != null) {
// Shut down the existing server connection.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import com.velocitypowered.api.event.player.PlayerModInfoEvent;
import com.velocitypowered.api.event.player.PlayerSettingsChangedEvent;
import com.velocitypowered.api.event.player.ServerPreConnectEvent;
import com.velocitypowered.api.event.player.configuration.PlayerEnterConfigurationEvent;
import com.velocitypowered.api.network.ProtocolState;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.permission.PermissionFunction;
Expand All @@ -56,8 +57,9 @@
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.connection.player.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.ResourcePackHandler;
import com.velocitypowered.proxy.connection.player.bundle.BundleDelimiterHandler;
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.handler.ResourcePackHandler;
import com.velocitypowered.proxy.connection.util.ConnectionMessages;
import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl;
import com.velocitypowered.proxy.connection.util.VelocityInboundConnection;
Expand Down Expand Up @@ -799,7 +801,7 @@ private void handleKickEvent(KickedFromServerEvent originalEvent, Component frie
}, connection.eventLoop());
} else if (event.getResult() instanceof final Notify res) {
if (event.kickedDuringServerConnect() && previousConnection != null) {
sendMessage(Identity.nil(), res.getMessageComponent());
sendMessage(res.getMessageComponent());
} else {
disconnect(res.getMessageComponent());
}
Expand Down Expand Up @@ -1154,11 +1156,12 @@ public void switchToConfigState() {
CompletableFuture.runAsync(() -> {
connection.write(StartUpdatePacket.INSTANCE);
connection.getChannel().pipeline()
.get(MinecraftEncoder.class).setState(StateRegistry.CONFIG);
.get(MinecraftEncoder.class).setState(StateRegistry.CONFIG);
// Make sure we don't send any play packets to the player after update start
connection.addPlayPacketQueueHandler();
server.getEventManager().fireAndForget(new PlayerEnterConfigurationEvent(this));
}, 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;
});
}
Expand Down Expand Up @@ -1293,24 +1296,20 @@ public CompletableFuture<Boolean> connectWithIndication() {
}

switch (status.getStatus()) {
case ALREADY_CONNECTED:
sendMessage(Identity.nil(), ConnectionMessages.ALREADY_CONNECTED);
break;
case CONNECTION_IN_PROGRESS:
sendMessage(Identity.nil(), ConnectionMessages.IN_PROGRESS);
break;
case CONNECTION_CANCELLED:
case ALREADY_CONNECTED -> sendMessage(ConnectionMessages.ALREADY_CONNECTED);
case CONNECTION_IN_PROGRESS -> sendMessage(ConnectionMessages.IN_PROGRESS);
case CONNECTION_CANCELLED -> {
// Ignored; the plugin probably already handled this.
break;
case SERVER_DISCONNECTED:
Component reason = status.getReasonComponent()
.orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
}
case SERVER_DISCONNECTED -> {
final Component reason = status.getReasonComponent()
.orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR);
handleConnectionException(toConnect,
DisconnectPacket.create(reason, getProtocolVersion(), connection.getState()), status.isSafe());
break;
default:
DisconnectPacket.create(reason, getProtocolVersion(), connection.getState()), status.isSafe());
}
default -> {
// The only remaining value is successful (no need to do anything!)
break;
}
}
}, connection.eventLoop()).thenApply(Result::isSuccessful);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.connection.client;
package com.velocitypowered.proxy.connection.player.bundle;

import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.protocol.StateRegistry;
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
import java.util.concurrent.CompletableFuture;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.connection.player;
package com.velocitypowered.proxy.connection.player.resourcepack;

import com.google.common.base.Preconditions;
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.connection.player.resourcepack;
package com.velocitypowered.proxy.connection.player.resourcepack.handler;

import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent;
import com.velocitypowered.proxy.VelocityServer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.connection.player.resourcepack;
package com.velocitypowered.proxy.connection.player.resourcepack.handler;

import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.connection.player.resourcepack.ResourcePackResponseBundle;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -109,7 +110,7 @@ private void tickResourcePackQueue() {
break;
}
onResourcePackResponse(new ResourcePackResponseBundle(queued.getId(),
new String(queued.getHash()),
queued.getHash() == null ? null : new String(queued.getHash()),
PlayerResourcePackStatusEvent.Status.DECLINED));
queued = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.velocitypowered.proxy.connection.player.resourcepack;
package com.velocitypowered.proxy.connection.player.resourcepack.handler;

import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import com.velocitypowered.api.event.player.PlayerResourcePackStatusEvent;
import com.velocitypowered.api.proxy.player.ResourcePackInfo;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
import com.velocitypowered.proxy.connection.player.resourcepack.ResourcePackResponseBundle;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
Expand Down
Loading