From 53a5f11dd63d1c1d13b8d15d23628e4716bbd1a4 Mon Sep 17 00:00:00 2001 From: xfy2412 Date: Mon, 6 Jul 2026 22:13:13 +0800 Subject: [PATCH 1/4] feat: Add connectionId to MinecraftConnection --- .../velocitypowered/api/proxy/InboundConnection.java | 9 +++++++++ .../proxy/connection/MinecraftConnection.java | 12 ++++++++++++ .../proxy/connection/client/ConnectedPlayer.java | 5 +++++ .../connection/client/LoginInboundConnection.java | 5 +++++ .../connection/util/VelocityInboundConnection.java | 5 +++++ 5 files changed, 36 insertions(+) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java index 884cd4111a..b3b4523c79 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java @@ -68,4 +68,13 @@ public interface InboundConnection { * @return the intent of the connection */ HandshakeIntent getHandshakeIntent(); + + /** + * Returns a unique, stable identifier for this connection. + * + * @return the connection id + */ + default long getConnectionId() { + return -1; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 0cb95752aa..76c5595220 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -86,7 +86,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { private static final Logger logger = LogManager.getLogger(MinecraftConnection.class); + private static final java.util.concurrent.atomic.AtomicLong CONNECTION_ID_COUNTER = + new java.util.concurrent.atomic.AtomicLong(); + private final long connectionId = CONNECTION_ID_COUNTER.incrementAndGet(); private final Channel channel; public boolean pendingConfigurationSwitch = false; private SocketAddress remoteAddress; @@ -322,6 +325,15 @@ public Channel getChannel() { return channel; } + /** + * Returns a unique, stable identifier for this connection. + * + * @return the connection id + */ + public long getConnectionId() { + return connectionId; + } + public boolean isClosed() { return !channel.isActive(); } 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 8d39fcf9f6..0fc85e504a 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 @@ -321,6 +321,11 @@ public MinecraftConnection getConnection() { return connection; } + @Override + public long getConnectionId() { + return connection.getConnectionId(); + } + @Override public long getPing() { return this.ping; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java index 9922c5095e..0e92f063f6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java @@ -183,4 +183,9 @@ public ProtocolState getProtocolState() { public HandshakeIntent getHandshakeIntent() { return delegate.getHandshakeIntent(); } + + @Override + public long getConnectionId() { + return delegate.getConnectionId(); + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java index 31a8863994..25cc691231 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java @@ -26,4 +26,9 @@ public interface VelocityInboundConnection extends InboundConnection { MinecraftConnection getConnection(); + + @Override + default long getConnectionId() { + return getConnection().getConnectionId(); + } } From 3a1ec207b3523454a2ced69ac877474e22d61751 Mon Sep 17 00:00:00 2001 From: xfy2412 Date: Mon, 6 Jul 2026 23:55:31 +0800 Subject: [PATCH 2/4] fix: use UUID instead Long type --- .../velocitypowered/api/proxy/InboundConnection.java | 11 +++++++---- .../proxy/connection/MinecraftConnection.java | 12 ++++++------ .../proxy/connection/client/ConnectedPlayer.java | 2 +- .../connection/client/LoginInboundConnection.java | 3 ++- .../connection/util/VelocityInboundConnection.java | 3 ++- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java index b3b4523c79..6b67aab3bc 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java @@ -12,6 +12,7 @@ import com.velocitypowered.api.network.ProtocolVersion; import java.net.InetSocketAddress; import java.util.Optional; +import java.util.UUID; /** * Represents an incoming connection to the proxy. @@ -70,11 +71,13 @@ public interface InboundConnection { HandshakeIntent getHandshakeIntent(); /** - * Returns a unique, stable identifier for this connection. + * Returns a unique, stable UUID for this connection, generated at + * connection creation time. The UUID remains consistent across all + * login-phase events for the same TCP connection. * - * @return the connection id + * @return the connection UUID, or {@code null} if not supported */ - default long getConnectionId() { - return -1; + default UUID getConnectionId() { + return null; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 76c5595220..520a45a84d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -72,6 +72,7 @@ import java.util.EnumMap; import java.util.Map; import java.util.Objects; +import java.util.UUID; import java.util.concurrent.TimeUnit; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @@ -86,10 +87,8 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { private static final Logger logger = LogManager.getLogger(MinecraftConnection.class); - private static final java.util.concurrent.atomic.AtomicLong CONNECTION_ID_COUNTER = - new java.util.concurrent.atomic.AtomicLong(); - private final long connectionId = CONNECTION_ID_COUNTER.incrementAndGet(); + private final UUID connectionId = UUID.randomUUID(); private final Channel channel; public boolean pendingConfigurationSwitch = false; private SocketAddress remoteAddress; @@ -326,11 +325,12 @@ public Channel getChannel() { } /** - * Returns a unique, stable identifier for this connection. + * Returns a unique, stable UUID for this connection, generated at + * connection creation time. * - * @return the connection id + * @return the connection UUID */ - public long getConnectionId() { + public UUID getConnectionId() { return connectionId; } 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 0fc85e504a..0cddad2a0a 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 @@ -322,7 +322,7 @@ public MinecraftConnection getConnection() { } @Override - public long getConnectionId() { + public UUID getConnectionId() { return connection.getConnectionId(); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java index 0e92f063f6..da47bc689f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java @@ -33,6 +33,7 @@ import java.net.InetSocketAddress; import java.util.Optional; import java.util.Queue; +import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import net.kyori.adventure.text.Component; @@ -185,7 +186,7 @@ public HandshakeIntent getHandshakeIntent() { } @Override - public long getConnectionId() { + public UUID getConnectionId() { return delegate.getConnectionId(); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java index 25cc691231..fa7bd9de5c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java @@ -19,6 +19,7 @@ import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.proxy.connection.MinecraftConnection; +import java.util.UUID; /** * Base internal interface for a {@link InboundConnection}. @@ -28,7 +29,7 @@ public interface VelocityInboundConnection extends InboundConnection { MinecraftConnection getConnection(); @Override - default long getConnectionId() { + default UUID getConnectionId() { return getConnection().getConnectionId(); } } From 48e7519ec4209aa4a4c0cd0cfaa4a941cca03cc4 Mon Sep 17 00:00:00 2001 From: xfy2412 Date: Wed, 8 Jul 2026 13:35:57 +0800 Subject: [PATCH 3/4] feat: inject session UUID from connection origin instead of per-instance random generation --- .../api/proxy/InboundConnection.java | 13 ++++++------- .../proxy/connection/MinecraftConnection.java | 16 +++++++++------- .../backend/VelocityServerConnection.java | 3 ++- .../proxy/connection/client/ConnectedPlayer.java | 4 ++-- .../client/LoginInboundConnection.java | 4 ++-- .../util/VelocityInboundConnection.java | 4 ++-- .../proxy/network/ServerChannelInitializer.java | 3 ++- .../proxy/server/VelocityRegisteredServer.java | 2 +- 8 files changed, 26 insertions(+), 23 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java index 6b67aab3bc..9c1202bee9 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java @@ -71,13 +71,12 @@ public interface InboundConnection { HandshakeIntent getHandshakeIntent(); /** - * Returns a unique, stable UUID for this connection, generated at - * connection creation time. The UUID remains consistent across all - * login-phase events for the same TCP connection. + * Returns the unique, stable session UUID for this connection, generated when + * the client initially connects to the proxy. The session id remains consistent + * across all login-phase events and all proxy-to-backend connections for the + * same player session. * - * @return the connection UUID, or {@code null} if not supported + * @return the session UUID, never {@code null} */ - default UUID getConnectionId() { - return null; - } + UUID getSessionId(); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 520a45a84d..762a091cc6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -88,7 +88,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { private static final Logger logger = LogManager.getLogger(MinecraftConnection.class); - private final UUID connectionId = UUID.randomUUID(); + private final @Nullable UUID sessionId; private final Channel channel; public boolean pendingConfigurationSwitch = false; private SocketAddress remoteAddress; @@ -107,10 +107,11 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { * @param channel the channel on the connection * @param server the Velocity instance */ - public MinecraftConnection(Channel channel, VelocityServer server) { + public MinecraftConnection(Channel channel, VelocityServer server, @Nullable UUID sessionId) { this.channel = channel; this.remoteAddress = channel.remoteAddress(); this.server = server; + this.sessionId = sessionId; this.state = StateRegistry.HANDSHAKE; this.sessionHandlers = new EnumMap<>(StateRegistry.class); @@ -325,13 +326,14 @@ public Channel getChannel() { } /** - * Returns a unique, stable UUID for this connection, generated at - * connection creation time. + * Returns the session UUID for this connection. Client connections have a + * unique session UUID; backend connections share the client's session UUID; + * ping connections have {@code null}. * - * @return the connection UUID + * @return the session UUID, or {@code null} for ping connections */ - public UUID getConnectionId() { - return connectionId; + public @Nullable UUID getSessionId() { + return sessionId; } public boolean isClosed() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index c40a7aaac6..7178d35881 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -105,7 +105,8 @@ public CompletableFuture connect() { .connect(registeredServer.getServerInfo().getAddress()) .addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { - connection = new MinecraftConnection(future.channel(), server); + connection = new MinecraftConnection(future.channel(), server, + proxyPlayer.getConnection().getSessionId()); connection.setAssociation(VelocityServerConnection.this); future.channel().pipeline().addLast(HANDLER, connection); 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 0cddad2a0a..0652524126 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 @@ -322,8 +322,8 @@ public MinecraftConnection getConnection() { } @Override - public UUID getConnectionId() { - return connection.getConnectionId(); + public UUID getSessionId() { + return connection.getSessionId(); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java index da47bc689f..019ac2b0a6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/LoginInboundConnection.java @@ -186,7 +186,7 @@ public HandshakeIntent getHandshakeIntent() { } @Override - public UUID getConnectionId() { - return delegate.getConnectionId(); + public UUID getSessionId() { + return delegate.getSessionId(); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java index fa7bd9de5c..c2dca886c9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java @@ -29,7 +29,7 @@ public interface VelocityInboundConnection extends InboundConnection { MinecraftConnection getConnection(); @Override - default UUID getConnectionId() { - return getConnection().getConnectionId(); + default UUID getSessionId() { + return getConnection().getSessionId(); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java index 68c990ea6c..2153ca767e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -42,6 +42,7 @@ import io.netty.channel.ChannelInitializer; import io.netty.handler.codec.haproxy.HAProxyMessageDecoder; import io.netty.handler.timeout.ReadTimeoutHandler; +import java.util.UUID; import java.util.concurrent.TimeUnit; /** @@ -69,7 +70,7 @@ protected void initChannel(final Channel ch) { .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.SERVERBOUND)) .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.CLIENTBOUND)); - final MinecraftConnection connection = new MinecraftConnection(ch, this.server); + final MinecraftConnection connection = new MinecraftConnection(ch, this.server, UUID.randomUUID()); connection.setActiveSessionHandler(StateRegistry.HANDSHAKE, new HandshakeSessionHandler(connection, this.server)); ch.pipeline().addLast(Connections.HANDLER, connection); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java index e48881f399..14b69828d5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/server/VelocityRegisteredServer.java @@ -123,7 +123,7 @@ protected void initChannel(Channel ch) { .addLast(MINECRAFT_DECODER, new MinecraftDecoder(ProtocolUtils.Direction.CLIENTBOUND)) .addLast(MINECRAFT_ENCODER, new MinecraftEncoder(ProtocolUtils.Direction.SERVERBOUND)); - ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server)); + ch.pipeline().addLast(HANDLER, new MinecraftConnection(ch, server, null)); } }).connect(serverInfo.getAddress()).addListener((ChannelFutureListener) future -> { if (future.isSuccess()) { From 3bfc840818a22214e3c3484c3cad13d60bab047e Mon Sep 17 00:00:00 2001 From: xfy2412 Date: Thu, 9 Jul 2026 00:31:12 +0800 Subject: [PATCH 4/4] fix: enforce non-null sessionId in InboundConnection and clarify documentation --- .../com/velocitypowered/api/proxy/InboundConnection.java | 2 +- .../proxy/connection/MinecraftConnection.java | 8 +------- .../proxy/connection/util/VelocityInboundConnection.java | 3 ++- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java index 9c1202bee9..17ecfc281a 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/InboundConnection.java @@ -74,7 +74,7 @@ public interface InboundConnection { * Returns the unique, stable session UUID for this connection, generated when * the client initially connects to the proxy. The session id remains consistent * across all login-phase events and all proxy-to-backend connections for the - * same player session. + * same player session. This should not be confused with Mojang's server-wide play session ID introduced in Minecraft 26.2. * * @return the session UUID, never {@code null} */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java index 762a091cc6..6284af510c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -325,13 +325,7 @@ public Channel getChannel() { return channel; } - /** - * Returns the session UUID for this connection. Client connections have a - * unique session UUID; backend connections share the client's session UUID; - * ping connections have {@code null}. - * - * @return the session UUID, or {@code null} for ping connections - */ + public @Nullable UUID getSessionId() { return sessionId; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java index c2dca886c9..ec9b28c0de 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/VelocityInboundConnection.java @@ -19,6 +19,7 @@ import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.proxy.connection.MinecraftConnection; +import java.util.Objects; import java.util.UUID; /** @@ -30,6 +31,6 @@ public interface VelocityInboundConnection extends InboundConnection { @Override default UUID getSessionId() { - return getConnection().getSessionId(); + return Objects.requireNonNull(getConnection().getSessionId(), "sessionId"); } }