From 75d68115effe52bb459207ce3c985e5da2502451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ZX=E5=A4=8F=E5=A4=9C=E4=B9=8B=E9=A3=8E?= Date: Mon, 10 Nov 2025 00:34:58 +0800 Subject: [PATCH 01/48] feat: PlayerChannelUnregisterEvent (#1686) * feat: PlayerChannelUnregisterEvent * style: fix checkstyle issues --- .../player/PlayerChannelUnregisterEvent.java | 44 +++++++++++++++++++ .../client/ClientPlaySessionHandler.java | 9 +++- 2 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java new file mode 100644 index 00000000..86eeb2bc --- /dev/null +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2025 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; + +import com.google.common.base.Preconditions; +import com.velocitypowered.api.proxy.Player; +import com.velocitypowered.api.proxy.messages.ChannelIdentifier; +import java.util.List; + +/** + * This event is fired when a client ({@link Player}) sends a plugin message through the + * unregister channel. Velocity will not wait on this event to finish firing. + */ +public final class PlayerChannelUnregisterEvent { + + private final Player player; + private final List channels; + + public PlayerChannelUnregisterEvent(Player player, List channels) { + this.player = Preconditions.checkNotNull(player, "player"); + this.channels = Preconditions.checkNotNull(channels, "channels"); + } + + public Player getPlayer() { + return player; + } + + public List getChannels() { + return channels; + } + + @Override + public String toString() { + return "PlayerChannelUnregisterEvent{" + + "player=" + player + + ", channels=" + channels + + '}'; + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 17eb708b..a4ddacc9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -24,6 +24,7 @@ import com.mojang.brigadier.suggestion.Suggestion; import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.player.CookieReceiveEvent; import com.velocitypowered.api.event.player.PlayerChannelRegisterEvent; +import com.velocitypowered.api.event.player.PlayerChannelUnregisterEvent; import com.velocitypowered.api.event.player.PlayerClientBrandEvent; import com.velocitypowered.api.event.player.TabCompleteEvent; import com.velocitypowered.api.event.player.configuration.PlayerEnteredConfigurationEvent; @@ -318,8 +319,12 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { new PlayerChannelRegisterEvent(player, ImmutableList.copyOf(channels))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isUnregister(packet)) { - player.getClientsideChannels() - .removeAll(PluginMessageUtil.getChannels(0, packet, this.player.getProtocolVersion())); + List channels = + PluginMessageUtil.getChannels(0, packet, this.player.getProtocolVersion()); + player.getClientsideChannels().removeAll(channels); + server.getEventManager() + .fireAndForget( + new PlayerChannelUnregisterEvent(player, ImmutableList.copyOf(channels))); backendConn.write(packet.retain()); } else if (PluginMessageUtil.isMcBrand(packet)) { String brand = PluginMessageUtil.readBrandMessage(packet.content()); From a046f700751be4097718ec5fd43a6299df72c1f0 Mon Sep 17 00:00:00 2001 From: SzymON/OFF Date: Sun, 9 Nov 2025 20:59:06 +0100 Subject: [PATCH 02/48] Fix exception message formatting in command invocation (#1687) --- .../velocitypowered/proxy/command/VelocityCommandManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java index 095445bf..49dceb31 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -256,7 +256,7 @@ public class VelocityCommandManager implements CommandManager { } } catch (final Throwable e) { // Ugly, ugly swallowing of everything Throwable, because plugins are naughty. - throw new RuntimeException("Unable to invoke command " + parsed.getReader().getString() + "for " + source, e); + throw new RuntimeException("Unable to invoke command " + parsed.getReader().getString() + " for " + source, e); } finally { eventManager.fireAndForget(new PostCommandInvocationEvent(source, parsed.getReader().getString(), result)); } @@ -400,4 +400,4 @@ public class VelocityCommandManager implements CommandManager { return MoreExecutors.directExecutor(); } } -} \ No newline at end of file +} From 6cc1be7746ec49d2b600b1af1dcec99584750d38 Mon Sep 17 00:00:00 2001 From: Adrian Gonzales Date: Sun, 9 Nov 2025 15:23:36 -0500 Subject: [PATCH 03/48] [ci skip] Replaced slf4j javadocs provider with javadocs.dev --- api/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index b96208c1..8f969cca 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -63,7 +63,7 @@ tasks { o.use() o.links( - "https://www.slf4j.org/apidocs/", + "https://www.javadocs.dev/org.slf4j/slf4j-api/${libs.slf4j.get().version}/", "https://guava.dev/releases/${libs.guava.get().version}/api/docs/", "https://google.github.io/guice/api-docs/${libs.guice.get().version}/javadoc/", "https://docs.oracle.com/en/java/javase/17/docs/api/", From 8f65a8142029717d3af09ecf82792f7345dc873a Mon Sep 17 00:00:00 2001 From: Adrian <68704415+4drian3d@users.noreply.github.com> Date: Sun, 7 Dec 2025 15:28:00 -0500 Subject: [PATCH 04/48] Minecraft 1.21.11 (#1690) * 1.21.11-pre2 I have not identified any changes that affect us at this time * 1.21.11-pre3 * 1.21.11-pre4 * 1.21.11-pre5 * 1.21.11-rc1 * 1.21.11-rc2 * Minecraft 1.21.11 release support --- .../java/com/velocitypowered/api/network/ProtocolVersion.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index f2a629b1..e803c302 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -93,7 +93,8 @@ public enum ProtocolVersion implements Ordered { MINECRAFT_1_21_5(770, "1.21.5"), MINECRAFT_1_21_6(771, "1.21.6"), MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"), - MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"); + MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"), + MINECRAFT_1_21_11(774, "1.21.11"); private static final int SNAPSHOT_BIT = 30; From 4bc3f00424380da339dae3be346c0b84f0fbd1c3 Mon Sep 17 00:00:00 2001 From: Aaron <71191102+RealBauHD@users.noreply.github.com> Date: Sat, 27 Dec 2025 19:41:43 +0100 Subject: [PATCH 05/48] bump adventure to 4.26.1 (#1697) --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d0bb2c84..12dc2cb4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -12,8 +12,8 @@ shadow = "com.gradleup.shadow:8.3.6" spotless = "com.diffplug.spotless:6.25.0" [libraries] -adventure-bom = "net.kyori:adventure-bom:4.25.0" -adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.25.0" +adventure-bom = "net.kyori:adventure-bom:4.26.1" +adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.26.1" adventure-facet = "net.kyori:adventure-platform-facet:4.3.4" asm = "org.ow2.asm:asm:9.8" auto-service = "com.google.auto.service:auto-service:1.0.1" From a03bd884aa7a53744b4e85b44cdf124ddb744526 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Thu, 8 Jan 2026 16:53:58 +0000 Subject: [PATCH 06/48] Restrict empty packet frames from clients --- .../proxy/protocol/netty/MinecraftVarintFrameDecoder.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java index 7d4d8d6d..31ddda0e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java @@ -44,6 +44,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { + "Velocity with -Dvelocity.packet-decode-logging=true to see more."); private static final QuietDecoderException BAD_PACKET_LENGTH = new QuietDecoderException("Bad packet length"); + private static final QuietDecoderException INVALID_PREAMBLE = + new QuietDecoderException("Invalid packet preamble"); private static final QuietDecoderException VARINT_TOO_BIG = new QuietDecoderException("VarInt too big"); private static final QuietDecoderException UNKNOWN_PACKET = @@ -74,9 +76,15 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { } // skip any runs of 0x00 we might find + int wLength = in.readableBytes(); int packetStart = in.forEachByte(FIND_NON_NUL); if (packetStart == -1) { in.clear(); + // Apply a more strict check in serverbound direction, we really shouldn't be seeing this many 0x00s + // even from the server, the only reason we even allow these is due to bugged servers + if (direction == ProtocolUtils.Direction.SERVERBOUND && wLength > 16) { + throw INVALID_PREAMBLE; + } return; } in.readerIndex(packetStart); From 372a3b28bd3bbaebf5934b4582dbb2feba70a93e Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Thu, 8 Jan 2026 17:13:08 +0000 Subject: [PATCH 07/48] Conformity --- .../proxy/protocol/netty/MinecraftVarintFrameDecoder.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java index 31ddda0e..35016c31 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java @@ -76,13 +76,13 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { } // skip any runs of 0x00 we might find - int wLength = in.readableBytes(); + int wlen = in.readableBytes(); int packetStart = in.forEachByte(FIND_NON_NUL); if (packetStart == -1) { in.clear(); // Apply a more strict check in serverbound direction, we really shouldn't be seeing this many 0x00s // even from the server, the only reason we even allow these is due to bugged servers - if (direction == ProtocolUtils.Direction.SERVERBOUND && wLength > 16) { + if (direction == ProtocolUtils.Direction.SERVERBOUND && wlen > 16) { throw INVALID_PREAMBLE; } return; From 21671daebe661633a80a69852b2598a2714f844a Mon Sep 17 00:00:00 2001 From: Warrior <50800980+Warriorrrr@users.noreply.github.com> Date: Mon, 19 Jan 2026 13:43:06 +0100 Subject: [PATCH 08/48] Provide an IDE pattern hint for plugin IDs (#1712) * Provide an IDE pattern hint for plugin IDs * order my imports the right way --- .../api/plugin/ap/SerializedPluginDescription.java | 3 ++- .../main/java/com/velocitypowered/api/plugin/Dependency.java | 3 +++ api/src/main/java/com/velocitypowered/api/plugin/Plugin.java | 3 +++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java index da0a1ae4..b712d896 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java @@ -24,7 +24,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; */ public final class SerializedPluginDescription { - public static final Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}"); + public static final String ID_PATTERN_STRING = "[a-z][a-z0-9-_]{0,63}"; + public static final Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING); // @Nullable is used here to make GSON skip these in the serialized file private final String id; diff --git a/api/src/main/java/com/velocitypowered/api/plugin/Dependency.java b/api/src/main/java/com/velocitypowered/api/plugin/Dependency.java index dfe1908f..413dd9e5 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/Dependency.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/Dependency.java @@ -7,9 +7,11 @@ package com.velocitypowered.api.plugin; +import com.velocitypowered.api.plugin.ap.SerializedPluginDescription; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.intellij.lang.annotations.Pattern; /** * Indicates that the {@link Plugin} depends on another plugin in order to enable. @@ -24,6 +26,7 @@ public @interface Dependency { * @return The dependency plugin ID * @see Plugin#id() */ + @Pattern(SerializedPluginDescription.ID_PATTERN_STRING) String id(); /** diff --git a/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java b/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java index 523648e6..d3b458ca 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/Plugin.java @@ -7,10 +7,12 @@ package com.velocitypowered.api.plugin; +import com.velocitypowered.api.plugin.ap.SerializedPluginDescription; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.intellij.lang.annotations.Pattern; /** * Annotation used to describe a Velocity plugin. @@ -26,6 +28,7 @@ public @interface Plugin { * * @return the ID for this plugin */ + @Pattern(SerializedPluginDescription.ID_PATTERN_STRING) String id(); /** From 3022793418739656aa35584eadce104897b82f8c Mon Sep 17 00:00:00 2001 From: mason Date: Wed, 21 Jan 2026 10:56:22 -0800 Subject: [PATCH 09/48] Fix ByteBuf memory leak in MinecraftVarintFrameDecoder (#1715) - Reset buffer reader index on exception to prevent memory leaks when packet decoding fails. --- .../netty/MinecraftVarintFrameDecoder.java | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java index 35016c31..71ac4fcc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java @@ -91,29 +91,35 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { // try to read the length of the packet in.markReaderIndex(); - int length = readRawVarInt21(in); - if (packetStart == in.readerIndex()) { - return; - } - if (length < 0) { - throw BAD_PACKET_LENGTH; - } + try { + int length = readRawVarInt21(in); + if (packetStart == in.readerIndex()) { + return; + } + if (length < 0) { + throw BAD_PACKET_LENGTH; + } - if (length > 0) { - if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) { - if (validateServerboundHandshakePacket(in, length)) { - return; + if (length > 0) { + if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) { + if (validateServerboundHandshakePacket(in, length)) { + return; + } } } - } - // note that zero-length packets are ignored - if (length > 0) { - if (in.readableBytes() < length) { - in.resetReaderIndex(); - } else { - out.add(in.readRetainedSlice(length)); + // note that zero-length packets are ignored + if (length > 0) { + if (in.readableBytes() < length) { + in.resetReaderIndex(); + } else { + out.add(in.readRetainedSlice(length)); + } } + } catch (Exception e) { + // Reset buffer to consistent state before propagating exception to prevent memory leaks + in.resetReaderIndex(); + throw e; } } @@ -122,34 +128,40 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION); final int index = in.readerIndex(); - final int packetId = readRawVarInt21(in); - // Index hasn't changed, we've read nothing - if (index == in.readerIndex()) { - in.resetReaderIndex(); - return true; - } - final int payloadLength = length - ProtocolUtils.varIntBytes(packetId); + try { + final int packetId = readRawVarInt21(in); + // Index hasn't changed, we've read nothing + if (index == in.readerIndex()) { + in.resetReaderIndex(); + return true; + } + final int payloadLength = length - ProtocolUtils.varIntBytes(packetId); - MinecraftPacket packet = registry.createPacket(packetId); + MinecraftPacket packet = registry.createPacket(packetId); - // We handle every packet in this phase, if you said something we don't know, something is really wrong - if (packet == null) { - throw UNKNOWN_PACKET; - } + // We handle every packet in this phase, if you said something we don't know, something is really wrong + if (packet == null) { + throw UNKNOWN_PACKET; + } - // We 'technically' have the incoming bytes of a payload here, and so, these can actually parse - // the packet if needed, so, we'll take advantage of the existing methods - int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version); - int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version); - if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) { - throw handleOverflow(packet, expectedMaxLen, in.readableBytes()); - } - if (payloadLength < expectedMinLen) { - throw handleUnderflow(packet, expectedMaxLen, in.readableBytes()); - } + // We 'technically' have the incoming bytes of a payload here, and so, these can actually parse + // the packet if needed, so, we'll take advantage of the existing methods + int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version); + int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version); + if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) { + throw handleOverflow(packet, expectedMaxLen, in.readableBytes()); + } + if (payloadLength < expectedMinLen) { + throw handleUnderflow(packet, expectedMaxLen, in.readableBytes()); + } - in.readerIndex(index); - return false; + in.readerIndex(index); + return false; + } catch (Exception e) { + // Reset buffer to consistent state before propagating exception to prevent memory leaks + in.readerIndex(index); + throw e; + } } @Override From 6b1ea78ff77a7f060947a2597ad3a50274d71351 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 25 Jan 2026 18:20:04 +0100 Subject: [PATCH 10/48] release 3.4.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 55c2ed10..23127d6f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=com.velocitypowered -version=3.4.0-SNAPSHOT +version=3.4.0 From 1df79a403bfbdfaaaf972435ae5cf59652b8f3fc Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 25 Jan 2026 18:23:01 +0100 Subject: [PATCH 11/48] Update fill --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 12dc2cb4..7a22c365 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ log4j = "2.24.3" netty = "4.2.7.Final" [plugins] -fill = "io.papermc.fill.gradle:1.0.3" +fill = "io.papermc.fill.gradle:1.0.10" indra-publishing = "net.kyori.indra.publishing:2.0.6" shadow = "com.gradleup.shadow:8.3.6" spotless = "com.diffplug.spotless:6.25.0" From 7e4f37b5f5dc7b9f99f11d85014b2065d2283388 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 25 Jan 2026 18:53:56 +0100 Subject: [PATCH 12/48] Bump version to 3.5.0-SNAPSHOT --- gradle.properties | 2 +- proxy/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 23127d6f..d048feb7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=com.velocitypowered -version=3.4.0 +version=3.5.0-SNAPSHOT diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 1559f5fd..e74485e4 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -115,7 +115,7 @@ fill { project("velocity") build { - channel = BuildChannel.STABLE + channel = BuildChannel.BETA versionFamily("3.0.0") version(projectVersion) From d69431a08ee757464b368ceb5dff91b451597d6a Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 25 Jan 2026 19:13:08 +0100 Subject: [PATCH 13/48] Update dependencies (#1717) --- .github/workflows/gradle.yml | 8 ++--- gradle/libs.versions.toml | 43 +++++++++++------------ gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 46175 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 16 ++++----- gradlew.bat | 7 ++-- proxy/build.gradle.kts | 4 +++ settings.gradle.kts | 2 +- 8 files changed, 40 insertions(+), 42 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 07f49bf1..865c9390 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -6,16 +6,16 @@ on: [push, pull_request] jobs: build: - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false - name: Set up Gradle - uses: gradle/actions/setup-gradle@v4 + uses: gradle/actions/setup-gradle@v5 - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: java-version: 21 distribution: 'zulu' diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7a22c365..7be8d469 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,27 +1,26 @@ [versions] configurate3 = "3.7.3" -configurate4 = "4.1.2" +configurate4 = "4.2.0" flare = "2.0.1" -log4j = "2.24.3" +log4j = "2.25.3" netty = "4.2.7.Final" [plugins] fill = "io.papermc.fill.gradle:1.0.10" -indra-publishing = "net.kyori.indra.publishing:2.0.6" -shadow = "com.gradleup.shadow:8.3.6" -spotless = "com.diffplug.spotless:6.25.0" +shadow = "com.gradleup.shadow:9.3.1" +spotless = "com.diffplug.spotless:8.2.0" [libraries] adventure-bom = "net.kyori:adventure-bom:4.26.1" adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.26.1" -adventure-facet = "net.kyori:adventure-platform-facet:4.3.4" -asm = "org.ow2.asm:asm:9.8" -auto-service = "com.google.auto.service:auto-service:1.0.1" -auto-service-annotations = "com.google.auto.service:auto-service-annotations:1.0.1" +adventure-facet = "net.kyori:adventure-platform-facet:4.4.1" +asm = "org.ow2.asm:asm:9.9.1" +auto-service = "com.google.auto.service:auto-service:1.1.1" +auto-service-annotations = "com.google.auto.service:auto-service-annotations:1.1.1" brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT" -bstats = "org.bstats:bstats-base:3.0.3" -caffeine = "com.github.ben-manes.caffeine:caffeine:3.1.8" -checker-qual = "org.checkerframework:checker-qual:3.42.0" +bstats = "org.bstats:bstats-base:3.1.0" +caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3" +checker-qual = "org.checkerframework:checker-qual:3.53.0" checkstyle = "com.puppycrawl.tools:checkstyle:10.9.3" completablefutures = "com.spotify:completable-futures:0.3.6" configurate3-hocon = { module = "org.spongepowered:configurate-hocon", version.ref = "configurate3" } @@ -34,21 +33,21 @@ disruptor = "com.lmax:disruptor:4.0.0" fastutil = "it.unimi.dsi:fastutil:8.5.15" flare-core = { module = "space.vectrix.flare:flare", version.ref = "flare" } flare-fastutil = { module = "space.vectrix.flare:flare-fastutil", version.ref = "flare" } -jline = "org.jline:jline-terminal-jansi:3.30.2" +jline = "org.jline:jline-terminal-jansi:3.30.6" jopt = "net.sf.jopt-simple:jopt-simple:5.0.4" -junit = "org.junit.jupiter:junit-jupiter:5.10.2" -jspecify = "org.jspecify:jspecify:0.3.0" +junit = "org.junit.jupiter:junit-jupiter:5.14.2" +jspecify = "org.jspecify:jspecify:1.0.0" kyori-ansi = "net.kyori:ansi:1.1.1" -guava = "com.google.guava:guava:25.1-jre" -gson = "com.google.code.gson:gson:2.10.1" -guice = "com.google.inject:guice:6.0.0" +guava = "com.google.guava:guava:33.5.0-jre" +gson = "com.google.code.gson:gson:2.13.2" +guice = "com.google.inject:guice:7.0.0" lmbda = "org.lanternpowered:lmbda:2.0.0" log4j-api = { module = "org.apache.logging.log4j:log4j-api", version.ref = "log4j" } log4j-core = { module = "org.apache.logging.log4j:log4j-core", version.ref = "log4j" } log4j-slf4j-impl = { module = "org.apache.logging.log4j:log4j-slf4j2-impl", version.ref = "log4j" } log4j-iostreams = { module = "org.apache.logging.log4j:log4j-iostreams", version.ref = "log4j" } log4j-jul = { module = "org.apache.logging.log4j:log4j-jul", version.ref = "log4j" } -mockito = "org.mockito:mockito-core:5.10.0" +mockito = "org.mockito:mockito-core:5.21.0" netty-codec = { module = "io.netty:netty-codec", version.ref = "netty" } netty-codec-haproxy = { module = "io.netty:netty-codec-haproxy", version.ref = "netty" } netty-codec-http = { module = "io.netty:netty-codec-http", version.ref = "netty" } @@ -56,10 +55,10 @@ netty-handler = { module = "io.netty:netty-handler", version.ref = "netty" } netty-transport-native-epoll = { module = "io.netty:netty-transport-native-epoll", version.ref = "netty" } netty-transport-native-kqueue = { module = "io.netty:netty-transport-native-kqueue", version.ref = "netty" } netty-transport-native-iouring = { module = "io.netty:netty-transport-native-io_uring", version.ref = "netty" } -nightconfig = "com.electronwill.night-config:toml:3.6.7" +nightconfig = "com.electronwill.night-config:toml:3.8.3" slf4j = "org.slf4j:slf4j-api:2.0.17" -snakeyaml = "org.yaml:snakeyaml:1.33" -spotbugs-annotations = "com.github.spotbugs:spotbugs-annotations:4.7.3" +snakeyaml = "org.yaml:snakeyaml:2.5" +spotbugs-annotations = "com.github.spotbugs:spotbugs-annotations:4.9.8" terminalconsoleappender = "net.minecrell:terminalconsoleappender:1.3.0" [bundles] diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..61285a659d17295f1de7c53e24fdf13ad755c379 100644 GIT binary patch delta 38035 zcmXVWV|bn4*K``=#I|iaX>8lJokpk8iEZ0%?8del=ft*}Ce7R5|9L;``}2M6wPx1r zS<}A^xqAxP=zs!bo|!=mWkZAB^C!DW#Qin@oM}+04xJ_rY}o9uCmT%+dw!~ET{An* zf$hDbx9ZSP^nRAVJc@6&M~tVr$A7>WT(Ops&!zB=AEq>i$KvnKjiFs$O;mx_YF~D8 zp=T(9%1+vAR7ciFm5HFIXCD(o5tR($k#s&TFzn7vBQc?hFEr}gh2Fr^Z||xHueNp3 zBhB*tfmBt1gSVfX(ochcfarusS->VrSwWE}B*E(OotATIk7*lJmr5+I$k)FmNwFiy zvCOzk5kMsZ!h7TQIPx?fM(rYXiZ{GwPQl!GWOYsJs%0+AuxQB!e2t-y!N{OUIK((& zU^SW@Lo)NYd{C58woIzBrsF2a&qJLcOy2z~Wyg&ETV1jOdcolUJ@hX77dI%^8@&Jk z3Z+u-IG%Gd1qeK}05DwQq+olwPIcjmm_`?~eUk<3XnV33OD_r)BKkVMrDkgRv=t zri3cZK4V^FneIzAZ7=VyZy#>URjY-6k^j3E%pds`+`Mp?^0BB6Emh=+DQ;$r0})&YE|49V1e7TOAhGj2)L!%%5_L8e|#V zRG)C_4%$TQSPMbt3TC;~zIQpY7yhKrtf$l$yUY|>2!pk&=}t#GR1cXVt{ zN7^v*mUBt&Zx(We^TiTh2IJr0R^#z;3x+5nM6O)oa+!@^M*if7c37cZf;Mg5#pPjo z;s;%`i4*xZ$hyaDr0|{@`BCKWE6*XEHrES!KsV2*dE}5yV)nkeh3`g=+(KH$8)UePNw>L5|P$+FT;9Dg4X55j){1L*U!0iZP?eExH z0^5XYoYY-_UC^`dmq4c>JXCg}|3`uK@s zsWXTvgmt)eRAhIB2y_s2d@E|wJ~5`dmmXpd++o}H25cG|eY;tmY~U460DxI| zZyM7Hv%&UaaHUb_cjlY2K^5IXJ8^G>M-YJU@1f|8)S`T;xMDe|fVCR%p=u(yg;4EtVf5^= zBHm?$!e+YT0FX^PK8SO!c~kCG_I#c#e;9AyE!H%I{OTbzyU<;8Sr~4}v%F`_pl8qR z42wan+otRiWyqK8bKvT6;K?kX_0C+O>&qM$X!g~X?4ormV?gj*aIIOk*kg^8X#;GA zU)#8|f{oWSa1U|Yf{YjH+hR_|huYlknc&rGSN|9!sS3b``cBOlXQW- znzj#T#TzRxw>5ah=WHHtR*m{KbO7z3EzlXF&E9`7+7==?b1WpjyF&)5RjeV_tk`JS zdZ_{7DSAyPSdM@pZbyJJ&N{ZmY|)F#c4poghaHe)t9V%5WKo*lNB)6*<&ykYL0C1~ zl8_7Q&(?zy*nO^D7Qvi~Hpsj@TTtBZ%;_3Wr{B}v+K!ky>-4Z6bRn!>pTV70gK+@w zlip`>H$yK&djo&wmRyS&1mD#EU)O!P5ur2q*L7_v!IZ=)yJXZUv;|baRxJmOO>Hz` zTtnz+_=ZH892#jDKwCJbV&s4w0a*hIw1C@S?3p6x+Wm<3{1D~DymG~F(wUR@@0K*o zS@WeIt66_5%NZvWePQm(o@Lu+g}Z&`u6I^MKl=hvO%ZoFgn-YNW?-Av!6#%hofSPT z6P@PjYhC1_!#?n@>?2Je47i>R<^`I0wX@>PtH{MyX-dOpt@A9ZcB9e`$Hi89uS7p@ zQpI=*bB+0Oqk&f`1)^cLwdRrTGTRIZOyC_iuLSmM!3Bp$y-SMKL@PaID6_$K9&#BO zZE-6Ouw8Yu8qOSPX&ibkjWhG5k6fK&e0z)U&UcMC8R*e(@r-`=kUwR!)o=n;-9RWdb_}#EKb%jLNOKjYy}*L; zhObT=W5Ye~DGeNjfW=RC+mz)Sn?DHi|Mnm%rHltlF{ZT3=JC?01N=!S1%rG04R`hc z3DhSsh0$ke+kjAD=IK(%m{uYFLa!7-29uGL>V_aOHi~~FHmHMz&8uW{(bQ`uXy6^@ z4{%f(fR_#(R|jx5MQz*kH*k*OE1!}6mT5TwJF6#(wE<%UWG&ESwCGkP0-&y(@+$lI z@$Ke+PXugu&(?7>oBi<#T9#rAPXYA8O_7;Jn^mTzSSs{dCx==tV^1tcW@MiZKZ+b| z_c6`im7<%uRsWerzwa0A!`5elX{MXZ96$yQQ1(a`yG)KBdVsDhGu=T8&X(s48xf|S8UjLDe4F#^&a;KK5 z{2FVUZ?41sggERLoc;{DUP5BV?mJ!>9+@9+G9(DPB$ARSf{k)@{q zTX7|24-F)*2w-wbku05E8E02fSC^IaQu=6=vqxwRO2rWUN)%0nulvSCd7kP^sXd<% z#$;)+9XIAmIEvE6CEwq#aCaL^TiVfiF-ix}N-OUDtOCIQJbyR1NOhMeQ_srlVYnR(S2O@DG|<{YJnA8ON7 zTpGgFFf}C}`0{>%QQ$8UUb!UrW-Y75FzBGV8eoJ)dcB-&30WMCazUzFzp4EgJIH@k zJY!z0lebc4o1Rs(!cyovTqqX@NpWwrohC;a395?Wo?LsyQEqI+0<-wW0ZgROIG*A1 z@yARKAR<;}Pcl*bLk_emsDPv4das_0YrgE0BO}6v00rm`EFWCL_fe(?sb*;rQ(G8t z0=q`JtrmZziN8o8FV?-r)es3^5;@fj$VDSGm1<4C3|ZZOXl8w{JxRXf%STHRYNY{< zRNqayvqc6C;|aiCf0tQcx~3~XVyG9G!Co=Ei%J}&zbnSn+KhWpU>S)NTg*!t^kFSX ztxy5SjxWIvg%TcH$@<9^;bRF#^V#fm}&9ek@x%)q`VqWTUrsA=&%anAOc2icK9) zKug)Im2G;d1Leh4Vf%KO`T-3<_Zp~Ew1$wNojQOfvZ5(s)H#YwLZY)r7)i@>1v)J_ zdt%;c0*!g|*@sPp*B^g#D%RcGrw)TPkNR73O$NF36ce|otvWJ}P2@FMc;LliXwwe=bCnKGchJ-!nYv=gt-~a%*)N2fbMQueb9X~!bhu}hv zBY)^YY#Q85^#gr&-?1kk$H^px66~RA#?zm<;zZIu%_l5j86al+Dbyz`gP$X)Y14;c z)9X)Z`13bMAH~)mh9@<0GLAkLpe?g+lG#)>e3OE&UTS3d6Mkw*`7uT~RJs`&gWE?G z$vaJ-R)ovmCRYma2S3XJHoGO^-L}5rK;Qo3Gu21T1ss4D^aE70q-kV_E|Yb{(|^JK zOj*soebjcYpSo)_Lhw+V%P>E2pmS&O<%ruJ^mKv|B%f3mQHaON5d`7{difHI(uyil z)YfgKmHx%hf!QSlw9;=*T8~y)SQ$PXyw-S?9gN(siS;n6E~|d{z7Uq3@?4E5-0;3S zp(X75VEN}%)ZrtZ2=24^5#IP=lgVzlvVY?jEkfGQy{`TV(W_3M#8r^Ir1_)dJj~bC z8S@EyuAH{xN=;P-H(AmJc*3B+AQ7znw4b&2ahCM&MEyH*U^jK>ro290JD=Rrno}TE zE+4SZ9lbk!J`>Myc;^=K+R5nW-*HG3NnF=P`o`}=HxT*dlzjS$z@$>fQy@$3P%u&P z&HgLlspCwE1IZIuGCuWiK`?)ek~e+6fUN!_G+1+O(x$3t-sS>KM zYodcfbz&4at-#fom#~Ja;yAh$2!&L80wb|MmYMsQ4t%1T)Ww*%!PNoQRPz$k3cdmh z#Ja>-8r+dRZrf4si6oS~Pq_LudaTEG_UuRQO!N}47^e>pmHSdV9Y zz_d-P2CpzfLfI58ektHU&rvxm&E?V7Bj78+?&QH6q79Sbp(A-I+yVN2ub8bdMR`%= zT+92KZE0n_;Md0R_WlBszk&mEF;5iqpM>jBO*`@@R8o z#(>CXQlJ?t_2J}?N~U5t-#qW1{jR$}w9;)EzQcuFRJ6N$`{bV+_CnH=UGy~xm{zfV z9?@M(g@_%p+gah6s|L3mZhhk0{3^Y_3ABa{!uAE8tWgASRW66&G$TmOc}1itSFA7v zWm!X;^Xug2iY7n*XOysLOOTnuK|lzgLO`gdEMtqLpcGO8^E8}P{@DXTEKpq;%BBM7 zyYq+}O<(oNX{e(eGm{3=>II~hyMm>rJewU-okF9cW;h)f9bT@dc! z2C;>(9-D@M5<{2p9=w;|irRXHwpEu~>YaRh9Qc|*R?OVEF1!eYEwJx-`4`EQm#zmm z#NjQ(^pbnBIX(Uq@boyp4W6uft#r**{0m?##$Dcee`2W+>9B3xL3NwKZMjPgdFG8) z-+VLFcPM?#g)4$T&gVCiO(xvtdx{9|#lMrK!?UUc5>E)T(Ocx2ZK-JDrLV>xl0XZU zHj2Od$9oq40r)(nz-zYQNk3JjF=KzL{6|AH-0uHhI7_%Z?TJJLCNs?Kk-s z746y);6XE%Vd?K%YO(J6NLvx-^H1~-S3~R!_M9VCNNJh^UqN3UZc2{?- zHy2V1VM!nfjDC%0wlplIB@$8t=dNq@8+J;8F1o13W4ii0lbCs;I& z+bAD3$$30!;%oNh(F{nk=yZ6j;bPmbd~B`kEqw2lWRAN1!~V=R=Kw_C^ac*xL$sIzCZ4b+6~& zRGZ(bR~iZv!1;WS)N}I9hwy7Jm5uVJ$u8?>wW;s6>-XAK{ zC!XI2k{ihb-QdsIxBw;&0n|`1B>?2|TU^I$wKS)@;WVZxGK5$QiV*f5)A?#1!EPlr zMz~}8aW=qK_Cz-=OY|9h`Bz%a?yov|Mf_|>^2%c4UdD|u+r0wWUkhQIOyPsmb=fMy z!hVkTN3CYGTu3pKTas*TDdrdRd&aLW({J>X`foA zTJ!q`2!|*sw8p<-Adi29=Fr-T4t%`_OvGVw0msHi@o9L2%S_2{hu@Id5!?%o5^SCwCa0_SKQo0zFVlb5{6Mb)eiE2+lLOb&y#9Y$EbyUGH5^eBAB#{lJ41`E(??kA zu;hyV?++OP>&7M9=N-obEhyq_axKkl+DfL-18J94rQI$V&z&pXgoS)pPLDG5dKywS zE1HGHAJInoLZQ?)?%A|Z%eVn#Nvmqb?A!EE9vVv@S;Yxqv5hUiAxN+D`YsPQH2;e8 z@uuPCO*5D}or}4+*9~DPrYk9<=)>kzBx!E~Jz-U9wBSwWi1bI}(Fh(O5yZ#&8Z z+n4Lgm~~;WjZ`-l%NEQRzu$>r6rja&;{~uUZJ&9Y^>cI|jf{WJi|*CXsA4F+fB8%I zbd9qw<3N*@%kOd1=`*`^Bia`L)fmqWLLD1p-Ee7T;YA6zu_w%4SR%*!eI*6=C3K~s zrW}L53-`G#nz9o^kT}Z?tlL~3-KtiibteCwOwXC?oc*;oY8d)Itd(}O;K>6w`&nh^ za{&0FNo4>2^YWB^NZw1xIk)O6$+5MqVxQxlpRS{rBIeA_a4-o)lGQ>7Zh%3h)uKcp%$zqA-+J69_UOjAaZU4TS<`uO0)(pFJ(%q@P$ zmsPL)`>imTi@eZCRIEu8fB)Ej8aT2a^r2Mc4toWCM1GB|_7OSBZ^ZDK@;5crc|Lz^ zc~K=5fjvB66~R*0uSH!>_Z;`XmeJ|4IiUE5a_j$ds@)jB0+VLsq1e&JXjj|x>sD`4 zGDajAjd1J4)$R)E;H5^Q;at|Y&v>$x2h7U1rfg%C&rAV}qNm)~GuaCsi?3f^h5 zdV2eNAb-*@vHJ%2@-^)8i=aBIhR?QPw&Yf0o_0`Dsf24g*GiQ3h(!sBVQdPyh4R4i z%JC}aUg2aQ0JZa!4@Y|r5U1dWW;RB(io-sMLPJSUbV-7WIR$NwXbt^R)rl){`33 zLv*2w+&6A2?%3Zd{&K_Gk+=igyTzkC6U535J9ER>fq1N6Ne}_jQ)6jUkd}2O(ZA~w z!Z^1=AQ|rRx4J8zEN_{%F3t@e&E{XK5WW6|cdp>(jqN6 z>mN_n?w3c=l1Efdkw}3BWAP1KB9_1d%*Gs(;_0j07nH3zVHftLWna5dW3WoJZHX zJjImR2Z%L^nC^m&rL)}T*$t1!h=)nVPC&?3j29Wzx!ucz)a{egZLo~@4Xt2+G#g9t z9SrrVI=ZgjB9;si74)#V=J&9+zG>JM4T9AD$ux8l8j5?A;Fo6LFTU|s?Cf+QwT<|m zeQ`IATndJ3E9}6?|A+KL6jWpf8C`#~ZPcd`pwo4DapfA(&j4UJxThg~n0uMTLST`2wbY%vU7se8V^ah0{ENkSEu5EC)L1<&-Zk7L zJMq7*LT36&He>LOhn-I38NW`E>QcjDK452}RiEjDuZ`qRwlv8y^8#KJYHcPF(ITS= zsCgzk4{KyD>w3fn(Dwc>(U2Sgu*{ggRANVC{VW%jq5ZEND-j*KeH6{gcz1 zhOglD9ae(lg{!})h!mGoma>LCw9mMdtyF9%{1@TEeCWPg2Fp!+0W##^g^{Yv%jE&;aR(QEU96NHJ zez7)|C_OPpEKx?iOuY>Y%B3Go6~$)u3Cg8ZQmyr2%)zYjRd%c=@4^EV-Li$&?8 zVF3Tvdmr)iUY`G`V+{Jg7gsnXeu^;~NeWp3Y)U*EI?zZ5QwA?+6q6usxr>@tWl7PF=xA@8(gBz>gTuZ(UUs0e$9gb}SLq&rkXMn+m!$ zK#NaDrL_sujBn>$O5tjY0CJ`ox+E`SU7kFt=fC+o`F~Rxjt>$fOab5!y=E*oqa~P7 zNBuI-iT!Gp#pwF7X6v#+WUtiB(M~HQ1@T1iEf7j%Zb^Vw{_K4ks)!HcnUm{ej5gw- z^UToN(bi9hlb@d}$s#h&Z!f##%uXS7*xWByFupNXY{M;ibNDRU)MUv~qy#A~c-xB4 zQd{_9r7YxN=X>L(ud{2n&}a<{)S8zEIGx=l6G?h!cc}3*#M*Y28uYdJ!5ccll@EZR z1OzB`^HFg{EQFN9Q}F$Yge9_qH!7_810B)koV_xkhrkXhscz&}sLVn>K|=AdZ}ZvO zhToAez#DTF3SmR(NWB6$Mfqp+cj*MCF2v~{-7O!}aR-X7;}8A;)cKE7fuUe0RB#bh z8Q8myk{f1BPx3KjToFk@ZWzSqVe_W~z$Ll+*L{v$1;rJMO+mPTaJd(#XgfYb&P(*B zVOPs;jUZ`2mwf5`L3B=eX1O@uN5Sx&O3J(fzOCSv`=wyE#?C-17{e`ZWXz1A(t}Dm zTu_r3N8-lYv2D68#8(#+L~$<5aqL1NH*4`T&9X86_<{@pmp7q_vf~o=5u=_BINTmj zxay_0?>EY@!Z7Fx!odbdQGywUG}8$|XXA!iRwj;}2dUfS9tOvwASt&9P#;x;1HDJD z{&6a{W^;7yyjO>~T1yqpQM_ivOZN3C0+=A&b+u(&6!hSAm|cw-w_OQee}Jj8Na!DV ztum@^GtPp zsB@z4ulF;f?Cx>3W{P1|Yu%x!>JYA8r&_5R-Wl}GF~pm2hbstoBb2(QZSq*bwPJ{s z+bY3g=M|Wpz1BoySvtvdraHv!CO~CY$ShJWQTyI$q0U08kbUeOkCLJdfwL8aK=uHLg#rM~QM21V@r95>BU#Hos<}g+*68=zX%}c#By^qQ zQeX#|0weHH)Oj_JD_fPjK63Rd3Cj%YI4GIsLTJv#F#?H0BRiE4_=r3Nsr9nAXcS#Q zK0V*QOE34F>6NS_xS#+fQ%1BTO-jo6eneAF6wJRtZJEH|IGb-a%?+tNk5)87w=JV<{4m=yB~1i(#Ur zicbiL8^=0H|$@um<4(_!(qGPD&*fL301ZU>KCn|9B20rR;4 z{iPGNfO5muxE<_Cy7i%K_ZV}IdyNZffcf`eHzGuplImJR){a0Z3-R>HC@KUxhXxetRp4 zUW}mCM=K5i{;u9&NaItP&kz`?m32iJhoPTI!>hrztEm-KjXB#ANyUSS&3Jb<-a&0T zIb>$Z;B%l_sk6V*XiEpskbi9Vv8$o#r=Lns1ILnNJwpQ3w3<>lMH(8ZU0tEp zQrk3P2R*?XN$5*V@!2hmM6ZQC?2sg-98R0#zV4_VhgaS^yoW{$16lE}PT)CCOm@Bd z`S2f(bg7lUyf|q*PG?+#q@EU1kByWVw|gk;TJ%`9^lXwc`pqpsntJLYdkooVAqRlt zuh8yc^08VKBaZ@yfu4?tRM*a%5sGw6bCQ_>OD9VkNC|JMc_9-mqX#s^JUCL!+giIL z?DO#_o}Z*2{tEHv!o!sK55G!XwTJ*7PB-9B_V|r`ifVL;&Bjt@T9F6}zNQg0$5R|H zk&4qNf8C&5Ft<2Rqu{Nk3UWx|+4Uz|-uKC7=&!^NWQ^n6uz^+!j#GQ{wpbaqI-HNC zL~nwH+#V*kkRs=ew2vCvl+@< zmLk?XzQOfdpHo(FNFr;p&^#Gxx~tr{SaJiAITd;O6#+Ii{0^XLG zP9D&2u~+@ej8&&MJ=cLc58NT&WSk9W z(mFtC8{2;9eD4^xntIpC0;Hr*bnhSm*lj3nPyv1qf~6EaOC?l&|Nr*ZAu+dTVgHy) z9X{obUmK`8B|r2POW49;Y4xpgr7ng^as;mhu`HSlh8KqcQ9NVmkcT*r%8G_Q@-*TV zm!-6D5AIcM-)SH(XX@KbC+EY*!yU{X9wB4{D=Tjutq)l!oV?rh-AH(D1{GrclaE^V;F_}x1o43ia_{MC-aOIh2rS@7jS(e85)@Aoe) z9zoNipIP#n-YlxW)_ZG;qRSYFmZ1qg4~c6vo1*oRtuz^QC5;MyfnSPehryyavA=RC z*&PnnP20jDDNO?#L`Uvvwg2d7)L!*kd?065APM2BzQX)B53X{1Y}Ef5GPNmUXv8UR zbf_spq9`eYC6qufttlT&Exga|a<(O|aEu*wGk8ey840=sbrQrcT-i8OUy(Jz-tH-Y zyy>tkIR&YoynU`JI+wo~@>4>DqZJam+)mWzzzy>yciky%sTjDOHrFq&f&G7a?;rYi zKOjtbojDb^JKVZH^(|8`ECv}QVJZCBF%nL_%j`3^I30nEYE4KXhw*GMJ}~rCTS})^ zMG2j)(S-PP?n~HrvaP9=xAudHc;SQBeMbIoP*Qmw11L6qC)Tz40Q(ZLioFnPxr&j5J6#Asp`}bxQa;}Oe%ahyc$yKWy)?1 z0i$4yh#a7uoH8Hc27VXogIhjFrGD(6p&`m)R_ETyp}@wyDvj!<44Wk#unJmFbQ9pKtb357?{wNfrpQ@9sA zyQEOWBh4dX(JgfS<{JSwx1aO;xZ*@nWMGPx0dsnTNyxkgs=ik9t>#>KTY zA>fcAu^W*{7Ple8fivi~IUezOky2qWC0ucnd+H%35uu3mk6;rj6yRz>F=cvy?0F9j zd!W!b8DID77-~jV8fIR`?GH~;4%{dD-Vm;`Xjltb!zXdR_@g{N5GK|n#h0P#)4^$O z!X!2mDd~+~X@F37R{2QVgWjyU>L_XP3Gi0jOfA|5-D*SyjQqQL>7ML|(?n@>bE?ZZ zHNi3(sH_jkMZHK)qOM_a>yHuEplq|jj`^=gXhDnY;^CRxF=4m&YL;quM!JsiMsN0+ z67C_U@qq)t#jL(Xy0Dqu53Y@X1Y}!=M>6RTlD!oM7@O0mw$oZYHa|af>NB>bKZ9%3aP|(l`cZGg3Vdl!to9A{#%GU4giLa7 zb^~)zZixo?;|NE;Jzz@aRk!a5)BImn5ypQ|>yDn=CtF*P8Ow$>&4p58^$Jl7> zjs6`6$)(a_2`eZ%oc9lDf^{RcKk4Q}M3>C9xn8Z{iiXV1o^b8ynez5Xo$gB{>*>r` zMN)MMYeC*X{=4ao#QbFbC^&*|GO_G}5#ZA(qHNN@`5qaF>Xuv-zjfO?df-cJbL`|j zo8@@~H*|77u42|-y8g;Z0_-Deh}->0Xs>AeZG5oyYmKubwP3)u@5H==4OuNhZS2S{ z7X3xO@57(&w8fXsZ;G3l_Tq+X~yiR!%6t|uh2)14(qYnpCZ~!S zw2*aIc`+i|^H&2BDyE5(7YKRTTMOOt8g}(CZEd?;Gy(|(;>rNx8^gv|(O*N9!SU5g zBC8Ak!XvPdgrA^2x2nqaOEZbWz{whn+c|~5ah!Sql}c=1BPy!qFeHVE#%ObqUvUC_ zK)a28oA6zyL%>2*($iKj>gy28jW5$J_EkbVpiS@4BE`gj>9*-H2Z~H+6wi^nPXGV> zp|jUVUO9~m#wUZU6DZ8MiiC312EY6 zpm!|^{DnHH9UN}da2#$Ys-dr+MiV3&7wIOEZK)jaE2We4nNDaN2=}qIc`Bc$F*9Y} z&&p|n&0lQW`}b8Yue02(`Ua)Nn(RjI6Fnkzn1P&wAqt;3d7=~NAg=XIe<;EBG%zz9 zjjnw$7~!mJk!oI6iD+0_Iy)p-OF%V>Iz^Vahm&J!yhpW@yPA`ZV3*U6Q;CmLgD4dm z=jBKhR-eZ0wyRkMSmeb<*@&SmYf}n|T4P`lEFW6z=W)^AV-?evQ-euIPI!6MXOGwc z97UOgYv#-prm*H zWc|iiqUxp9K^f=O#IazA)A0h7H~`hBs||1m+vWT~&Np~+h*iVob!{fw#-MY$e?pvY zXX-C>%IZxbRua0j6Fc zuZ^Oos41~0cVn=r;vSkaxyQKWrs2*<_gp@y*tvZ^nroMfOVx-XvJc6z#4zr`+XtcW zHHbMH*&6zZGfO%r8mr`kU4z#c+*)0?Et)JnQkX?Wjen+5+3W%v^32QSi+8 ziK~Wi;WBy6{ZC^yK=0VWeV(!Hc0_+(@{|y3?fgmVj}M;@`c7D$&nPd-sKzq1G_0_5 zY;S>2PA9O4clNK*`oVLLZyGI4G+->}DU+RK2D_sGG9!cPK>p)U#+3MU_!Ja5gcNTnHlUKre{LAqii3}b8g=bfv?7$7X~4>Upqn~LU06ym~x2CoI!59TsWIs$Rn`}%~M7@ zjDq)osq6wl5AXO6v8SiM-j`j_VZ_EFN*dtxcv{IlU!I~s^f0WL+w;pU$5zLvJ~tn< zSTTn;H`8dwct$+?AXA;o?*{dijxarIm|{mi`j0wA+T%@doJhJCfET~lf?eP!0EEhT z2rAGFi-2|HofGT~e{UGTP7==kpt9Y=?_Q5lh@`r<)k)+uO z#9o!Sk$nea;C>=8DL-_m8V!*X;<+dh3qEaM74Z>nkY-UwxdomcGJ~`ifFdP0gq@h+ zS%I}eVl43yh5fJ=sI!obp0Mv)B@u{*6RNIj%u5478IMvx%D5U*az($8G= zmVfmPc0NV1AQk!^ve zfERC4)e!J)6HE9vnP#pP-@WyP{iT$$&ZVB{7+Vu>`$gW*UHRFds?`dDYF(;28#p)P zF*BkCS+YgJUP+g5v&ctw-iEs!ug)m5QZbdInvQOk5axE>zo$b<@0`wX zi2_2jwWstoULIaP+!URI3c5OxEO3|fW_s7{nCVc}sCOile7s-q7^93v?agzz8g8e{S5Sxdt^ zWChMHi#5ytQ!J*Q1hfkOlHnNtm!Ei%l>i$2H~s$Qg$&YR7#QewaF?Bm>Y_73e1jQ` zzklt(BP1Db6l{sv+!pADiTamC3r!HIS-{|C7qQzjJnrn9o}nFVeKgxPT!8ajVoZ08fNMLUiOHuPX9=h5U>(=n0|qTJ z!9PTqu)Mw9BKicd7iQc~P_R;8u|-%Jk@R?4B{p(2#;%WoIEd_+0++8jKR(|&30(8tz!vM8U7JRG;C=s!MW4(8({_t5K+}GA^wWD$ zqsKF^=-aUO)gFyRh1yAssCgvboeY7dEdy4IU1V_?jMAwoUpDRl;N`u@EmVk)>4E;qN8NRACNWxnNX=y})DRLvm3{`@+d%Wz;tyDMSM z*7~Uy3&7rTGyh9N9;*~3c>@`w@tK$uV!*Zja|)+}C@tBAjf>!Jq!y$WTZJc`PV+nC zj>+1`Gf-#5Db|7S`|R!B^*?%L;o=s?o#zdG%R8BhCj(-3evxJbc0sk+7q&)g`-zkq z;a(A**3q~d*xr18|78%?4`p_2G|k9GA?}h@S$IJl-#;o(p)+uXcy=djUSM|kmeGdR zK(?M$E(4PxLb3F{0dH0*a7eY7gi9SR`!)V}HV3o7O;CpV8i01alQWD%(z9+YA~r|D z^*)F}ffz^get^4y{}bz+MN+cuPxL$NfAa{^qiPxMA40_b439 zF9O8!oMqufSOrDFp2=CkESWTpPF>+lVakgfExIPw&NK~q-&}lelyDNGkr<+pDBvsU zoUvh?(v<0vq+qH$3PYlci}(9jD_hC#w*FWz%5kg)ZLscc`ONm7YUWnhiRzA9M}Yxn3m%b&)}w6v z?Z})GTV~FJEx30E=8P813tXi2{n9WN@Km)SdHaNMOg6ga>%c7E(bXkA64Iupfc(w7 zr`5=;*2fk|(xDKew?>k=b8DKQiJvU_?%2y5%hq*@piQb>Eh({#Tt`Z9kCT<-HJ=ga zz+D4A*F>qX=itXvfGVryHpjN0gkh!U=&7I#C)FvzmKk4@!iKJEoMVr{+*0vx8Xp-Z zf1iS+1MPvbN}wlOZtf4o`{X>j=HPB1OZFC z*BV6zOFqq}+I|WoGHXFZMo~UFm%s4<2W)ua+K`Nq9q{Q$EH|q8xadn9Kt$t*3d2SH zR|vcKLb+N8YhAvXmnoh|O!~+qQI4&vLkqE7=G9R*l=Vw}1f4yPa^nOAKOJ)|2t@5A zeT>~|8ziAf9bZKK^56wbwR!pS6RAi80vkes9E~Tg6L0`JWAt|PsKs6-EXVHu~2#Zmm2t4HltT|R+VpBcha> z0V4NiYMFyBtQ2i1>RRS2@%BIQb%I#i_tIQ1ClZu+MD~p1-(o&OlPZL4TS}J?cNxxs z>_Bm$3HKA|RrZNpel#@I6@hw5)70s<$_5@n>dT&w+ukHLEs_hvZGD}rc<}ccD^j4V z+rRSsJqR&atFZe?y#7@@-dj<2>@W_|t^jC&SdE z^rpm0uy}$#D zXs)Dqk!F;F<^d4M)Xv;sL)W-N2i*c|vk*n3D=T)aMxz*hyd88fe(!yiq<$?I`#P|l zs<^M3?qorc*R^BYw%M_5+qP}q9oy>Iwr$(CopkKv@8|vg zgFV(5HLA|`!KztvUh8v9jpn8_NEKc6FIUCXKtkg9++PDl^0aw(#Djbwg1*6IL(^jj z7O`%M{tsCF?AsGp+krDNwI;jV;%epIX~@Q-zP8c;c5kq_NEf~l$B8L`3w`Fsv&<14 zLqw1AW!`~PDA(pH^{cg1Lxw-NL1{SFNnLYh#ul5}T;~^O)DFkrX`r0GRw~B#4|Z`K zRo-JgxyupVc^-zElhx}b2w%uu^zu8`cCkcQnu+fhY*wa!mZWJj6VTA~*y>fiZT!gx z_gW=%gje9^P%q^R?;I_F#h(tok^>3Vkg{*P{LiCU9c$WAtQqba8^yiP(N`&;m%UOr zjpV2%$wC_JQ%llN9@pq-cD(5(-D&Eh2iNvRHt{YdZxc&QhwGB)Pwe%Kg~oD_ZvQqa zP8$|7*(ZrmzdzPFVvt{E<;~$K1PnC(dJ{QojyF^ftxL3;@>5Fy7v14o=ps>Bx$pVR zrR$~mNP(yt;T&_(VS{sM$Ck+6dAa$$AzZxb`hKe-w6${4((jaT==ASFP(Qz?4zHk<-jtm52u0cCZ5kjTV zFk}UaPDEqy!VG8oS)nQ;POucW+hOSGL=txovJKs#kj-a#ew1|yYi#|3T`b=uD5KcG z5SZq#CMQuLU7<~~^@E2t(Ro70KblLshXsiN7D@dBeP#)Oqgeby%}rOJ>uJb3BaqC* zY`McWPG=xJ8N|HOaG4j8&&()#$>bsj3hB1v0q94{kWdnaOH(~D+gk?XQ*bf3ruWFb z>Ti-zZ5vX#X_>*EIssjt*zFH)N<(rH4e^nEezKIQ!WXgFE=|f&B#dzK7U8$8Ceau7gM5|N^Vj=xH z>A6Spx%#e&CDdXZdjM|IeD^R-z^ZR!K51DbKm>Gtor)~MGVk{|gD|3tc?YYltY4`BhchFSHAhQu*& zWn(LVmf`IY>U2U$nT0R%?DdQAy9;BHixXQ-sm~Gi{Sv)%7rMvTo%|O4=+_Y@6TkG6 z4?>KB(lYuXi>G?*?7kP5cl}w=I|zFh70|Z0rvaH^V2gB(xPEtIDV_N?)* zJ%_pAFsqPJ?4?!N4ty6$zd&BfjRg^o2c(mH!K&_?DfbpOw@^I#4q(3f3=qmKh5A90 zUn!I&3x^bR#m}B)v(}Ck@$5|KBSl8WV!jIy4Z_3CceUnG7gc5@r&8 z60SNGKnaO24P@ItPg6emYRs-EgDzYgD) z=8OvR#*cuyQ#)?`mTV6gJPTKy>c(~wr0ycLx z?Ad&_^p>CYK+i)n`S_{#`goPJYeC zG@606{Jt~T%FSpWBB?PGPV-c5G;nXxhUZw58E8}uXulB1+#R@%_9}&g4*@B0)G)lq z7GS^ihw=J046JmqwY8!u7<%!0R{zzHQTGVWQY&E8qRcfs09~VDfA0kHMS9~0G}45Z zi#qmy5@AKuAx09RrVaqoS7*8Xr>D}Xwl;-)SSp!1E10w1%pxH_{kHdT;l zYK3-XYwkaK4G!zJh;=(sqT1- zEmu)*TJHXi&&-S8>E_|tB_^SNa=1Dz$FFU-MY+zE?ve&lJT8DWSz$`RgrtR;oY|1< z>o5))Xa4L$ zjkZ=Bd~K-%#NUFQU{tt+=gJ^Jfpi^R21lGG^=jaPi8N(IOVdE3v%)=Fz#6a8H(PwF zs5Nt4b!ZJQ3Kt+7HKnSdr$K`kgX=b`vY$ghs@5vzf795bJy>5P?OsyO5gZqCd9ZJ) zu^k(W8!ahLPMO3P;8%jJ1{p~DagE(S6k6<)UJ_l!J~DXTB+Z>vIyrVFn~seH93@vG zR@h)&E=Fo6+EA`p(rQmP1%cUanJ9nEnr`)7Y^0Vk!3uzeWE0j(9g=k!#b;`OJ+Qw& zV~r_cna+TcF2GB{xZzGjV0PT41m)ndV+z#F(Vu z8KfpncT$QXQdHQaE3n%S-Y>{&UV$lqv~hqc#jt7u-BH<0Vn)_V|C6wCrnX0G_Bb?1 zLZV_-=BgLrBIBq$0lHz;`fHP*ggi|`G_q0Qmsd7AeJZE05W|MTOVS zVgx{x6C0jn7l_zSus3WESq-CmkXuhd!m!Gb*PdWEi8q5aj?&{X+%jO2X{$1b#O(LK zTZc@cJk~bJ&1_(5@1|^@S7$z3<0wphGx?&7qj62uVqOC7S=kI!>rV_ec1)~Mu~Z@IFQ*QUY$gUmms4hrwM zkV7pKt7>tM{ot~M*dk-EuQnO3!D-j1y@wTHl=#xsQssSpu)nzZ+m70Q2b$U>J3|0; zNOb1dV7sCYE9Yd}?D}a7&;^C86$?7~UC1yxgXi|)|BP9RD0G!2xZd>Y`&9kLV=In` zu|7QABAnwqqsRj-(m&w9MZ$Z^jTPc9o0cPo>f}HPJm=fo*#$4Zyeg#!HTggIvv2Yi z3*x~?ow6aldgWUew`Fbgsj)EFu(AQ>6ELUGwi5mZ#fZ#y5dSO z0&1MC;RVvU;@=`1i{@ElW5K@-f8e$aKlQnBTu3 zYj!=$vLf=Qf6S!MiacIO%s|v7#qR5 z3d%70l~M=m4GL>vQ@%JBCw>5U2E`6UnaAts>NN^N1IKD<{W46L3iBLp-ibZn)@rLo zX(vzZ_3r87yP?u1<7H09kTgN~6E;rs9_K#78oQW1Tg(aE04hQMV1!lKmD5E|6%p#$ zH-+{uCO+D>FG4h^@oGc$`*#)7TCp*p3}Y)~fD-1{7L8M{Uiuxey;STv+h^O)v}z{1-Ai z2eUdth4oenO%ot>M@a-K^&<+vAo~vdOkk>(!|bNQNk2Vz_=VvORx}*wt@nu7VPJWZ zt9+?wqOdiV=ixcdd<&S|Ba7`PTcmFUhT{SgtT3MK>-A$sQzz87EoN(C#!DY+g5NbhF z8iEbJXEKZ*!J@I{Td#+=;Kx^3Lqa>Y)gN+u3x8GE=03K&nQ9VbEtd*hA1Kz8C4>nol}+yQ6s}^ubOF z;luZ7-Z!2?F$Nf2w{`L8TB_fB0|z)6_m?e1gyzxWr2+5yk{BOVhs+zt4p$(WO{a~G zurRf?&06zWv+Wc;h$B0~-YY6CN`54oL+p*h8E~%K1b{RU=)DCmJ`)@TRG;|-m3Xmk z7BWL5Xvs}yUcP{N5biWo_E4|+dMfxl)C}r)G_iNKVFRl1IqpvON7~g{XPO(FPO4Xa zXS_t~x1E?315x?mI$+i#gRR$FSZ_h#22~~So*ZOj5Sgc0y*)_8ux`yX{R38oW*R>3 z@nQY)WK>au9*%BnA*x3=LX#*sysY{FrG1xx{0d~UV8A~NW7wI6bVaxmVhtjnfz8m< zJNSJmHV;^LxbqM_9mK-`eSj7v()~rUpvOmAubxVj(92@QZzS4KfPWzG*)7Q;BYk0F z>)tREeZDo!u_w#vZvnU5Ohp*ORiQLss$xV-?39ISCMbc(R0^hy3Q^yN9b2)bvVkq5 zq=t=uWD55>I=wW%T_0=|S=3L@Fyq(~y%^nYK>_gOgPq%f@ zs;;6TZ#FB0CwJ7LJMLD`>y5Q?hdxR*ptn3hI43m zKg4n7OKXzF?J5<@XcV28Db{tQ;GHzX@sK$mC~8vBd^M&$eQ?CID*1`wU-@hD`j>L{ zhzEcO-_UuwNfSRMYS#!IcuFn0Dws=JE{rFJuN-Uf6WZP-RBCtp76WF4la1PBrIn+l z=|~66KetQJC|a>)rKFP8Ux2snpF4Y5vUE^ST%~FfY4{3MJtI+EDsr+N9ksN4fwgZo z>~)YE5YGh8^?bE+Wl&m=MA{updWMj?dw)GIso`C zXnrQQnGXDjY<^Y~4Rj(wnJqCHJ&JMgBLhKi2~CH|IQ)R|$wLdv9KcZSv zTjeF@e*EDSP=YA^#97>m0JWcoNnx@pV!)Oi&QYf!yI+#NNtp^wMeoUf0QXUL7M5YYq6s*JN>Gjbz#x-fg_+KZ(1?>i9(ChGq$QJ`7vo z4vk$WMe{IA!af>TvKxwHB4x{1_f&0xNJs{bdw3e_WH)FMoL;pm@fE)2Hv-BX!Qv?S zefb{Sggt8xH`ySNk{0>NlAVk07nTY~DVLC97SugG+Wo+D5uiSyD=FIf7OeSQS~J`@Zz)I1h21X93XeU0N5 zpoHmQXtE1n(oL19Ko=F`&VW+50zJR|M9j{$fFs2HCiJhm zm$5WG$`&!%lEtk>S@pWxNdR00EFOnqU7PawB!s#8YvmVsnR;+c{c97!%gOLLq6rf4 zTYz=zX%Y15sb_=@41hS|CMR*kKuy7Fu9aQAk!~uIMPT0y!gMFd-~>JcnXw^aN4Z(e zXt)DWi02G5uuY>J<6eiwV^9AWYm`OmXz-F;Cl4pc246w_E*{SR0|%fCR%b3)z{7HR zt5Kz5*>jkf8u*+3LoXsOhja}4uF`dovzGQ_M|!4w61gjYL1T=9jcNfN4L(*gsJB&y z@1(%Nz*$ZI*EvMFoR;4#KT5l*byzqRbXcHQ_BVZFK!d1;IjtI%0TmU=J6&N+cT$78 z(;joNwq^}PV9~IG)IWI;HJ!xWLPO3sN4atd`tjJ&OtXr8mv(e;-Lwezt7G{c*2ii> z+KAZjL}lqf<81vwN=B<%m;A9#d{B@Q5NFB8yiEbt(E=6#dI%Lwk*m zl#`t%EoWiycV{`mZ!hLE5X$Vad+PM9H#PEdJ%6Ov%Fs|4e;YR3-CY7U%ot71P%6G%LuGdcl8i6w#@~kZ8v7m_W`YegekGt= z>1ULl?~AR15d;7#Gud#C3}oD4GEVt0wlY|GcM?;1MmtVTm?*pgRUo|>gxiECH&TDm zYE7Dx4!2q_zQqkwQR5H)CB|227+Eo%rnfuxXpzE@f14nsIU~;r6|`I;PUb`>#w1yS zQeU(m1toALWR`S)nw0LK!+Crun+|O-6pe$A)L}S48Ukox-lcAOpBmtKArO=okYXOHL@nB65etTGDY+TTGR6#iDKxM7t$YOI04iw0ez8VJMK2_^U2o zq}GPdm62E&i8nnykDhNBo7$FkQg+kyF8c(e_k=|3ALw_q!y);UzjA@c_O!T?vDa`h z@Z$ctdIH!v-$^O#{z99W7rJERlw1u%Ah5kGt^1HN6k-%**%|4Wh( z1{}}7wmbL6E1Z8E&Cxp>ao!?b{=utOq$}6R8xBweY8?w9|1jEJ@nJ+vA%|PU2&9ph z^G_c6{ls{3Mq4@#%ZfhXHBd<~GarJ-hwu0Zza92t81hqz?3m4cjze zBtWv8Gd8aPw%|ncB}?)KmgonzRLL#T=gu$L+ZAOF{JM&=wk~lT^th=g@O8^2Fb9M^ zM+9irn4EVhwd%+t-+}Ftdpfm(oB&fz5B3gPWs;l?>oN=5W_(;Eba`CG`_jA8`#s0? zzG`)k2G+dR_R7Y{&j5iJ%cdQ2qUKVy<#JcGs+7MT2PH+zN^LEeWZF#9fWd+Z3Up@; zjC6*}4atK&Jf)9TDoSxgi#SL0%lQiF)&|h!{%d#xNWmVrNM)}px3ta2<%)lh#f8^r zXk$s))CO^O_6|LtZDX5NZtmgl03PG|D#v4!M&yB-9ePH*cr)R6rnWs`#|H6jIAQsQ zA)nIymS@n-*yz~G`egw45){D$b43KW^k|>vqk4d{D$eaWZb5e6{k7rP6ZDVJ(jy>& zX$)6{pr<6amd~P_J$x0?>tA-h70!`%hFbxhq=_gIlvAJbh_W}#1MY7Pw0r3oI%HY+ z++)~~MRS(^KN$8<;Hpy7K$wVK{Cu_;D|*r3I7vEi?T||L~+IiP6OC!MKG)P5V zu6rn?5L88qm*5LGh?$=wY85YudNNNXsF{E52|a4^XW$&RzwIB4EESX>dGO{2md|5F zK}JQ|2kt;&>2ATR2^_OJqzpIdM!c=D=MfyJQs_&|?z4VQaWokp? z{l2e~ZyRJ0w+JRCJWHvEgj)bH+RuR;R_HhjQ|UYS`$pmb9hbF10p$Eq0mi+r1H4wJ zKK{Pm^qF2c&sPu1K^uHL#qNv4Cdyv!L8sI0Cb#%p*zwnQ6?o29m)IW){Bwi+mQgEy zl5PIHU*9G3sFaXsYbv`pYMbwEAk-D`&-m|G&-~(#*`>D{r)Zd4klFyn5+D)0+P@~M zgiWH=&s2-Sg2Lg&Y|7yi8A8LT*4G*(t4GON`6~~s%_mA9VN$jA)wb89kgY3OrO!fU z?q`NbNG{G3pXwi^tc<3WR)mTe$H}xGDaD|Xgp{>^sVbc(w69Xb0@+_i+~XP$CN)fi zh6ftlM>Ga|vKBtM^4S6HUEAvLb@Y=E$=AXrhn}Y`F5u{c>;%PX8z&xIW~CDAhY?a@Zr_Ff$W4w({zVJ}gz z|74$9a^r-KYqz81b2WumoZ)Z#!j^@ z1o=6*I3`ccEutE6XY*Xbd~e+K8FTSx?BBYEy_Bm*ABrBbQNEKO_zucfDuv#*@^2Dn zx2;QkN0xMklF-1{*n`v&1Ng*>V`%8f)Xy`BGqQdl)`{Pt%2&cZJN1h<)jBkaKf?73 z*l5%kHT{l}+Qk4ttij?^w9v4>fP0{3i8pjX&c;FJkTxnBA}s6H9LW3%{4N!Mrn7*c z?sb5AWSqEzXJ)v%T*rYLeHSDtzO$|zp1N(ayKZ!SJlk*W1_hW_*d2FGv9f4`PFoh!)~Ahx)|?Rp+$2 zPb?Ezf2d!3Vr+#KP^@ai(iz7b?ihQOjMAm-%RaLvW;fOR^XoQ$%WL)BKO6vN`)iXM zh@CO^yA1bvHTveqh?T&qc>}8*y^Yevv+F&EWDHPZVY6G3l-IJUxv*l)6CV5MNG}Hu zR0q|i*T(>%b^2WJKe*30exE4N6RUb;X=D`g7_xLtf8sNd$wMvZ?b1|+ysvJ9EkDNP zAxvY17`yvC`8fSCW&IHmgbt;1L54pJHz1MX6z0*qGfEod7uV$Mk6DhC2ujW;xGEHT zME{ZZEK8;(8f~M-ZFHm??QAS#s}oK(+!uItIHm!uRKF-MKt;u>o`aw#pCR{7iF zQCBqdEeiRx*Y?`RwFNXj@bt~KC1%gfs&=)dI3I3Dt%L>IKEW4PlveFuCQSo7613Nd zb2J}umd#&c9TVS-+J}bPmztuNc>dbAn)1LBuy&4Dd6oFk8)uy2nRwlaQjw0}K5` z4fB(bbPhWwAu)P;swf>~%&o{sm_PC)2_(ikLf}r2N=`yT!{AED39q?4EYoCiByTQ~Y{0QB0prBUz8%nK8H=RPUToWqg< zDGqxVK08WVS`(MX-HBk6FZZhnS@!huxJT`X=xtSjIZSzNP$LP?p~KQ@t!{UCtHsO6 zQ=i5NFihqzbx(99p5@abTb}Ep_qL8rc?+tj%gc;a)>_!n>+L58)_gP&J$rWiMh+fm z9i#kAz>UqhjLu!~b_1myJlxuO>a*%dBT7VZC0sJ~)Q;J8i#CdSMeT7xcIVX}i#*|d zvhIwhEK!*$x#5QMrtEv|4bQ2K^g8%IyltD(baHJ>v`* zF1JiH4B2cHh?&!nCSxX^!D!v_tSg&8>_OkT=!}_YG!HzwY zVm!}47P(rlCuC{>NIfP?OoVOnc`UOsbi$Bq{%Z*??Ybv%&uQ~CCt#5hdq1>or!X+DYW@ufgO zmfECS>(sKlD7EJqoc#=1!jb6AL8K@1wh=9I;|Uh{xLRz<`_)LozQi{ibHp(!caN5%Z=Gw+sJi)Ig;ql zU8J_NXGgA;Y1h}QRjuLPDgWkHXFmC4^s=HDe>ASZenlrusrSCNv%**qgGaUA8lw7w z=!M@~^|T(KQ=-FJoI&YL%Y11Hv}V79>EnfB9)oGKD)jAvE%QanE*0mC%c#u z%gwzW((+uVfqGVIgS;gRRq<4sl&@S<=E_sg>ay~ZoI`r=mA`dnTrroshc4R_e=}mo zhJ9Haq9SJ2j%NP&P7ILGR;R{#{EIZCfhBXx3Q+n4Luh-P1!u)FVKJK^fh&kbC&<6X zdgLM}!hZ|&Drpde`bxJeTa|E13x&xh?r{Z`f{RC z0IbxE<=Y8lc$qT*U<*K>kWM7lbeaJGf4m8Wj; zh6W_D#1C13N*pMH9 zHo$w?ahT$iSI!!VUBEsH68ey8c$Tz}0S@ph5H^+k5yQld>}}jQ>G>%&FyO+U-X1TT zffs#eN%?|9aOnoaF)(j&h%{HDIBy%ZYb|LBgik+ZoMdQc<=?MJ_J!$Q21kF_jeL7P z`p$xuYK@T$ruJtX$FN57sMuv$5cW8>n^VwR_Y>ls&=A?IDlCWQuHc*;5ndua0JpTx zzC^~cmgU4OXi%8K$TKQ6bor)uXYt5*u{ZIk5{0Cm@i++kJj;lP`}4$~zru1wr|<|6 z(~%E>xQC5Wh_%{kskNKN&dU80G2jn9xOi2*MorAoU#4>|ESiS_d@aQ!;#!qjI_Exi zP0jZv7gO2~scD^2)P1|c(^oTz08vG?2K<<0so#~kxFZ6$BQjhRwfD!W!~P=(0t@VE zVK&K9gQ}ixj08*An7* z^VIg?Si}s=8UkA)xqLXxXW_`r$*v;S*xPTYD0o65Wd-8dI82i_A;>YRfOipb%x%4N z62*B+&mOKG;Z%mQEOiAn2+sZ3Oap$sg0y`#p4nd zjnY%j;&leu&0f`hFn+@^*Z0&!r*PwO-NJgQMA)%CZn-VtHblk=k$+-bXAd8*6db`> z6#W$*Z}~4VZ`J-GUO3nU0E+al6#_PhfvFCK=^(r%XON$4o-0nk(*+#-thx@XYz6QW zS&pJcxrgN|gIjkfM_HVuXC=*+f#PqfIgjpJ(C_pLvBBRk zANEgv!iON>z0)t)F|cT#?z=+&itidnfm1*r;r({)zap^5Qvmp{o_(~BfWv$j-M-*p zQoT0zoU$?~{yp_$wA9Vp`?=Gw)FpBPGy`(>a8SY&vS%B7@GrijWZ>vn=H5umW1Vkc zv8YyIG0%Q#zI!M491DLdsozmUYYr+IVHH;0sVrc5;+E@=*n)l}YjaNME3vT&phU?2 zxPHP_r*h!~#-}rmqR-iSr~3E`+w7%D(nM9yB9xNli1zCc97|B{;dv-`wG~maa_H&C43E3Bjs@K=+MM~KJsY** zg1aK!mQ%fIw7p{_&STG$wi8u+G76P8E^**9e`_&rxpkhp8&*aB06qi<1k`|)gq*~Zgzila*!+(S82Y2xti397 zxj)jW_IJr`UY&|&2dW?s3MMek$)h929Fc6(oA{lmCj^tk^FPeofvuXTDG|%VX{G?N z*N>+k=-g0N-{Ih(*5yohVm~~2e&;oWUF!{mRTee9OA3X4R_IU%vD^ZRgZn>F1Ohlm z3$BhwCw+5qMTVoxo_#*4Ccw4_kHao4bY$hOLA*?v^r2dGJ^nnQ^nk$h}ro z>k95AJ!4Uhj{pdT-_7sawb;P)^B&*Gb{*XrofLjbVU;><1RC-Dk}kpczH`vJT93MVCh3w(N%*D zZQOJGHFHVl@j&GSlvJ6P#`s6uN4)wwI-N2vF7+LwSmD2XgmuTogZ00>-s!*ZKX)8j zk`xkp(v%M)0M-+4*^Pho2EW(U9XgRNfK`6}fG> z@r07+lA`o+Y^!PZDO);|64$BIr=}V$Zj4b@+El#7q|qwj5$g+r`GwS-on+h?vnJgs zL+tV;wM=&V9k89xmHY1mVeS}c8`&s3pmGa|n5vr7m@6vtxJxfs3nPD<(UREe`egsE z^Bo{)fKWeiW4yuz2ac8AoSC_QlM8EY@q+iMr~c&eqpt;ErJ>nXo47WQ+{1FTd8R29 z|9XqXH!P=wws@DBX$ zpBL&vf3tj5PcXT_GH7M%z(X{)xZzGD8f7UJk5+-&bp4axDhw~AE$v1OGe3ZHKi_}^ zUKZM`9!w?K{ON|hRX(m~vs!DwXz4lw+kvo+kv79RCC@)qTx1hwD?Z)Qg1FYTg8zX9 zD7o5H+P;yoNhL4KZ>|*xnfzg%0n7!L5qZ{m}lYgAwjSTyqNTsl+OvmxkiIkPUh~*7=f$& z?Q*HTiJ+lFDtc)JYE!Q?cc5hh1CogYFc*C}ddT2a$)^{(FjiQ_S#c*toSym=4X<%$ zSc-wQrq1iFXXEFIZMhq+&A0Iqh;J{`b_%gaD#BVp=+O)JE-y~?E>oDh=8(EAqyBXq zvk#&pthZ`ht)fz5U#_*No@BnV5?xhcM%j0AW_qR`)^R9`5S*iIr}EFKMy)0Q$S1#k z4DK+>a3~-ZQ+bWhJdkV8;+#U$U5iOgwp<3m~m@=$L|EWxQ-j@sp`e^CBR*nij1Hv~| zvj;cWz(SZK76*H@%N)e&F0m2;$kDgLM#8Ua6Ok?Q8BIHuD;|;jmrcbvo`A<(ZXHkBo_OQ9ieW%gmi{DcL@87a8l2+ND$Y}rR&;2}T=!=0pBj#KR4!nJ(zz5 zH=d$MDo8xe&W{E@HaDqrYr@Vnw1ipYBEi2wqkTxJGdY&=(rJa4kl_`js;$ObOi|BjPmabd zQ7`_u>uQ9#@l|eUL)6EKve>Vg;M1@3v+x)nu~hJttiR4LyQO4?jj)PNC=xfyPan(K zHc_euUxMWxny<%M?-W>jm7R<*!BNDyv{sUOu>`Ri zp2A|33dy)f;rrHKr=+dtDtJ`VW0>o4S#P<@9?2@4&O4iI(z__gv`|_N5~D9xbUOCc z!Rg>PUS} ziX*i;s>eD(@Ex-Y?0pJkAUPAQ zT?Kxw*I8Tw%!}(C^zk+jEbv~yDA>(J7oT4*!Lz+jyzeBWWvIhtUHx4oT3MY9h2w+ryT4Y<{M2$k-xI@-#_T zNGSJ)mn*fz8%lpK{6@P*D^92AuuXppCU*TN@8NI4Im~(kv1>^dI&3Mi+6~Yk#G}FEL;l#TuINipF7C$916XBPPNEIZIN(;jJwys76rfC z(gj)&k4Ncb!RMZ%K!xfR@P;4;4=}iM8IR^pf<-~n@oB?+hkjC#_Q_Zg3&T;O zb|1Z;6MN035w4pzpOCBLTP7a?J6fAg-*yL7oo~+<0t{ac;MB%gY#m#`2g6pFRXt3) zs%eaA**w^E)cKHN%F#sq@-Lo;8O1m(tv68NOl2ZazA)h?W7S@7+}jqRqM@7d<^f}s zl~WE4-EdH@=m%ATuDw2%=0^A_TKZ9(@ z1M5EOGz! zVXBEHi++4SGtQ6CO2&cAZ|N5C}W>%&$M* z@`KW%JM@4@jxiUt6#aH0NszGY~p+me1Wcr z@Mf1!)aX+761_+y#gHZ;5ftqOLZwIY*nhFt)(kA?vpr`oK%qPCw`i1EPL#->K5h;< z0xed=v_!LpN!vp-zjek2YotZ+nM@(SFzQ&(cj#Lc)7A@gz%Zmhh}(h(Cvj{e#Cnq7*^F1)&VNS1N+DO53C zrq5>t@9;BX?7X@e!ua|3(hU2-8}m)_wMMojmuvaR=$ZBPZBBPZzc5bnh4w5E{H5|( zXAxC9kLj~7brH_?&c3X4-sAEpS%8~K7}9SuxI=y!^;jMRK#D6@Amlv zVpvEj%~NJoDk}ZmQhEsEL+(_xc^LucRVdQ)OboCs`(7Q?9~GM=+soVSB5G~}f@NJW z`^5#^KkaNgcza?M=9d-N^J0}Q>_L^RQl?mdPWFH=i2}o?X#6m65Q|#+wpSB{MkUnI zYh0g~hk?WmV4={1?2JNsMfz|>_M&B%rTS`v%J|qDm2mvDd9B%(h{tXDAeRkq z5haT^!OAiFta;Myq=BKWH6D{FsALDZJ3VV(JbK`DaR#=1r+4Ikf^&!QdI>r5in~D1 zK%r$2Hih@7XTZyGXBkgAJ%1B5#-w`}PVf&ic|?x|%qP9R`UU*;=Bv*{1eG=xdmnUp zv|t|l{zRiU|M)rXA75CdICu29;_dFwa-hHxRe7AQbBO$|kp%2sS3k@Iu9R9iVQcSZ z)A>=RI^I39e=DTk5Qgs+wK6tgp8Ht5o`N)JA!(eai0jad9v4m2M`$0dN$VVWvguKd z;y0-PVx2ZfM}@daMoC@KASf4*FnD7Vs7FEg=p??cQ}W)D@$jLFu_2>4S$pZW-+4b= zlafGla!2AFytVRIxgz_QhW65P{6zAd1jEntw3P;`yOe=WilaTod%NLciH?eaV#AnL z<^|Ha#XXEcPakv&u20V(El@g1BO1|8enk@is()Ik--!nxfz^KqU#&cP84nj zY3y^b!R`G7EpM)OdY%nt(|kcyh+fiGF7zmJU3WmmLGG@P1qIrY^yue77wQ*Lu(o(z zYXhF=fj+#4;UK3WC#PYzw#$%kEfOdT$VP3&7~WrO^3b|&$PnKRlIXB*V(_(o)uf3v zwI=w23rSsO_a^jxWTlUzKa}dOJgJ)d)m+s=B|aG7u0U#h+)0;T*-~lV@CbIfNd%`( zi-QpSRo{3J3y}~CKbarYff?S=P5L*&>n~iz(@DTR+kO^=lf|1q{J?;PYzEW|fPwQS zQZ@n=lZL!k7Fd3ja*+Q!P}o6&VGc($h?+u7H#Qes@!qwz$jkIyzazH?GGo*sh+ir< zi8W3ZkQ14Bl5n1OrY7|;_Nei9^55DIl7eB$zrB3*f(yKX7zFzk+Oe{XC^F>Jq>Hq} zIR7@frmay}5u_8Kef+luXpKbv?{xM7!GC4(0QWwJnFA^)H93!4n<+n>Tpk-sV+beK zn(VjvdXZ6xh+o!3z5am4abPDf$$_(!d9-_4Pl}KY7=0QN1Aeo7gL+J|P{uA*(Jw+-Y=@bPS2xyV$e^2;0 zQEY(xK4I!)WkDoGUG&X?hAmcjHj2=p;39ovc<~-NkFe{3oi*5ze-Xn^7`Dg=!hh3I zNS=c3;OK?xQnIhipR*sjPGx7NUUm(7fi(wF2Iu$pAMSOUXJYvF|MiX5S7opj{~M69 z_RKf^Z$OGS6<$B7P!v3YmAD9&kJ5qo1>haQgQPwWBK726u(3GIs;0VTORspX&UfOL zELKE#X>Wu13ud-~k63uKQIZeINVHv&k+Fs$l}!b&?DoA6Yk^Gw8vbs~9c-|OP`d;D z--ML+%Xr8DsHX}CEfUqa>0e!wh;28HvkSQ^9wErIXJ%M@DugKe>0LKa;C^s?AAksY zV~CdNIiKCPKO<~3 z>AALHM(6*`#qb0xL;fVZBC3(g?tskNUuS8=KWJRAYA4;}bqfjGTUUP^-<-?jCb-h? z5!ia_=I6Z*ZnbfP5?TM0*4WQcn_^WByUr0l?1cnlH>hz3E13Kha531xc-2>l`6UWV~PwCQ9=)4CfkQNCXT$p?^)l3S8 z4woD&z#+3l;nJH|4!xHq2RV$RsBh4_>DZ^0_Vo-OGguo&Vx< zi5>utBNWZ{Dw5}o%&z>yJu(2O%!3tWaOQe~{O@O@tO1GmZy2-o|AsN^BO(5ew{=*C zm$VZD3&5^iqf~rel3vWKMyh}!@kBuj*=fzRYPdE>bzk&E`uL}wQuYTS?ukU8&IdLA zBHVT8O*a$h-4OsX1o45>XV3gNi1Lor(q#RytyXRhcnbe!vbgD&H(YR&ob2*L)f75IN;oq0G^ZyU!)A=?-x zgBaV`P4<1?$(}697LqMnk}ZsNYza+v%C5B8k`hAJ>|(P2#+D^Ag{Fx2H1B);G`(|O z^WW#X@B2A3=Q+=IzTcdi#V1=JJ|CTj8%xABAVPVr8!mxL)g}?y_Guq@eK?ynzwgSQ zj}_f+A*vH^%?p%O~)7yjn(q-bqp zMx;yNN| z+yKeQc-d#P6oqu|efCQYDs7KV%+R!WZzrFRp48H^wKsO+ohv@cx+n9DR$VNT3S^rz zwcW&L>@(^Nmm_Xt=psz!J*Q=arN&o;SKX-aRlE&U8Mwd$|8%M_f4xr69jP5Ts{s{Q zL3#B>@OuVqZ1s190xE$F_Df-Ccs>tTuuMP*+CQ^`z2Pb45RveYu;}C#lL*Xduy$3z z%6Q=+-r@*>4m!z#VUy`a#y6rTAuc)9`L71O9ODhm87@j9Fzfc8>=ec5vyBiU!Au6! zc`mC;MHkX5tk1+WrRD#3R))jr_SyOVOgY8)!(IghLR9^H$iczp|h>_x;+GP zrfLE~_96uGA|4T^m?Z2OoGHa1cQcAL>|>C=VFUKMc6$1X8%vhh z1;HP!s?2n=1aP*L)yxX6EcBl&R1PR(3U98YDiOPAf6JmBNkHSmEozqR+8=&p?rxuJ ztl#;X<(H%TO4$R7cC*I@mFB~Ib(g)|4!09)e6Gw_8l6IdFW)N=h0}?GWpYx_4V5N;*FlspAOrP zDYht~Q`v%vyVgAN=h{?;SR^ zU$5}`E=5=Fl|9HPK_B#ub@?TIBCKE96V@`&LcIX1wu0}QJ=wdrVe`1Hs*Uq$M})4y z9@Mk7TZEDUJZDaaV=PyT!~JtWrB3lhj_U55j(g)dP2@v|w#1mocsEWIPVXd#6OCxV zPdlF?hxLvRxthYmWeut1WxP}m?qgiFx|mA9>Z9^tu)*~3A#pemXe0bu3Xni|I|b}- zxuTHV=d6|(_Ce)ZwALE;1T)Dy>tmwR)5~A_K%NB;%)a1b`@tPadD+9|$^xx=6jz_Z zbko=c`spRNpif8nvxSqtcK5r@Kt1i0(Pk_xKW0v?#W4@%2pAb%sNowpr`v36Vd*9O zI;(13sv|V^(d|6CSeREuGR#^T}N?kauZX+hPftszd)RWU#Ja!=7j&#Ul9 z&#Dxhtv$Tx6O55awkzn8%ZHKW4n$ovzj#{1T0F&5VK2g61h>98@Wdl)4Y zmXT_+-jc0u^wy8ft7TJ*8zD|7G73?-G|cnYE4RQeM99(8l{7G=)@qxF7pV#JNLl66 z-@SdPE~;Qt>s}gWuH8%lO$tbi7F8iEQhXZtr=%@!b3#`g%w;-l`G+~oKGRB&cW7>R zn9TI0989eYPT(D#k*I@!@8i}WJqjvRd#c)MwB(6jzK;lp{h%3Ujq2E73aZIDRWeF% zGblG5;`*)l@uy|o*bdyoNu5S_In^7i}=RI=%~H~ncbrp*o)?<$-a)*(|Fgjac2+ZGF07G z5-Pip;`dEEm8Tx%u%FRIE8%vizmUT9Ri*_T?!&$C>VVLWr@&_w=@TM6F16MCx&u}W zdRz1HAggnt6kM7h4{qI1=yS4;k;_t1P*D0w&zoUqlBl;O<6Lm-^h`d}6`X+ak35Eb zngc;CIMg(TDiFt2B(FFd=P8d;J1HzER2O?<+ALSxEM=;ET7 z+Lt7EhwwJ`q1S{GK{eb$+8aDI%TVY7M(pq-`-4C{zs=s;N;PF1EF^#;%_Z1A9CknK zA4wJzO;=XQO<{0M|Ffut$`M+&N5ET^_2;-NfkJ=ADt;=*+VbH{* z!(E*DvP)>R!XWm|6BSEa4Wy4S`7jggWiOw@>&eun{H%niWXSn&bj~7k?N+^bY=B)oyI7}dRZe}w=FYq(0vnLr^{UuIF^^*zZP4P;Qg`L1zPn0?KCga+ z6Ww8%qs(Y{en|j2(RT@|s6F^lMbfP&{)9Xf@_KP1R>h${5TzZH?L0>oYH9kgHp}QU ztJ2%CtT+KFD~Z6-dM00~nU5Q*Orp9bbjE{zPB|7M0fmFtWnrp3uA?4?8@ATHlJ&cT zaI=@C7BX;p3Xjqf;fYx~r0uoM@w8GO@z}~2K7ODZ5m`}~`Fa18icUf4s6qy6{9bk(&(I z3`y7xFG)ovhIkZmF5K3{O0_cPlYgtE)DHfQ{peAcxu<;QX^Qj%f_@m~5vBFo2)gZ529G5REB} z!8k1S6^xAg%70J|yg-kP=aXgGvi_pE&d-D^y5OIZ6>x>E%(Kqxr!&jZIoKS(-x1&3 zvQ7|Q8xs<&w7Bp{M{{)R(?pK%?a$U%IcIHiPCkWyC&s={d7pj=3eIhca zL93kH4pI@?wt2xUJ-4s@S&5r@j@3pttIKSd`9PfPEKLeMlh})9|8o6=I`n=z9ObYGW1(b>y$5kgQKbZi~FX zlZnNnxt`+&0yw;^_}&Z*=UCsYxjGNa9#B@Wut3%J2J*eppB1;T^W{==YHW6dJVI@& zG1Y{>tA2GElGf*ykW`N4)o@6nsg?y1XK2vBNYZ=w&1#ys4yq;k1v<-9ZDD%1`9cZX@V;*-)y`@vP zY8&P8OB&Y!IpNrPCL-y94psIwt<}++VSXdRtd)DXxbu0rJakHh>WeJu0{-!PI`Yl0 zRx3EUk;LBsAjsxz8nBD#9Q1x*}kjfy^YIamNY?zGqtkfh>9iut&g1T zzW2M;8=0v$i%p?&@Ajq}yY+%SkOtqg%QlPE?ozt!tIFM#+e33Au3z@Vj|^YoD>u3@ z(M84{%APh|?R|SvA%N3p|Jgqwef#WXmaUblXTn6(qCWxe+~C&v4Mk(b!sAO1R=cw^G;`Xl^D!mNb+H45BL2cQIAGbm)JPHBu=Dp`$%g|y3Or-KM);`3(Phl z6qObcn>DKnj!Bat@4F_AWbQW`hSeF|Qd?`(i*>>p>`<+k(dK^{V`?rmr2Jk?4VHP9 zau}yud_zvH1+5_ycqcUJK?>rctxavSIf}1feK&59zj?%Ubu6ea4F2FUziaGb*U53_>s^3b4&`XkRojXo{`ZwJBb`JN#qwG(q6?=}Ic_M4Sf1NCim1JO&~d4xGFB4U&CP6Z$==Zvcjk(j;KqX#nKKn4V@Qf~A0T zi6syX131#FkbnlvL{RX74E#^adQ}pLfsF{|J&=X}b{jVaQf31wNh2-s5Fz>^8TheR zGYCW)sgw_ZgfYFmT*SJL9fCn11(KATf<$n?NCbZD3Hx^|e+dJSDV*p!3S87dpe`wr zC`o6DH4PSv!2h&|R40LQ#E6i5i9Gz+FzxRvA0r7s2*64b^1E=3W51%m!CpBKhCzu3 zFj*s#;D0@LfCA5Aa!TPCxRMC5@y8w#f4A$hDu%I)9WdsRh9A2Y0K&8+Wp8K!kUht- z#61Y4MgoxOf-vHm=ZLwEwbnr(aT3ZLusV4N!-Q({6TxGd=)d#n84$t$O0C5J-q5utE_LqOB64VE}_bij}{6r~d$L5#luf delta 35367 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 bGw(yDn9y5uP{^#BHc#sZ2+}>FxUKvR8%l3M diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ff23a68d..19a6bdeb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 5bdb31f8..adff685a 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -203,18 +200,17 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"' +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. @@ -249,4 +245,4 @@ eval "set -- $( tr '\n' ' ' )" '"$@"' -exec "$JAVACMD" "$@" \ No newline at end of file +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 6042cb3e..e509b2dd 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -36,7 +36,7 @@ set APP_HOME=%DIRNAME% for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m" +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell @@ -91,4 +90,4 @@ exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal -:omega \ No newline at end of file +:omega diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index e74485e4..15b803ae 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -27,6 +27,10 @@ tasks { } shadowJar { + filesMatching("META-INF/org/apache/logging/log4j/core/config/plugins/**") { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + transform(Log4j2PluginsCacheFileTransformer::class.java) // Exclude all the collection types we don"t intend to use diff --git a/settings.gradle.kts b/settings.gradle.kts index 40384465..5af9d03e 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,7 +17,7 @@ pluginManagement { } plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } rootProject.name = "velocity" From 75ecb641596ab63f21de6a54078ed01654a20684 Mon Sep 17 00:00:00 2001 From: Adrian <68704415+4drian3d@users.noreply.github.com> Date: Sun, 25 Jan 2026 13:22:54 -0500 Subject: [PATCH 14/48] Update minimum Java version to 21 (#1649) --- api/build.gradle.kts | 2 +- build.gradle.kts | 2 +- proxy/build.gradle.kts | 4 +- proxy/log4j2-plugin/build.gradle.kts | 4 - .../proxy/command/SuggestionsProvider.java | 2 +- .../proxy/command/VelocityCommandManager.java | 2 +- .../proxy/command/VelocityCommands.java | 53 ++++----- .../VelocityArgumentCommandNode.java | 6 +- .../command/builtin/VelocityCommand.java | 2 +- .../proxy/config/VelocityConfiguration.java | 13 +-- .../proxy/connection/MinecraftConnection.java | 6 +- .../backend/BackendPlaySessionHandler.java | 4 +- .../backend/BungeeCordMessageResponder.java | 82 ++++---------- .../backend/TransitionSessionHandler.java | 5 +- .../backend/VelocityServerConnection.java | 5 +- .../connection/client/ConnectedPlayer.java | 97 ++++++++-------- .../client/InitialLoginSessionHandler.java | 15 ++- .../handler/ModernResourcePackHandler.java | 6 +- .../util/ServerListPingHandler.java | 105 +++++++++--------- .../proxy/console/VelocityConsole.java | 11 +- .../netty/SeparatePoolInetNameResolver.java | 2 +- .../plugin/loader/java/JavaPluginLoader.java | 39 +++---- .../protocol/netty/GameSpyQueryHandler.java | 11 +- .../packet/AvailableCommandsPacket.java | 21 +--- .../proxy/protocol/packet/BossBarPacket.java | 76 ++++++------- .../packet/LegacyPlayerListItemPacket.java | 71 +++++------- .../StringArgumentPropertySerializer.java | 31 ++---- .../protocol/packet/chat/ComponentHolder.java | 100 +++++++++-------- .../packet/chat/SystemChatPacket.java | 11 +- .../packet/title/GenericTitlePacket.java | 28 ++--- .../packet/title/LegacyTitlePacket.java | 17 +-- .../protocol/util/PluginMessageUtil.java | 27 ++--- .../proxy/tablist/VelocityTabListLegacy.java | 2 +- .../proxy/util/InformationUtils.java | 73 ++++++------ .../proxy/util/StripAnsiConverter.java | 0 .../VelocityArgumentCommandNodeTests.java | 4 +- .../proxy/testutil/FakePluginManager.java | 16 +-- settings.gradle.kts | 5 - 38 files changed, 410 insertions(+), 550 deletions(-) delete mode 100644 proxy/log4j2-plugin/build.gradle.kts rename proxy/{log4j2-plugin => }/src/main/java/com/velocitypowered/proxy/util/StripAnsiConverter.java (100%) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 8f969cca..268a8197 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -59,7 +59,7 @@ tasks { val o = options as StandardJavadocDocletOptions o.encoding = "UTF-8" - o.source = "17" + o.source = "21" o.use() o.links( diff --git a/build.gradle.kts b/build.gradle.kts index a761de5f..e01f345a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ subprojects { java { toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } } diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 15b803ae..599baba1 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -10,7 +10,7 @@ plugins { application { mainClass.set("com.velocitypowered.proxy.Velocity") - applicationDefaultJvmArgs += listOf("-Dvelocity.packet-decode-logging=true"); + applicationDefaultJvmArgs += listOf("-Dvelocity.packet-decode-logging=true") } tasks { @@ -135,7 +135,6 @@ fill { dependencies { implementation(project(":velocity-api")) implementation(project(":velocity-native")) - implementation(project(":velocity-proxy-log4j2-plugin")) implementation(libs.bundles.log4j) implementation(libs.kyori.ansi) @@ -172,4 +171,5 @@ dependencies { testImplementation(libs.mockito) annotationProcessor(libs.auto.service) + annotationProcessor(libs.log4j.core) } diff --git a/proxy/log4j2-plugin/build.gradle.kts b/proxy/log4j2-plugin/build.gradle.kts deleted file mode 100644 index 0a193944..00000000 --- a/proxy/log4j2-plugin/build.gradle.kts +++ /dev/null @@ -1,4 +0,0 @@ -dependencies { - implementation(libs.bundles.log4j) - annotationProcessor(libs.log4j.core) -} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/SuggestionsProvider.java b/proxy/src/main/java/com/velocitypowered/proxy/command/SuggestionsProvider.java index 93088cf6..9c65c023 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/SuggestionsProvider.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/SuggestionsProvider.java @@ -344,7 +344,7 @@ final class SuggestionsProvider { return 0; }); } - return potentials.get(0); + return potentials.getFirst(); } return new ParseResults<>(contextSoFar, originalReader, Collections.emptyMap()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java index 49dceb31..7c04a76d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommandManager.java @@ -140,7 +140,7 @@ public class VelocityCommandManager implements CommandManager { command + " implements multiple registrable Command subinterfaces: " + implementedInterfaces); } else { - this.internalRegister(commandRegistrars.get(0), command, meta); + this.internalRegister(commandRegistrars.getFirst(), command, meta); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommands.java b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommands.java index 3c2ad199..1e4a01ce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommands.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/VelocityCommands.java @@ -70,33 +70,34 @@ public final class VelocityCommands { maybeCommand = VelocityBrigadierCommandWrapper.wrap(delegate.getCommand(), registrant); } - if (delegate instanceof LiteralCommandNode lcn) { - var literalBuilder = shallowCopyAsBuilder(lcn, delegate.getName(), true); - literalBuilder.executes(maybeCommand); - // we also need to wrap any children - for (final CommandNode child : delegate.getChildren()) { - literalBuilder.then(wrap(child, registrant)); + return switch (delegate) { + case LiteralCommandNode lcn -> { + var literalBuilder = shallowCopyAsBuilder(lcn, delegate.getName(), true); + literalBuilder.executes(maybeCommand); + // we also need to wrap any children + for (final CommandNode child : delegate.getChildren()) { + literalBuilder.then(wrap(child, registrant)); + } + if (delegate.getRedirect() != null) { + literalBuilder.redirect(wrap(delegate.getRedirect(), registrant)); + } + yield literalBuilder.build(); } - if (delegate.getRedirect() != null) { - literalBuilder.redirect(wrap(delegate.getRedirect(), registrant)); + case VelocityArgumentCommandNode vacn -> vacn.withCommand(maybeCommand) + .withRedirect(delegate.getRedirect() != null ? wrap(delegate.getRedirect(), registrant) : null); + case ArgumentCommandNode node -> { + var argBuilder = node.createBuilder().executes(maybeCommand); + // we also need to wrap any children + for (final CommandNode child : delegate.getChildren()) { + argBuilder.then(wrap(child, registrant)); + } + if (delegate.getRedirect() != null) { + argBuilder.redirect(wrap(delegate.getRedirect(), registrant)); + } + yield argBuilder.build(); } - return literalBuilder.build(); - } else if (delegate instanceof VelocityArgumentCommandNode vacn) { - return vacn.withCommand(maybeCommand) - .withRedirect(delegate.getRedirect() != null ? wrap(delegate.getRedirect(), registrant) : null); - } else if (delegate instanceof ArgumentCommandNode) { - var argBuilder = delegate.createBuilder().executes(maybeCommand); - // we also need to wrap any children - for (final CommandNode child : delegate.getChildren()) { - argBuilder.then(wrap(child, registrant)); - } - if (delegate.getRedirect() != null) { - argBuilder.redirect(wrap(delegate.getRedirect(), registrant)); - } - return argBuilder.build(); - } else { - throw new IllegalArgumentException("Unsupported node type: " + delegate.getClass()); - } + default -> throw new IllegalArgumentException("Unsupported node type: " + delegate.getClass()); + }; } // Normalization @@ -133,7 +134,7 @@ public final class VelocityCommands { if (nodes.isEmpty()) { throw new IllegalArgumentException("Cannot read alias from empty node list"); } - return nodes.get(0).getNode().getName(); + return nodes.getFirst().getNode().getName(); } public static final String ARGS_NODE_NAME = "arguments"; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNode.java b/proxy/src/main/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNode.java index 03ba6d35..e5382d00 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNode.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNode.java @@ -118,14 +118,12 @@ public class VelocityArgumentCommandNode extends ArgumentCommandNode that = (VelocityArgumentCommandNode) o; return this.type.equals(that.type); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java index 6b233b87..101a5069 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java @@ -242,7 +242,7 @@ public final class VelocityCommand { hoverText.append(Component.newline()); if (description.getAuthors().size() == 1) { hoverText.append(Component.translatable("velocity.command.plugin-tooltip-author", - Component.text(description.getAuthors().get(0)))); + Component.text(description.getAuthors().getFirst()))); } else { hoverText.append( Component.translatable("velocity.command.plugin-tooltip-author", diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index 6f0fb61c..e86c82e7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -156,19 +156,16 @@ public class VelocityConfiguration implements ProxyConfig { } switch (playerInfoForwardingMode) { - case NONE: - logger.warn("Player info forwarding is disabled! All players will appear to be connecting " + case NONE -> logger.warn("Player info forwarding is disabled! All players will appear to be connecting " + "from the proxy and will have offline-mode UUIDs."); - break; - case MODERN: - case BUNGEEGUARD: + case MODERN, BUNGEEGUARD -> { if (forwardingSecret == null || forwardingSecret.length == 0) { logger.error("You don't have a forwarding secret set. This is required for security."); valid = false; } - break; - default: - break; + } + default -> { + } } if (servers.getServers().isEmpty()) { 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 3d7ed448..f7de55e0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -153,13 +153,13 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { if (msg instanceof MinecraftPacket pkt) { if (!pkt.handle(activeSessionHandler)) { - activeSessionHandler.handleGeneric((MinecraftPacket) msg); + activeSessionHandler.handleGeneric(pkt); } } else if (msg instanceof HAProxyMessage proxyMessage) { this.remoteAddress = new InetSocketAddress(proxyMessage.sourceAddress(), proxyMessage.sourcePort()); - } else if (msg instanceof ByteBuf) { - activeSessionHandler.handleUnknown((ByteBuf) msg); + } else if (msg instanceof ByteBuf buf) { + activeSessionHandler.handleUnknown(buf); } } finally { ReferenceCountUtil.release(msg); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index ed30057a..6d37520b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -452,8 +452,8 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { @Override public void handleGeneric(MinecraftPacket packet) { - if (packet instanceof PluginMessagePacket) { - ((PluginMessagePacket) packet).retain(); + if (packet instanceof PluginMessagePacket pluginMessage) { + pluginMessage.retain(); } playerConnection.delayedWrite(packet); if (++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java index a2ea94d6..50edfaee 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BungeeCordMessageResponder.java @@ -344,66 +344,30 @@ public class BungeeCordMessageResponder { return false; } - ByteBufDataInput in = new ByteBufDataInput(message.content()); - String subChannel = in.readUTF(); + final ByteBufDataInput in = new ByteBufDataInput(message.content()); + final String subChannel = in.readUTF(); switch (subChannel) { - case "GetPlayerServer": - this.processGetPlayerServer(in); - break; - case "ForwardToPlayer": - this.processForwardToPlayer(in); - break; - case "Forward": - this.processForwardToServer(in); - break; - case "Connect": - this.processConnect(in); - break; - case "ConnectOther": - this.processConnectOther(in); - break; - case "IP": - this.processIp(in); - break; - case "PlayerCount": - this.processPlayerCount(in); - break; - case "PlayerList": - this.processPlayerList(in); - break; - case "GetServers": - this.processGetServers(); - break; - case "Message": - this.processMessage(in); - break; - case "MessageRaw": - this.processMessageRaw(in); - break; - case "GetServer": - this.processGetServer(); - break; - case "UUID": - this.processUuid(); - break; - case "UUIDOther": - this.processUuidOther(in); - break; - case "IPOther": - this.processIpOther(in); - break; - case "ServerIP": - this.processServerIp(in); - break; - case "KickPlayer": - this.processKick(in); - break; - case "KickPlayerRaw": - this.processKickRaw(in); - break; - default: - // Do nothing, unknown command - break; + case "GetPlayerServer" -> this.processGetPlayerServer(in); + case "ForwardToPlayer" -> this.processForwardToPlayer(in); + case "Forward" -> this.processForwardToServer(in); + case "Connect" -> this.processConnect(in); + case "ConnectOther" -> this.processConnectOther(in); + case "IP" -> this.processIp(in); + case "PlayerCount" -> this.processPlayerCount(in); + case "PlayerList" -> this.processPlayerList(in); + case "GetServers" -> this.processGetServers(); + case "Message" -> this.processMessage(in); + case "MessageRaw" -> this.processMessageRaw(in); + case "GetServer" -> this.processGetServer(); + case "UUID" -> this.processUuid(); + case "UUIDOther" -> this.processUuidOther(in); + case "IPOther" -> this.processIpOther(in); + case "ServerIP" -> this.processServerIp(in); + case "KickPlayer" -> this.processKick(in); + case "KickPlayerRaw" -> this.processKickRaw(in); + default -> { + // Do nothing, unknown command + } } return true; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index a74f7c56..e713769a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -122,9 +122,8 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { // Change the client to use the ClientPlaySessionHandler if required. ClientPlaySessionHandler playHandler; if (player.getConnection() - .getActiveSessionHandler() instanceof ClientPlaySessionHandler) { - playHandler = - (ClientPlaySessionHandler) player.getConnection().getActiveSessionHandler(); + .getActiveSessionHandler() instanceof ClientPlaySessionHandler sessionHandler) { + playHandler = sessionHandler; } else { playHandler = new ClientPlaySessionHandler(server, player); player.getConnection().setActiveSessionHandler(StateRegistry.PLAY, playHandler); 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 71ebd7bc..c40a7aaa 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 @@ -180,9 +180,8 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, handshake.setServerAddress(createBungeeGuardForwardingAddress(secret)); } else if (proxyPlayer.getConnection().getType() == ConnectionTypes.LEGACY_FORGE) { handshake.setServerAddress(playerVhost + HANDSHAKE_HOSTNAME_TOKEN); - } else if (proxyPlayer.getConnection().getType() instanceof ModernForgeConnectionType) { - handshake.setServerAddress(playerVhost + ((ModernForgeConnectionType) proxyPlayer - .getConnection().getType()).getModernToken()); + } else if (proxyPlayer.getConnection().getType() instanceof ModernForgeConnectionType forgeConnection) { + handshake.setServerAddress(playerVhost + forgeConnection.getModernToken()); } else { handshake.setServerAddress(playerVhost); } 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 0807789f..bff41a44 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 @@ -811,61 +811,56 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, return; } - if (event.getResult() instanceof final DisconnectPlayer res) { - disconnect(res.getReasonComponent()); - } else if (event.getResult() instanceof final RedirectPlayer res) { - createConnectionRequest(res.getServer(), previousConnection).connect() - .whenCompleteAsync((status, throwable) -> { - if (throwable != null) { - handleConnectionException(res.getServer(), throwable, true); - return; - } + switch (event.getResult()) { + case DisconnectPlayer res -> disconnect(res.getReasonComponent()); + case RedirectPlayer res -> createConnectionRequest(res.getServer(), previousConnection).connect() + .whenCompleteAsync((status, throwable) -> { + if (throwable != null) { + handleConnectionException(res.getServer(), throwable, true); + return; + } - switch (status.getStatus()) { - // Impossible/nonsensical cases - case ALREADY_CONNECTED: - logger.error("{}: already connected to {}", this, - status.getAttemptedConnection().getServerInfo().getName()); - break; - case CONNECTION_IN_PROGRESS: - // Fatal case - case CONNECTION_CANCELLED: - Component fallbackMsg = res.getMessageComponent(); - if (fallbackMsg == null) { - fallbackMsg = friendlyReason; + switch (status.getStatus()) { + // Impossible/nonsensical cases + case ALREADY_CONNECTED -> logger.error("{}: already connected to {}", this, + status.getAttemptedConnection().getServerInfo().getName()); + case CONNECTION_IN_PROGRESS, CONNECTION_CANCELLED -> { + Component fallbackMsg = res.getMessageComponent(); + if (fallbackMsg == null) { + fallbackMsg = friendlyReason; + } + disconnect(status.getReasonComponent().orElse(fallbackMsg)); + } + case SERVER_DISCONNECTED -> { + Component reason = status.getReasonComponent() + .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); + handleConnectionException(res.getServer(), + DisconnectPacket.create(reason, getProtocolVersion(), connection.getState()), + ((Impl) status).isSafe()); + } + case SUCCESS -> { + Component requestedMessage = res.getMessageComponent(); + if (requestedMessage == null) { + requestedMessage = friendlyReason; + } + if (requestedMessage != Component.empty()) { + sendMessage(requestedMessage); + } + } + default -> { + // The only remaining value is successful (no need to do anything!) + } } - disconnect(status.getReasonComponent().orElse(fallbackMsg)); - break; - case SERVER_DISCONNECTED: - Component reason = status.getReasonComponent() - .orElse(ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR); - handleConnectionException(res.getServer(), - DisconnectPacket.create(reason, getProtocolVersion(), connection.getState()), - ((Impl) status).isSafe()); - break; - case SUCCESS: - Component requestedMessage = res.getMessageComponent(); - if (requestedMessage == null) { - requestedMessage = friendlyReason; - } - if (requestedMessage != Component.empty()) { - sendMessage(requestedMessage); - } - break; - default: - // The only remaining value is successful (no need to do anything!) - break; - } - }, connection.eventLoop()); - } else if (event.getResult() instanceof final Notify res) { - if (event.kickedDuringServerConnect() && previousConnection != null) { - sendMessage(res.getMessageComponent()); - } else { - disconnect(res.getMessageComponent()); + }, connection.eventLoop()); + case Notify res -> { + if (event.kickedDuringServerConnect() && previousConnection != null) { + sendMessage(res.getMessageComponent()); + } else { + disconnect(res.getMessageComponent()); + } } - } else { // In case someone gets creative, assume we want to disconnect the player. - disconnect(friendlyReason); + default -> disconnect(friendlyReason); } }, connection.eventLoop()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index 00187d34..92f14191 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -214,6 +214,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { server.getVersion().getName() + "/" + server.getVersion().getVersion()) .uri(URI.create(url)) .build(); + //noinspection resource final HttpClient httpClient = server.createHttpClient(); httpClient.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString()) .whenCompleteAsync((response, throwable) -> { @@ -268,14 +269,12 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { } }, mcConnection.eventLoop()) .thenRun(() -> { - if (httpClient instanceof final AutoCloseable closeable) { - try { - closeable.close(); - } catch (Exception e) { - // In Java 21, the HttpClient does not throw any Exception - // when trying to clean its resources, so this should not happen - logger.error("An unknown error occurred while trying to close an HttpClient", e); - } + try { + httpClient.close(); + } catch (Exception e) { + // In Java 21, the HttpClient does not throw any Exception + // when trying to clean its resources, so this should not happen + logger.error("An unknown error occurred while trying to close an HttpClient", e); } }); } catch (GeneralSecurityException e) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java index 077ce701..f0fd5e08 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java @@ -94,7 +94,7 @@ public final class ModernResourcePackHandler extends ResourcePackHandler { this.outstandingResourcePacks.get(info.getId()); outstandingResourcePacks.add(info); if (outstandingResourcePacks.size() == 1) { - tickResourcePackQueue(outstandingResourcePacks.get(0).getId()); + tickResourcePackQueue(outstandingResourcePacks.getFirst().getId()); } } @@ -111,7 +111,7 @@ public final class ModernResourcePackHandler extends ResourcePackHandler { final List outstandingResourcePacks = this.outstandingResourcePacks.get(uuid); if (!outstandingResourcePacks.isEmpty()) { - sendResourcePackRequestPacket(outstandingResourcePacks.get(0)); + sendResourcePackRequestPacket(outstandingResourcePacks.getFirst()); } } @@ -124,7 +124,7 @@ public final class ModernResourcePackHandler extends ResourcePackHandler { this.outstandingResourcePacks.get(uuid); final boolean peek = bundle.status().isIntermediate(); final ResourcePackInfo queued = outstandingResourcePacks.isEmpty() ? null : - peek ? outstandingResourcePacks.get(0) : outstandingResourcePacks.remove(0); + peek ? outstandingResourcePacks.getFirst() : outstandingResourcePacks.removeFirst(); server.getEventManager() .fire(new PlayerResourcePackStatusEvent(this.player, uuid, bundle.status(), queued)) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ServerListPingHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ServerListPingHandler.java index 7740139c..12c6be2b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ServerListPingHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/util/ServerListPingHandler.java @@ -100,65 +100,60 @@ public class ServerListPingHandler { CompletableFuture> pingResponses = CompletableFutures.successfulAsList(pings, (ex) -> fallback); - switch (mode) { - case ALL: - return pingResponses.thenApply(responses -> { - // Find the first non-fallback - for (ServerPing response : responses) { - if (response == fallback) { - continue; - } - - if (response.getDescriptionComponent() == null) { - return response.asBuilder() - .description(Component.empty()) - .build(); - } - - return response; + return switch (mode) { + case ALL -> pingResponses.thenApply(responses -> { + // Find the first non-fallback + for (ServerPing response : responses) { + if (response == fallback) { + continue; } - return fallback; - }); - case MODS: - return pingResponses.thenApply(responses -> { - // Find the first non-fallback that contains a mod list - for (ServerPing response : responses) { - if (response == fallback) { - continue; - } - Optional modInfo = response.getModinfo(); - if (modInfo.isPresent()) { - return fallback.asBuilder().mods(modInfo.get()).build(); - } - } - return fallback; - }); - case DESCRIPTION: - return pingResponses.thenApply(responses -> { - // Find the first non-fallback. If it includes a modlist, add it too. - for (ServerPing response : responses) { - if (response == fallback) { - continue; - } - if (response.getDescriptionComponent() == null) { - continue; - } - - return new ServerPing( - fallback.getVersion(), - fallback.getPlayers().orElse(null), - response.getDescriptionComponent(), - fallback.getFavicon().orElse(null), - response.getModinfo().orElse(null) - ); + if (response.getDescriptionComponent() == null) { + return response.asBuilder() + .description(Component.empty()) + .build(); } - return fallback; - }); + + return response; + } + return fallback; + }); + case MODS -> pingResponses.thenApply(responses -> { + // Find the first non-fallback that contains a mod list + for (ServerPing response : responses) { + if (response == fallback) { + continue; + } + Optional modInfo = response.getModinfo(); + if (modInfo.isPresent()) { + return fallback.asBuilder().mods(modInfo.get()).build(); + } + } + return fallback; + }); + case DESCRIPTION -> pingResponses.thenApply(responses -> { + // Find the first non-fallback. If it includes a modlist, add it too. + for (ServerPing response : responses) { + if (response == fallback) { + continue; + } + if (response.getDescriptionComponent() == null) { + continue; + } + + return new ServerPing( + fallback.getVersion(), + fallback.getPlayers().orElse(null), + response.getDescriptionComponent(), + fallback.getFavicon().orElse(null), + response.getModinfo().orElse(null) + ); + } + return fallback; + }); // Not possible, but covered for completeness. - default: - return CompletableFuture.completedFuture(fallback); - } + default -> CompletableFuture.completedFuture(fallback); + }; } /** diff --git a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java index 90b6292f..fd7d881d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/console/VelocityConsole.java @@ -33,6 +33,7 @@ import net.kyori.adventure.permission.PermissionChecker; import net.kyori.adventure.platform.facet.FacetPointers; import net.kyori.adventure.platform.facet.FacetPointers.Type; import net.kyori.adventure.pointer.Pointers; +import net.kyori.adventure.pointer.PointersSupplier; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.logger.slf4j.ComponentLogger; @@ -59,11 +60,11 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons private final VelocityServer server; private PermissionFunction permissionFunction = ALWAYS_TRUE; - private final @NotNull Pointers pointers = ConsoleCommandSource.super.pointers().toBuilder() - .withDynamic(PermissionChecker.POINTER, this::getPermissionChecker) - .withDynamic(Identity.LOCALE, () -> ClosestLocaleMatcher.INSTANCE + private static final @NotNull PointersSupplier POINTERS = PointersSupplier.builder() + .resolving(PermissionChecker.POINTER, VelocityConsole::getPermissionChecker) + .resolving(Identity.LOCALE, (console) -> ClosestLocaleMatcher.INSTANCE .lookupClosest(Locale.getDefault())) - .withStatic(FacetPointers.TYPE, Type.CONSOLE) + .resolving(FacetPointers.TYPE, (console) -> Type.CONSOLE) .build(); public VelocityConsole(VelocityServer server) { @@ -153,6 +154,6 @@ public final class VelocityConsole extends SimpleTerminalConsole implements Cons @Override public @NotNull Pointers pointers() { - return pointers; + return POINTERS.view(this); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/netty/SeparatePoolInetNameResolver.java b/proxy/src/main/java/com/velocitypowered/proxy/network/netty/SeparatePoolInetNameResolver.java index 2997d840..5fc309ae 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/netty/SeparatePoolInetNameResolver.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/netty/SeparatePoolInetNameResolver.java @@ -71,7 +71,7 @@ public final class SeparatePoolInetNameResolver extends InetNameResolver { protected void doResolve(String inetHost, Promise promise) throws Exception { List addresses = cache.getIfPresent(inetHost); if (addresses != null) { - promise.trySuccess(addresses.get(0)); + promise.trySuccess(addresses.getFirst()); return; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/JavaPluginLoader.java b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/JavaPluginLoader.java index d1df777d..5b69e49a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/JavaPluginLoader.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/plugin/loader/java/JavaPluginLoader.java @@ -83,7 +83,7 @@ public class JavaPluginLoader implements PluginLoader { @Override public PluginDescription createPluginFromCandidate(PluginDescription candidate) throws Exception { - if (!(candidate instanceof JavaVelocityPluginDescriptionCandidate)) { + if (!(candidate instanceof JavaVelocityPluginDescriptionCandidate candidateInst)) { throw new IllegalArgumentException("Description provided isn't of the Java plugin loader"); } @@ -93,8 +93,6 @@ public class JavaPluginLoader implements PluginLoader { PluginClassLoader loader = new PluginClassLoader(new URL[]{pluginJarUrl}); loader.addToClassloaders(); - JavaVelocityPluginDescriptionCandidate candidateInst = - (JavaVelocityPluginDescriptionCandidate) candidate; Class mainClass = loader.loadClass(candidateInst.getMainClass()); return createDescription(candidateInst, mainClass); } @@ -102,11 +100,10 @@ public class JavaPluginLoader implements PluginLoader { @Override public Module createModule(PluginContainer container) { PluginDescription description = container.getDescription(); - if (!(description instanceof JavaVelocityPluginDescription)) { + if (!(description instanceof JavaVelocityPluginDescription javaDescription)) { throw new IllegalArgumentException("Description provided isn't of the Java plugin loader"); } - JavaVelocityPluginDescription javaDescription = (JavaVelocityPluginDescription) description; Optional source = javaDescription.getSource(); if (source.isEmpty()) { @@ -118,24 +115,23 @@ public class JavaPluginLoader implements PluginLoader { @Override public void createPlugin(PluginContainer container, Module... modules) { - if (!(container instanceof VelocityPluginContainer)) { + if (!(container instanceof VelocityPluginContainer pluginContainer)) { throw new IllegalArgumentException("Container provided isn't of the Java plugin loader"); } - PluginDescription description = container.getDescription(); - if (!(description instanceof JavaVelocityPluginDescription)) { + PluginDescription description = pluginContainer.getDescription(); + if (!(description instanceof JavaVelocityPluginDescription javaPluginDescription)) { throw new IllegalArgumentException("Description provided isn't of the Java plugin loader"); } Injector injector = Guice.createInjector(modules); - Object instance = injector - .getInstance(((JavaVelocityPluginDescription) description).getMainClass()); + Object instance = injector.getInstance(javaPluginDescription.getMainClass()); if (instance == null) { throw new IllegalStateException( "Got nothing from injector for plugin " + description.getId()); } - ((VelocityPluginContainer) container).setInstance(instance); + pluginContainer.setInstance(instance); } private Optional getSerializedPluginInfo(Path source) @@ -145,22 +141,23 @@ public class JavaPluginLoader implements PluginLoader { new BufferedInputStream(Files.newInputStream(source)))) { JarEntry entry; while ((entry = in.getNextJarEntry()) != null) { - if (entry.getName().equals("velocity-plugin.json")) { - try (Reader pluginInfoReader = new InputStreamReader(in, StandardCharsets.UTF_8)) { - return Optional.of(VelocityServer.GENERAL_GSON.fromJson(pluginInfoReader, - SerializedPluginDescription.class)); + switch (entry.getName()) { + case "velocity-plugin.json" -> { + try (Reader pluginInfoReader = new InputStreamReader(in, StandardCharsets.UTF_8)) { + return Optional.of(VelocityServer.GENERAL_GSON.fromJson(pluginInfoReader, + SerializedPluginDescription.class)); + } + } + case "paper-plugin.yml", "plugin.yml", "bungee.yml" -> foundBungeeBukkitPluginFile = true; + default -> { } - } - - if (entry.getName().equals("plugin.yml") || entry.getName().equals("bungee.yml")) { - foundBungeeBukkitPluginFile = true; } } if (foundBungeeBukkitPluginFile) { throw new InvalidPluginException("The plugin file " + source.getFileName() + " appears to " - + "be a Bukkit or BungeeCord plugin. Velocity does not support Bukkit or BungeeCord " - + "plugins."); + + "be a Paper, Bukkit or BungeeCord plugin. Velocity does not support plugins from these " + + "platforms."); } return Optional.empty(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GameSpyQueryHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GameSpyQueryHandler.java index 57c0b318..b22a2442 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GameSpyQueryHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/GameSpyQueryHandler.java @@ -119,7 +119,7 @@ public class GameSpyQueryHandler extends SimpleChannelInboundHandler { // Generate new challenge token and put it into the sessions cache int challengeToken = random.nextInt(); sessions.put(senderAddress, challengeToken); @@ -132,10 +132,9 @@ public class GameSpyQueryHandler extends SimpleChannelInboundHandler { // Check if query was done with session previously generated using a handshake packet int challengeToken = queryMessage.readInt(); Integer session = sessions.getIfPresent(senderAddress); @@ -190,10 +189,10 @@ public class GameSpyQueryHandler extends SimpleChannelInboundHandler { + // Invalid query type - just don't respond + } } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java index d3fc3a82..2746b23f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java @@ -25,7 +25,6 @@ import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; @@ -331,12 +330,10 @@ public class AvailableCommandsPacket implements MinecraftPacket { .add("redirectTo", redirectTo); if (args != null) { - if (args instanceof LiteralArgumentBuilder) { - helper.add("argsLabel", - ((LiteralArgumentBuilder) args).getLiteral()); - } else if (args instanceof RequiredArgumentBuilder) { - helper.add("argsName", - ((RequiredArgumentBuilder) args).getName()); + if (args instanceof LiteralArgumentBuilder literal) { + helper.add("argsLabel", literal.getLiteral()); + } else if (args instanceof RequiredArgumentBuilder required) { + helper.add("argsName", required.getName()); } } @@ -348,17 +345,11 @@ public class AvailableCommandsPacket implements MinecraftPacket { * A placeholder {@link SuggestionProvider} used internally to preserve the suggestion provider * name. */ - public static class ProtocolSuggestionProvider implements SuggestionProvider { - - private final String name; - - public ProtocolSuggestionProvider(String name) { - this.name = name; - } + public record ProtocolSuggestionProvider(String name) implements SuggestionProvider { @Override public CompletableFuture getSuggestions(CommandContext context, - SuggestionsBuilder builder) throws CommandSyntaxException { + SuggestionsBuilder builder) { return builder.buildFuture(); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java index cc4c2671..d7748eff 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java @@ -207,30 +207,22 @@ public class BossBarPacket implements MinecraftPacket { this.uuid = ProtocolUtils.readUuid(buf); this.action = ProtocolUtils.readVarInt(buf); switch (action) { - case ADD: + case ADD -> { this.name = ComponentHolder.read(buf, version); this.percent = buf.readFloat(); this.color = ProtocolUtils.readVarInt(buf); this.overlay = ProtocolUtils.readVarInt(buf); this.flags = buf.readUnsignedByte(); - break; - case REMOVE: - break; - case UPDATE_PERCENT: - this.percent = buf.readFloat(); - break; - case UPDATE_NAME: - this.name = ComponentHolder.read(buf, version); - break; - case UPDATE_STYLE: + } + case REMOVE -> {} + case UPDATE_PERCENT -> this.percent = buf.readFloat(); + case UPDATE_NAME -> this.name = ComponentHolder.read(buf, version); + case UPDATE_STYLE -> { this.color = ProtocolUtils.readVarInt(buf); this.overlay = ProtocolUtils.readVarInt(buf); - break; - case UPDATE_PROPERTIES: - this.flags = buf.readUnsignedByte(); - break; - default: - throw new UnsupportedOperationException("Unknown action " + action); + } + case UPDATE_PROPERTIES -> this.flags = buf.readUnsignedByte(); + default -> throw new UnsupportedOperationException("Unknown action " + action); } } @@ -242,36 +234,30 @@ public class BossBarPacket implements MinecraftPacket { ProtocolUtils.writeUuid(buf, uuid); ProtocolUtils.writeVarInt(buf, action); switch (action) { - case ADD: - if (name == null) { - throw new IllegalStateException("No name specified!"); - } - name.write(buf); - buf.writeFloat(percent); + case ADD -> { + if (name == null) { + throw new IllegalStateException("No name specified!"); + } + name.write(buf); + buf.writeFloat(percent); + ProtocolUtils.writeVarInt(buf, color); + ProtocolUtils.writeVarInt(buf, overlay); + buf.writeByte(flags); + } + case REMOVE -> {} + case UPDATE_PERCENT -> buf.writeFloat(percent); + case UPDATE_NAME -> { + if (name == null) { + throw new IllegalStateException("No name specified!"); + } + name.write(buf); + } + case UPDATE_STYLE -> { ProtocolUtils.writeVarInt(buf, color); ProtocolUtils.writeVarInt(buf, overlay); - buf.writeByte(flags); - break; - case REMOVE: - break; - case UPDATE_PERCENT: - buf.writeFloat(percent); - break; - case UPDATE_NAME: - if (name == null) { - throw new IllegalStateException("No name specified!"); - } - name.write(buf); - break; - case UPDATE_STYLE: - ProtocolUtils.writeVarInt(buf, color); - ProtocolUtils.writeVarInt(buf, overlay); - break; - case UPDATE_PROPERTIES: - buf.writeByte(flags); - break; - default: - throw new UnsupportedOperationException("Unknown action " + action); + } + case UPDATE_PROPERTIES -> buf.writeByte(flags); + default -> throw new UnsupportedOperationException("Unknown action " + action); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java index 268c707d..9dbe9cbc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java @@ -69,33 +69,25 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { Item item = new Item(ProtocolUtils.readUuid(buf)); items.add(item); switch (action) { - case ADD_PLAYER: + case ADD_PLAYER -> { item.setName(ProtocolUtils.readString(buf)); item.setProperties(ProtocolUtils.readProperties(buf)); item.setGameMode(ProtocolUtils.readVarInt(buf)); item.setLatency(ProtocolUtils.readVarInt(buf)); item.setDisplayName(readOptionalComponent(buf, version)); - if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) { - if (buf.readBoolean()) { - item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf)); - } + if (buf.readBoolean()) { + item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf)); + } } - break; - case UPDATE_GAMEMODE: - item.setGameMode(ProtocolUtils.readVarInt(buf)); - break; - case UPDATE_LATENCY: - item.setLatency(ProtocolUtils.readVarInt(buf)); - break; - case UPDATE_DISPLAY_NAME: - item.setDisplayName(readOptionalComponent(buf, version)); - break; - case REMOVE_PLAYER: - //Do nothing, all that is needed is the uuid - break; - default: - throw new UnsupportedOperationException("Unknown action " + action); + } + case UPDATE_GAMEMODE -> item.setGameMode(ProtocolUtils.readVarInt(buf)); + case UPDATE_LATENCY -> item.setLatency(ProtocolUtils.readVarInt(buf)); + case UPDATE_DISPLAY_NAME -> item.setDisplayName(readOptionalComponent(buf, version)); + case REMOVE_PLAYER -> { + //Do nothing, all that is needed is the uuid + } + default -> throw new UnsupportedOperationException("Unknown action " + action); } } } else { @@ -126,39 +118,32 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { ProtocolUtils.writeUuid(buf, uuid); switch (action) { - case ADD_PLAYER: + case ADD_PLAYER -> { ProtocolUtils.writeString(buf, item.getName()); ProtocolUtils.writeProperties(buf, item.getProperties()); ProtocolUtils.writeVarInt(buf, item.getGameMode()); ProtocolUtils.writeVarInt(buf, item.getLatency()); writeDisplayName(buf, item.getDisplayName(), version); if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) { - if (item.getPlayerKey() != null) { - buf.writeBoolean(true); - ProtocolUtils.writePlayerKey(buf, item.getPlayerKey()); - } else { - buf.writeBoolean(false); - } + if (item.getPlayerKey() != null) { + buf.writeBoolean(true); + ProtocolUtils.writePlayerKey(buf, item.getPlayerKey()); + } else { + buf.writeBoolean(false); + } } - break; - case UPDATE_GAMEMODE: - ProtocolUtils.writeVarInt(buf, item.getGameMode()); - break; - case UPDATE_LATENCY: - ProtocolUtils.writeVarInt(buf, item.getLatency()); - break; - case UPDATE_DISPLAY_NAME: - writeDisplayName(buf, item.getDisplayName(), version); - break; - case REMOVE_PLAYER: + } + case UPDATE_GAMEMODE -> ProtocolUtils.writeVarInt(buf, item.getGameMode()); + case UPDATE_LATENCY -> ProtocolUtils.writeVarInt(buf, item.getLatency()); + case UPDATE_DISPLAY_NAME -> writeDisplayName(buf, item.getDisplayName(), version); + case REMOVE_PLAYER -> { // Do nothing, all that is needed is the uuid - break; - default: - throw new UnsupportedOperationException("Unknown action " + action); + } + default -> throw new UnsupportedOperationException("Unknown action " + action); } } } else { - Item item = items.get(0); + Item item = items.getFirst(); Component displayNameComponent = item.getDisplayName(); if (displayNameComponent != null) { String displayName = LegacyComponentSerializer.legacySection() @@ -269,7 +254,7 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { return this; } - public IdentifiedKey getPlayerKey() { + public @Nullable IdentifiedKey getPlayerKey() { return playerKey; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/StringArgumentPropertySerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/StringArgumentPropertySerializer.java index 75f5ecc8..d4567095 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/StringArgumentPropertySerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/StringArgumentPropertySerializer.java @@ -37,32 +37,21 @@ class StringArgumentPropertySerializer implements ArgumentPropertySerializer StringArgumentType.word(); + case 1 -> StringArgumentType.string(); + case 2 -> StringArgumentType.greedyString(); + default -> throw new IllegalArgumentException("Invalid string argument type " + type); + }; } @Override public void serialize(StringArgumentType object, ByteBuf buf, ProtocolVersion protocolVersion) { switch (object.getType()) { - case SINGLE_WORD: - ProtocolUtils.writeVarInt(buf, 0); - break; - case QUOTABLE_PHRASE: - ProtocolUtils.writeVarInt(buf, 1); - break; - case GREEDY_PHRASE: - ProtocolUtils.writeVarInt(buf, 2); - break; - default: - throw new IllegalArgumentException("Invalid string argument type " + object.getType()); + case SINGLE_WORD -> ProtocolUtils.writeVarInt(buf, 0); + case QUOTABLE_PHRASE -> ProtocolUtils.writeVarInt(buf, 1); + case GREEDY_PHRASE -> ProtocolUtils.writeVarInt(buf, 2); + default -> throw new IllegalArgumentException("Invalid string argument type " + object.getType()); } } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java index 01f36d0e..0b003326 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java @@ -113,23 +113,18 @@ public class ComponentHolder { public static BinaryTag serialize(JsonElement json) { if (json instanceof JsonPrimitive jsonPrimitive) { if (jsonPrimitive.isNumber()) { - Number number = json.getAsNumber(); + final Number number = json.getAsNumber(); - if (number instanceof Byte) { - return ByteBinaryTag.byteBinaryTag((Byte) number); - } else if (number instanceof Short) { - return ShortBinaryTag.shortBinaryTag((Short) number); - } else if (number instanceof Integer) { - return IntBinaryTag.intBinaryTag((Integer) number); - } else if (number instanceof Long) { - return LongBinaryTag.longBinaryTag((Long) number); - } else if (number instanceof Float) { - return FloatBinaryTag.floatBinaryTag((Float) number); - } else if (number instanceof Double) { - return DoubleBinaryTag.doubleBinaryTag((Double) number); - } else if (number instanceof LazilyParsedNumber) { - return IntBinaryTag.intBinaryTag(number.intValue()); - } + return switch (number) { + case Byte b -> ByteBinaryTag.byteBinaryTag(b); + case Short s -> ShortBinaryTag.shortBinaryTag(s); + case Integer i -> IntBinaryTag.intBinaryTag(i); + case Long l -> LongBinaryTag.longBinaryTag(l); + case Float f -> FloatBinaryTag.floatBinaryTag(f); + case Double d -> DoubleBinaryTag.doubleBinaryTag(d); + case LazilyParsedNumber l -> IntBinaryTag.intBinaryTag(l.intValue()); + default -> throw new IllegalArgumentException("Unknown number type: " + number); + }; } else if (jsonPrimitive.isString()) { return StringBinaryTag.stringBinaryTag(jsonPrimitive.getAsString()); } else if (jsonPrimitive.isBoolean()) { @@ -137,16 +132,16 @@ public class ComponentHolder { } else { throw new IllegalArgumentException("Unknown JSON primitive: " + jsonPrimitive); } - } else if (json instanceof JsonObject) { + } else if (json instanceof JsonObject object) { CompoundBinaryTag.Builder compound = CompoundBinaryTag.builder(); - for (Map.Entry property : ((JsonObject) json).entrySet()) { + for (Map.Entry property : object.entrySet()) { compound.put(property.getKey(), serialize(property.getValue())); } return compound.build(); - } else if (json instanceof JsonArray) { - List jsonArray = ((JsonArray) json).asList(); + } else if (json instanceof JsonArray array) { + List jsonArray = array.asList(); if (jsonArray.isEmpty()) { return ListBinaryTag.empty(); @@ -206,20 +201,21 @@ public class ComponentHolder { } public static JsonElement deserialize(BinaryTag tag) { - switch (tag.type().id()) { - case 1://BinaryTagTypes.BYTE: - return new JsonPrimitive(((ByteBinaryTag) tag).value()); - case 2://BinaryTagTypes.SHORT: - return new JsonPrimitive(((ShortBinaryTag) tag).value()); - case 3://BinaryTagTypes.INT: - return new JsonPrimitive(((IntBinaryTag) tag).value()); - case 4://BinaryTagTypes.LONG: - return new JsonPrimitive(((LongBinaryTag) tag).value()); - case 5://BinaryTagTypes.FLOAT: - return new JsonPrimitive(((FloatBinaryTag) tag).value()); - case 6://BinaryTagTypes.DOUBLE: - return new JsonPrimitive(((DoubleBinaryTag) tag).value()); - case 7://BinaryTagTypes.BYTE_ARRAY: + return switch (tag.type().id()) { + //BinaryTagTypes.BYTE + case 1 -> new JsonPrimitive(((ByteBinaryTag) tag).value()); + //BinaryTagTypes.SHORT + case 2 -> new JsonPrimitive(((ShortBinaryTag) tag).value()); + //BinaryTagTypes.INT: + case 3 -> new JsonPrimitive(((IntBinaryTag) tag).value()); + //BinaryTagTypes.LONG: + case 4 -> new JsonPrimitive(((LongBinaryTag) tag).value()); + //BinaryTagTypes.FLOAT: + case 5 -> new JsonPrimitive(((FloatBinaryTag) tag).value()); + //BinaryTagTypes.DOUBLE: + case 6 -> new JsonPrimitive(((DoubleBinaryTag) tag).value()); + //BinaryTagTypes.BYTE_ARRAY: + case 7 -> { byte[] byteArray = ((ByteArrayBinaryTag) tag).value(); JsonArray jsonByteArray = new JsonArray(byteArray.length); @@ -227,10 +223,12 @@ public class ComponentHolder { jsonByteArray.add(new JsonPrimitive(b)); } - return jsonByteArray; - case 8://BinaryTagTypes.STRING: - return new JsonPrimitive(((StringBinaryTag) tag).value()); - case 9://BinaryTagTypes.LIST: + yield jsonByteArray; + } + //BinaryTagTypes.STRING: + case 8 -> new JsonPrimitive(((StringBinaryTag) tag).value()); + //BinaryTagTypes.LIST: + case 9 -> { ListBinaryTag items = (ListBinaryTag) tag; JsonArray jsonList = new JsonArray(items.size()); @@ -238,8 +236,10 @@ public class ComponentHolder { jsonList.add(deserialize(subTag)); } - return jsonList; - case 10://BinaryTagTypes.COMPOUND: + yield jsonList; + } + //BinaryTagTypes.COMPOUND: + case 10 -> { CompoundBinaryTag compound = (CompoundBinaryTag) tag; JsonObject jsonObject = new JsonObject(); @@ -252,8 +252,10 @@ public class ComponentHolder { jsonObject.add(key.isEmpty() ? "text" : key, deserialize(compound.get(key))); }); - return jsonObject; - case 11://BinaryTagTypes.INT_ARRAY: + yield jsonObject; + } + //BinaryTagTypes.INT_ARRAY: + case 11 -> { int[] intArray = ((IntArrayBinaryTag) tag).value(); JsonArray jsonIntArray = new JsonArray(intArray.length); @@ -261,8 +263,10 @@ public class ComponentHolder { jsonIntArray.add(new JsonPrimitive(i)); } - return jsonIntArray; - case 12://BinaryTagTypes.LONG_ARRAY: + yield jsonIntArray; + } + //BinaryTagTypes.LONG_ARRAY: + case 12 -> { long[] longArray = ((LongArrayBinaryTag) tag).value(); JsonArray jsonLongArray = new JsonArray(longArray.length); @@ -270,10 +274,10 @@ public class ComponentHolder { jsonLongArray.add(new JsonPrimitive(l)); } - return jsonLongArray; - default: - throw new IllegalArgumentException("Unknown NBT tag: " + tag); - } + yield jsonLongArray; + } + default -> throw new IllegalArgumentException("Unknown NBT tag: " + tag); + }; } public static ComponentHolder read(ByteBuf buf, ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java index b36014d5..1a26affd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java @@ -59,14 +59,9 @@ public class SystemChatPacket implements MinecraftPacket { component.write(buf); if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) { switch (type) { - case SYSTEM: - buf.writeBoolean(false); - break; - case GAME_INFO: - buf.writeBoolean(true); - break; - default: - throw new IllegalArgumentException("Invalid chat type"); + case SYSTEM -> buf.writeBoolean(false); + case GAME_INFO -> buf.writeBoolean(true); + default -> throw new IllegalArgumentException("Invalid chat type"); } } else { ProtocolUtils.writeVarInt(buf, type.getId()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java index d6f5e0e5..8641173e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java @@ -105,26 +105,14 @@ public abstract class GenericTitlePacket implements MinecraftPacket { public static GenericTitlePacket constructTitlePacket(ActionType type, ProtocolVersion version) { GenericTitlePacket packet = null; if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) { - switch (type) { - case SET_ACTION_BAR: - packet = new TitleActionbarPacket(); - break; - case SET_SUBTITLE: - packet = new TitleSubtitlePacket(); - break; - case SET_TIMES: - packet = new TitleTimesPacket(); - break; - case SET_TITLE: - packet = new TitleTextPacket(); - break; - case HIDE: - case RESET: - packet = new TitleClearPacket(); - break; - default: - throw new IllegalArgumentException("Invalid ActionType"); - } + packet = switch (type) { + case SET_ACTION_BAR -> new TitleActionbarPacket(); + case SET_SUBTITLE -> new TitleSubtitlePacket(); + case SET_TIMES -> new TitleTimesPacket(); + case SET_TITLE -> new TitleTextPacket(); + case HIDE, RESET -> new TitleClearPacket(); + default -> throw new IllegalArgumentException("Invalid ActionType"); + }; } else { packet = new LegacyTitlePacket(); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java index 0425f2d3..ebae8a9e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java @@ -40,24 +40,19 @@ public class LegacyTitlePacket extends GenericTitlePacket { ProtocolUtils.writeVarInt(buf, getAction().getAction(version)); switch (getAction()) { - case SET_TITLE: - case SET_SUBTITLE: - case SET_ACTION_BAR: + case SET_TITLE, SET_SUBTITLE, SET_ACTION_BAR -> { if (component == null) { throw new IllegalStateException("No component found for " + getAction()); } component.write(buf); - break; - case SET_TIMES: + } + case SET_TIMES -> { buf.writeInt(fadeIn); buf.writeInt(stay); buf.writeInt(fadeOut); - break; - case HIDE: - case RESET: - break; - default: - throw new UnsupportedOperationException("Unknown action " + getAction()); + } + case HIDE, RESET -> {} + default -> throw new UnsupportedOperationException("Unknown action " + getAction()); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java index 1936eb3f..298e74d4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/util/PluginMessageUtil.java @@ -230,23 +230,20 @@ public final class PluginMessageUtil { } // Before falling into the fallback, explicitly rewrite certain messages. - switch (name) { - case REGISTER_CHANNEL_LEGACY: - return REGISTER_CHANNEL; - case UNREGISTER_CHANNEL_LEGACY: - return UNREGISTER_CHANNEL; - case BRAND_CHANNEL_LEGACY: - return BRAND_CHANNEL; - case "BungeeCord": - // This is a special historical case we are compelled to support for the benefit of - // BungeeQuack. - return "bungeecord:main"; - default: + return switch (name) { + case REGISTER_CHANNEL_LEGACY -> REGISTER_CHANNEL; + case UNREGISTER_CHANNEL_LEGACY -> UNREGISTER_CHANNEL; + case BRAND_CHANNEL_LEGACY -> BRAND_CHANNEL; + // This is a special historical case we are compelled to support for the benefit of + // BungeeQuack. + case "BungeeCord" -> "bungeecord:main"; + default -> { // This is very likely a legacy name, so transform it. Velocity uses the same scheme as // BungeeCord does to transform channels, but also removes clearly invalid characters as // well. - String lower = name.toLowerCase(Locale.ROOT); - return "legacy:" + INVALID_IDENTIFIER_REGEX.matcher(lower).replaceAll(""); - } + final String lower = name.toLowerCase(Locale.ROOT); + yield "legacy:" + INVALID_IDENTIFIER_REGEX.matcher(lower).replaceAll(""); + } + }; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java index a49d24de..037ab262 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/tablist/VelocityTabListLegacy.java @@ -85,7 +85,7 @@ public class VelocityTabListLegacy extends KeyedVelocityTabList { @Override public void processLegacy(LegacyPlayerListItemPacket packet) { - Item item = packet.getItems().get(0); // Only one item per packet in 1.7 + Item item = packet.getItems().getFirst(); // Only one item per packet in 1.7 switch (packet.getAction()) { case LegacyPlayerListItemPacket.ADD_PLAYER: diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java index d8cdb7c3..59aae3e4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/InformationUtils.java @@ -145,45 +145,44 @@ public enum InformationUtils { * @return {@link String} address with public parts redacted */ public static String anonymizeInetAddress(InetAddress address) { - if (address instanceof Inet4Address) { - Inet4Address v4 = (Inet4Address) address; - if (v4.isAnyLocalAddress() || v4.isLoopbackAddress() - || v4.isLinkLocalAddress() - || v4.isSiteLocalAddress()) { - return address.getHostAddress(); - } else { - byte[] addr = v4.getAddress(); - return (addr[0] & 0xff) + "." + (addr[1] & 0xff) + ".XXX.XXX"; - } - } else if (address instanceof Inet6Address) { - Inet6Address v6 = (Inet6Address) address; - if (v6.isAnyLocalAddress() || v6.isLoopbackAddress() - || v6.isSiteLocalAddress() - || v6.isSiteLocalAddress()) { - return address.getHostAddress(); - } else { - String[] bits = v6.getHostAddress().split(":"); - String ret = ""; - boolean flag = false; - for (int iter = 0; iter < bits.length; iter++) { - if (flag) { - ret += ":X"; - continue; - } - if (!bits[iter].equals("0")) { - if (iter == 0) { - ret = bits[iter]; - } else { - ret = "::" + bits[iter]; - } - flag = true; - } + return switch (address) { + case Inet4Address v4 -> { + if (v4.isAnyLocalAddress() || v4.isLoopbackAddress() + || v4.isLinkLocalAddress() + || v4.isSiteLocalAddress()) { + yield address.getHostAddress(); + } else { + byte[] addr = v4.getAddress(); + yield (addr[0] & 0xff) + "." + (addr[1] & 0xff) + ".XXX.XXX"; + } + } case Inet6Address v6 -> { + if (v6.isAnyLocalAddress() || v6.isLoopbackAddress() + || v6.isSiteLocalAddress() + || v6.isSiteLocalAddress()) { + yield address.getHostAddress(); + } else { + String[] bits = v6.getHostAddress().split(":"); + String ret = ""; + boolean flag = false; + for (int iter = 0; iter < bits.length; iter++) { + if (flag) { + ret += ":X"; + continue; + } + if (!bits[iter].equals("0")) { + if (iter == 0) { + ret = bits[iter]; + } else { + ret = "::" + bits[iter]; + } + flag = true; + } + } + yield ret; } - return ret; } - } else { - return address.getHostAddress(); - } + default -> address.getHostAddress(); + }; } /** diff --git a/proxy/log4j2-plugin/src/main/java/com/velocitypowered/proxy/util/StripAnsiConverter.java b/proxy/src/main/java/com/velocitypowered/proxy/util/StripAnsiConverter.java similarity index 100% rename from proxy/log4j2-plugin/src/main/java/com/velocitypowered/proxy/util/StripAnsiConverter.java rename to proxy/src/main/java/com/velocitypowered/proxy/util/StripAnsiConverter.java diff --git a/proxy/src/test/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNodeTests.java b/proxy/src/test/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNodeTests.java index fb5f57e3..90420da0 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNodeTests.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/command/brigadier/VelocityArgumentCommandNodeTests.java @@ -64,8 +64,8 @@ public class VelocityArgumentCommandNodeTests { assertFalse(reader.canRead()); assertFalse(this.contextBuilder.getNodes().isEmpty()); - assertSame(node, this.contextBuilder.getNodes().get(0).getNode()); - assertEquals(expectedRange, this.contextBuilder.getNodes().get(0).getRange()); + assertSame(node, this.contextBuilder.getNodes().getFirst().getNode()); + assertEquals(expectedRange, this.contextBuilder.getNodes().getFirst().getRange()); assertTrue(this.contextBuilder.getArguments().containsKey("foo")); final ParsedArgument parsed = diff --git a/proxy/src/test/java/com/velocitypowered/proxy/testutil/FakePluginManager.java b/proxy/src/test/java/com/velocitypowered/proxy/testutil/FakePluginManager.java index 7992ac52..4d1f66cc 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/testutil/FakePluginManager.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/testutil/FakePluginManager.java @@ -62,16 +62,12 @@ public class FakePluginManager implements PluginManager { @Override public @NonNull Optional getPlugin(@NonNull String id) { - switch (id) { - case "a": - return Optional.of(containerA); - case "b": - return Optional.of(containerB); - case "velocity": - return Optional.of(containerVelocity); - default: - return Optional.empty(); - } + return switch (id) { + case "a" -> Optional.of(containerA); + case "b" -> Optional.of(containerB); + case "velocity" -> Optional.of(containerVelocity); + default -> Optional.empty(); + }; } @Override diff --git a/settings.gradle.kts b/settings.gradle.kts index 5af9d03e..3159fc73 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -36,8 +36,3 @@ sequenceOf( val deprecatedConfigurateModule = ":deprecated-configurate3" include(deprecatedConfigurateModule) project(deprecatedConfigurateModule).projectDir = file("proxy/deprecated/configurate3") - -// Log4J2 plugin -val log4j2ProxyPlugin = ":velocity-proxy-log4j2-plugin" -include(log4j2ProxyPlugin) -project(log4j2ProxyPlugin).projectDir = file("proxy/log4j2-plugin") From eb2bea79baab112ce3df20bbaab3a5377fe6e26d Mon Sep 17 00:00:00 2001 From: Adrian <68704415+4drian3d@users.noreply.github.com> Date: Sun, 25 Jan 2026 14:06:03 -0500 Subject: [PATCH 15/48] Implement MiniMessage Velocity translations (#1108) * Implement MiniMessage Velocity translations * Implemented migration from old language format * Updated year in default translations * Fixed compilation * Use MiniMessageTranslationStore * Simplify MiniMessageTranslationsMigration#shouldMigrate * Added support to named placeholders * Updated translation arguments to MiniMessage translation placeholders --- .../velocitypowered/proxy/VelocityServer.java | 13 ++-- .../proxy/command/builtin/GlistCommand.java | 6 +- .../proxy/command/builtin/SendCommand.java | 5 +- .../proxy/command/builtin/ServerCommand.java | 5 +- .../command/builtin/VelocityCommand.java | 13 ++-- .../proxy/config/VelocityConfiguration.java | 2 + .../migration/ConfigurationMigration.java | 1 + .../MiniMessageTranslationsMigration.java | 65 +++++++++++++++++++ .../connection/client/ConnectedPlayer.java | 9 +-- .../client/HandshakeSessionHandler.java | 3 +- .../proxy/l10n/messages.properties | 32 ++++----- .../proxy/l10n/messages_ar_SA.properties | 28 ++++---- .../proxy/l10n/messages_bg_BG.properties | 32 ++++----- .../proxy/l10n/messages_cs_CZ.properties | 32 ++++----- .../proxy/l10n/messages_da_DK.properties | 32 ++++----- .../proxy/l10n/messages_de_DE.properties | 32 ++++----- .../proxy/l10n/messages_es_ES.properties | 32 ++++----- .../proxy/l10n/messages_et_EE.properties | 32 ++++----- .../proxy/l10n/messages_fi_FI.properties | 32 ++++----- .../proxy/l10n/messages_fr_FR.properties | 32 ++++----- .../proxy/l10n/messages_he_IL.properties | 32 ++++----- .../proxy/l10n/messages_hu_HU.properties | 32 ++++----- .../proxy/l10n/messages_it_IT.properties | 32 ++++----- .../proxy/l10n/messages_ja_JP.properties | 32 ++++----- .../proxy/l10n/messages_ko_KR.properties | 32 ++++----- .../proxy/l10n/messages_nb_NO.properties | 32 ++++----- .../proxy/l10n/messages_nl_NL.properties | 32 ++++----- .../proxy/l10n/messages_nn_NO.properties | 32 ++++----- .../proxy/l10n/messages_pl_PL.properties | 32 ++++----- .../proxy/l10n/messages_pt_BR.properties | 32 ++++----- .../proxy/l10n/messages_ro_RO.properties | 32 ++++----- .../proxy/l10n/messages_ru_RU.properties | 32 ++++----- .../proxy/l10n/messages_sk_SK.properties | 32 ++++----- .../proxy/l10n/messages_sq_AL.properties | 32 ++++----- .../proxy/l10n/messages_sr_CS.properties | 30 ++++----- .../proxy/l10n/messages_sr_Latn.properties | 32 ++++----- .../proxy/l10n/messages_sv_SE.properties | 32 ++++----- .../proxy/l10n/messages_tl_PH.properties | 32 ++++----- .../proxy/l10n/messages_tr_TR.properties | 32 ++++----- .../proxy/l10n/messages_uk_UA.properties | 32 ++++----- .../proxy/l10n/messages_vi_VN.properties | 32 ++++----- .../proxy/l10n/messages_zh_CN.properties | 32 ++++----- .../proxy/l10n/messages_zh_HK.properties | 32 ++++----- .../proxy/l10n/messages_zh_TW.properties | 32 ++++----- 44 files changed, 639 insertions(+), 565 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/config/migration/MiniMessageTranslationsMigration.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index ccfc5f14..95f10bcb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -82,7 +82,6 @@ import java.net.http.HttpClient; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyPair; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -105,8 +104,8 @@ import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.ForwardingAudience; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.translation.MiniMessageTranslationStore; import net.kyori.adventure.translation.GlobalTranslator; -import net.kyori.adventure.translation.TranslationStore; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bstats.MetricsBase; @@ -242,8 +241,6 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { console.setupStreams(); pluginManager.registerPlugin(this.createVirtualPlugin()); - registerTranslations(); - // Yes, you're reading that correctly. We're generating a 1024-bit RSA keypair. Sounds // dangerous, right? We're well within the realm of factoring such a key... // @@ -292,6 +289,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { this.doStartupConfigLoad(); + registerTranslations(); + for (ServerInfo cliServer : options.getServers()) { servers.register(cliServer); } @@ -342,8 +341,8 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { } private void registerTranslations() { - final TranslationStore.StringBased translationRegistry = - TranslationStore.messageFormat(Key.key("velocity", "translations")); + final MiniMessageTranslationStore translationRegistry = + MiniMessageTranslationStore.create(Key.key("velocity", "translations")); translationRegistry.defaultLocale(Locale.US); try { ResourceUtils.visitResources(VelocityServer.class, path -> { @@ -835,7 +834,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { public VelocityChannelRegistrar getChannelRegistrar() { return channelRegistrar; } - + @Override public boolean isShuttingDown() { return shutdownInProgress.get(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/GlistCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/GlistCommand.java index 2b73dcc1..ea43182e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/GlistCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/GlistCommand.java @@ -38,6 +38,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.translation.Argument; /** * Implements the Velocity default {@code /glist} command. @@ -111,7 +112,7 @@ public class GlistCommand { if (registeredServer.isEmpty()) { source.sendMessage( CommandMessages.SERVER_DOES_NOT_EXIST - .arguments(Component.text(serverName))); + .arguments(Argument.string("server", serverName))); return -1; } sendServerPlayers(source, registeredServer.get(), false); @@ -126,7 +127,8 @@ public class GlistCommand { ? "velocity.command.glist-player-singular" : "velocity.command.glist-player-plural" ).color(NamedTextColor.YELLOW) - .arguments(Component.text(Integer.toString(online), NamedTextColor.GREEN)); + .arguments(Argument.component( + "players", Component.text(Integer.toString(online), NamedTextColor.GREEN))); target.sendMessage(msg.build()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/SendCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/SendCommand.java index d0df0348..aeeca118 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/SendCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/SendCommand.java @@ -35,6 +35,7 @@ import java.util.Objects; import java.util.Optional; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.translation.Argument; /** * Implements the Velocity default {@code /send} command. @@ -121,7 +122,7 @@ public class SendCommand { if (maybeServer.isEmpty()) { context.getSource().sendMessage( - CommandMessages.SERVER_DOES_NOT_EXIST.arguments(Component.text(serverName)) + CommandMessages.SERVER_DOES_NOT_EXIST.arguments(Argument.string("server", serverName)) ); return 0; } @@ -133,7 +134,7 @@ public class SendCommand { && !Objects.equals(player, "all") && !Objects.equals(player, "current")) { context.getSource().sendMessage( - CommandMessages.PLAYER_NOT_FOUND.arguments(Component.text(player)) + CommandMessages.PLAYER_NOT_FOUND.arguments(Argument.string("player", player)) ); return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/ServerCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/ServerCommand.java index 4ec40070..99fd348d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/ServerCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/ServerCommand.java @@ -37,6 +37,7 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TranslatableComponent; import net.kyori.adventure.text.event.ClickEvent; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.translation.Argument; /** * Implements Velocity's {@code /server} command. @@ -76,7 +77,7 @@ public final class ServerCommand { final Optional toConnect = server.getServer(serverName); if (toConnect.isEmpty()) { player.sendMessage(CommandMessages.SERVER_DOES_NOT_EXIST - .arguments(Component.text(serverName))); + .arguments(Argument.string("server", serverName))); return -1; } @@ -135,7 +136,7 @@ public final class ServerCommand { } else { playersTextComponent.key("velocity.command.server-tooltip-players-online"); } - playersTextComponent.arguments(Component.text(connectedPlayers)); + playersTextComponent.arguments(Argument.component("players", Component.text(connectedPlayers))); if (serverInfo.getName().equals(currentPlayerServer)) { serverTextComponent.color(NamedTextColor.GREEN) .hoverEvent( diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java index 101a5069..562efee4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/command/builtin/VelocityCommand.java @@ -62,6 +62,7 @@ import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; +import net.kyori.adventure.text.minimessage.translation.Argument; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -165,9 +166,9 @@ public final class VelocityCommand { .build(); final Component copyright = Component .translatable("velocity.command.version-copyright", - Component.text(version.getVendor()), - Component.text(version.getName()), - Component.text(LocalDate.now().getYear())); + Argument.string("vendor", version.getVendor()), + Argument.string("name", version.getName()), + Argument.component("year", Component.text(LocalDate.now().getYear()))); source.sendMessage(velocity); source.sendMessage(copyright); @@ -220,7 +221,7 @@ public final class VelocityCommand { final TranslatableComponent output = Component.translatable() .key("velocity.command.plugins-list") .color(NamedTextColor.YELLOW) - .arguments(listBuilder.build()) + .arguments(Argument.component("plugins", listBuilder.build())) .build(); source.sendMessage(output); return Command.SINGLE_SUCCESS; @@ -236,7 +237,7 @@ public final class VelocityCommand { hoverText.append(Component.newline()); hoverText.append(Component.translatable( "velocity.command.plugin-tooltip-website", - Component.text(url))); + Argument.component("url", Component.text(url)))); }); if (!description.getAuthors().isEmpty()) { hoverText.append(Component.newline()); @@ -246,7 +247,7 @@ public final class VelocityCommand { } else { hoverText.append( Component.translatable("velocity.command.plugin-tooltip-author", - Component.text(String.join(", ", description.getAuthors())) + Argument.string("authors", String.join(", ", description.getAuthors())) ) ); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index e86c82e7..8dd8d327 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -29,6 +29,7 @@ import com.velocitypowered.api.util.Favicon; import com.velocitypowered.proxy.config.migration.ConfigurationMigration; import com.velocitypowered.proxy.config.migration.ForwardingMigration; import com.velocitypowered.proxy.config.migration.KeyAuthenticationMigration; +import com.velocitypowered.proxy.config.migration.MiniMessageTranslationsMigration; import com.velocitypowered.proxy.config.migration.MotdMigration; import com.velocitypowered.proxy.config.migration.TransferIntegrationMigration; import com.velocitypowered.proxy.util.AddressUtil; @@ -501,6 +502,7 @@ public class VelocityConfiguration implements ProxyConfig { new ForwardingMigration(), new KeyAuthenticationMigration(), new MotdMigration(), + new MiniMessageTranslationsMigration(), new TransferIntegrationMigration() }; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/migration/ConfigurationMigration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/migration/ConfigurationMigration.java index a7fbb89f..d28578a6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/migration/ConfigurationMigration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/migration/ConfigurationMigration.java @@ -28,6 +28,7 @@ public sealed interface ConfigurationMigration permits ForwardingMigration, KeyAuthenticationMigration, MotdMigration, + MiniMessageTranslationsMigration, TransferIntegrationMigration { boolean shouldMigrate(CommentedFileConfig config); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/migration/MiniMessageTranslationsMigration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/migration/MiniMessageTranslationsMigration.java new file mode 100644 index 00000000..aff5424a --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/migration/MiniMessageTranslationsMigration.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2024 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.config.migration; + +import com.electronwill.nightconfig.core.file.CommentedFileConfig; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Pattern; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.apache.logging.log4j.Logger; + +/** + * Migration from old to modern language argument format with MiniMessage. + * Also migrates possible use of legacy colors to MiniMessage format. + */ +public final class MiniMessageTranslationsMigration implements ConfigurationMigration { + @Override + public boolean shouldMigrate(final CommentedFileConfig config) { + // Checking whether translations should be migrated would be just as costly as attempting to migrate them directly. + return true; + } + + @Override + public void migrate(final CommentedFileConfig config, final Logger logger) throws IOException { + final Path langFolder = Path.of("lang"); + if (Files.notExists(langFolder)) { + return; + } + final Pattern oldPlaceholderPattern = Pattern.compile("\\{(\\d+)}"); + try (final DirectoryStream stream + = Files.newDirectoryStream(langFolder, Files::isRegularFile)) { + for (final Path path : stream) { + String content = Files.readString(path, StandardCharsets.UTF_8); + if (content.indexOf('{') == -1) { + continue; + } + // Migrate old arguments + content = oldPlaceholderPattern.matcher(content).replaceAll(""); + // Some setups use legacy color codes, this format is migrated to MiniMessage + content = MiniMessage.miniMessage().serialize( + LegacyComponentSerializer.legacySection().deserialize(content)); + Files.writeString(path, content, StandardCharsets.UTF_8); + } + } + } +} 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 bff41a44..d6deeaef 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 @@ -135,6 +135,7 @@ import net.kyori.adventure.sound.SoundStop; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.logger.slf4j.ComponentLogger; +import net.kyori.adventure.text.minimessage.translation.Argument; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import net.kyori.adventure.title.Title.Times; @@ -713,12 +714,12 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, Component friendlyError; if (connectedServer != null && connectedServer.getServerInfo().equals(server.getServerInfo())) { friendlyError = Component.translatable("velocity.error.connected-server-error", - Component.text(server.getServerInfo().getName())); + Argument.string("server", server.getServerInfo().getName())); } else { logger.error("{}: unable to connect to server {}", this, server.getServerInfo().getName(), wrapped); friendlyError = Component.translatable("velocity.error.connecting-server-error", - Component.text(server.getServerInfo().getName())); + Argument.string("server", server.getServerInfo().getName())); } handleConnectionException(server, null, friendlyError.color(NamedTextColor.RED), safe); } @@ -746,7 +747,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, } handleConnectionException(server, disconnectReason, Component.translatable("velocity.error.moved-to-new-server", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), + Argument.string("server", server.getServerInfo().getName()), disconnectReason), safe); } else { if (this.server.getConfiguration().isLogPlayerConnections()) { @@ -755,7 +756,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, } handleConnectionException(server, disconnectReason, Component.translatable("velocity.error.cant-connect", NamedTextColor.RED, - Component.text(server.getServerInfo().getName()), + Argument.string("server", server.getServerInfo().getName()), disconnectReason), safe); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index 80260d2b..4fb4fa1f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -45,6 +45,7 @@ import java.net.InetSocketAddress; import java.util.Optional; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.minimessage.translation.Argument; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; @@ -129,7 +130,7 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler { connection.setState(StateRegistry.LOGIN); ic.disconnectQuietly(Component.translatable() .key("multiplayer.disconnect.outdated_client") - .arguments(Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING)) + .arguments(Argument.string("versions", ProtocolVersion.SUPPORTED_VERSION_STRING)) .build()); return; } diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages.properties index d56ca9c6..744cb68b 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=You are already connected to this server! velocity.error.already-connected-proxy=You are already connected to this proxy! velocity.error.already-connecting=You are already trying to connect to a server! -velocity.error.cant-connect=Unable to connect to {0}: {1} -velocity.error.connecting-server-error=Unable to connect you to {0}. Please try again later. -velocity.error.connected-server-error=Your connection to {0} encountered a problem. +velocity.error.cant-connect=Unable to connect to : +velocity.error.connecting-server-error=Unable to connect you to . Please try again later. +velocity.error.connected-server-error=Your connection to encountered a problem. velocity.error.internal-server-connection-error=An internal server connection error occurred. velocity.error.logging-in-too-fast=You are logging in too fast, try again later. velocity.error.online-mode-only=You are not logged into your Minecraft account. If you are logged into your Minecraft account, try restarting your Minecraft client. velocity.error.player-connection-error=An internal error occurred in your connection. velocity.error.modern-forwarding-needs-new-client=This server is only compatible with Minecraft 1.13 and above. velocity.error.modern-forwarding-failed=Your server did not send a forwarding request to the proxy. Make sure the server is configured for Velocity forwarding. -velocity.error.moved-to-new-server=You were kicked from {0}: {1} +velocity.error.moved-to-new-server=You were kicked from : velocity.error.no-available-servers=There are no available servers to connect you to. Try again later or contact an admin. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=An error occurred while running this command. velocity.command.command-does-not-exist=This command does not exist. velocity.command.players-only=Only players can run this command. -velocity.command.server-does-not-exist=The specified server {0} does not exist. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=You are currently connected to {0}. +velocity.command.server-does-not-exist=The specified server does not exist. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=You are currently connected to . velocity.command.server-too-many=There are too many servers set up. Use tab completion to view all servers available. velocity.command.server-available=Available servers: -velocity.command.server-tooltip-player-online={0} player online -velocity.command.server-tooltip-players-online={0} players online +velocity.command.server-tooltip-player-online= player online +velocity.command.server-tooltip-players-online= players online velocity.command.server-tooltip-current-server=Currently connected to this server velocity.command.server-tooltip-offer-connect-server=Click to connect to this server -velocity.command.glist-player-singular={0} player is currently connected to the proxy. -velocity.command.glist-player-plural={0} players are currently connected to the proxy. +velocity.command.glist-player-singular= player is currently connected to the proxy. +velocity.command.glist-player-plural= players are currently connected to the proxy. velocity.command.glist-view-all=To view all players on servers, use /glist all. velocity.command.reload-success=Velocity configuration successfully reloaded. velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=There are no plugins currently installed. -velocity.command.plugins-list=Plugins: {0} -velocity.command.plugin-tooltip-website=Website: {0} -velocity.command.plugin-tooltip-author=Author: {0} -velocity.command.plugin-tooltip-authors=Authors: {0} +velocity.command.plugins-list=Plugins: +velocity.command.plugin-tooltip-website=Website: +velocity.command.plugin-tooltip-author=Author: +velocity.command.plugin-tooltip-authors=Authors: velocity.command.dump-uploading=Uploading gathered information... velocity.command.dump-send-error=An error occurred while communicating with the Velocity servers. The servers may be temporarily unavailable or there is an issue with your network settings. You can find more information in the log or console of your Velocity server. velocity.command.dump-success=Created an anonymised report containing useful information about this proxy. If a developer requested it, you may share the following link with them: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ar_SA.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ar_SA.properties index 8f79f570..c93bbb46 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ar_SA.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ar_SA.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=أنت بالفعل متصل بهذا السيرفر\! velocity.error.already-connected-proxy=أنت بالفعل متصل بهذا الوكيل\! velocity.error.already-connecting=أنت بالفعل تحاول الاتصال بأحد السيرفرات\! -velocity.error.cant-connect=فشل الاتصال بـ{0}\: {1} -velocity.error.connecting-server-error=فشل الاتصال بـ{0}، حاول في وقتٍ لاحق. -velocity.error.connected-server-error=واجه اتصالك بـ{0} مشكلة. +velocity.error.cant-connect=فشل الاتصال بـ\: +velocity.error.connecting-server-error=فشل الاتصال بـ، حاول في وقتٍ لاحق. +velocity.error.connected-server-error=واجه اتصالك بـ مشكلة. velocity.error.internal-server-connection-error=حدث خطأ في الاتصال بالسيرفر الداخلي. velocity.error.logging-in-too-fast=لقد حاولت تسجيل الدخول كثيرًا مؤخرًا، حاول في وقتٍ لاحق. velocity.error.online-mode-only=لم تقم بتسجيل الدخول بحساب ماينكرافت. إذا كنت مسجل بالفعل جرب إعادة تشغيل اللعبة. velocity.error.player-connection-error=حدث خطأ داخلي في الاتصال الخاص بك. velocity.error.modern-forwarding-needs-new-client=هذا السيرفر متوافق فقط مع ماينكرافت 1.13 و ما فوق. velocity.error.modern-forwarding-failed=السيرفر الخاص بك لم يرسل طلب إعادة توجيه إلى الوكيل. تأكد من إعداد الخادم لإعادة التوجيه بـVelocity. -velocity.error.moved-to-new-server=لقد تم طردك من {0}\: {1} +velocity.error.moved-to-new-server=لقد تم طردك من \: velocity.error.no-available-servers=لا توجد سيرفرات متاحة للاتصال. حاول مرة أخرى أو اتصل بالأدمِن. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=حدث خطأ أثناء تنفيذ هذا الأمر. velocity.command.command-does-not-exist=هذا الأمر غير موجود. velocity.command.players-only=يمكن للاعبين فقط تشغيل هذا الأمر. -velocity.command.server-does-not-exist=السيرفر المطلوب {0} غير موجود. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=أنت الآن متصل بـ{0} +velocity.command.server-does-not-exist=السيرفر المطلوب غير موجود. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=أنت الآن متصل بـ velocity.command.server-too-many=هناك العديد من السيرفرات المتاحة، استخدم البحث بزر tab لتصفح قائمة السيرفرات. velocity.command.server-available=السيرفرات المتاحة\: velocity.command.server-tooltip-player-online=لاعب واحد متصل -velocity.command.server-tooltip-players-online={0} لاعبين متصلون +velocity.command.server-tooltip-players-online= لاعبين متصلون velocity.command.server-tooltip-current-server=انت متصل حاليًا بهذا السيرفر velocity.command.server-tooltip-offer-connect-server=انقر للاتصال بهذا السيرفر velocity.command.glist-player-singular=هناك لاعب واحد متصل بالوكيل. -velocity.command.glist-player-plural=هناك {0} لاعبين متصلون بالوكيل. +velocity.command.glist-player-plural=هناك لاعبين متصلون بالوكيل. velocity.command.glist-view-all=لعرض اللاعبين على جميع السيرفرات استخدم /glist all velocity.command.reload-success=تم إعادة تحميل إعدادات Velocity بنجاح. velocity.command.reload-failure=فشلت إعادة تحميل إعدادات Velocity. تفقد الـconsole للمزيد من التفاصيل. -velocity.command.version-copyright=حقوق الطبع والنشر 2018-{2} {0}. {1} مرخصة بموجب شروط الإصدار الثالث لرخصة GNU العامة (GPLv3). +velocity.command.version-copyright=حقوق الطبع والنشر 2018- . مرخصة بموجب شروط الإصدار الثالث لرخصة GNU العامة (GPLv3). velocity.command.no-plugins=لا توجد إضافات مثبتة على Velocity. -velocity.command.plugins-list=الإضافات\: {0} -velocity.command.plugin-tooltip-website=موقعها\: {0} -velocity.command.plugin-tooltip-author=تصميم\: {0} -velocity.command.plugin-tooltip-authors=تصميم\: {0} +velocity.command.plugins-list=الإضافات\: +velocity.command.plugin-tooltip-website=موقعها\: +velocity.command.plugin-tooltip-author=تصميم\: +velocity.command.plugin-tooltip-authors=تصميم\: velocity.command.dump-uploading=جاري تجميع و رفع معلومات نظامك... velocity.command.dump-send-error=حدث خطأ أثناء الاتصال بسيرفر Velocity. قد يكون السيرفر غير متاح مؤقتاً أو هناك مشكلة في إعدادات الشبكة الخاصة بك. يمكنك العثور على مزيد من المعلومات في log أو console وكيل Velocity الخاص بك. velocity.command.dump-success=تم إنشاء تقرير مفصل يحتوي على معلومات مفيدة عن الوكيل الخاص بك. إذا طلبه المطور، يمكنك مشاركة الرابط التالي معه\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_bg_BG.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_bg_BG.properties index c554fa3d..792065f2 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_bg_BG.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_bg_BG.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Вече сте свързани към този сървър\! velocity.error.already-connected-proxy=Вече сте свързани към това прокси\! velocity.error.already-connecting=Вече се опитвате да се свържете към сървър\! -velocity.error.cant-connect=Не успяхме да Ви свържем към {0}\: {1} -velocity.error.connecting-server-error=Не успяхме да Ви свържем към {0}. Моля, опитайте по-късно. -velocity.error.connected-server-error=Възникна грешка, докато бяхте свързан към {0}. +velocity.error.cant-connect=Не успяхме да Ви свържем към \: +velocity.error.connecting-server-error=Не успяхме да Ви свържем към . Моля, опитайте по-късно. +velocity.error.connected-server-error=Възникна грешка, докато бяхте свързан към . velocity.error.internal-server-connection-error=Възникна вътрешна грешка със сървърната връзка. velocity.error.logging-in-too-fast=Опитвате се да влизате твърде бързо - моля, опитайте по-късно. velocity.error.online-mode-only=Не сте влезли в своя Minecraft акаунт. Ако вече сте го направили, опитайте да рестартирате играта и лаунчера и опитайте отново. velocity.error.player-connection-error=Възникна грешка с вашата връзка. velocity.error.modern-forwarding-needs-new-client=Този сървър е съвместим само с Minecraft 1.13 или по-нова версия. velocity.error.modern-forwarding-failed=Сървъра Ви не изпрати заявка за препращане на информация към проксито. Моля, убедете се, че сървъра Ви е настроен за работа с Velocity. -velocity.error.moved-to-new-server=Ти беше изхвърлен от {0}\: {1} +velocity.error.moved-to-new-server=Ти беше изхвърлен от \: velocity.error.no-available-servers=Няма налични сървъри, км които да Ви свържем. Моля, опитайте по-късно, или се свържете с администратор. velocity.error.illegal-chat-characters=Неодобрени символи в чата # Commands velocity.command.generic-error=Възникна грешка при изпълняването на командата. velocity.command.command-does-not-exist=Тази команда не съществува. velocity.command.players-only=Само играчи могат да изпълняват тази команда. -velocity.command.server-does-not-exist=Сървър с името {0} не съществува. -velocity.command.player-not-found=Играч с името {0} не съществува. -velocity.command.server-current-server=В момента сте свързан към {0}. +velocity.command.server-does-not-exist=Сървър с името не съществува. +velocity.command.player-not-found=Играч с името не съществува. +velocity.command.server-current-server=В момента сте свързан към . velocity.command.server-too-many=Има прекалено много регистрирани сървъри. Използвайте TAB, за да видите всички налични сървъри. velocity.command.server-available=Налични сървъри\: -velocity.command.server-tooltip-player-online={0} играч на линия -velocity.command.server-tooltip-players-online={0} играчи на линия +velocity.command.server-tooltip-player-online= играч на линия +velocity.command.server-tooltip-players-online= играчи на линия velocity.command.server-tooltip-current-server=В момента сте свързани към този сървър velocity.command.server-tooltip-offer-connect-server=Натиснете тук, за да Ви свържем към този сървър -velocity.command.glist-player-singular={0} играч е свързан към проксито. -velocity.command.glist-player-plural={0} играчи са свързани към проксито. +velocity.command.glist-player-singular= играч е свързан към проксито. +velocity.command.glist-player-plural= играчи са свързани към проксито. velocity.command.glist-view-all=За да видите всички играчи, разпределени по сървъри, използвайте /glist all. velocity.command.reload-success=Настройките на Velocity бяха презаредени успешно. velocity.command.reload-failure=Не успяхме да презаредим настройките на Velocity. Моля, проверете конзолата за повече информация. -velocity.command.version-copyright=Авторско право 2018-{2} {0}. {1} е лицензиран под условията на GNU General Public License v3. +velocity.command.version-copyright=Авторско право 2018- . е лицензиран под условията на GNU General Public License v3. velocity.command.no-plugins=За момента няма инсталирани добавки. -velocity.command.plugins-list=Добавки\: {0} -velocity.command.plugin-tooltip-website=Уебсайт\: {0} -velocity.command.plugin-tooltip-author=Автор\: {0} -velocity.command.plugin-tooltip-authors=Автори\: {0} +velocity.command.plugins-list=Добавки\: +velocity.command.plugin-tooltip-website=Уебсайт\: +velocity.command.plugin-tooltip-author=Автор\: +velocity.command.plugin-tooltip-authors=Автори\: velocity.command.dump-uploading=Качваме събраната информация... velocity.command.dump-send-error=Възникна грешка при комуникацията със сървърите на Velocity. Сървърите може временно да не са налични, или да имате проблем с мрежовите настройки. Ще откриете повече информация в логовете или конзолата на Вашето Velocity прокси. velocity.command.dump-success=Създадохме анонимен доклад, съдържащ полезна информация относно това прокси. Ако разработчик Ви го е поискал, може да споделите този линк с тях\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_cs_CZ.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_cs_CZ.properties index 980e4591..336211c1 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_cs_CZ.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_cs_CZ.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=K tomuto serveru jsi již připojen\! velocity.error.already-connected-proxy=K tomuto proxy serveru jsi již připojen\! velocity.error.already-connecting=Již se pokoušíš o připojení k serveru\! -velocity.error.cant-connect=Nepodařilo se připojit k serveru {0}\: {1} -velocity.error.connecting-server-error=Nepodařilo se tě připojit k serveru {0}. Zkus to prosím později. -velocity.error.connected-server-error=Nastala chyba ve tvém připojení k serveru {0}. +velocity.error.cant-connect=Nepodařilo se připojit k serveru \: +velocity.error.connecting-server-error=Nepodařilo se tě připojit k serveru . Zkus to prosím později. +velocity.error.connected-server-error=Nastala chyba ve tvém připojení k serveru . velocity.error.internal-server-connection-error=V připojení k serveru se vyskytla interní chyba. velocity.error.logging-in-too-fast=Přihlašuješ se příliš rychle, počkej chvíli. velocity.error.online-mode-only=Nejsi připojen ke svému Minecraft účtu. Pokud ano, nastala chyba. Zkus restartovat hru. velocity.error.player-connection-error=Ve tvém připojení nastala chyba. velocity.error.modern-forwarding-needs-new-client=Tento server je kompatibilní pouze s verzí Minecraftu 1.13 a vyšší. velocity.error.modern-forwarding-failed=Tvůj server neodeslal přesměrovávací požadavek na proxy server. Ujisti se, že je server nastaven na Velocity přesměrování. -velocity.error.moved-to-new-server=Byl jsi vyhozen ze serveru {0}\: {1} +velocity.error.moved-to-new-server=Byl jsi vyhozen ze serveru \: velocity.error.no-available-servers=Nejsou k dispozici žádné servery, ke kterým by ses mohl připojit. Zkus to později nebo kontaktuj správce. velocity.error.illegal-chat-characters=Nepovolené znaky v chatu # Commands velocity.command.generic-error=Při vykonávání tohoto příkazu nastala chyba. velocity.command.command-does-not-exist=Tento příkaz neexistuje. velocity.command.players-only=Tento příkaz mohou vykonávat pouze hráči. -velocity.command.server-does-not-exist=Zadaný server {0} neexistuje. -velocity.command.player-not-found=Zadaný hráč {0} neexistuje. -velocity.command.server-current-server=Právě jsi připojen k serveru {0}. +velocity.command.server-does-not-exist=Zadaný server neexistuje. +velocity.command.player-not-found=Zadaný hráč neexistuje. +velocity.command.server-current-server=Právě jsi připojen k serveru . velocity.command.server-too-many=Je nastaveno příliš mnoho serverů. Klávesa tab ukáže všechny dostupné servery. velocity.command.server-available=Dostupné servery\: -velocity.command.server-tooltip-player-online={0} hráč online -velocity.command.server-tooltip-players-online=Počet hráčů online\: {0} +velocity.command.server-tooltip-player-online= hráč online +velocity.command.server-tooltip-players-online=Počet hráčů online\: velocity.command.server-tooltip-current-server=Právě jsi připojen k tomuto serveru velocity.command.server-tooltip-offer-connect-server=Kliknutím se připojíš k tomuto serveru -velocity.command.glist-player-singular=K tomuto proxy serveru je připojen {0} hráč. -velocity.command.glist-player-plural=Počet hráčů připojených k tomuto proxy serveru\: {0} +velocity.command.glist-player-singular=K tomuto proxy serveru je připojen hráč. +velocity.command.glist-player-plural=Počet hráčů připojených k tomuto proxy serveru\: velocity.command.glist-view-all=Ke zobrazení všech hráčů na všech serverech použij /glist all. velocity.command.reload-success=Konfigurace Velocity úspěšně načtena. velocity.command.reload-failure=Nebylo možné načíst konfiguraci Velocity. Podrobnosti jsou na konzoli. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} je licencovaný pod podmínkami GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . je licencovaný pod podmínkami GNU General Public License v3. velocity.command.no-plugins=V tuto chvíli nejsou nainstalovány žádné zásuvné moduly. -velocity.command.plugins-list=Zásuvné moduly\: {0} -velocity.command.plugin-tooltip-website=Webová stránka\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autoři\: {0} +velocity.command.plugins-list=Zásuvné moduly\: +velocity.command.plugin-tooltip-website=Webová stránka\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autoři\: velocity.command.dump-uploading=Nahrávání získaných informací... velocity.command.dump-send-error=Nastala chyba při komunikaci s Velocity servery. Servery mohou být dočasně nedostupné nebo je chyba v přístupu na internet. Podrobnosti jsou v logu a na konzoli Velocity serveru. velocity.command.dump-success=Byla vytvořena anonymizovaná zpráva obsahující užitečné informace o tomto serveru. Vyžádal-li si je vývojář, můžeš mu poslat nasledující odkaz\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_da_DK.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_da_DK.properties index 1a82cbdf..4d80e07f 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_da_DK.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_da_DK.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Du er allerede tilsluttet til den server\! velocity.error.already-connected-proxy=Du er allerede tilsluttet til proxyen\! velocity.error.already-connecting=Du forsøger allerede at oprette forbindelse til en server\! -velocity.error.cant-connect=Kan ikke forbinde til {0}\: {1} -velocity.error.connecting-server-error=Kan ikke forbinde dig til {0}. Prøv igen senere. -velocity.error.connected-server-error=Din forbindelse til {0} stødte på et problem. +velocity.error.cant-connect=Kan ikke forbinde til \: +velocity.error.connecting-server-error=Kan ikke forbinde dig til . Prøv igen senere. +velocity.error.connected-server-error=Din forbindelse til stødte på et problem. velocity.error.internal-server-connection-error=Der opstod en intern server forbindelsesfejl. velocity.error.logging-in-too-fast=Du logger ind for hurtigt, prøv igen senere. velocity.error.online-mode-only=Du er ikke logget ind på din Minecraft-konto. Hvis du er logget ind på din Minecraft-konto, så prøv at genstarte din Minecraft-klient. velocity.error.player-connection-error=Der opstod en intern fejl i din forbindelse. velocity.error.modern-forwarding-needs-new-client=Denne server er kun kompatibel med Minecraft 1.13 og derover. velocity.error.modern-forwarding-failed=Din server sendte ikke en viderestillingsanmodning til proxyen. Sørg for, at serveren er konfigureret til Velocity forwarding. -velocity.error.moved-to-new-server=Du blev smidt ud fra {0}\: {1} +velocity.error.moved-to-new-server=Du blev smidt ud fra \: velocity.error.no-available-servers=Der er ingen tilgængelige servere at forbinde dig til. Prøv igen senere eller kontakt en administrator. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Der opstod en fejl da du kørte kommandoen. velocity.command.command-does-not-exist=Denne kommando eksisterer ikke. velocity.command.players-only=Kun spillere kan køre denne kommando. -velocity.command.server-does-not-exist=Den angivne server {0} findes ikke. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Du er i øjeblikket forbundet til {0}. +velocity.command.server-does-not-exist=Den angivne server findes ikke. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Du er i øjeblikket forbundet til . velocity.command.server-too-many=Der er sat for mange servere op. Brug tab færdiggørelse til at se alle tilgængelige servere. velocity.command.server-available=Tilgængelige servere\: -velocity.command.server-tooltip-player-online={0} spiller online -velocity.command.server-tooltip-players-online={0} spillere online +velocity.command.server-tooltip-player-online= spiller online +velocity.command.server-tooltip-players-online= spillere online velocity.command.server-tooltip-current-server=I øjeblikket forbundet til serveren velocity.command.server-tooltip-offer-connect-server=Klik for at forbinde til denne server -velocity.command.glist-player-singular={0} spiller er i øjeblikket forbundet til proxyen. -velocity.command.glist-player-plural={0} spillere er i øjeblikket forbundet til proxyen. +velocity.command.glist-player-singular= spiller er i øjeblikket forbundet til proxyen. +velocity.command.glist-player-plural= spillere er i øjeblikket forbundet til proxyen. velocity.command.glist-view-all=For at se alle spillere på servere, brug /glist all. velocity.command.reload-success=Velocity konfiguration blev genindlæst. velocity.command.reload-failure=Kan ikke genindlæse din Velocity konfiguration. Tjek konsollen for flere detaljer. -velocity.command.version-copyright=Ophavsret 2018-{2} {0}. {1} er licenseret under betingelserne i GNU General Public License v3. +velocity.command.version-copyright=Ophavsret 2018- . er licenseret under betingelserne i GNU General Public License v3. velocity.command.no-plugins=Der er ingen plugins installeret i øjeblikket. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Hjemmeside\: {0} -velocity.command.plugin-tooltip-author=Forfatter\: {0} -velocity.command.plugin-tooltip-authors=Skabere\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Hjemmeside\: +velocity.command.plugin-tooltip-author=Forfatter\: +velocity.command.plugin-tooltip-authors=Skabere\: velocity.command.dump-uploading=Uploader indsamlet information... velocity.command.dump-send-error=Der opstod en fejl under kommunikation med Velocity serverne. Serverne kan være midlertidigt utilgængelige, eller der er et problem med dine netværksindstillinger. Du kan finde mere information i loggen eller konsollen på din Velocity server. velocity.command.dump-success=Oprettet en anonymiseret rapport med nyttige oplysninger om denne proxy. Hvis en udvikler anmodede om det, kan du dele følgende link med dem\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_de_DE.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_de_DE.properties index 4de00f9e..65004a1d 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_de_DE.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_de_DE.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Du bist bereits mit diesem Server verbunden\! velocity.error.already-connected-proxy=Du bist bereits mit diesem Proxy verbunden\! velocity.error.already-connecting=Du versuchst dich bereits mit einem Server zu verbinden\! -velocity.error.cant-connect=Kein Verbindungsaufbau zu {0} möglich\: {1} -velocity.error.connecting-server-error=Kein Verbindungsaufbau zu {0} möglich. Bitte versuche es später erneut. -velocity.error.connected-server-error=Bei der Verbindung zu {0} ist ein Problem aufgetreten. +velocity.error.cant-connect=Kein Verbindungsaufbau zu möglich\: +velocity.error.connecting-server-error=Kein Verbindungsaufbau zu möglich. Bitte versuche es später erneut. +velocity.error.connected-server-error=Bei der Verbindung zu ist ein Problem aufgetreten. velocity.error.internal-server-connection-error=Bei der Verbindung mit dem Server ist ein interner Fehler aufgetreten. velocity.error.logging-in-too-fast=Du meldest dich zu schnell an, versuche es später noch einmal. velocity.error.online-mode-only=Du bist nicht in deinem Minecraft Konto eingeloggt. Wenn du in deinem Minecraft Konto eingeloggt bist, versuche deinen Minecraft Client neu zu starten. velocity.error.player-connection-error=Bei deiner Verbindung ist ein interner Fehler aufgetreten. velocity.error.modern-forwarding-needs-new-client=Dieser Server ist nur mit der Minecraft Version 1.13 und höher kompatibel. velocity.error.modern-forwarding-failed=Dein Server hat keine Weiterleitungsanforderung an den Proxy gesendet. Stelle sicher, dass der Server für die Velocity Weiterleitung konfiguriert ist. -velocity.error.moved-to-new-server=Du wurdest von {0} vom Server geworfen\: {1} +velocity.error.moved-to-new-server=Du wurdest von vom Server geworfen\: velocity.error.no-available-servers=Es gibt keine verfügbaren Server mit denen du dich verbinden kannst. Versuche es später erneut oder kontaktiere einen Admin. velocity.error.illegal-chat-characters=Ungültige Zeichen im Chat # Commands velocity.command.generic-error=Beim Ausführen des Befehls ist ein Fehler aufgetreten. velocity.command.command-does-not-exist=Dieser Befehl existiert nicht. velocity.command.players-only=Nur Spieler können diesen Befehl ausführen. -velocity.command.server-does-not-exist=Der angegebene Server {0} existiert nicht. -velocity.command.player-not-found=Der angegebene Spieler {0} existiert nicht. -velocity.command.server-current-server=Du bist derzeit mit {0} verbunden. +velocity.command.server-does-not-exist=Der angegebene Server existiert nicht. +velocity.command.player-not-found=Der angegebene Spieler existiert nicht. +velocity.command.server-current-server=Du bist derzeit mit verbunden. velocity.command.server-too-many=Es sind zu viele Server eingerichtet. Verwende die Tabvervollständigung, um alle verfügbaren Server aufzulisten. velocity.command.server-available=Verfügbare Server\: -velocity.command.server-tooltip-player-online={0} Spieler online -velocity.command.server-tooltip-players-online={0} Spieler online +velocity.command.server-tooltip-player-online= Spieler online +velocity.command.server-tooltip-players-online= Spieler online velocity.command.server-tooltip-current-server=Du bist derzeit mit diesem Server verbunden velocity.command.server-tooltip-offer-connect-server=Klicke, um dich mit diesem Server zu verbinden -velocity.command.glist-player-singular={0} Spieler ist derzeit mit dem Proxy verbunden. -velocity.command.glist-player-plural={0} Spieler sind derzeit mit dem Proxy verbunden. +velocity.command.glist-player-singular= Spieler ist derzeit mit dem Proxy verbunden. +velocity.command.glist-player-plural= Spieler sind derzeit mit dem Proxy verbunden. velocity.command.glist-view-all=Um alle Spieler auf Servern aufzulisten, verwende /glist all. velocity.command.reload-success=Velocity-Konfiguration erfolgreich neu geladen. velocity.command.reload-failure=Die Velocity-Konfiguration konnte nicht neu geladen werden. Prüfe die Konsole für weitere Details. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} ist lizenziert unter den Bedingungen der GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . ist lizenziert unter den Bedingungen der GNU General Public License v3. velocity.command.no-plugins=Es sind derzeit keine Plugins installiert. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Webseite\: {0} -velocity.command.plugin-tooltip-author=Entwickler\: {0} -velocity.command.plugin-tooltip-authors=Entwickler\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Webseite\: +velocity.command.plugin-tooltip-author=Entwickler\: +velocity.command.plugin-tooltip-authors=Entwickler\: velocity.command.dump-uploading=Erfasste Daten werden hochgeladen... velocity.command.dump-send-error=Bei der Kommunikation mit den Velocity-Servern ist ein Fehler aufgetreten. Diese Server sind möglicherweise vorübergehend nicht verfügbar oder es gibt ein Problem mit deinen Netzwerkeinstellungen. Weitere Informationen findest du in der Log-Datei oder in der Konsole deines Velocity-Servers. velocity.command.dump-success=Ein anonymisierter Bericht mit nützlichen Informationen über diesen Proxy wurde erstellt. Wenn ein Entwickler den Bericht angefordert hat, kannst du diesen über folgenden Link mit ihm teilen\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_es_ES.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_es_ES.properties index 0d484bc9..00b0bea5 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_es_ES.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_es_ES.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=¡Ya estás conectado a este servidor\! velocity.error.already-connected-proxy=¡Ya estás conectado a este proxy\! velocity.error.already-connecting=¡Ya estás intentando conectarte a un servidor\! -velocity.error.cant-connect=No se ha podido conectar a {0}\: {1} -velocity.error.connecting-server-error=No hemos podido conectarte a {0}. Por favor, inténtalo de nuevo más tarde. -velocity.error.connected-server-error=Tu conexión a {0} ha sufrido un problema. +velocity.error.cant-connect=No se ha podido conectar a \: +velocity.error.connecting-server-error=No hemos podido conectarte a . Por favor, inténtalo de nuevo más tarde. +velocity.error.connected-server-error=Tu conexión a ha sufrido un problema. velocity.error.internal-server-connection-error=Se ha producido un error interno en la conexión al servidor. velocity.error.logging-in-too-fast=Estás iniciando sesión demasiado rápido, inténtalo de nuevo más tarde. velocity.error.online-mode-only=No has iniciado sesión con tu cuenta de Minecraft. Si crees que ya lo estás, intenta reiniciar tu cliente de Minecraft. velocity.error.player-connection-error=Se ha producido un error interno en tu conexión. velocity.error.modern-forwarding-needs-new-client=Este servidor solo es compatible con Minecraft 1.13 y superior. velocity.error.modern-forwarding-failed=El servidor no ha enviado una solicitud de reenvío al proxy. Asegúrate de que tu servidor está configurado para usar el método de reenvío de Velocity. -velocity.error.moved-to-new-server=Has sido echado de {0}\: {1} +velocity.error.moved-to-new-server=Has sido echado de \: velocity.error.no-available-servers=No hay servidores disponibles a los que conectarte. Inténtalo de nuevo más tarde o contacta con un administrador. velocity.error.illegal-chat-characters=Caracteres no válidos en el chat # Commands velocity.command.generic-error=Se ha producido un error al ejecutar este comando. velocity.command.command-does-not-exist=Este comando no existe. velocity.command.players-only=Solo los jugadores pueden ejecutar este comando. -velocity.command.server-does-not-exist=El servidor especificado {0} no existe. -velocity.command.player-not-found=El jugador especificado {0} no existe. -velocity.command.server-current-server=Estás conectado a {0}. +velocity.command.server-does-not-exist=El servidor especificado no existe. +velocity.command.player-not-found=El jugador especificado no existe. +velocity.command.server-current-server=Estás conectado a . velocity.command.server-too-many=Hay demasiados servidores registrados. Usa la finalización con tabulación para ver todos los servidores disponibles. velocity.command.server-available=Servidores disponibles\: -velocity.command.server-tooltip-player-online={0} jugador conectado -velocity.command.server-tooltip-players-online={0} jugadores conectados +velocity.command.server-tooltip-player-online= jugador conectado +velocity.command.server-tooltip-players-online= jugadores conectados velocity.command.server-tooltip-current-server=Estás conectado a este servidor velocity.command.server-tooltip-offer-connect-server=Haz clic para conectarte a este servidor -velocity.command.glist-player-singular={0} jugador está conectado al proxy. -velocity.command.glist-player-plural={0} jugadores están conectados al proxy. +velocity.command.glist-player-singular= jugador está conectado al proxy. +velocity.command.glist-player-plural= jugadores están conectados al proxy. velocity.command.glist-view-all=Para ver todos los jugadores por servidores, usa /glist all. velocity.command.reload-success=La configuración de Velocity ha sido recargada correctamente. velocity.command.reload-failure=No ha sido posible recargar la configuración de Velocity. Para obtener más información, revisa la consola. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} está licenciado bajo los términos de la Licencia Pública General de GNU v3. +velocity.command.version-copyright=Copyright 2018- . está licenciado bajo los términos de la Licencia Pública General de GNU v3. velocity.command.no-plugins=Actualmente no hay plugins instalados. -velocity.command.plugins-list=Complementos\: {0} -velocity.command.plugin-tooltip-website=Página web\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autores\: {0} +velocity.command.plugins-list=Complementos\: +velocity.command.plugin-tooltip-website=Página web\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autores\: velocity.command.dump-uploading=Subiendo la información recopilada... velocity.command.dump-send-error=Se ha producido un error al comunicarse con los servidores de Velocity. Es posible que los servidores no estén disponibles temporalmente o que exista un problema en tu configuración de red. Puedes encontrar más información en el archivo de registro o la consola de tu servidor Velocity. velocity.command.dump-success=Se ha creado un informe anónimo que contiene información útil sobre este proxy. Si un desarrollador lo solicita, puedes compartir el siguiente enlace con él\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_et_EE.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_et_EE.properties index 0e4ea63d..a46fa3e8 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_et_EE.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_et_EE.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Sa oled juba antud serveriga ühendatud\! velocity.error.already-connected-proxy=Sa oled juba antud proksiga ühendatud\! velocity.error.already-connecting=Sa juba ühendad severiga\! -velocity.error.cant-connect=Unable to connect to {0}\: {1} -velocity.error.connecting-server-error=Unable to connect you to {0}. Please try again later. -velocity.error.connected-server-error=Your connection to {0} encountered a problem. +velocity.error.cant-connect=Unable to connect to \: +velocity.error.connecting-server-error=Unable to connect you to . Please try again later. +velocity.error.connected-server-error=Your connection to encountered a problem. velocity.error.internal-server-connection-error=An internal server connection error occurred. velocity.error.logging-in-too-fast=Sa logid sisse liiga kiiresti, proovi hiljem uuesti. velocity.error.online-mode-only=You are not logged into your Minecraft account. If you are logged into your Minecraft account, try restarting your Minecraft client. velocity.error.player-connection-error=An internal error occurred in your connection. velocity.error.modern-forwarding-needs-new-client=This server is only compatible with Minecraft 1.13 and above. velocity.error.modern-forwarding-failed=Your server did not send a forwarding request to the proxy. Make sure the server is configured for Velocity forwarding. -velocity.error.moved-to-new-server=You were kicked from {0}\: {1} +velocity.error.moved-to-new-server=You were kicked from \: velocity.error.no-available-servers=There are no available servers to connect you to. Try again later or contact an admin. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=An error occurred while running this command. velocity.command.command-does-not-exist=Antud käsklust ei eksisteeri. velocity.command.players-only=Ainult mängijad saavad antud käsklust kasutada. -velocity.command.server-does-not-exist=Server {0} ei eksisteeri. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Sa oled hetkel ühendatud serveriga {0}. +velocity.command.server-does-not-exist=Server ei eksisteeri. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Sa oled hetkel ühendatud serveriga . velocity.command.server-too-many=There are too many servers set up. Use tab completion to view all servers available. velocity.command.server-available=Saadaolevad serverid\: -velocity.command.server-tooltip-player-online={0} mängija online -velocity.command.server-tooltip-players-online={0} mängijat online +velocity.command.server-tooltip-player-online= mängija online +velocity.command.server-tooltip-players-online= mängijat online velocity.command.server-tooltip-current-server=Currently connected to this server velocity.command.server-tooltip-offer-connect-server=Vajuta, et ühendada antud serveriga -velocity.command.glist-player-singular={0} player is currently connected to the proxy. -velocity.command.glist-player-plural={0} players are currently connected to the proxy. +velocity.command.glist-player-singular= player is currently connected to the proxy. +velocity.command.glist-player-plural= players are currently connected to the proxy. velocity.command.glist-view-all=Et näha kõiki mängijaid kõikides serverites, kasuta käsklust /glist all. velocity.command.reload-success=Velocity seadistus edukalt taaslaetud. velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=There are no plugins currently installed. -velocity.command.plugins-list=Pluginad\: {0} -velocity.command.plugin-tooltip-website=Veebileht\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autorid\: {0} +velocity.command.plugins-list=Pluginad\: +velocity.command.plugin-tooltip-website=Veebileht\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autorid\: velocity.command.dump-uploading=Kogutud informatsiooni üleslaadimine... velocity.command.dump-send-error=An error occurred while communicating with the Velocity servers. The servers may be temporarily unavailable or there is an issue with your network settings. You can find more information in the log or console of your Velocity server. velocity.command.dump-success=Created an anonymised report containing useful information about this proxy. If a developer requested it, you may share the following link with them\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fi_FI.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fi_FI.properties index 39c8f374..beb49a4d 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fi_FI.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fi_FI.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Olet jo yhteydessä tälle palvelimelle\! velocity.error.already-connected-proxy=Olet jo yhteydessä tälle välityspalvelimelle\! velocity.error.already-connecting=Yrität jo yhdistää palvelimeen\! -velocity.error.cant-connect={0} ei saatu yhteyttä\: {1} -velocity.error.connecting-server-error=Yhteyttä palvelimeen {0} ei voitu muodostaa. Yritä myöhemmin uudelleen. -velocity.error.connected-server-error=Yhteydessäsi palvelimeen {0} tapahtui virhe. +velocity.error.cant-connect= ei saatu yhteyttä\: +velocity.error.connecting-server-error=Yhteyttä palvelimeen ei voitu muodostaa. Yritä myöhemmin uudelleen. +velocity.error.connected-server-error=Yhteydessäsi palvelimeen tapahtui virhe. velocity.error.internal-server-connection-error=Tapahtui palvelimen sisäinen yhteysvirhe. velocity.error.logging-in-too-fast=Kirjaudut sisään liian nopeasti, yritä uudelleen hetken kuluttua. velocity.error.online-mode-only=Et ole kirjautuneena Minecraft-tilillesi. Jos olet kirjautuneena sisään, yritä pelin uudelleenkäynnistämistä. velocity.error.player-connection-error=Yhteydessäsi tapahtui sisäinen virhe. velocity.error.modern-forwarding-needs-new-client=Tämä palvelin on yhteensopiva vain Minecraft 1.13\:n ja sitä uudempien versioiden kanssa. velocity.error.modern-forwarding-failed=Valitsemasi palvelin ei lähettänyt välityspyyntöä välityspalvelimelle. Tarkista että palvelin on määritetty oikein Velocityä varten. -velocity.error.moved-to-new-server=Sinut potkittiin pois palvelimelta {0}\: {1} +velocity.error.moved-to-new-server=Sinut potkittiin pois palvelimelta \: velocity.error.no-available-servers=Yhtään palvelinta ei ole tällä hetkellä saatavilla. Yritä myöhemmin uudelleen tai ota yhteyttä palvelimen ylläpitäjään. velocity.error.illegal-chat-characters=Kiellettyjä merkkejä chatissa # Commands velocity.command.generic-error=Tämän komennon suorittamisessa tapahtui virhe. velocity.command.command-does-not-exist=Tuota komentoa ei ole olemassa. velocity.command.players-only=Vain pelaajat voivat käyttää tuota komentoa. -velocity.command.server-does-not-exist=Palvelinta {0} ei ole olemassa. -velocity.command.player-not-found=Annettua pelaajaa {0} ei ole olemassa. -velocity.command.server-current-server=Olet tällä hetkellä yhdistettynä palvelimeen {0}. +velocity.command.server-does-not-exist=Palvelinta ei ole olemassa. +velocity.command.player-not-found=Annettua pelaajaa ei ole olemassa. +velocity.command.server-current-server=Olet tällä hetkellä yhdistettynä palvelimeen . velocity.command.server-too-many=Liian monta palvelinta on määritetty. Paina Tab -näppäintä nähdäksesi kaikki saatavilla olevat palvelimet. velocity.command.server-available=Saatavilla olevat palvelimet\: -velocity.command.server-tooltip-player-online={0} pelaaja paikalla -velocity.command.server-tooltip-players-online={0} pelaajaa paikalla +velocity.command.server-tooltip-player-online= pelaaja paikalla +velocity.command.server-tooltip-players-online= pelaajaa paikalla velocity.command.server-tooltip-current-server=Tällä hetkellä yhdistetty tähän palvelimeen velocity.command.server-tooltip-offer-connect-server=Napsauta yhdistääksesi tähän palvelimeen -velocity.command.glist-player-singular={0} pelaaja on tällä hetkellä yhdistänyt välityspalvelimelle. -velocity.command.glist-player-plural={0} pelaajaa on tällä hetkellä yhdistänyt välityspalvelimelle. +velocity.command.glist-player-singular= pelaaja on tällä hetkellä yhdistänyt välityspalvelimelle. +velocity.command.glist-player-plural= pelaajaa on tällä hetkellä yhdistänyt välityspalvelimelle. velocity.command.glist-view-all=Nähdäksesi pelaajat kaikilla palvelimilla, käytä komentoa /glist all. velocity.command.reload-success=Velocityn konfiguraatio uudelleenladattiin onnistuneesti. velocity.command.reload-failure=Velocityn konfiguraation uudelleenlataus epäonnistui. Katso tarkemmat lisätiedot konsolista. -velocity.command.version-copyright=Tekijänoikeus 2018-{2} {0}. {1} on lisensoitu GNU General Public License v3\:n ehtojen mukaisesti. +velocity.command.version-copyright=Tekijänoikeus 2018- . on lisensoitu GNU General Public License v3\:n ehtojen mukaisesti. velocity.command.no-plugins=Yhtäkään pluginia ei ole asennettu. -velocity.command.plugins-list=Pluginit\: {0} -velocity.command.plugin-tooltip-website=Verkkosivu\: {0} -velocity.command.plugin-tooltip-author=Tekijä\: {0} -velocity.command.plugin-tooltip-authors=Tekijät\: {0} +velocity.command.plugins-list=Pluginit\: +velocity.command.plugin-tooltip-website=Verkkosivu\: +velocity.command.plugin-tooltip-author=Tekijä\: +velocity.command.plugin-tooltip-authors=Tekijät\: velocity.command.dump-uploading=Lähetetään kerättyjä tietoja... velocity.command.dump-send-error=Velocity-palvelimien kanssa kommunikoidessa tapahtui virhe. Palvelimet eivät ehkä ole tilapäisesti käytettävissä tai verkkoasetuksissa on ongelma. Löydät lisätietoja Velocity-palvelimesi lokista tai konsolista. velocity.command.dump-success=Luotiin anonyymi raportti, joka sisältää hyödyllistä tietoa tästä välityspalvelimesta. Jos jokin kehittäjä on pyytänyt sitä, voit jakaa seuraavan linkin heidän kanssaan\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fr_FR.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fr_FR.properties index 64fa63ee..50d2a556 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fr_FR.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_fr_FR.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Vous êtes déjà connecté(e) à ce serveur \! velocity.error.already-connected-proxy=Vous êtes déjà connecté(e) à ce proxy \! velocity.error.already-connecting=Vous êtes déjà en train d'essayer de vous connecter à un serveur \! -velocity.error.cant-connect=Impossible de se connecter à {0} \: {1} -velocity.error.connecting-server-error=Impossible de vous connecter à {0}. Veuillez réessayer ultérieurement. -velocity.error.connected-server-error=Votre connexion à {0} a rencontré un problème. +velocity.error.cant-connect=Impossible de se connecter à \: +velocity.error.connecting-server-error=Impossible de vous connecter à . Veuillez réessayer ultérieurement. +velocity.error.connected-server-error=Votre connexion à a rencontré un problème. velocity.error.internal-server-connection-error=Une erreur interne s'est produite lors de la connexion au serveur. velocity.error.logging-in-too-fast=Vous vous connectez trop rapidement, réessayez ultérieurement. velocity.error.online-mode-only=Vous n'êtes pas connecté(e) à votre compte Minecraft. Si vous l'êtes, essayez de redémarrer votre client Minecraft. velocity.error.player-connection-error=Une erreur interne s'est produite lors de votre connexion. velocity.error.modern-forwarding-needs-new-client=Ce serveur est uniquement compatible avec Minecraft 1.13 et les versions ultérieures. velocity.error.modern-forwarding-failed=Votre serveur n'a pas envoyé de requête de transfert vers le proxy. Assurez-vous que le serveur est configuré pour le transfert Velocity. -velocity.error.moved-to-new-server=Vous avez été expulsé(e) de {0} \: {1} +velocity.error.moved-to-new-server=Vous avez été expulsé(e) de \: velocity.error.no-available-servers=Il n'y a pas de serveurs disponibles auxquels vous connecter. Réessayez ultérieurement ou contactez un administrateur. velocity.error.illegal-chat-characters=Caractères interdits dans le chat. # Commands velocity.command.generic-error=Une erreur est survenue lors de l'exécution de cette commande. velocity.command.command-does-not-exist=Cette commande n'existe pas. velocity.command.players-only=Seuls les joueurs peuvent exécuter cette commande. -velocity.command.server-does-not-exist=Le serveur spécifié {0} n'existe pas. -velocity.command.player-not-found=Le joueur spécifié {0} n'existe pas. -velocity.command.server-current-server=Vous êtes actuellement connecté(e) à {0}. +velocity.command.server-does-not-exist=Le serveur spécifié n'existe pas. +velocity.command.player-not-found=Le joueur spécifié n'existe pas. +velocity.command.server-current-server=Vous êtes actuellement connecté(e) à . velocity.command.server-too-many=Il y a trop de serveurs configurés. Utilisez la saisie semi-automatique via la touche Tab pour afficher tous les serveurs disponibles. velocity.command.server-available=Serveurs disponibles \: -velocity.command.server-tooltip-player-online={0} joueur connecté -velocity.command.server-tooltip-players-online={0} joueurs connectés +velocity.command.server-tooltip-player-online= joueur connecté +velocity.command.server-tooltip-players-online= joueurs connectés velocity.command.server-tooltip-current-server=Actuellement connecté(e) à ce serveur velocity.command.server-tooltip-offer-connect-server=Cliquez pour vous connecter à ce serveur -velocity.command.glist-player-singular={0} joueur est actuellement connecté au proxy. -velocity.command.glist-player-plural={0} joueurs sont actuellement connectés au proxy. +velocity.command.glist-player-singular= joueur est actuellement connecté au proxy. +velocity.command.glist-player-plural= joueurs sont actuellement connectés au proxy. velocity.command.glist-view-all=Pour afficher tous les joueurs connectés aux serveurs, utilisez /glist all. velocity.command.reload-success=Configuration de Velocity rechargée avec succès. velocity.command.reload-failure=Impossible de recharger votre configuration de Velocity. Consultez la console pour plus de détails. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} est sous la licence GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . est sous la licence GNU General Public License v3. velocity.command.no-plugins=Il n'y a aucun plugin actuellement installé. -velocity.command.plugins-list=Plugins \: {0} -velocity.command.plugin-tooltip-website=Site Internet \: {0} -velocity.command.plugin-tooltip-author=Auteur \: {0} -velocity.command.plugin-tooltip-authors=Auteurs \: {0} +velocity.command.plugins-list=Plugins \: +velocity.command.plugin-tooltip-website=Site Internet \: +velocity.command.plugin-tooltip-author=Auteur \: +velocity.command.plugin-tooltip-authors=Auteurs \: velocity.command.dump-uploading=Envoi des informations collectées... velocity.command.dump-send-error=Une erreur est survenue lors de la communication avec les serveurs Velocity. Soit les serveurs sont temporairement indisponibles, soit il y a un problème avec les paramètres de votre réseau. Vous trouverez plus d'informations dans le journal ou la console de votre serveur Velocity. velocity.command.dump-success=Un rapport anonyme contenant des informations utiles sur ce proxy a été créé. Si un développeur vous le demande, vous pouvez le partager avec le lien suivant \: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_he_IL.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_he_IL.properties index 85cd9f99..dbe34bbf 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_he_IL.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_he_IL.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=אתה כבר מחובר לשרת זה\! velocity.error.already-connected-proxy=אתה כבר מחובר ל- proxy זה\! velocity.error.already-connecting=אתה כבר מנסה להתחבר לשרת\! -velocity.error.cant-connect=לא ניתן להתחבר ל- {0}\: {1} -velocity.error.connecting-server-error=לא ניתן לחבר אותך ל- {0}. אנא נסה שנית מאוחר יותר. -velocity.error.connected-server-error=החיבור שלך ל- {0} נתקל בבעיה. +velocity.error.cant-connect=לא ניתן להתחבר ל- \: +velocity.error.connecting-server-error=לא ניתן לחבר אותך ל- . אנא נסה שנית מאוחר יותר. +velocity.error.connected-server-error=החיבור שלך ל- נתקל בבעיה. velocity.error.internal-server-connection-error=התרחשה שגיאת חיבור שרת פנימית. velocity.error.logging-in-too-fast=אתה נכנס מהר מדי, נסה שוב מאוחר יותר. velocity.error.online-mode-only=אינך מחובר לחשבון Minecraft שלך. אם אתה מחובר לחשבון Minecraft שלך, נסה להפעיל מחדש את המשחק שלך. velocity.error.player-connection-error=התרחשה שגיאה פנימית בחיבור שלך. velocity.error.modern-forwarding-needs-new-client=שרת זה תואם רק עם Minecraft 1.13 ומעלה. velocity.error.modern-forwarding-failed=השרת שלך לא שלח בקשת העברה ל- proxy. ודא שתצורת השרת נקבעה להעברת Velocity. -velocity.error.moved-to-new-server=אתה הורחקת מ- {0}\: {1} +velocity.error.moved-to-new-server=אתה הורחקת מ- \: velocity.error.no-available-servers=אין שרתים זמינים אליהם יש לחבר אותך. נסה שוב מאוחר יותר או פנה למנהל מערכת. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=התרחשה שגיאה בעת הפעלת פקודה זו. velocity.command.command-does-not-exist=פקודה זו אינה קיימת. velocity.command.players-only=רק שחקנים יכולים להפעיל פקודה זו. -velocity.command.server-does-not-exist=השרת {0} שצוין אינו קיים. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=אתה מחובר כעת ל- {0}. +velocity.command.server-does-not-exist=השרת שצוין אינו קיים. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=אתה מחובר כעת ל- . velocity.command.server-too-many=הוגדרו שרתים רבים מדי. השתמש בהשלמת כרטיסיה כדי להציג את כל השרתים הזמינים. velocity.command.server-available=שרתים זמינים\: -velocity.command.server-tooltip-player-online=שחקן {0} מחובר -velocity.command.server-tooltip-players-online={0} שחקנים מחוברים +velocity.command.server-tooltip-player-online=שחקן מחובר +velocity.command.server-tooltip-players-online= שחקנים מחוברים velocity.command.server-tooltip-current-server=מחובר כעת לשרת זה velocity.command.server-tooltip-offer-connect-server=לחץ על מנת להתחבר לשרת זה -velocity.command.glist-player-singular=שחקן {0} כעת מחובר ל- proxy. -velocity.command.glist-player-plural={0} שחקנים מחוברים כעת ל- proxy. +velocity.command.glist-player-singular=שחקן כעת מחובר ל- proxy. +velocity.command.glist-player-plural= שחקנים מחוברים כעת ל- proxy. velocity.command.glist-view-all=כדי להציג את כל השחקנים בשרתים, השתמש ב- glist all/. velocity.command.reload-success=תצורת Velocity נטענה מחדש בהצלחה. velocity.command.reload-failure=אין אפשרות לטעון מחדש את תצורת ה- Velocity שלך. עיין בקונסולה לקבלת פרטים נוספים. -velocity.command.version-copyright=זכויות יוצרים 2018-{2} {0}. {1} מורשה על פי תנאי v3 הרישיון הציבורי הכללי של GNU. +velocity.command.version-copyright=זכויות יוצרים 2018- . מורשה על פי תנאי v3 הרישיון הציבורי הכללי של GNU. velocity.command.no-plugins=לא מותקנים כעת תוספים. -velocity.command.plugins-list=תוספים\: {0} -velocity.command.plugin-tooltip-website=אתר אינטרנט\: {0} -velocity.command.plugin-tooltip-author=יוצר\: {0} -velocity.command.plugin-tooltip-authors=יוצרים\: {0} +velocity.command.plugins-list=תוספים\: +velocity.command.plugin-tooltip-website=אתר אינטרנט\: +velocity.command.plugin-tooltip-author=יוצר\: +velocity.command.plugin-tooltip-authors=יוצרים\: velocity.command.dump-uploading=מעלה מידע שנאסף... velocity.command.dump-send-error=התרחשה שגיאה בעת קיום תקשורת עם שרתי ה- Velocity. ייתכן שהשרתים אינם זמינים באופן זמני או שקיימת בעיה בהגדרות הרשת שלך. באפשרותך למצוא מידע נוסף ביומן הרישום או בקונסולה של שרת ה- Velocity שלך. velocity.command.dump-success=נוצר דוח אנונימיות המכיל מידע שימושי אודות proxy זה. אם מפתח ביקש זאת, באפשרותך לשתף איתם את הקישור הבא\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_hu_HU.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_hu_HU.properties index b43f69b5..80861b04 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_hu_HU.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_hu_HU.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Már csatlakozva vagy ehhez a szerverhez\! velocity.error.already-connected-proxy=Már csatlakozva vagy ehhez a proxyhoz\! velocity.error.already-connecting=Jelenleg is csatlakozol egy szerverre\! -velocity.error.cant-connect=Nem lehet csatlakozni a(z) {0} szerverhez\: {1} -velocity.error.connecting-server-error=Nem tudunk csatlakoztatni a(z) {0} szerverhez. Kérlek próbáld újra később. -velocity.error.connected-server-error=A kapcsolatod a(z) {0} szerverhez hibába ütközött. +velocity.error.cant-connect=Nem lehet csatlakozni a(z) szerverhez\: +velocity.error.connecting-server-error=Nem tudunk csatlakoztatni a(z) szerverhez. Kérlek próbáld újra később. +velocity.error.connected-server-error=A kapcsolatod a(z) szerverhez hibába ütközött. velocity.error.internal-server-connection-error=Egy szerveroldali hiba történt. velocity.error.logging-in-too-fast=Túl gyorsan próbálsz csatlakozni, próbáld újra később. velocity.error.online-mode-only=Nem vagy belépve a Minecraft profilodba. Ha mégis be vagy lépve, kérlek próbáld újraindítani a Minecraft kliensedet. velocity.error.player-connection-error=Egy belső hiba keletkezett a kapcsolatodban. velocity.error.modern-forwarding-needs-new-client=Ez a szerver csak a Minecraft 1.13 és afölötti verziókkal kompatibilis. velocity.error.modern-forwarding-failed=A szerver ahonnan csatlakoztál nem küldött modern átirányítási kérelmet a proxy felé. Bizonyosodj meg róla, hogy a szerver be van állítva a modern Velocity átirányítás használatára. -velocity.error.moved-to-new-server=Ki lettél rúgva a(z) {0} szerverről\: {1} +velocity.error.moved-to-new-server=Ki lettél rúgva a(z) szerverről\: velocity.error.no-available-servers=Jelenleg nincs elérhető szerver ahová csatlakoztatni tudnánk. Próbáld újra később, vagy lépj kapcsolatba egy adminisztrátorral. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Hiba történt a parancs futtatása közben. velocity.command.command-does-not-exist=Ilyen parancs nem létezik. velocity.command.players-only=Ezt a parancsot csak játékosok használhatják. -velocity.command.server-does-not-exist=A megadott szerver ({0}) nem létezik. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Jelenleg a(z) {0} szerveren tartózkodsz. +velocity.command.server-does-not-exist=A megadott szerver () nem létezik. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Jelenleg a(z) szerveren tartózkodsz. velocity.command.server-too-many=Túl sok szerver van beállítva. Használd a tab parancs befejező funkciót, hogy megnézd az összes elérhető szervert. velocity.command.server-available=Elérhető szerverek\: -velocity.command.server-tooltip-player-online={0} játékos online -velocity.command.server-tooltip-players-online={0} játékos online +velocity.command.server-tooltip-player-online= játékos online +velocity.command.server-tooltip-players-online= játékos online velocity.command.server-tooltip-current-server=Jelenleg ezen a szerveren tartózkodsz velocity.command.server-tooltip-offer-connect-server=Kattints ide, hogy csatlakozz erre a szerverre -velocity.command.glist-player-singular={0} játékos van jelenleg csatlakozva a proxyhoz. -velocity.command.glist-player-plural={0} játékos van jelenleg csatlakozva a proxyhoz. +velocity.command.glist-player-singular= játékos van jelenleg csatlakozva a proxyhoz. +velocity.command.glist-player-plural= játékos van jelenleg csatlakozva a proxyhoz. velocity.command.glist-view-all=Hogy megnézd az összes játékost az összes szerveren, használd a /glist all parancsot. velocity.command.reload-success=A Velocity beállításai sikeresen frissítve lettek. velocity.command.reload-failure=Hiba történt a Velocity beállításainak frissítése közben. Több információt a konzolban találsz. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} licenszelve van a GNU General Public License v3 alatt. +velocity.command.version-copyright=Copyright 2018- . licenszelve van a GNU General Public License v3 alatt. velocity.command.no-plugins=Jelenleg egyetlen plugin sincs telepítve. -velocity.command.plugins-list=Pluginok\: {0} -velocity.command.plugin-tooltip-website=Weboldal\: {0} -velocity.command.plugin-tooltip-author=Készítő\: {0} -velocity.command.plugin-tooltip-authors=Készítők\: {0} +velocity.command.plugins-list=Pluginok\: +velocity.command.plugin-tooltip-website=Weboldal\: +velocity.command.plugin-tooltip-author=Készítő\: +velocity.command.plugin-tooltip-authors=Készítők\: velocity.command.dump-uploading=Az összegyűjtött információ feltöltése... velocity.command.dump-send-error=Egy hiba lépett fel miközben kommunikálni próbáltunk a Velocity szerverekkel. Lehetséges, hogy a szerver(ek) ideiglenesen elérhetetlenek, vagy ez egy hiba a te hálózati beállításaiddal. Több információt a logban, vagy a Velocity konzoljában találsz. velocity.command.dump-success=Egy anonimizált jelentés sikeresen el lett készítve erről a proxyról. Ha egy fejlesztő kérte, akkor innen kimásolhatod a linket, és megoszthatod velük\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_it_IT.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_it_IT.properties index d2a79886..93ffc11f 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_it_IT.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_it_IT.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Sei già connesso a questo server\! velocity.error.already-connected-proxy=Sei già connesso a questo proxy\! velocity.error.already-connecting=Stai già cercando di connetterti a un server\! -velocity.error.cant-connect=Impossibile connettersi a {0}\: {1} -velocity.error.connecting-server-error=Impossibile connetterti a {0}. Prova più tardi. -velocity.error.connected-server-error=La tua connessione a {0} ha incontrato un problema. +velocity.error.cant-connect=Impossibile connettersi a \: +velocity.error.connecting-server-error=Impossibile connetterti a . Prova più tardi. +velocity.error.connected-server-error=La tua connessione a ha incontrato un problema. velocity.error.internal-server-connection-error=Si è verificato un errore di connessione interna al server. velocity.error.logging-in-too-fast=Stai accedendo troppo velocemente, riprova più tardi. velocity.error.online-mode-only=Non sei connesso al tuo account Minecraft. Se hai effettuato l'accesso al tuo account Minecraft, prova a riavviare il tuo client Minecraft. velocity.error.player-connection-error=Si è verificato un errore interno nella connessione. velocity.error.modern-forwarding-needs-new-client=Questo server è compatibile solo con versioni uguali o superiori a Minecraft 1.13. velocity.error.modern-forwarding-failed=Il server non ha inviato una richiesta di inoltro al proxy. Assicurati che il server sia configurato per l'inoltro di Velocity. -velocity.error.moved-to-new-server=Sei stato cacciato da {0}\: {1} +velocity.error.moved-to-new-server=Sei stato cacciato da \: velocity.error.no-available-servers=Non ci sono server disponibili per connetterti. Riprova più tardi o contatta un amministratore. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Si è verificato un errore durante l'esecuzione di questo comando. velocity.command.command-does-not-exist=Questo comando non esiste. velocity.command.players-only=Solo i giocatori possono eseguire questo comando. -velocity.command.server-does-not-exist=Il server {0} non esiste. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Sei già connesso a {0}. +velocity.command.server-does-not-exist=Il server non esiste. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Sei già connesso a . velocity.command.server-too-many=Ci sono troppi server impostati. Usa il completamento con il tasto tab per visualizzare tutti i server disponibili. velocity.command.server-available=Server disponibili\: -velocity.command.server-tooltip-player-online={0} giocatore online -velocity.command.server-tooltip-players-online={0} giocatori online +velocity.command.server-tooltip-player-online= giocatore online +velocity.command.server-tooltip-players-online= giocatori online velocity.command.server-tooltip-current-server=Sei già connesso a questo server velocity.command.server-tooltip-offer-connect-server=Clicca per connetterti a questo server -velocity.command.glist-player-singular={0} giocatore è attualmente connesso al proxy. -velocity.command.glist-player-plural={0} giocatori sono attualmente connessi al proxy. +velocity.command.glist-player-singular= giocatore è attualmente connesso al proxy. +velocity.command.glist-player-plural= giocatori sono attualmente connessi al proxy. velocity.command.glist-view-all=Per visualizzare tutti i giocatori sui server, usa /glist all. velocity.command.reload-success=La configurazione di Velocity è stata ricaricata con successo. velocity.command.reload-failure=Impossibile ricaricare la configurazione di Velocity. Controlla la console per maggiori dettagli. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} è concesso in licenza secondo i termini della GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . è concesso in licenza secondo i termini della GNU General Public License v3. velocity.command.no-plugins=Non ci sono plugin installati. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Sito web\: {0} -velocity.command.plugin-tooltip-author=Autore\: {0} -velocity.command.plugin-tooltip-authors=Autori\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Sito web\: +velocity.command.plugin-tooltip-author=Autore\: +velocity.command.plugin-tooltip-authors=Autori\: velocity.command.dump-uploading=Caricamento informazioni raccolte... velocity.command.dump-send-error=Si è verificato un errore durante la comunicazione con i server Velocity. I server potrebbero essere temporaneamente non disponibili o c'è un problema con le impostazioni di rete. Puoi trovare maggiori informazioni nel log o nella console del tuo server Velocity. velocity.command.dump-success=Creato un report anonimo contenente informazioni utili su questo proxy. Se uno sviluppatore lo richiede, è possibile condividere con loro il seguente link\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ja_JP.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ja_JP.properties index 235de499..3a9ba332 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ja_JP.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ja_JP.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=すでにこのサーバーに接続されています。 velocity.error.already-connected-proxy=すでにこのプロキシに接続されています。 velocity.error.already-connecting=すでにサーバーに接続しようとしています! -velocity.error.cant-connect={0} に接続できません\: {1} -velocity.error.connecting-server-error={0} に接続できませんでした。後でもう一度お試しください。 -velocity.error.connected-server-error={0} との接続に問題が発生しました。 +velocity.error.cant-connect= に接続できません\: +velocity.error.connecting-server-error= に接続できませんでした。後でもう一度お試しください。 +velocity.error.connected-server-error= との接続に問題が発生しました。 velocity.error.internal-server-connection-error=内部サーバー接続エラーが発生しました。 velocity.error.logging-in-too-fast=ログイン速度が速すぎます。後でもう一度お試しください。 velocity.error.online-mode-only=無効なセッションです(ゲームとランチャーを再起動してください) velocity.error.player-connection-error=接続中に内部エラーが発生しました。 velocity.error.modern-forwarding-needs-new-client=このサーバーは Minecraft 1.13以降のみ互換性があります。 velocity.error.modern-forwarding-failed=サーバーがプロキシに転送要求を送信しませんでした。 サーバーが Velocity 用に構成されていることを確認してください。 -velocity.error.moved-to-new-server=あなたは {0} からキックされました\: {1} +velocity.error.moved-to-new-server=あなたは からキックされました\: velocity.error.no-available-servers=接続できるサーバーがありません。後でもう一度試すか、管理者にお問い合わせください。 velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=このコマンドの実行中にエラーが発生しました。 velocity.command.command-does-not-exist=未知のコマンドです。 velocity.command.players-only=このコマンドはプレイヤーのみ実行できます。 -velocity.command.server-does-not-exist=指定されたサーバー {0} は存在しません。 -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=現在 {0} に接続しています。 +velocity.command.server-does-not-exist=指定されたサーバー は存在しません。 +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=現在 に接続しています。 velocity.command.server-too-many=設定されているサーバー数が多すぎます。タブ補完を使い、利用可能なすべてのサーバーを表示してください。 velocity.command.server-available=利用可能なサーバー\: -velocity.command.server-tooltip-player-online={0} 人のプレイヤーがオンライン -velocity.command.server-tooltip-players-online={0} 人のプレイヤーがオンライン +velocity.command.server-tooltip-player-online= 人のプレイヤーがオンライン +velocity.command.server-tooltip-players-online= 人のプレイヤーがオンライン velocity.command.server-tooltip-current-server=現在、このサーバーに接続しています velocity.command.server-tooltip-offer-connect-server=クリックしてこのサーバーに接続 -velocity.command.glist-player-singular={0} 人が現在プロキシに接続しています。 -velocity.command.glist-player-plural={0} 人が現在プロキシに接続しています。 +velocity.command.glist-player-singular= 人が現在プロキシに接続しています。 +velocity.command.glist-player-plural= 人が現在プロキシに接続しています。 velocity.command.glist-view-all=サーバー上のすべてのプレイヤーを表示するには、/glist allを使用してください。 velocity.command.reload-success=Velocityの設定が再読み込みされました。 velocity.command.reload-failure=Velocityの設定を再読み込みできません。詳細はコンソールで確認してください。 -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} は、GNU General Public License v3に基づいてライセンスされています。 +velocity.command.version-copyright=Copyright 2018- . は、GNU General Public License v3に基づいてライセンスされています。 velocity.command.no-plugins=現在インストールされているプラグインはありません。 -velocity.command.plugins-list=プラグイン\: {0} -velocity.command.plugin-tooltip-website=ウェブサイト\: {0} -velocity.command.plugin-tooltip-author=作者\: {0} -velocity.command.plugin-tooltip-authors=作者\: {0} +velocity.command.plugins-list=プラグイン\: +velocity.command.plugin-tooltip-website=ウェブサイト\: +velocity.command.plugin-tooltip-author=作者\: +velocity.command.plugin-tooltip-authors=作者\: velocity.command.dump-uploading=収集した情報をアップロードしています... velocity.command.dump-send-error=Velocityサーバーとの通信中にエラーが発生しました。サーバーが一時的に利用できないか、ネットワーク設定に問題がある可能性があります。詳細はコンソールまたはサーバーログで確認できます。 velocity.command.dump-success=このプロキシに関する有用な情報を含む匿名化されたレポートを作成しました。開発者が要求した場合は、次のリンクを共有してください\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ko_KR.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ko_KR.properties index e7e528cc..624c481f 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ko_KR.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ko_KR.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=이미 이 서버에 연결되어 있습니다\! velocity.error.already-connected-proxy=이미 이 프록시에 연결되어 있습니다\! velocity.error.already-connecting=이미 이 서버에 연결하는 중입니다\! -velocity.error.cant-connect={0}에 연결할 수 없습니다\: {1} -velocity.error.connecting-server-error={0}에 연결할 수 없습니다. 나중에 다시 시도하세요. -velocity.error.connected-server-error={0}에 연결하던 도중 문제가 발생했습니다. +velocity.error.cant-connect=에 연결할 수 없습니다\: +velocity.error.connecting-server-error=에 연결할 수 없습니다. 나중에 다시 시도하세요. +velocity.error.connected-server-error=에 연결하던 도중 문제가 발생했습니다. velocity.error.internal-server-connection-error=내부 서버 연결 오류가 발생했습니다. velocity.error.logging-in-too-fast=너무 빠르게 로그인을 시도했습니다. 나중에 다시 시도하세요. velocity.error.online-mode-only=Minecraft 계정에 로그인하지 않았습니다. Minecraft 계정에 로그인한 경우, Minecraft 클라이언트를 다시 시작해보세요. velocity.error.player-connection-error=연결에 내부 오류가 발생했습니다. velocity.error.modern-forwarding-needs-new-client=이 서버는 Minecraft 1.13 이상만 지원합니다. velocity.error.modern-forwarding-failed=서버가 프록시에 포워딩 요청을 보내지 않았습니다. 서버가 Velocity 포워딩을 사용하도록 설정되어 있는지 확인하세요. -velocity.error.moved-to-new-server={0}에서 추방됐습니다\: {1} +velocity.error.moved-to-new-server=에서 추방됐습니다\: velocity.error.no-available-servers=연결할 수 있는 서버가 없습니다. 나중에 다시 시도하거나 관리자에게 문의하세요. velocity.error.illegal-chat-characters=채팅에 올바르지 않은 문자가 있습니다. # Commands velocity.command.generic-error=명령어를 실행하는 도중 오류가 발생했습니다. velocity.command.command-does-not-exist=존재하지 않는 명령어입니다. velocity.command.players-only=이 명령어는 플레이어만 사용할 수 있습니다. -velocity.command.server-does-not-exist=지정한 서버 {0}이(가) 존재하지 않습니다. -velocity.command.player-not-found=지정한 플레이어 {0}이(가) 존재하지 않습니다. -velocity.command.server-current-server=현재 {0}에 연결되어 있습니다. +velocity.command.server-does-not-exist=지정한 서버 이(가) 존재하지 않습니다. +velocity.command.player-not-found=지정한 플레이어 이(가) 존재하지 않습니다. +velocity.command.server-current-server=현재 에 연결되어 있습니다. velocity.command.server-too-many=너무 많은 서버가 존재합니다. tab 자동완성으로 사용 가능한 모든 서버를 볼 수 있습니다. velocity.command.server-available=사용 가능한 서버\: -velocity.command.server-tooltip-player-online=플레이어 {0}명 접속 중 -velocity.command.server-tooltip-players-online=플레이어 {0}명 접속 중 +velocity.command.server-tooltip-player-online=플레이어 명 접속 중 +velocity.command.server-tooltip-players-online=플레이어 명 접속 중 velocity.command.server-tooltip-current-server=현재 이 서버에 연결되어 있습니다 velocity.command.server-tooltip-offer-connect-server=서버에 연결하려면 클릭 -velocity.command.glist-player-singular=플레이어 {0}명이 현재 프록시에 연결되어 있습니다. -velocity.command.glist-player-plural=플레이어 {0}명이 현재 프록시에 연결되어 있습니다. +velocity.command.glist-player-singular=플레이어 명이 현재 프록시에 연결되어 있습니다. +velocity.command.glist-player-plural=플레이어 명이 현재 프록시에 연결되어 있습니다. velocity.command.glist-view-all=서버에 있는 모든 플레이어를 보려면, /glist all을 사용하세요. velocity.command.reload-success=Velocity 설정을 성공적으로 다시 불러왔습니다. velocity.command.reload-failure=Velocity 설정을 다시 불러올 수 없습니다. 자세한 내용은 콘솔을 확인하세요. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1}은(는) GNU General Public License v3 라이센스의 약관을 따릅니다. +velocity.command.version-copyright=Copyright 2018- . 은(는) GNU General Public License v3 라이센스의 약관을 따릅니다. velocity.command.no-plugins=설치된 플러그인이 없습니다. -velocity.command.plugins-list=플러그인\: {0} -velocity.command.plugin-tooltip-website=웹사이트\: {0} -velocity.command.plugin-tooltip-author=제작자\: {0} -velocity.command.plugin-tooltip-authors=제작자\: {0} +velocity.command.plugins-list=플러그인\: +velocity.command.plugin-tooltip-website=웹사이트\: +velocity.command.plugin-tooltip-author=제작자\: +velocity.command.plugin-tooltip-authors=제작자\: velocity.command.dump-uploading=수집된 정보를 업로드하는 중... velocity.command.dump-send-error=Velocity 서버와 통신하는 동안 오류가 발생했습니다. 서버를 일시적으로 사용할 수 없거나 네트워크 설정에 문제가 있을 수 있습니다. Velocity 서버의 로그 또는 콘솔에서 자세한 정보를 찾아볼 수 있습니다. velocity.command.dump-success=이 프록시와 관련된 유용한 정보를 담은 익명 보고서를 만들었습니다. 만약 개발자가 요청한다면, 다음 링크를 그들에게 공유해보세요\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nb_NO.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nb_NO.properties index 05a17545..d43db965 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nb_NO.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nb_NO.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Du er allerede tilkoblet denne serveren\! velocity.error.already-connected-proxy=Du er allerede tilkoblet denne proxyen\! velocity.error.already-connecting=Du tilkobles allerede en server\! -velocity.error.cant-connect=Kan ikke koble til {0}\: {1} -velocity.error.connecting-server-error=Kan ikke koble deg til {0}. Vennligst prøv igjen senere. -velocity.error.connected-server-error=Din oppkobling mot {0} traff et uventet problem. +velocity.error.cant-connect=Kan ikke koble til \: +velocity.error.connecting-server-error=Kan ikke koble deg til . Vennligst prøv igjen senere. +velocity.error.connected-server-error=Din oppkobling mot traff et uventet problem. velocity.error.internal-server-connection-error=Et internt problem oppstod. velocity.error.logging-in-too-fast=Du logger inn for raskt, prøv igjen senere. velocity.error.online-mode-only=Du er ikke innlogget på din Minecraft konto. Om du er innlogget, prøv å restarte din Minecraft klient. velocity.error.player-connection-error=Et internt problem oppstod. velocity.error.modern-forwarding-needs-new-client=Denne serveren er bare kompatibel med Minecraft 1.13 og nyere. velocity.error.modern-forwarding-failed=Din server sendte ikke en viderekoblingsforespørsel til proxyen. Pass på at serveren er konfigurert for Velocity viderekobling. -velocity.error.moved-to-new-server=Du ble sparket ut fra {0}\: {1} +velocity.error.moved-to-new-server=Du ble sparket ut fra \: velocity.error.no-available-servers=Det finnes ingen tilgjengelige servere å koble deg til. Prøv igjen senere eller kontakt en administrator. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=En feil oppstod under gjennomføringen av denne kommandoen. velocity.command.command-does-not-exist=Denne kommandoen finnes ikke. velocity.command.players-only=Bare spillere kan utføre denne kommandoen. -velocity.command.server-does-not-exist=Den spesifiserte serveren {0} finnes ikke. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Du er for øyeblikket tilkoblet {0}. +velocity.command.server-does-not-exist=Den spesifiserte serveren finnes ikke. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Du er for øyeblikket tilkoblet . velocity.command.server-too-many=Det er for mange servere satt opp. Bruk tabfullførelse for å se alle tilgjengelige servere. velocity.command.server-available=Tilgjengelige servere\: -velocity.command.server-tooltip-player-online={0} spiller tilkoblet -velocity.command.server-tooltip-players-online={0} spillere tilkoblet +velocity.command.server-tooltip-player-online= spiller tilkoblet +velocity.command.server-tooltip-players-online= spillere tilkoblet velocity.command.server-tooltip-current-server=Du er for øyeblikket tilkoblet denne serveren velocity.command.server-tooltip-offer-connect-server=Trykk for å koble til denne serveren -velocity.command.glist-player-singular={0} spiller er for øyeblikket tilkoblet denne proxyen. -velocity.command.glist-player-plural={0} spillere er for øyeblikket tilkoblet denne proxyen. +velocity.command.glist-player-singular= spiller er for øyeblikket tilkoblet denne proxyen. +velocity.command.glist-player-plural= spillere er for øyeblikket tilkoblet denne proxyen. velocity.command.glist-view-all=For å se alle tilkoblede spillere, utfør /glist all. velocity.command.reload-success=Velocity konfigurasjonen ble lastet inn på nytt. velocity.command.reload-failure=Kan ikke laste inn Velocity konfigurasjonen din. Sjekk konsollen for mer detaljer. -velocity.command.version-copyright=Opphavsrett 2018-{2} {0}. {1} er lisensiert under betingelsene av GNU General Public License v3. +velocity.command.version-copyright=Opphavsrett 2018- . er lisensiert under betingelsene av GNU General Public License v3. velocity.command.no-plugins=Ingen plugin er installert. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Hjemmeside\: {0} -velocity.command.plugin-tooltip-author=Skaper\: {0} -velocity.command.plugin-tooltip-authors=Skapere\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Hjemmeside\: +velocity.command.plugin-tooltip-author=Skaper\: +velocity.command.plugin-tooltip-authors=Skapere\: velocity.command.dump-uploading=Laster opp diagnostisk informasjon... velocity.command.dump-send-error=En feil oppstod under kommunikasjon med Velocityserverne. Enten er disse serverne midlertidig utilgjengelige, ellers er det noe galt med dine nettverksinnstillinger. Du kan finne mer informasjon i din logg eller i konsollen på Velocityservern. velocity.command.dump-success=Skapte en anonymisert rapport med utfyllende informasjon om denne proxyen. Om en utvikler forespurte den, kan du dele følgende lenke med dem\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nl_NL.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nl_NL.properties index cbb5f6b8..8b93adb8 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nl_NL.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nl_NL.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Je bent al met deze server verbonden\! velocity.error.already-connected-proxy=Je bent al met deze proxy verbonden\! velocity.error.already-connecting=Je probeert al verbinding te maken met een server\! -velocity.error.cant-connect=Kan geen verbinding maken met {0}\: {1} -velocity.error.connecting-server-error=Kan je niet verbinden met {0}. Probeer het later opnieuw. -velocity.error.connected-server-error=Er is een probleem opgetreden bij je verbinding met {0}. +velocity.error.cant-connect=Kan geen verbinding maken met \: +velocity.error.connecting-server-error=Kan je niet verbinden met . Probeer het later opnieuw. +velocity.error.connected-server-error=Er is een probleem opgetreden bij je verbinding met . velocity.error.internal-server-connection-error=Er is een interne serververbindingsfout opgetreden. velocity.error.logging-in-too-fast=Je logt te snel in, probeer het later opnieuw. velocity.error.online-mode-only=Je bent niet aangemeld bij je Minecraft-account. Als je wel bent ingelogd bij je Minecraft account, probeer dan je Minecraft-client opnieuw op te starten. velocity.error.player-connection-error=Er is een interne fout opgetreden bij je verbinding. velocity.error.modern-forwarding-needs-new-client=Deze server ondersteunt alleen Minecraft 1.13 en nieuwer. velocity.error.modern-forwarding-failed=Je server heeft geen forwarding verzoek naar de proxy gestuurd. Zorg ervoor dat de server is geconfigureerd voor Velocity forwarding. -velocity.error.moved-to-new-server=Je bent verwijderd van {0}\: {1} +velocity.error.moved-to-new-server=Je bent verwijderd van \: velocity.error.no-available-servers=Er zijn geen beschikbare servers om je met te verbinden. Probeer het later opnieuw of neem contact op met een administrator. velocity.error.illegal-chat-characters=Ongeldige karakters in de chat # Commands velocity.command.generic-error=Er is een fout opgetreden bij het uitvoeren van dit commando. velocity.command.command-does-not-exist=Dit commando bestaat niet. velocity.command.players-only=Alleen spelers kunnen dit commando uitvoeren. -velocity.command.server-does-not-exist=De opgegeven server {0} bestaat niet. -velocity.command.player-not-found=De opgegeven speler {0} bestaat niet. -velocity.command.server-current-server=Je bent op dit moment verbonden met {0}. +velocity.command.server-does-not-exist=De opgegeven server bestaat niet. +velocity.command.player-not-found=De opgegeven speler bestaat niet. +velocity.command.server-current-server=Je bent op dit moment verbonden met . velocity.command.server-too-many=Er zijn te veel servers ingesteld. Gebruik tab-aanvulling om alle beschikbare servers te bekijken. velocity.command.server-available=Beschikbare servers\: -velocity.command.server-tooltip-player-online={0} speler online -velocity.command.server-tooltip-players-online={0} spelers online +velocity.command.server-tooltip-player-online= speler online +velocity.command.server-tooltip-players-online= spelers online velocity.command.server-tooltip-current-server=Momenteel verbonden met deze server velocity.command.server-tooltip-offer-connect-server=Klik om te verbinden met deze server -velocity.command.glist-player-singular={0} speler is momenteel verbonden met de proxy. -velocity.command.glist-player-plural={0} spelers zijn momenteel verbonden met de proxy. +velocity.command.glist-player-singular= speler is momenteel verbonden met de proxy. +velocity.command.glist-player-plural= spelers zijn momenteel verbonden met de proxy. velocity.command.glist-view-all=Om alle spelers op de servers te bekijken, gebruik /glist all. velocity.command.reload-success=Velocity configuratie succesvol herladen. velocity.command.reload-failure=De Velocity-configuratie kan niet opnieuw worden geladen. Kijk in de console voor meer details. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is gelicentieerd onder de voorwaarden van de GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is gelicentieerd onder de voorwaarden van de GNU General Public License v3. velocity.command.no-plugins=Er zijn momenteel geen plugins geïnstalleerd. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Website\: {0} -velocity.command.plugin-tooltip-author=Auteur\: {0} -velocity.command.plugin-tooltip-authors=Auteurs\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Website\: +velocity.command.plugin-tooltip-author=Auteur\: +velocity.command.plugin-tooltip-authors=Auteurs\: velocity.command.dump-uploading=Verzamelde informatie uploaden... velocity.command.dump-send-error=Er is een fout opgetreden tijdens de communicatie met de Velocity-servers. De servers zijn mogelijk tijdelijk niet beschikbaar of er is een probleem met je netwerkinstellingen. Je kunt meer informatie vinden in de logs of de console van je Velocity-server. velocity.command.dump-success=Een anoniem rapport is gemaakt met nuttige informatie over deze proxy. Als een ontwikkelaar dit heeft verzocht, kun je de volgende link delen\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nn_NO.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nn_NO.properties index b23ce960..8755b2ad 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nn_NO.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_nn_NO.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Du er allereie tilkopla denne sørvaren\! velocity.error.already-connected-proxy=Du er allereie tilkopla denne proxyen\! velocity.error.already-connecting=Du tilkoplas allereie ein sørvar\! -velocity.error.cant-connect=Kan ikkje kopla til {0}\: {1} -velocity.error.connecting-server-error=Kan ikkje kopla deg til {0}. Prøv gjerne igjen seinare. -velocity.error.connected-server-error=Din oppkopling mot {0} trefte eit uventa problem. +velocity.error.cant-connect=Kan ikkje kopla til \: +velocity.error.connecting-server-error=Kan ikkje kopla deg til . Prøv gjerne igjen seinare. +velocity.error.connected-server-error=Din oppkopling mot trefte eit uventa problem. velocity.error.internal-server-connection-error=Eit internt problem oppstod. velocity.error.logging-in-too-fast=Du loggar inn for raskt, prøv igjen seinare. velocity.error.online-mode-only=Du er ikkje innlogga på din Minecraft konto. Dersom du er innlogga, prøv å restarta din Minecraft klient. velocity.error.player-connection-error=Eit internt problem oppstod. velocity.error.modern-forwarding-needs-new-client=Denne sørvaren er bare kompatibel med Minecraft 1.13 og nyare. velocity.error.modern-forwarding-failed=Din server sende ikkje ein vidarekoplingsførespurnad til proxyen. Pass på at sørvaren er konfigurert for Velocity vidarekopling. -velocity.error.moved-to-new-server=Du blei sparka ut frå {0}\: {1} +velocity.error.moved-to-new-server=Du blei sparka ut frå \: velocity.error.no-available-servers=Det finst ingen tilgjengelege sørvarar å kopla deg til. Prøv igjen seinare eller kontakt ein administrator. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Ein feil oppstod under utføringa av denne kommandoen. velocity.command.command-does-not-exist=Denne kommandoen finst ikkje. velocity.command.players-only=Bare spelarar kan utføra denne kommandoen. -velocity.command.server-does-not-exist=Den oppgjevne sørvaren {0} finst ikkje. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Du er for augneblinken tilkopla {0}. +velocity.command.server-does-not-exist=Den oppgjevne sørvaren finst ikkje. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Du er for augneblinken tilkopla . velocity.command.server-too-many=Det er for mange sørvarar sette opp. Bruk tabfullføring for å sjå alle tilgjengelege sørvarar. velocity.command.server-available=Tilgjengelege sørvarar\: -velocity.command.server-tooltip-player-online={0} spelar tilkopla -velocity.command.server-tooltip-players-online={0} spelarar tilkopla +velocity.command.server-tooltip-player-online= spelar tilkopla +velocity.command.server-tooltip-players-online= spelarar tilkopla velocity.command.server-tooltip-current-server=Du er for augneblinken tilkopla denne sørvaren velocity.command.server-tooltip-offer-connect-server=Trykk for å kopla til denne sørvaren -velocity.command.glist-player-singular={0} spelar er for augneblinken tilkopla denne proxyen. -velocity.command.glist-player-plural={0} spelare er for augneblinken tilkopla denne proxyen. +velocity.command.glist-player-singular= spelar er for augneblinken tilkopla denne proxyen. +velocity.command.glist-player-plural= spelare er for augneblinken tilkopla denne proxyen. velocity.command.glist-view-all=For å sjå alle tilkopla spelarar, gjer /glist all. velocity.command.reload-success=Velocity konfigurasjonen blei lasta inn på nytt. velocity.command.reload-failure=Kan ikkje lasta inn Velocity konfigurasjonen din. Sjekk konsollen for meir detaljar. -velocity.command.version-copyright=Opphavsrett 2018-{2} {0}. {1} er lisensiert under vilkåra av GNU General Public License v3. +velocity.command.version-copyright=Opphavsrett 2018- . er lisensiert under vilkåra av GNU General Public License v3. velocity.command.no-plugins=Det er ingen plugins installert. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Heimeside\: {0} -velocity.command.plugin-tooltip-author=Skapar\: {0} -velocity.command.plugin-tooltip-authors=Skaparar\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Heimeside\: +velocity.command.plugin-tooltip-author=Skapar\: +velocity.command.plugin-tooltip-authors=Skaparar\: velocity.command.dump-uploading=Uploading gathered information... velocity.command.dump-send-error=An error occurred while communicating with the Velocity servers. The servers may be temporarily unavailable or there is an issue with your network settings. You can find more information in the log or console of your Velocity server. velocity.command.dump-success=Created an anonymised report containing useful information about this proxy. If a developer requested it, you may share the following link with them\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pl_PL.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pl_PL.properties index 02a90f87..9e6764bb 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pl_PL.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pl_PL.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Jesteś już połączony z tym serwerem\! velocity.error.already-connected-proxy=Jesteś już połączony z tym proxy\! velocity.error.already-connecting=Jesteś już w trakcie łączenia się do serwera\! -velocity.error.cant-connect=Nie udało się połączyć z serwerem {0}\: {1} -velocity.error.connecting-server-error=Nie udało się połączyć cię z serwerem {0}. Spróbuj ponownie później. -velocity.error.connected-server-error=Podczas łączenia cię z serwerem {0} wystąpił problem. +velocity.error.cant-connect=Nie udało się połączyć z serwerem \: +velocity.error.connecting-server-error=Nie udało się połączyć cię z serwerem . Spróbuj ponownie później. +velocity.error.connected-server-error=Podczas łączenia cię z serwerem wystąpił problem. velocity.error.internal-server-connection-error=Wystąpił wewnętrzny błąd połączenia serwera. velocity.error.logging-in-too-fast=Logujesz się zbyt szybko, spróbuj ponownie później. velocity.error.online-mode-only=Nie jesteś zalogowany do swojego konta Minecraft. Jeżeli jesteś zalogowany, spróbuj zrestartować grę. velocity.error.player-connection-error=Wystąpił wewnętrzny błąd w twoim połączeniu. velocity.error.modern-forwarding-needs-new-client=Ten serwer wspiera tylko wersje Minecraft 1.13 lub nowsze. velocity.error.modern-forwarding-failed=Twój serwer nie wysłał żądania o przekazanie danych do proxy. Upewnij się, że serwer jest skonfigurowany do nowoczesnego przekazywania Velocity. -velocity.error.moved-to-new-server=Zostałeś wyrzucony z {0}\: {1} +velocity.error.moved-to-new-server=Zostałeś wyrzucony z \: velocity.error.no-available-servers=Nie ma dostępnych serwerów, do których można cię połączyć. Spróbuj ponownie później lub skontaktuj się z administratorem. velocity.error.illegal-chat-characters=Niedozwolone znaki na czacie # Commands velocity.command.generic-error=Wystąpił błąd podczas wykonywania tego polecenia. velocity.command.command-does-not-exist=To polecenie nie istnieje. velocity.command.players-only=Tylko gracze mogą wykonać to polecenie. -velocity.command.server-does-not-exist=Wybrany serwer {0} nie istnieje. -velocity.command.player-not-found=Gracz {0} nie istnieje. -velocity.command.server-current-server=Jesteś obecnie połączony z {0}. +velocity.command.server-does-not-exist=Wybrany serwer nie istnieje. +velocity.command.player-not-found=Gracz nie istnieje. +velocity.command.server-current-server=Jesteś obecnie połączony z . velocity.command.server-too-many=Skonfigurowano zbyt wiele serwerów. Użyj autouzupełniania, aby wyświetlić wszystkie dostępne serwery. velocity.command.server-available=Dostępne serwery\: -velocity.command.server-tooltip-player-online={0} gracz online -velocity.command.server-tooltip-players-online={0} graczy online +velocity.command.server-tooltip-player-online= gracz online +velocity.command.server-tooltip-players-online= graczy online velocity.command.server-tooltip-current-server=Jesteś obecnie połączony z tym serwerem velocity.command.server-tooltip-offer-connect-server=Kliknij, aby połączyć się z tym serwerem -velocity.command.glist-player-singular=Z tym proxy jest obecnie połączony {0} gracz. -velocity.command.glist-player-plural=Z tym proxy jest obecnie połączonych {0} graczy. +velocity.command.glist-player-singular=Z tym proxy jest obecnie połączony gracz. +velocity.command.glist-player-plural=Z tym proxy jest obecnie połączonych graczy. velocity.command.glist-view-all=Aby zobaczyć wszystkich graczy na wszystkich serwerach, użyj /glist all. velocity.command.reload-success=Konfiguracja Velocity została pomyślnie załadowana ponownie. velocity.command.reload-failure=Nie udało się ponownie załadować twojej konfiguracji Velocity. Sprawdź konsolę po więcej szczegółów. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} jest objęty licencją na warunkach GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . jest objęty licencją na warunkach GNU General Public License v3. velocity.command.no-plugins=Obecnie nie ma zainstalowanych żadnych pluginów. -velocity.command.plugins-list=Pluginy\: {0} -velocity.command.plugin-tooltip-website=Strona internetowa\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autorzy\: {0} +velocity.command.plugins-list=Pluginy\: +velocity.command.plugin-tooltip-website=Strona internetowa\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autorzy\: velocity.command.dump-uploading=Przesyłanie zebranych informacji… velocity.command.dump-send-error=Wystąpił błąd podczas komunikacji z serwerami Velocity. Serwery mogą być chwilowo niedostępne lub wystąpił problem z ustawieniami sieci. Możesz znaleźć więcej informacji w logach lub konsoli swojego serwera Velocity. velocity.command.dump-success=Utworzono anonimowy raport zawierający przydatne informacje o tym proxy. Możesz udostępnić deweloperowi następujący odnośnik, jeśli o niego poprosił\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pt_BR.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pt_BR.properties index e0708942..39d697cc 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pt_BR.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_pt_BR.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Você já está conectado a esse servidor\! velocity.error.already-connected-proxy=Você já está conectado a esse proxy\! velocity.error.already-connecting=Você já está tentando se conectar a um servidor\! -velocity.error.cant-connect=Não foi possível se conectar a {0}\: {1} -velocity.error.connecting-server-error=Não foi possível conectar você a {0}. Tente novamente mais tarde. -velocity.error.connected-server-error=Sua conexão com o servidor {0} encontrou um problema. +velocity.error.cant-connect=Não foi possível se conectar a \: +velocity.error.connecting-server-error=Não foi possível conectar você a . Tente novamente mais tarde. +velocity.error.connected-server-error=Sua conexão com o servidor encontrou um problema. velocity.error.internal-server-connection-error=Ocorreu um erro interno de conexão com o servidor. velocity.error.logging-in-too-fast=Você está entrando muito rápido, tente novamente mais tarde. velocity.error.online-mode-only=Você não está logado na sua conta do Minecraft. Se você já está logado na sua conta do Minecraft, tente reiniciar seu cliente do Minecraft. velocity.error.player-connection-error=Um erro interno ocorreu em sua conexão. velocity.error.modern-forwarding-needs-new-client=Este servidor é compatível apenas com o Minecraft 1.13 e superior. velocity.error.modern-forwarding-failed=Seu servidor não enviou uma solicitação de encaminhamento para o proxy. Certifique-se de que o servidor está configurado para encaminhamento Velocity. -velocity.error.moved-to-new-server=Você foi expulso de {0}\: {1} +velocity.error.moved-to-new-server=Você foi expulso de \: velocity.error.no-available-servers=Não há servidores disponíveis para conectá-lo. Tente novamente mais tarde ou contate um administrador. velocity.error.illegal-chat-characters=Caracteres não permitidos no chat # Commands velocity.command.generic-error=Ocorreu um erro ao executar este comando. velocity.command.command-does-not-exist=Esse comando não existe. velocity.command.players-only=Apenas jogadores podem executar esse comando. -velocity.command.server-does-not-exist=O servidor {0} não existe. -velocity.command.player-not-found=O jogador {0} não existe. -velocity.command.server-current-server=Você está atualmente conectado a {0}. +velocity.command.server-does-not-exist=O servidor não existe. +velocity.command.player-not-found=O jogador não existe. +velocity.command.server-current-server=Você está atualmente conectado a . velocity.command.server-too-many=Há muitos servidores configurados. Utilize o auto-preenchimento tab para ver todos os servidores disponíveis. velocity.command.server-available=Servidores disponíveis\: -velocity.command.server-tooltip-player-online={0} jogador conectado -velocity.command.server-tooltip-players-online={0} jogadores conectados +velocity.command.server-tooltip-player-online= jogador conectado +velocity.command.server-tooltip-players-online= jogadores conectados velocity.command.server-tooltip-current-server=Atualmente conectado a este servidor velocity.command.server-tooltip-offer-connect-server=Clique para conectar a este servidor -velocity.command.glist-player-singular=O jogador {0} está atualmente conectado ao proxy. -velocity.command.glist-player-plural={0} jogadores estão atualmente conectados ao proxy. +velocity.command.glist-player-singular=O jogador está atualmente conectado ao proxy. +velocity.command.glist-player-plural= jogadores estão atualmente conectados ao proxy. velocity.command.glist-view-all=Para ver todos os jogadores em todos os servidores, use /glist all. velocity.command.reload-success=Configuração do Velocity recarregada com êxito. velocity.command.reload-failure=Não foi possível recarregar a configuração do Velocity. Verifique o console para mais detalhes. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} está licenciado sobre os termos da Licença Pública Geral GNU v3. +velocity.command.version-copyright=Copyright 2018- . está licenciado sobre os termos da Licença Pública Geral GNU v3. velocity.command.no-plugins=Não há plugins instalados atualmente. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Site\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autores\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Site\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autores\: velocity.command.dump-uploading=Enviando informações coletadas... velocity.command.dump-send-error=Ocorreu um erro ao se comunicar com os servidores Velocity. Os servidores podem estar temporariamente indisponíveis ou há um problema com suas configurações de rede. Você pode encontrar mais informações no log ou no console de seu servidor Velocity. velocity.command.dump-success=Foi criado um relatório anônimo contendo informações úteis sobre este proxy. Se um desenvolvedor o solicitou, você pode compartilhar o seguinte link com eles\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ro_RO.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ro_RO.properties index ea0d4609..e3d28fce 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ro_RO.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ro_RO.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=You are already connected to this server\! velocity.error.already-connected-proxy=You are already connected to this proxy\! velocity.error.already-connecting=You are already trying to connect to a server\! -velocity.error.cant-connect=Unable to connect to {0}\: {1} -velocity.error.connecting-server-error=Unable to connect you to {0}. Please try again later. -velocity.error.connected-server-error=Your connection to {0} encountered a problem. +velocity.error.cant-connect=Unable to connect to \: +velocity.error.connecting-server-error=Unable to connect you to . Please try again later. +velocity.error.connected-server-error=Your connection to encountered a problem. velocity.error.internal-server-connection-error=An internal server connection error occurred. velocity.error.logging-in-too-fast=You are logging in too fast, try again later. velocity.error.online-mode-only=You are not logged into your Minecraft account. If you are logged into your Minecraft account, try restarting your Minecraft client. velocity.error.player-connection-error=An internal error occurred in your connection. velocity.error.modern-forwarding-needs-new-client=This server is only compatible with Minecraft 1.13 and above. velocity.error.modern-forwarding-failed=Your server did not send a forwarding request to the proxy. Make sure the server is configured for Velocity forwarding. -velocity.error.moved-to-new-server=You were kicked from {0}\: {1} +velocity.error.moved-to-new-server=You were kicked from \: velocity.error.no-available-servers=There are no available servers to connect you to. Try again later or contact an admin. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=An error occurred while running this command. velocity.command.command-does-not-exist=This command does not exist. velocity.command.players-only=Only players can run this command. -velocity.command.server-does-not-exist=The specified server {0} does not exist. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=You are currently connected to {0}. +velocity.command.server-does-not-exist=The specified server does not exist. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=You are currently connected to . velocity.command.server-too-many=There are too many servers set up. Use tab completion to view all servers available. velocity.command.server-available=Available servers\: -velocity.command.server-tooltip-player-online={0} player online -velocity.command.server-tooltip-players-online={0} players online +velocity.command.server-tooltip-player-online= player online +velocity.command.server-tooltip-players-online= players online velocity.command.server-tooltip-current-server=Currently connected to this server velocity.command.server-tooltip-offer-connect-server=Click to connect to this server -velocity.command.glist-player-singular={0} player is currently connected to the proxy. -velocity.command.glist-player-plural={0} players are currently connected to the proxy. +velocity.command.glist-player-singular= player is currently connected to the proxy. +velocity.command.glist-player-plural= players are currently connected to the proxy. velocity.command.glist-view-all=To view all players on servers, use /glist all. velocity.command.reload-success=Velocity configuration successfully reloaded. velocity.command.reload-failure=Unable to reload your Velocity configuration. Check the console for more details. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=There are no plugins currently installed. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Website\: {0} -velocity.command.plugin-tooltip-author=Author\: {0} -velocity.command.plugin-tooltip-authors=Authors\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Website\: +velocity.command.plugin-tooltip-author=Author\: +velocity.command.plugin-tooltip-authors=Authors\: velocity.command.dump-uploading=Uploading gathered information... velocity.command.dump-send-error=An error occurred while communicating with the Velocity servers. The servers may be temporarily unavailable or there is an issue with your network settings. You can find more information in the log or console of your Velocity server. velocity.command.dump-success=Created an anonymised report containing useful information about this proxy. If a developer requested it, you may share the following link with them\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ru_RU.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ru_RU.properties index 5e5be8e6..8681198f 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ru_RU.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_ru_RU.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Вы уже подключены к этому серверу\! velocity.error.already-connected-proxy=Игрок с таким ником уже играет на сервере\! velocity.error.already-connecting=Вы уже подключаетесь к серверу\! -velocity.error.cant-connect=Не удалось подключиться к серверу {0}\: {1} -velocity.error.connecting-server-error=Не удалось подключить вас к серверу {0}. Пожалуйста, попробуйте снова через некоторое время. -velocity.error.connected-server-error=С вашим подключением к серверу {0} возникла проблема. +velocity.error.cant-connect=Не удалось подключиться к серверу \: +velocity.error.connecting-server-error=Не удалось подключить вас к серверу . Пожалуйста, попробуйте снова через некоторое время. +velocity.error.connected-server-error=С вашим подключением к серверу возникла проблема. velocity.error.internal-server-connection-error=На сервере произошла внутренняя ошибка подключения. velocity.error.logging-in-too-fast=Вы входите слишком быстро, попробуйте снова через некоторое время. velocity.error.online-mode-only=Вы не вошли в свой аккаунт Minecraft. Если вы уверены, что вошли в аккаунт, попробуйте перезапустить свой клиент Minecraft. velocity.error.player-connection-error=В вашем подключении произошла внутренняя ошибка. velocity.error.modern-forwarding-needs-new-client=Этот сервер совместим только с Minecraft 1.13 и выше. velocity.error.modern-forwarding-failed=Ваш сервер не посылал запрос на переадресацию на прокси-сервер. Убедитесь, что сервер настроен на переадресацию Velocity. -velocity.error.moved-to-new-server=Вы были кикнуты с сервера {0}\: {1} +velocity.error.moved-to-new-server=Вы были кикнуты с сервера \: velocity.error.no-available-servers=Нет серверов, доступных для подключения. Попробуйте позже или свяжитесь с администратором. velocity.error.illegal-chat-characters=Недопустимые символы в чате # Commands velocity.command.generic-error=Во время выполнения этой команды произошла ошибка. velocity.command.command-does-not-exist=Этой команды не существует. velocity.command.players-only=Только игроки могут использовать эту команду. -velocity.command.server-does-not-exist=Указанный сервер {0} не существует. -velocity.command.player-not-found=Указанный игрок {0} не существует. -velocity.command.server-current-server=На данный момент вы подключены к серверу {0}. +velocity.command.server-does-not-exist=Указанный сервер не существует. +velocity.command.player-not-found=Указанный игрок не существует. +velocity.command.server-current-server=На данный момент вы подключены к серверу . velocity.command.server-too-many=Настроено слишком много серверов. Для просмотра всех доступных серверов, используйте автозаполнение клавишей Tab. velocity.command.server-available=Доступные серверы\: -velocity.command.server-tooltip-player-online={0} игрок онлайн -velocity.command.server-tooltip-players-online={0} игрок(а, ов) онлайн +velocity.command.server-tooltip-player-online= игрок онлайн +velocity.command.server-tooltip-players-online= игрок(а, ов) онлайн velocity.command.server-tooltip-current-server=Подключен к этому серверу velocity.command.server-tooltip-offer-connect-server=Кликните, чтобы присоединиться к этому серверу -velocity.command.glist-player-singular={0} игрок подключен к прокси на данный момент. -velocity.command.glist-player-plural={0} игрок(а, ов) подключены к прокси на данный момент. +velocity.command.glist-player-singular= игрок подключен к прокси на данный момент. +velocity.command.glist-player-plural= игрок(а, ов) подключены к прокси на данный момент. velocity.command.glist-view-all=Чтобы просмотреть всех игроков на серверах, используйте /glist all. velocity.command.reload-success=Конфигурация Velocity успешно перезагружена. velocity.command.reload-failure=Не удалось перезагрузить конфигурацию Velocity. Проверьте консоль для получения более подробной информации. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} лицензирована на условиях GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . лицензирована на условиях GNU General Public License v3. velocity.command.no-plugins=Ни одного плагина не установлено. -velocity.command.plugins-list=Плагины\: {0} -velocity.command.plugin-tooltip-website=Веб-сайт\: {0} -velocity.command.plugin-tooltip-author=Автор\: {0} -velocity.command.plugin-tooltip-authors=Авторы\: {0} +velocity.command.plugins-list=Плагины\: +velocity.command.plugin-tooltip-website=Веб-сайт\: +velocity.command.plugin-tooltip-author=Автор\: +velocity.command.plugin-tooltip-authors=Авторы\: velocity.command.dump-uploading=Загрузка полученной информации... velocity.command.dump-send-error=Произошла ошибка при попытке связаться с серверами Velocity. Возможно, серверы временно недоступны или ваша сеть настроена неправильно. Более подробную информацию можно найти в логах или консоли вашего сервера Velocity. velocity.command.dump-success=Создан анонимный отчет, содержащий полезную информацию об этом прокси. Если этот отчёт запросил разработчик, вы можете поделиться с ним следующей ссылкой\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sk_SK.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sk_SK.properties index 04e75974..d1d8028b 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sk_SK.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sk_SK.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Na tento server si už pripojený\! velocity.error.already-connected-proxy=Na tento proxy server si už pripojený\! velocity.error.already-connecting=Už sa pokúšaš o pripojenie na server\! -velocity.error.cant-connect=Nepodarilo sa pripojiť na {0}\: {1} -velocity.error.connecting-server-error=Nepodarilo sa pripojiť ťa na {0}. Skús to prosím neskôr. -velocity.error.connected-server-error=V tvojom pripojení na {0} sa vyskytla chyba. +velocity.error.cant-connect=Nepodarilo sa pripojiť na \: +velocity.error.connecting-server-error=Nepodarilo sa pripojiť ťa na . Skús to prosím neskôr. +velocity.error.connected-server-error=V tvojom pripojení na sa vyskytla chyba. velocity.error.internal-server-connection-error=V serverovom pripojení sa vyskytla interná chyba. velocity.error.logging-in-too-fast=Pripájaš sa príliš rýchlo, skús to znova neskôr. velocity.error.online-mode-only=Nie si prihlásený do svojho Minecraft účtu. Ak si prihlásený, skús reštartovať svoj Minecraft klient. velocity.error.player-connection-error=V tvojom pripojení sa vyskytla interná chyba. velocity.error.modern-forwarding-needs-new-client=Tento server je kompatibilný len s Minecraftom 1.13 a novším. velocity.error.modern-forwarding-failed=Tvoj server neodoslal presmerovaciu požiadavku proxy serveru. Uisti sa, že server je nastavený na presmerovanie Velocity. -velocity.error.moved-to-new-server=Bol si odpojený z {0}\: {1} +velocity.error.moved-to-new-server=Bol si odpojený z \: velocity.error.no-available-servers=Nie sú k dispozícii žiadne servery na pripojenie. Skús to neskôr alebo kontaktuj admina. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Nastala chyba pri vykonávaní tohto príkazu. velocity.command.command-does-not-exist=Tento príkaz neexistuje. velocity.command.players-only=Len hráči môžu vykonať tento príkaz. -velocity.command.server-does-not-exist=Zadaný server {0} neexistuje. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Aktuálne si pripojený na {0}. +velocity.command.server-does-not-exist=Zadaný server neexistuje. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Aktuálne si pripojený na . velocity.command.server-too-many=Je nastavených príliš veľa serverov. Použi tab pre zobrazenie dostupných serverov. velocity.command.server-available=Dostupné servery\: -velocity.command.server-tooltip-player-online={0} hráč online -velocity.command.server-tooltip-players-online={0} hráčov online +velocity.command.server-tooltip-player-online= hráč online +velocity.command.server-tooltip-players-online= hráčov online velocity.command.server-tooltip-current-server=Aktuálne si pripojený na tento server velocity.command.server-tooltip-offer-connect-server=Klikni pre pripojenie na tento server -velocity.command.glist-player-singular={0} hráč je pripojený na tento proxy server. -velocity.command.glist-player-plural={0} hráčov je pripojených na tento proxy server. +velocity.command.glist-player-singular= hráč je pripojený na tento proxy server. +velocity.command.glist-player-plural= hráčov je pripojených na tento proxy server. velocity.command.glist-view-all=Pre zobrazenie všetkých hráčov na všetkých serveroch použi /glist all. velocity.command.reload-success=Konfigurácia Velocity úspešne načítaná. velocity.command.reload-failure=Nepodarilo sa načítať konfiguráciu Velocity. Pozri sa do konzoly pre viac informácií. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} je licencovaný pod podmienkami GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . je licencovaný pod podmienkami GNU General Public License v3. velocity.command.no-plugins=Aktuálne nie sú nainštalované žiadne pluginy. -velocity.command.plugins-list=Pluginy\: {0} -velocity.command.plugin-tooltip-website=Webstránka\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autori\: {0} +velocity.command.plugins-list=Pluginy\: +velocity.command.plugin-tooltip-website=Webstránka\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autori\: velocity.command.dump-uploading=Nahrávanie získaných informácií... velocity.command.dump-send-error=Nastala chyba pri komunikácii s Velocity servermi. Servery môžu byť dočasne nedostupné alebo je chyba v prístupe na internet. Viac informácií je v logu a v konzole tvojho Velocity servera. velocity.command.dump-success=Bol vytvorený anonymný záznam o tomto serveri. Ak si ho vyžiadal developer, môžeš mu poslať nasledujúci odkaz\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sq_AL.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sq_AL.properties index 711b8e84..fd2ed9c6 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sq_AL.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sq_AL.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Ju tashmë jeni lidhur me këtë server\! velocity.error.already-connected-proxy=Ju jeni lidhur tashmë me këtë përfaqësues\! velocity.error.already-connecting=Ju tashmë po përpiqeni të lidheni me një server\! -velocity.error.cant-connect=Nuk mund të lidhet me {0}\: {1} -velocity.error.connecting-server-error=Nuk mund të të lidh me {0}. Ju lutemi provoni përsëri më vonë. -velocity.error.connected-server-error=Lidhja juaj me {0} hasi një problem. +velocity.error.cant-connect=Nuk mund të lidhet me \: +velocity.error.connecting-server-error=Nuk mund të të lidh me . Ju lutemi provoni përsëri më vonë. +velocity.error.connected-server-error=Lidhja juaj me hasi një problem. velocity.error.internal-server-connection-error=Ndodhi një gabim i brendshëm i lidhjes së serverit. velocity.error.logging-in-too-fast=Po hyni shumë shpejt, provoni përsëri më vonë. velocity.error.online-mode-only=Ju nuk jeni regjistruar në llogarinë tuaj në Minecraft. Nëse jeni regjistruar në llogarinë tuaj Minecraft, provoni të rindizni klientin tuaj Minecraft. velocity.error.player-connection-error=Ndodhi një gabim i brendshëm në lidhjen tuaj. velocity.error.modern-forwarding-needs-new-client=Ky server është i pajtueshëm vetëm me Minecraft 1.13 e lart. velocity.error.modern-forwarding-failed=Serveri juaj nuk i dërgoi një kërkesë për transferim përfaqësuesit. Sigurohuni që serveri të jetë konfiguruar për transferimin e shpejtësisë. -velocity.error.moved-to-new-server=Ju kanë dëbuar nga {0}\: {1} +velocity.error.moved-to-new-server=Ju kanë dëbuar nga \: velocity.error.no-available-servers=Nuk ka servera të disponueshëm për t'ju lidhur. Provo përsëri më vonë ose kontakto një administrator. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Ndodhi një gabim gjatë ekzekutimit të kësaj komande. velocity.command.command-does-not-exist=Kjo komandë nuk ekziston. velocity.command.players-only=Vetëm lojtarët mund ta drejtojnë këtë komandë. -velocity.command.server-does-not-exist=Serveri i specifikuar {0} nuk ekziston. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Aktualisht jeni i lidhur me {0}. +velocity.command.server-does-not-exist=Serveri i specifikuar nuk ekziston. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Aktualisht jeni i lidhur me . velocity.command.server-too-many=Ka shumë servera të konfiguruar. Përdorni përfundimin e skedave për të parë të gjithë serverat e disponueshëm. velocity.command.server-available=Serverat e disponueshëm\: -velocity.command.server-tooltip-player-online={0} lojtar në internet -velocity.command.server-tooltip-players-online={0} lojtarë në internet +velocity.command.server-tooltip-player-online= lojtar në internet +velocity.command.server-tooltip-players-online= lojtarë në internet velocity.command.server-tooltip-current-server=Aktualisht e lidhur me këtë server velocity.command.server-tooltip-offer-connect-server=Klikoni për t'u lidhur me këtë server -velocity.command.glist-player-singular={0} lojtari aktualisht është i lidhur me përfaqësuesin. -velocity.command.glist-player-plural={0} lojtarët janë aktualisht të lidhur me përfaqësuesin. +velocity.command.glist-player-singular= lojtari aktualisht është i lidhur me përfaqësuesin. +velocity.command.glist-player-plural= lojtarët janë aktualisht të lidhur me përfaqësuesin. velocity.command.glist-view-all=Për të parë të gjithë lojtarët në servera, përdorni /glist all. velocity.command.reload-success=Konfigurimi i shpejtësisë u ringarkua me sukses. velocity.command.reload-failure=Nuk mund të ringarkohet konfigurimi i shpejtësisë. Kontrolloni konsolën për më shumë detaje. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=There are no plugins currently installed. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Website\: {0} -velocity.command.plugin-tooltip-author=Author\: {0} -velocity.command.plugin-tooltip-authors=Authors\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Website\: +velocity.command.plugin-tooltip-author=Author\: +velocity.command.plugin-tooltip-authors=Authors\: velocity.command.dump-uploading=Uploading gathered information... velocity.command.dump-send-error=An error occurred while communicating with the Velocity servers. The servers may be temporarily unavailable or there is an issue with your network settings. You can find more information in the log or console of your Velocity server. velocity.command.dump-success=Created an anonymised report containing useful information about this proxy. If a developer requested it, you may share the following link with them\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_CS.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_CS.properties index 006a3037..5433347b 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_CS.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_CS.properties @@ -18,40 +18,40 @@ velocity.error.already-connected=Već ste povezani na ovaj server\! velocity.error.already-connected-proxy=Već ste povezani na ovaj proxy\! velocity.error.already-connecting=Već pokušavate da se povežete na server\! -velocity.error.cant-connect=Nije moguće povezati se na {0}\: {1} -velocity.error.connecting-server-error=Nije moguće povezati Vas na {0}. Molimo pokušajte ponovo kasnije. -velocity.error.connected-server-error=Došlo je do problema sa Vašom vezom sa {0}. +velocity.error.cant-connect=Nije moguće povezati se na \: +velocity.error.connecting-server-error=Nije moguće povezati Vas na . Molimo pokušajte ponovo kasnije. +velocity.error.connected-server-error=Došlo je do problema sa Vašom vezom sa . velocity.error.internal-server-connection-error=Dogodila se interna greška sa konekcijom sa serverom. velocity.error.logging-in-too-fast=Logujete se prebrzo, molimo pokušajte kasnije. velocity.error.online-mode-only=Niste ulogovani na Vaš Minecraft nalog. Ako ipak jeste, probajte da restartujete Minecraft klijent. velocity.error.player-connection-error=Dogodila se interna greška sa Vašom konekcijom. velocity.error.modern-forwarding-needs-new-client=Ovaj server je kompatibilan samo sa Minecraft-om 1.13 i višim verzijama. velocity.error.modern-forwarding-failed=Vaš server nije poslao zahtev za prosleđivanje na proxy. Proverite je li server konfigurisan za Velocity prosleđivanje. -velocity.error.moved-to-new-server=Izbačeni ste iz {0}\: {1} +velocity.error.moved-to-new-server=Izbačeni ste iz \: velocity.error.no-available-servers=Nema dostupnih servera za povezati Vas. Pokušajte ponovo kasnije ili kontaktirajte nekog admina. # Commands velocity.command.generic-error=Došlo je do greške pri pokretanju te komande. velocity.command.command-does-not-exist=Ta komanda ne postoji. velocity.command.players-only=Tu komandu mogu pokrenuti samo igrači. -velocity.command.server-does-not-exist=Navedeni server {0} ne postoji. -velocity.command.server-current-server=Trenutno ste povezani na {0}. +velocity.command.server-does-not-exist=Navedeni server ne postoji. +velocity.command.server-current-server=Trenutno ste povezani na . velocity.command.server-too-many=Postoji mnogo servera. Koristite tab dovršavanje za pregled svih dostupnih servera. velocity.command.server-available=Dostupni serveri\: -velocity.command.server-tooltip-player-online={0} igrač online -velocity.command.server-tooltip-players-online={0} igrača online +velocity.command.server-tooltip-player-online= igrač online +velocity.command.server-tooltip-players-online= igrača online velocity.command.server-tooltip-current-server=Trenutno ste povezani na ovaj server velocity.command.server-tooltip-offer-connect-server=Kliknite za povezivanje na ovaj server -velocity.command.glist-player-singular={0} igrač je trenutno povezan na proxy. -velocity.command.glist-player-plural={0} igrača je trenutno povezano na proxy. +velocity.command.glist-player-singular= igrač je trenutno povezan na proxy. +velocity.command.glist-player-plural= igrača je trenutno povezano na proxy. velocity.command.glist-view-all=Za pregled svih igrača na serverima koristite /glist all. velocity.command.reload-success=Velocity konfiguracija uspešno ponovno učitana. velocity.command.reload-failure=Nije moguće ponovo učitati Vašu Velocity konfiguraciju. Proverite konzolu za više detalja. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} je licenciran pod uslovima licence GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . je licenciran pod uslovima licence GNU General Public License v3. velocity.command.no-plugins=Trenutno nema instaliranih plugin-a. -velocity.command.plugins-list=Plugin-i\: {0} -velocity.command.plugin-tooltip-website=Web stranica\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autori\: {0} +velocity.command.plugins-list=Plugin-i\: +velocity.command.plugin-tooltip-website=Web stranica\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autori\: velocity.command.dump-uploading=Otpremanje prikupljenih informacija... velocity.command.dump-send-error=Dogodila se greška pri komunikaciji sa Velocity serverima. Serveri su ili trenutno nedostupni, ili postoji problem sa Vašim mrežnim podešavanjima. Možete saznati više informacija u log-u ili konzoli Vašeg Velocity servera. velocity.command.dump-success=Kreiran anonimiziran izveštaj koji sadrži korisne informacije o ovom proxy-u. Ako ga developer zatraži, možete mu poslati ovaj link\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_Latn.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_Latn.properties index 6106bb7b..fe1731bb 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_Latn.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sr_Latn.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Već ste povezani na ovaj server\! velocity.error.already-connected-proxy=Već ste povezani na ovaj proxy\! velocity.error.already-connecting=Već pokušavate da se povežete na server\! -velocity.error.cant-connect=Nije moguće povezati se na {0}\: {1} -velocity.error.connecting-server-error=Nije moguće povezati Vas na {0}. Molimo pokušajte ponovo kasnije. -velocity.error.connected-server-error=Došlo je do problema sa Vašom vezom sa {0}. +velocity.error.cant-connect=Nije moguće povezati se na \: +velocity.error.connecting-server-error=Nije moguće povezati Vas na . Molimo pokušajte ponovo kasnije. +velocity.error.connected-server-error=Došlo je do problema sa Vašom vezom sa . velocity.error.internal-server-connection-error=Dogodila se interna greška sa konekcijom sa serverom. velocity.error.logging-in-too-fast=Logujete se prebrzo, molimo pokušajte kasnije. velocity.error.online-mode-only=Niste ulogovani na Vaš Minecraft nalog. Ako ipak jeste, probajte da restartujete Minecraft klijent. velocity.error.player-connection-error=Dogodila se interna greška sa Vašom konekcijom. velocity.error.modern-forwarding-needs-new-client=Ovaj server je kompatibilan samo sa Minecraft-om 1.13 i višim verzijama. velocity.error.modern-forwarding-failed=Vaš server nije poslao zahtev za prosleđivanje na proxy. Proverite je li server konfigurisan za Velocity prosleđivanje. -velocity.error.moved-to-new-server=Izbačeni ste iz {0}\: {1} +velocity.error.moved-to-new-server=Izbačeni ste iz \: velocity.error.no-available-servers=Nema dostupnih servera za povezati Vas. Pokušajte ponovo kasnije ili kontaktirajte nekog admina. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Došlo je do greške pri pokretanju te komande. velocity.command.command-does-not-exist=Ta komanda ne postoji. velocity.command.players-only=Tu komandu mogu pokrenuti samo igrači. -velocity.command.server-does-not-exist=Navedeni server {0} ne postoji. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Trenutno ste povezani na {0}. +velocity.command.server-does-not-exist=Navedeni server ne postoji. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Trenutno ste povezani na . velocity.command.server-too-many=Postoji mnogo servera. Koristite tab dovršavanje za pregled svih dostupnih servera. velocity.command.server-available=Dostupni serveri\: -velocity.command.server-tooltip-player-online={0} igrač online -velocity.command.server-tooltip-players-online={0} igrača online +velocity.command.server-tooltip-player-online= igrač online +velocity.command.server-tooltip-players-online= igrača online velocity.command.server-tooltip-current-server=Trenutno ste povezani na ovaj server velocity.command.server-tooltip-offer-connect-server=Kliknite za povezivanje na ovaj server -velocity.command.glist-player-singular={0} igrač je trenutno povezan na proxy. -velocity.command.glist-player-plural={0} igrača je trenutno povezano na proxy. +velocity.command.glist-player-singular= igrač je trenutno povezan na proxy. +velocity.command.glist-player-plural= igrača je trenutno povezano na proxy. velocity.command.glist-view-all=Za pregled svih igrača na serverima koristite /glist all. velocity.command.reload-success=Velocity konfiguracija uspešno ponovno učitana. velocity.command.reload-failure=Nije moguće ponovo učitati Vašu Velocity konfiguraciju. Proverite konzolu za više detalja. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=Trenutno nema instaliranih plugin-a. -velocity.command.plugins-list=Plugin-i\: {0} -velocity.command.plugin-tooltip-website=Web stranica\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Autori\: {0} +velocity.command.plugins-list=Plugin-i\: +velocity.command.plugin-tooltip-website=Web stranica\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Autori\: velocity.command.dump-uploading=Otpremanje prikupljenih informacija... velocity.command.dump-send-error=Dogodila se greška pri komunikaciji sa Velocity serverima. Serveri su ili trenutno nedostupni, ili postoji problem sa Vašim mrežnim podešavanjima. Možete saznati više informacija u log-u ili konzoli Vašeg Velocity servera. velocity.command.dump-success=Kreiran anonimiziran izveštaj koji sadrži korisne informacije o ovom proxy-u. Ako ga developer zatraži, možete mu poslati ovaj link\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sv_SE.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sv_SE.properties index 973506eb..0020b954 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sv_SE.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_sv_SE.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Du är redan ansluten till den här servern\! velocity.error.already-connected-proxy=Du är redan ansluten till den här proxyn\! velocity.error.already-connecting=Du försöker redan ansluta till en server\! -velocity.error.cant-connect=Det går inte att ansluta till {0}\: {1} -velocity.error.connecting-server-error=Det går inte att ansluta dig till {0}. Snälla försök igen senare. -velocity.error.connected-server-error=Din anslutning till {0} stötte på ett problem. +velocity.error.cant-connect=Det går inte att ansluta till \: +velocity.error.connecting-server-error=Det går inte att ansluta dig till . Snälla försök igen senare. +velocity.error.connected-server-error=Din anslutning till stötte på ett problem. velocity.error.internal-server-connection-error=Ett internt serveranslutningsfel uppstod. velocity.error.logging-in-too-fast=Du loggar in för snabbt, Försök igen senare. velocity.error.online-mode-only=Du är inte inloggad på ditt Minecraft konto. Om du är inloggad på ditt Minecraft konto, prova att starta om din Minecraft klient. velocity.error.player-connection-error=Ett internt fel uppstod i din anslutning. velocity.error.modern-forwarding-needs-new-client=Denna server är endast kompatibel med Minecraft 1.13 och högre. velocity.error.modern-forwarding-failed=Din server skickade inte en vidarebefordrings begäran till proxyn. Se till att servern är konfigurerad för Velocity vidarebefordrings begäran. -velocity.error.moved-to-new-server=Du blev sparkad från {0}\: {1} +velocity.error.moved-to-new-server=Du blev sparkad från \: velocity.error.no-available-servers=Det finns inga tillgängliga servrar att ansluta dig till. Försök igen senare eller kontakta en admin. velocity.error.illegal-chat-characters=Olagliga tecken i chatten # Commands velocity.command.generic-error=Ett fel uppstod när det här kommandot kördes. velocity.command.command-does-not-exist=Detta kommando finns inte. velocity.command.players-only=Bara spelare kan använda detta kommando. -velocity.command.server-does-not-exist=Den angivna servern {0} finns inte. -velocity.command.player-not-found=Den angivna spelaren {0} finns inte. -velocity.command.server-current-server=Du är just nu ansluten till {0}. +velocity.command.server-does-not-exist=Den angivna servern finns inte. +velocity.command.player-not-found=Den angivna spelaren finns inte. +velocity.command.server-current-server=Du är just nu ansluten till . velocity.command.server-too-many=Det finns för många servrar som är konfigurerade. Använd tab färdigställandet för att se alla tillgängliga servrar. velocity.command.server-available=Tillgängliga servrar\: -velocity.command.server-tooltip-player-online={0} spelare online -velocity.command.server-tooltip-players-online={0} spelare online +velocity.command.server-tooltip-player-online= spelare online +velocity.command.server-tooltip-players-online= spelare online velocity.command.server-tooltip-current-server=Just nu ansluten till denna servern velocity.command.server-tooltip-offer-connect-server=Klicka för att ansluta till servern -velocity.command.glist-player-singular={0} spelare är just nu ansluten till proxyn. -velocity.command.glist-player-plural={0} spelare är just nu ansluten till proxyn. +velocity.command.glist-player-singular= spelare är just nu ansluten till proxyn. +velocity.command.glist-player-plural= spelare är just nu ansluten till proxyn. velocity.command.glist-view-all=För att se alla spelare på servrar, använd /glist all. velocity.command.reload-success=Velocity konfigurationen har laddats om. velocity.command.reload-failure=Det gick inte att ladda om din Velocity konfiguration. Kontrollera konsolen för mer information. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} är licensierad enligt villkoren i GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . är licensierad enligt villkoren i GNU General Public License v3. velocity.command.no-plugins=Det finns inga tillägg installerade. -velocity.command.plugins-list=Tillägg\: {0} -velocity.command.plugin-tooltip-website=Webbsida\: {0} -velocity.command.plugin-tooltip-author=Utgivare\: {0} -velocity.command.plugin-tooltip-authors=Utgivare\: {0} +velocity.command.plugins-list=Tillägg\: +velocity.command.plugin-tooltip-website=Webbsida\: +velocity.command.plugin-tooltip-author=Utgivare\: +velocity.command.plugin-tooltip-authors=Utgivare\: velocity.command.dump-uploading=Laddar upp insamlad information... velocity.command.dump-send-error=Ett fel uppstod under kommunikationen med Velocity servrarna. Servrarna kan vara tillfälligt otillgängliga eller så finns det ett problem med dina nätverksinställningar. Du kan hitta mer information i loggen eller konsolen på din Velocity server. velocity.command.dump-success=Skapade en anonymiserad rapport med användbar information om denna proxy. Om en utvecklare begärde det, kan du dela följande länk med dem\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tl_PH.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tl_PH.properties index ec4cc9d2..053013f5 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tl_PH.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tl_PH.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Nakakonekta ka na sa serbidor na ito\! velocity.error.already-connected-proxy=Nakakonekta ka na sa proxy na ito\! velocity.error.already-connecting=Sinusubukan mo na makakonekta sa isang serbidor\! -velocity.error.cant-connect=Hindi makakonekta sa {0} dahil {1} -velocity.error.connecting-server-error=Hindi ka makakonekta sa {0}. Paki-ulitin mo ulit na mamaya. -velocity.error.connected-server-error=Maencounter isang problema ang koneksyon mo sa {0}. +velocity.error.cant-connect=Hindi makakonekta sa dahil +velocity.error.connecting-server-error=Hindi ka makakonekta sa . Paki-ulitin mo ulit na mamaya. +velocity.error.connected-server-error=Maencounter isang problema ang koneksyon mo sa . velocity.error.internal-server-connection-error=Nangyari isang internal server error. velocity.error.logging-in-too-fast=Masyadong mabilis ang mga attempt ng pagpapatunay mo. Paki-ulitin mo ulit na mamaya. velocity.error.online-mode-only=Hindi nakapagpatunay sa akawnt ng Minecraft mo. Kung nakapatunayan sa akawnt ng Minecraft mo, tapos sinubukan i-restart mo ang klient ng Minecraft niyo. velocity.error.player-connection-error=Nangyari isang internal server error sa ng koneksiyon mo. velocity.error.modern-forwarding-needs-new-client=Ang server na ito magkasundo lang kasama ang version 1.13 at sa itaas. velocity.error.modern-forwarding-failed=Hindi ipadala ang serbidor mo ng forwarding request sa proxy. Dapat nae-ensure mo ng naka-configure ang server para ng forwarding ng Velocity. -velocity.error.moved-to-new-server=Nanipa ka mula sa {0} dahil {1} +velocity.error.moved-to-new-server=Nanipa ka mula sa dahil velocity.error.no-available-servers=Wala na ang mga serbidor na magagamit para sa'yo. Paki-ulitin mo ulit o magcontact ka isang admin. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Nangyari isang pagkakamali kapag sinubukan ng serbidor magamit ang komando ng ito. velocity.command.command-does-not-exist=Walang komando sa serbidor. velocity.command.players-only=Mga manlalaro lang makagamit ang komando ito. -velocity.command.server-does-not-exist=Walang serbidor {0}. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Nakakonekta ka sa {0}. +velocity.command.server-does-not-exist=Walang serbidor . +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Nakakonekta ka sa . velocity.command.server-too-many=Meron masyadong serbidor sa konfig. Magamit ka ng tab completion sa makita lahat ng serbidor na magagamit. velocity.command.server-available=Magagamit na mga serbidor\: -velocity.command.server-tooltip-player-online={0} manlalaro sa online -velocity.command.server-tooltip-players-online={0} mga manlalaro sa online +velocity.command.server-tooltip-player-online= manlalaro sa online +velocity.command.server-tooltip-players-online= mga manlalaro sa online velocity.command.server-tooltip-current-server=Nakakonekta ka sa serbidor na ito velocity.command.server-tooltip-offer-connect-server=I-click dito sa kumonekta sa serbidor na ito -velocity.command.glist-player-singular={0} manlalaro nasa proxy. -velocity.command.glist-player-plural={0} mga manlalaro nasa proxy. +velocity.command.glist-player-singular= manlalaro nasa proxy. +velocity.command.glist-player-plural= mga manlalaro nasa proxy. velocity.command.glist-view-all=Para sa makita ang mga lahat ng manlalaro sa mga serbidor, magamit ka ng /glist all. velocity.command.reload-success=Matagumpay ang reload ng konfigurasyon ng Velocity. velocity.command.reload-failure=Hindi kaya ang magreload ng konfigurasyon mo sa Velocity. Magsiyasat ang konsole para mas maraming detalye. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=Walang plugin nang naka-install. -velocity.command.plugins-list=Mga plugin\: {0} -velocity.command.plugin-tooltip-website=Website\: {0} -velocity.command.plugin-tooltip-author=Autor\: {0} -velocity.command.plugin-tooltip-authors=Mga autor\: {0} +velocity.command.plugins-list=Mga plugin\: +velocity.command.plugin-tooltip-website=Website\: +velocity.command.plugin-tooltip-author=Autor\: +velocity.command.plugin-tooltip-authors=Mga autor\: velocity.command.dump-uploading=Inu-upload ang ipong impormasyon... velocity.command.dump-send-error=Nangyari isang pagkakamali sa panahon ng koneksiyon kasama ang mga serbidor ng Velocity. Baka hindi magagamit na pansamantalang ang mga serbidor o may isang isyu sa mga network settings mo. Hinapin mo mas impormasyon sa log o console sa serbidor ng Velocity mo. velocity.command.dump-success=Lumikha isang report ng hindi nagpapakilala ng may impormasyon mahalaga tungkol sa proxy ng ito. Kung hingin ito ng developer, makashare ka ang link na ito kasama siya\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tr_TR.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tr_TR.properties index 3c255d93..4bc6ebf3 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tr_TR.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_tr_TR.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Bu sunucuya zaten bağlısın\! velocity.error.already-connected-proxy=Bu sunucuya zaten bağlısın\! velocity.error.already-connecting=Bu sunucuya zaten bağlanmaya çalışıyorsun\! -velocity.error.cant-connect={0}\:{1} ile bağlantı kurulamadı -velocity.error.connecting-server-error=Seni {0}'ye bağlayamadık. Lütfen daha sonra tekrar deneyiniz. -velocity.error.connected-server-error={0} ile bağlantında bir problem meydana geldi. +velocity.error.cant-connect=\: ile bağlantı kurulamadı +velocity.error.connecting-server-error=Seni 'ye bağlayamadık. Lütfen daha sonra tekrar deneyiniz. +velocity.error.connected-server-error= ile bağlantında bir problem meydana geldi. velocity.error.internal-server-connection-error=Dahili sunucu bağlantısında bir hata meydana geldi. velocity.error.logging-in-too-fast=Çok hızlı bağlanmaya çalışıyorsun, daha sonra tekrar dene. velocity.error.online-mode-only=Minecraft hesabına bağlı değilsin. Eğer Minecraft hesabına bağlıysan, Minecraft istemcini kapatıp tekrardan başlat. velocity.error.player-connection-error=Bağlantında dahili bir hata meydana geldi. velocity.error.modern-forwarding-needs-new-client=Bu sunucuya Minecraft'ın sadece 1.13 ve üzeri sürümleri ile giriş yapabilirsin. velocity.error.modern-forwarding-failed=Sunucun Velocity'ye yönlendirme isteğinde bulunmadı. Sunucunun Velocity'nin ayarlarında ayarlandığına emin ol. -velocity.error.moved-to-new-server={0}\:{1} sunucusundan atıldınız +velocity.error.moved-to-new-server=\: sunucusundan atıldınız velocity.error.no-available-servers=Seni bağlayabileceğimiz bir sunucu bulamadık. Lütfen daha sonra tekrar dene veya bir yetkili ile iletişime geç. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Bu komutu çalıştırırken bir hata meydana geldi. velocity.command.command-does-not-exist=Böyle bir komut yok. velocity.command.players-only=Sadece oyuncular bu komutu çalıştırabilir. -velocity.command.server-does-not-exist=Belirlenmiş sunucu {0} bulunmuyor. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Şu anda {0} sunucusuna bağlısın. +velocity.command.server-does-not-exist=Belirlenmiş sunucu bulunmuyor. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Şu anda sunucusuna bağlısın. velocity.command.server-too-many=Ayarlanmış birçok sunucu mevcut. Mevcut bütün sunucuları görmek için tamamlama özelliğini kullan. velocity.command.server-available=Müsait sunucular\: -velocity.command.server-tooltip-player-online={0} oyuncu çevrimiçi -velocity.command.server-tooltip-players-online={0} oyuncu çevrimiçi +velocity.command.server-tooltip-player-online= oyuncu çevrimiçi +velocity.command.server-tooltip-players-online= oyuncu çevrimiçi velocity.command.server-tooltip-current-server=Şu anda bu sunucuya bağlısın velocity.command.server-tooltip-offer-connect-server=Bu sunucuya bağlanmak için tıkla -velocity.command.glist-player-singular=Şu anda sunucuya toplam {0} oyuncu bağlı. -velocity.command.glist-player-plural=Şu anda sunucuya toplam {0} oyuncu bağlı. +velocity.command.glist-player-singular=Şu anda sunucuya toplam oyuncu bağlı. +velocity.command.glist-player-plural=Şu anda sunucuya toplam oyuncu bağlı. velocity.command.glist-view-all=Sunucudaki bütün oyuncuları görüntülemek için /glist all komutunu kullan. velocity.command.reload-success=Velocity ayarları başarıyla güncellendi. velocity.command.reload-failure=Velocity ayarlarınız güncellenemiyor. Daha fazla bilgi için konsolu kontrol edin. -velocity.command.version-copyright=Talif hakkı 2018-{2} {0}. {1}, GNU General Public License v3 adı altında lisanslanmıştır. +velocity.command.version-copyright=Talif hakkı 2018- . , GNU General Public License v3 adı altında lisanslanmıştır. velocity.command.no-plugins=Yüklenmiş herhangi bir eklenti yok. -velocity.command.plugins-list=Eklentiler\: {0} -velocity.command.plugin-tooltip-website=Website\: {0} -velocity.command.plugin-tooltip-author=Yapımcı\: {0} -velocity.command.plugin-tooltip-authors=Yapımcılar\: {0} +velocity.command.plugins-list=Eklentiler\: +velocity.command.plugin-tooltip-website=Website\: +velocity.command.plugin-tooltip-author=Yapımcı\: +velocity.command.plugin-tooltip-authors=Yapımcılar\: velocity.command.dump-uploading=Toplanılan bilgiler yükleniyor... velocity.command.dump-send-error=Velocity sunucuları ile iletişim sırasında bir hata oluştu. Sunucular geçici olarak kullanılamıyor olabilir veya ağ ayarlarınızla ilgili bir sorun olabilir. Velocity sunucunuzun logunda veya konsolunda daha fazla bilgi bulabilirsiniz. velocity.command.dump-success=Bu proxy hakkında faydalı bilgiler içeren anonim bir rapor oluşturdu. Bir geliştirici talep ettiyse, aşağıdaki bağlantıyı onlarla paylaşabilirsiniz\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_uk_UA.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_uk_UA.properties index 2400bd29..66d82c3d 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_uk_UA.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_uk_UA.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Ви вже підключені до цього серверу\! velocity.error.already-connected-proxy=Ви вже приєднані до даного проксі\! velocity.error.already-connecting=Ви вже приєднуєтесь до сервера\! -velocity.error.cant-connect=Не вдалося приєднатись до сервера {0}\: {1} -velocity.error.connecting-server-error=Не вдалося приєднати вас до сервера {0}. Будь ласка, спробуйте пізніше. -velocity.error.connected-server-error=З вашим приєднанням до сервера {0} виникла проблема. +velocity.error.cant-connect=Не вдалося приєднатись до сервера \: +velocity.error.connecting-server-error=Не вдалося приєднати вас до сервера . Будь ласка, спробуйте пізніше. +velocity.error.connected-server-error=З вашим приєднанням до сервера виникла проблема. velocity.error.internal-server-connection-error=На сервері виникла внутрішня помилка приєднання. velocity.error.logging-in-too-fast=Ви приєднуєтесь дуже швидко. Будь ласка, спробуйте пізніше. velocity.error.online-mode-only=Ви не увійшли у свій профіль Minecraft. Якщо ви впевнені, що увійшли у профіль, спробуйте перезапустити свій клієнт Minecraft. velocity.error.player-connection-error=У вашому підключенні виникла внутрішня помилка. velocity.error.modern-forwarding-needs-new-client=Даний сервер сумісний з версією Minecraft 1.13 і вище. velocity.error.modern-forwarding-failed=Ваш сервер не давав запит на переадресацію на проксі-сервер. Упевніться, що сервер налаштований на переадресацію Velocity. -velocity.error.moved-to-new-server=Ви кікнуті з сервера {0}\: {1} +velocity.error.moved-to-new-server=Ви кікнуті з сервера \: velocity.error.no-available-servers=Нема серверів, доступних до приєднання. Спробуйте пізніше чи зв'яжіться з адміністратором. velocity.error.illegal-chat-characters=Заборонені символи у чаті # Commands velocity.command.generic-error=Під час виконання даної команди виникла помилка. velocity.command.command-does-not-exist=Цієї команди не існує. velocity.command.players-only=Тільки гравці можуть використовувати цю команду. -velocity.command.server-does-not-exist=Вказаного серверу {0} не існує. -velocity.command.player-not-found=Вказаного гравця {0} не існує. -velocity.command.server-current-server=Зараз ви приєднані до сервера {0}. +velocity.command.server-does-not-exist=Вказаного серверу не існує. +velocity.command.player-not-found=Вказаного гравця не існує. +velocity.command.server-current-server=Зараз ви приєднані до сервера . velocity.command.server-too-many=Налаштовано дуже багато серверів. Для перегляду всіх доступних серверів, використовуйте автозаповнення клавішею Tab. velocity.command.server-available=Доступні сервери\: -velocity.command.server-tooltip-player-online={0} гравець онлайн -velocity.command.server-tooltip-players-online={0} гравець(ця, ців) онлайн +velocity.command.server-tooltip-player-online= гравець онлайн +velocity.command.server-tooltip-players-online= гравець(ця, ців) онлайн velocity.command.server-tooltip-current-server=Приєднаний до даного серверу velocity.command.server-tooltip-offer-connect-server=Натисніть, щоб приєднатись до даного серверу -velocity.command.glist-player-singular={0} Гравець приєднаний до проксі на даний момент. -velocity.command.glist-player-plural={0} гравець(ця, ців) приєднані до проксі на даний момент. +velocity.command.glist-player-singular= Гравець приєднаний до проксі на даний момент. +velocity.command.glist-player-plural= гравець(ця, ців) приєднані до проксі на даний момент. velocity.command.glist-view-all=Щоб переглянути всіх гравців на серверах, використовуйте /glist all. velocity.command.reload-success=Конфігурація Velocity успішно перезавантажена. velocity.command.reload-failure=Не вдалося перезантажити конфігурацію Velocity. Перевірте консоль для подробиць. -velocity.command.version-copyright=Авторське право 2018-{2} {0}. {1} ліцензовано на умовах GNU General Public License v3. +velocity.command.version-copyright=Авторське право 2018- . ліцензовано на умовах GNU General Public License v3. velocity.command.no-plugins=Плагіни відсутні. -velocity.command.plugins-list=Плагіни\: {0} -velocity.command.plugin-tooltip-website=Веб-сайт\: {0} -velocity.command.plugin-tooltip-author=Автор\: {0} -velocity.command.plugin-tooltip-authors=Автори\: {0} +velocity.command.plugins-list=Плагіни\: +velocity.command.plugin-tooltip-website=Веб-сайт\: +velocity.command.plugin-tooltip-author=Автор\: +velocity.command.plugin-tooltip-authors=Автори\: velocity.command.dump-uploading=Завантаження отриманої інформації... velocity.command.dump-send-error=Під час зв'язку з серверами Velocity виникла помилка. Можливо, сервери тимчасово недоступні або проблема з налаштування ми вашої мережі. Більше інформації ви можете знайти в журнвлі або консолі вашого серверу Velocity. velocity.command.dump-success=Створено анонімний звіт, що містить корисну інформацію про проксі. Якщо цей звіт запросив розробник, ви можете поділитися з ним наступним посиланням\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_vi_VN.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_vi_VN.properties index 5450e21e..8c31a09d 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_vi_VN.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_vi_VN.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=Bạn đã kết nối đến máy chủ này\! velocity.error.already-connected-proxy=Bạn đã kết nối đến proxy này\! velocity.error.already-connecting=Bạn đang kết nối đến một máy chủ\! -velocity.error.cant-connect=Không thể kết nối đến {0}\: {1} -velocity.error.connecting-server-error=Không thể kết nối bạn đến {0}. Vui lòng thử lại sau. -velocity.error.connected-server-error=Kết nối của bạn đến {0} đã gặp một vấn đề. +velocity.error.cant-connect=Không thể kết nối đến \: +velocity.error.connecting-server-error=Không thể kết nối bạn đến . Vui lòng thử lại sau. +velocity.error.connected-server-error=Kết nối của bạn đến đã gặp một vấn đề. velocity.error.internal-server-connection-error=Đã xảy ra một lỗi kết nối máy chủ nội bộ. velocity.error.logging-in-too-fast=Bạn đang đăng nhập quá nhanh, vui lòng thử lại sau. velocity.error.online-mode-only=Bạn chưa đăng nhập vào tài khoản Minecraft của bạn. Nếu bạn đã đăng nhập vào tài khoản Minecraft của bạn, hãy thử khởi động lại Minecraft. velocity.error.player-connection-error=Đã xảy ra một lỗi nội bộ trong kết nối của bạn. velocity.error.modern-forwarding-needs-new-client=Máy chủ này chỉ tương thích với phiên bản Minecraft 1.13 và trở lên. velocity.error.modern-forwarding-failed=Máy chủ của bạn đã không gửi yêu cầu chuyển tiếp đến proxy. Hãy bảo đảm máy chủ đã được điều chỉnh cho chuyển tiếp đến Velocity. -velocity.error.moved-to-new-server=Bạn đã bị đá khỏi {0}\: {1} +velocity.error.moved-to-new-server=Bạn đã bị đá khỏi \: velocity.error.no-available-servers=Không có máy chủ nào cho bạn để kết nối. Vui lòng thử lại sau hoặc liên lạc một quản trị viên. velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=Đã có lỗi xảy ra khi thực hiện lệnh này. velocity.command.command-does-not-exist=Lệnh này không tồn tại. velocity.command.players-only=Chỉ có người chơi có thể thực hiện lệnh này. -velocity.command.server-does-not-exist=Máy chủ chỉ định {0} không tồn tại. -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=Hiện bạn đang kết nối đến {0}. +velocity.command.server-does-not-exist=Máy chủ chỉ định không tồn tại. +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=Hiện bạn đang kết nối đến . velocity.command.server-too-many=Có quá nhiều máy chủ được cài đặt. Dùng tab để xem hết tất cả máy chủ đang có. velocity.command.server-available=Máy chủ có sẵn\: -velocity.command.server-tooltip-player-online={0} người chơi online -velocity.command.server-tooltip-players-online={0} người chơi online +velocity.command.server-tooltip-player-online= người chơi online +velocity.command.server-tooltip-players-online= người chơi online velocity.command.server-tooltip-current-server=Hiện tại đang kết nối đến máy chủ này velocity.command.server-tooltip-offer-connect-server=Click để kết nối đến máy chủ này -velocity.command.glist-player-singular={0} người chơi hiện đang kết nối đến proxy. -velocity.command.glist-player-plural={0} người chơi hiện đang kết nối đến proxy. +velocity.command.glist-player-singular= người chơi hiện đang kết nối đến proxy. +velocity.command.glist-player-plural= người chơi hiện đang kết nối đến proxy. velocity.command.glist-view-all=Để xem tất cả người chơi trên toàn bộ máy chủ, dùng /glist all. velocity.command.reload-success=Điều chỉnh Velocity đã tải lại thành công. velocity.command.reload-failure=Không thể tải lại điều chỉnh Velocity. Kiểm tra console để xem thêm chi tiết. -velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} is licensed under the terms of the GNU General Public License v3. +velocity.command.version-copyright=Copyright 2018- . is licensed under the terms of the GNU General Public License v3. velocity.command.no-plugins=Hiện tại không có plugin được cài đặt. -velocity.command.plugins-list=Plugins\: {0} -velocity.command.plugin-tooltip-website=Website\: {0} -velocity.command.plugin-tooltip-author=Tác giả\: {0} -velocity.command.plugin-tooltip-authors=Các tác giả\: {0} +velocity.command.plugins-list=Plugins\: +velocity.command.plugin-tooltip-website=Website\: +velocity.command.plugin-tooltip-author=Tác giả\: +velocity.command.plugin-tooltip-authors=Các tác giả\: velocity.command.dump-uploading=Đang tải lên thông tin đã thu thập... velocity.command.dump-send-error=Đã xảy ra lỗi khi giao tiếp với máy chủ Velocity. Các máy chủ có thể tạm thời không khả dụng hoặc có sự cố với cài đặt mạng của bạn. Bạn có thể tìm thêm thông tin trong nhật ký hoặc bảng điều khiển của máy chủ Velocity của mình. velocity.command.dump-success=Đã tạo một báo cáo ẩn danh chứa thông tin hữu ích về proxy này. Nếu một nhà phát triển yêu cầu nó, bạn có thể chia sẻ liên kết sau với họ\: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_CN.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_CN.properties index 4b3b07d3..f56a89bc 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_CN.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_CN.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=您已经连接到此服务器了! velocity.error.already-connected-proxy=您已经连接到此代理服务器了! velocity.error.already-connecting=您已经在尝试连接服务器了! -velocity.error.cant-connect=无法连接至 {0}:{1} -velocity.error.connecting-server-error=无法将您连接至 {0},请稍后再试。 -velocity.error.connected-server-error=您与 {0} 的连接出现问题。 +velocity.error.cant-connect=无法连接至 +velocity.error.connecting-server-error=无法将您连接至 ,请稍后再试。 +velocity.error.connected-server-error=您与 的连接出现问题。 velocity.error.internal-server-connection-error=发送内部服务器连接错误。 velocity.error.logging-in-too-fast=您的登录过于频繁,请稍后重试。 velocity.error.online-mode-only=您尚未登录至 Minecraft 账户。若您已登录,请尝试重启您的客户端。 velocity.error.player-connection-error=您的连接发生内部错误。 velocity.error.modern-forwarding-needs-new-client=此服务器仅兼容 Minecraft 1.13 及更高版本。 velocity.error.modern-forwarding-failed=您的服务器未向代理服务器转发请求,请确保已配置 Velocity 转发。 -velocity.error.moved-to-new-server=您已被踢出 {0}:{1} +velocity.error.moved-to-new-server=您已被踢出 velocity.error.no-available-servers=您当前没有可连接的服务器,请稍后重试或联系管理员。 velocity.error.illegal-chat-characters=聊天中出现非法字符 # Commands velocity.command.generic-error=执行此命令时发生错误。 velocity.command.command-does-not-exist=此命令不存在。 velocity.command.players-only=只有玩家才能执行此命令。 -velocity.command.server-does-not-exist=指定的服务器 {0} 不存在。 -velocity.command.player-not-found=指定的玩家 {0} 不存在。 -velocity.command.server-current-server=您已连接至 {0}。 +velocity.command.server-does-not-exist=指定的服务器 不存在。 +velocity.command.player-not-found=指定的玩家 不存在。 +velocity.command.server-current-server=您已连接至 。 velocity.command.server-too-many=设置的服务器过多,请使用 Tab 键补全来查看所有可用的服务器。 velocity.command.server-available=可用的服务器: -velocity.command.server-tooltip-player-online={0} 名玩家在线 -velocity.command.server-tooltip-players-online={0} 名玩家在线 +velocity.command.server-tooltip-player-online= 名玩家在线 +velocity.command.server-tooltip-players-online= 名玩家在线 velocity.command.server-tooltip-current-server=当前已连接至此服务器 velocity.command.server-tooltip-offer-connect-server=点击连接至此服务器 -velocity.command.glist-player-singular=共有 {0} 名玩家已连接至此代理服务器。 -velocity.command.glist-player-plural=共有 {0} 名玩家已连接至此代理服务器。 +velocity.command.glist-player-singular=共有 名玩家已连接至此代理服务器。 +velocity.command.glist-player-plural=共有 名玩家已连接至此代理服务器。 velocity.command.glist-view-all=使用 /glist all 命令来查看所有服务器的全部玩家列表。 velocity.command.reload-success=Velocity 配置已成功重载。 velocity.command.reload-failure=无法重载 Velocity 配置,请查看控制台了解详情。 -velocity.command.version-copyright=Copyright 2018-{2} {0}。{1} 以 GNU 通用公共许可证第三版授权。 +velocity.command.version-copyright=Copyright 2018- 以 GNU 通用公共许可证第三版授权。 velocity.command.no-plugins=当前没有安装任何插件。 -velocity.command.plugins-list=插件:{0} -velocity.command.plugin-tooltip-website=网站:{0} -velocity.command.plugin-tooltip-author=作者:{0} -velocity.command.plugin-tooltip-authors=作者:{0} +velocity.command.plugins-list=插件: +velocity.command.plugin-tooltip-website=网站: +velocity.command.plugin-tooltip-author=作者: +velocity.command.plugin-tooltip-authors=作者: velocity.command.dump-uploading=正在上传已收集的信息... velocity.command.dump-send-error=与 Velocity 服务器通信时发生错误,服务器可能暂不可用或您的网络设置存在问题。您可在 Velocity 服务器日志或控制台中了解详情。 velocity.command.dump-success=已创建关于此代理的匿名反馈数据。若开发者需要,您可与其分享以下链接: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_HK.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_HK.properties index 37468347..f15eff97 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_HK.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_HK.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=你已經連接到這個伺服器\! velocity.error.already-connected-proxy=您已經連接到此代理伺服器了! velocity.error.already-connecting=您已經在嘗試連接伺服器了! -velocity.error.cant-connect=無法法連接至 {0}:{1} -velocity.error.connecting-server-error=無法將您連接至 {0},請稍后再試。 -velocity.error.connected-server-error=你與 {0} 的連線出現問題 +velocity.error.cant-connect=無法法連接至 +velocity.error.connecting-server-error=無法將您連接至 ,請稍后再試。 +velocity.error.connected-server-error=你與 的連線出現問題 velocity.error.internal-server-connection-error=出現內部伺服器連線問題 velocity.error.logging-in-too-fast=你登錄太快,請稍後再試 velocity.error.online-mode-only=你沒有登入你的Minecraft賬號。如果你已經登入,請嘗試重啟你的Minecraft用戶端。 velocity.error.player-connection-error=你的連線發生內部錯誤 velocity.error.modern-forwarding-needs-new-client=此伺服器只兼容Minecraft版本1.13以上 velocity.error.modern-forwarding-failed=你的伺服器未向代理伺服器發送轉發請求,請確保你的伺服器已配置Velocity轉發 -velocity.error.moved-to-new-server=你已被踢出{0}\:{1} +velocity.error.moved-to-new-server=你已被踢出\: velocity.error.no-available-servers=當前沒有可以連接你的伺服器,請稍後再試或聯繫管理員 velocity.error.illegal-chat-characters=Illegal characters in chat # Commands velocity.command.generic-error=執行命令時發生錯誤 velocity.command.command-does-not-exist=此命令不存在 velocity.command.players-only=只有玩家能執行此命令 -velocity.command.server-does-not-exist=指定的伺服器 {0} 不存在 -velocity.command.player-not-found=The specified player {0} does not exist. -velocity.command.server-current-server=您已連接至 {0}。 +velocity.command.server-does-not-exist=指定的伺服器 不存在 +velocity.command.player-not-found=The specified player does not exist. +velocity.command.server-current-server=您已連接至 。 velocity.command.server-too-many=設置的伺服器國多,請使用 Tab 鍵補全以查看所有可用的服务器。 velocity.command.server-available=可用的伺服器: -velocity.command.server-tooltip-player-online={0} 個玩家在線 -velocity.command.server-tooltip-players-online={0} 個玩家在線 +velocity.command.server-tooltip-player-online= 個玩家在線 +velocity.command.server-tooltip-players-online= 個玩家在線 velocity.command.server-tooltip-current-server=當前已連接至此伺服器 velocity.command.server-tooltip-offer-connect-server=點擊連接至此伺服器 -velocity.command.glist-player-singular=共有 {0} 個玩家已連接至此代理伺服器。 -velocity.command.glist-player-plural=共有 {0} 個玩家已連接至此代理伺服器。 +velocity.command.glist-player-singular=共有 個玩家已連接至此代理伺服器。 +velocity.command.glist-player-plural=共有 個玩家已連接至此代理伺服器。 velocity.command.glist-view-all=使用 /glist all 命令來查看所有伺服器的玩家列表。 velocity.command.reload-success=Velocity 配置重新加載完成。 velocity.command.reload-failure=無法重新加載 Velocity 配置,請查看控制台了解詳情。 -velocity.command.version-copyright=Copyright 2018-{2} {0} ( {1} 的授權條款爲: GNU 通用公共授權條款第三版) +velocity.command.version-copyright=Copyright 2018- 的授權條款爲: GNU 通用公共授權條款第三版) velocity.command.no-plugins=目前未有安裝任何 Velocity 插件。 -velocity.command.plugins-list=插件: {0} -velocity.command.plugin-tooltip-website=網站: {0} -velocity.command.plugin-tooltip-author=作者: {0} -velocity.command.plugin-tooltip-authors=作者: {0} +velocity.command.plugins-list=插件: +velocity.command.plugin-tooltip-website=網站: +velocity.command.plugin-tooltip-author=作者: +velocity.command.plugin-tooltip-authors=作者: velocity.command.dump-uploading=正在收集並上載 Velocity 設定資料... velocity.command.dump-send-error=與 Velocity 伺服器通信時發生錯誤,伺服器可能暫時不可用或您的網路設置存在問題。您可在 Velocity 伺服器日志或控制台中了解詳情。 velocity.command.dump-success=已創建關於此代理的匿名反饋數據。若開發人員需要,您可與其分享以下鏈接: diff --git a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_TW.properties b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_TW.properties index b7fe1b5b..8b0ff331 100644 --- a/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_TW.properties +++ b/proxy/src/main/resources/com/velocitypowered/proxy/l10n/messages_zh_TW.properties @@ -18,42 +18,42 @@ velocity.error.already-connected=您已經連線到此伺服器了! velocity.error.already-connected-proxy=您已經連線到此代理伺服器了! velocity.error.already-connecting=您已經在嘗試連線伺服器了! -velocity.error.cant-connect=無法連線到 {0}:{1} -velocity.error.connecting-server-error=無法將您連線至 {0},請稍後再試。 -velocity.error.connected-server-error=您與 {0} 的連線出現問題。 +velocity.error.cant-connect=無法連線到 +velocity.error.connecting-server-error=無法將您連線至 ,請稍後再試。 +velocity.error.connected-server-error=您與 的連線出現問題。 velocity.error.internal-server-connection-error=發送內部伺服器連線錯誤。 velocity.error.logging-in-too-fast=您的登入過於頻繁,請稍後再試。 velocity.error.online-mode-only=您尚未登入至 Minecraft 帳號。若您已登入,請嘗試重啟您的啟動器。 velocity.error.player-connection-error=您的連線發生內部錯誤。 velocity.error.modern-forwarding-needs-new-client=此伺服器僅相容 Minecraft 1.13 及更高版本。 velocity.error.modern-forwarding-failed=您的伺服器未向代理伺服器轉發請求,請確保已配置 Velocity 轉發。 -velocity.error.moved-to-new-server=您已被踢出 {0}:{1} +velocity.error.moved-to-new-server=您已被踢出 velocity.error.no-available-servers=您當前沒有可連線的伺服器,請稍後重試或聯絡管理員。 velocity.error.illegal-chat-characters=聊天欄中出現不允許的字符 # Commands velocity.command.generic-error=執行此指令時發生錯誤。 velocity.command.command-does-not-exist=此指令不存在。 velocity.command.players-only=只有玩家才能執行這個指令。 -velocity.command.server-does-not-exist=指定的伺服器 {0} 不存在。 -velocity.command.player-not-found=指定的玩家 {0} 不存在。 -velocity.command.server-current-server=您已連線到 {0}。 +velocity.command.server-does-not-exist=指定的伺服器 不存在。 +velocity.command.player-not-found=指定的玩家 不存在。 +velocity.command.server-current-server=您已連線到 。 velocity.command.server-too-many=設定的伺服器過多,請使用 Tab 鍵補全來查看所有可用的伺服器。 velocity.command.server-available=可用的伺服器: -velocity.command.server-tooltip-player-online={0} 名玩家在線 -velocity.command.server-tooltip-players-online={0} 名玩家在線 +velocity.command.server-tooltip-player-online= 名玩家在線 +velocity.command.server-tooltip-players-online= 名玩家在線 velocity.command.server-tooltip-current-server=當前已連線至此伺服器 velocity.command.server-tooltip-offer-connect-server=點擊連線至此伺服器 -velocity.command.glist-player-singular=共有 {0} 名玩家已連線至此代理伺服器。 -velocity.command.glist-player-plural=共有 {0} 名玩家已連線至此代理伺服器。 +velocity.command.glist-player-singular=共有 名玩家已連線至此代理伺服器。 +velocity.command.glist-player-plural=共有 名玩家已連線至此代理伺服器。 velocity.command.glist-view-all=使用 /glist all 命令來查看所有伺服器的全部玩家列表。 velocity.command.reload-success=Velocity 配置已成功重載。 velocity.command.reload-failure=無法重載 Velocity 配置,請查看控制台了解詳情。 -velocity.command.version-copyright=Copyright 2018-{2} {0}。{1} 以 GNU 通用公共許可證第三版授權。 +velocity.command.version-copyright=Copyright 2018- 以 GNU 通用公共許可證第三版授權。 velocity.command.no-plugins=當前沒有安裝任何插件。 -velocity.command.plugins-list=插件:{0} -velocity.command.plugin-tooltip-website=網站:{0} -velocity.command.plugin-tooltip-author=作者:{0} -velocity.command.plugin-tooltip-authors=作者:{0} +velocity.command.plugins-list=插件: +velocity.command.plugin-tooltip-website=網站: +velocity.command.plugin-tooltip-author=作者: +velocity.command.plugin-tooltip-authors=作者: velocity.command.dump-uploading=正在上傳已收集的訊息... velocity.command.dump-send-error=與 Velocity 伺服器通訊時發生錯誤,伺服器可能暫不可用或您的網路設置存在問題。您可在 Velocity 伺服器日誌或控制台中了解詳情。 velocity.command.dump-success=已創建關於此代理的匿名反饋資料。若開發者需要,您可與其分享以下連結: From fe8dc5eaa2bdd9b7509f6f81e1c13fa6c571e324 Mon Sep 17 00:00:00 2001 From: Emil <12966472+Emilxyz@users.noreply.github.com> Date: Sun, 25 Jan 2026 21:56:55 +0100 Subject: [PATCH 16/48] fix: TranslatableMapper not using fallback translation (#1716) --- .../com/velocitypowered/proxy/util/TranslatableMapper.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/TranslatableMapper.java b/proxy/src/main/java/com/velocitypowered/proxy/util/TranslatableMapper.java index 6f30d3d1..20ab4329 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/util/TranslatableMapper.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/TranslatableMapper.java @@ -43,6 +43,12 @@ public enum TranslatableMapper implements BiConsumer Date: Sun, 25 Jan 2026 21:20:14 -0800 Subject: [PATCH 17/48] fix #1695: add "velocity.legacyChatMaxServerboundLength" system property to allow overriding default legacy chat max length --- .../packet/chat/legacy/LegacyChatPacket.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java index 80b239d5..f5bb6b4f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java @@ -32,12 +32,24 @@ public class LegacyChatPacket implements MinecraftPacket { public static final byte GAME_INFO_TYPE = (byte) 2; public static final int MAX_SERVERBOUND_MESSAGE_LENGTH = 256; + private static final int MAX_SERVERBOUND_MESSAGE_LENGTH_LEGACY = getMaxServerboundMessageLength(); public static final UUID EMPTY_SENDER = new UUID(0, 0); private @Nullable String message; private byte type; private @Nullable UUID sender; + private static int getMaxServerboundMessageLength() { + final String value = System.getProperty("velocity.legacyChatMaxServerboundLength"); + if (value != null) { + try { + return Integer.parseInt(value.trim()); + } catch (final NumberFormatException e) { + } + } + return 100; + } + public LegacyChatPacket() { } @@ -92,7 +104,10 @@ public class LegacyChatPacket implements MinecraftPacket { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { message = ProtocolUtils.readString(buf, direction == ProtocolUtils.Direction.CLIENTBOUND - ? 262144 : version.noLessThan(ProtocolVersion.MINECRAFT_1_11) ? 256 : 100); + ? 262144 + : version.noLessThan(ProtocolVersion.MINECRAFT_1_11) + ? MAX_SERVERBOUND_MESSAGE_LENGTH + : MAX_SERVERBOUND_MESSAGE_LENGTH_LEGACY); if (direction == ProtocolUtils.Direction.CLIENTBOUND && version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) { type = buf.readByte(); From 7d0c002f89d1cc916fd7525bcb4f2a0f4bc31649 Mon Sep 17 00:00:00 2001 From: R00tB33rMan <36140389+R00tB33rMan@users.noreply.github.com> Date: Thu, 29 Jan 2026 08:31:50 -0500 Subject: [PATCH 18/48] Add various missing jd, bump remaining deps (#1718) --- api/build.gradle.kts | 9 +- .../plugin/ap/PluginAnnotationProcessor.java | 9 + .../ap/SerializedPluginDescription.java | 74 ++++++++ .../api/command/CommandSource.java | 30 ++-- .../api/command/VelocityBrigadierMessage.java | 6 + .../api/event/Continuation.java | 4 +- .../api/event/EventHandler.java | 16 ++ .../api/event/EventManager.java | 1 + .../velocitypowered/api/event/PostOrder.java | 29 +++- .../api/event/ResultedEvent.java | 35 ++++ .../event/command/CommandExecuteEvent.java | 14 ++ .../command/PlayerAvailableCommandsEvent.java | 10 ++ .../connection/ConnectionHandshakeEvent.java | 16 ++ .../api/event/connection/DisconnectEvent.java | 44 ++++- .../api/event/connection/LoginEvent.java | 10 ++ .../event/connection/PluginMessageEvent.java | 41 +++++ .../api/event/connection/PostLoginEvent.java | 10 ++ .../api/event/connection/PreLoginEvent.java | 26 +++ .../event/connection/PreTransferEvent.java | 37 ++++ .../permission/PermissionsSetupEvent.java | 16 ++ .../api/event/player/CookieReceiveEvent.java | 25 +++ .../api/event/player/CookieRequestEvent.java | 15 ++ .../api/event/player/CookieStoreEvent.java | 27 +++ .../event/player/GameProfileRequestEvent.java | 21 ++- .../event/player/KickedFromServerEvent.java | 22 +++ .../player/PlayerChannelRegisterEvent.java | 16 ++ .../player/PlayerChannelUnregisterEvent.java | 20 +++ .../api/event/player/PlayerChatEvent.java | 15 ++ .../PlayerChooseInitialServerEvent.java | 10 ++ .../event/player/PlayerClientBrandEvent.java | 16 +- .../api/event/player/PlayerModInfoEvent.java | 16 ++ .../player/PlayerResourcePackStatusEvent.java | 10 ++ .../player/PlayerSettingsChangedEvent.java | 16 ++ .../event/player/ServerConnectedEvent.java | 15 ++ .../player/ServerLoginPluginMessageEvent.java | 26 +++ .../event/player/ServerPostConnectEvent.java | 7 + .../event/player/ServerPreConnectEvent.java | 5 + .../player/ServerResourcePackRemoveEvent.java | 3 + .../player/ServerResourcePackSendEvent.java | 21 +++ .../PlayerConfigurationEvent.java | 1 + .../PlayerEnterConfigurationEvent.java | 3 +- .../PlayerEnteredConfigurationEvent.java | 1 + .../PlayerFinishConfigurationEvent.java | 3 +- .../PlayerFinishedConfigurationEvent.java | 1 + .../api/event/proxy/ListenerBoundEvent.java | 16 ++ .../api/event/proxy/ListenerCloseEvent.java | 16 ++ .../api/event/proxy/ProxyInitializeEvent.java | 6 + .../api/event/proxy/ProxyPingEvent.java | 6 + .../event/proxy/ProxyPreShutdownEvent.java | 6 + .../api/event/proxy/ProxyReloadEvent.java | 6 + .../api/event/proxy/ProxyShutdownEvent.java | 6 + .../proxy/server/ServerRegisteredEvent.java | 6 + .../proxy/server/ServerUnregisteredEvent.java | 6 + .../api/network/HandshakeIntent.java | 17 ++ .../api/network/ListenerType.java | 6 + .../api/network/ProtocolState.java | 5 + .../api/network/ProtocolVersion.java | 162 +++++++++++++++++- .../api/permission/Tristate.java | 2 +- .../api/plugin/InvalidPluginException.java | 19 ++ .../api/plugin/PluginDescription.java | 6 + .../com/velocitypowered/api/proxy/Player.java | 25 +-- .../api/proxy/crypto/IdentifiedKey.java | 23 ++- .../api/proxy/crypto/KeySigned.java | 2 +- .../messages/LegacyChannelIdentifier.java | 5 + .../messages/MinecraftChannelIdentifier.java | 15 ++ .../api/proxy/player/PlayerSettings.java | 24 +++ .../api/proxy/player/ResourcePackInfo.java | 7 +- .../api/proxy/player/SkinParts.java | 40 +++++ .../api/proxy/player/TabListEntry.java | 3 + .../api/proxy/server/QueryResponse.java | 18 +- .../api/proxy/server/ServerInfo.java | 18 +- .../api/proxy/server/ServerPing.java | 129 +++++++++++++- .../velocitypowered/api/util/GameProfile.java | 15 ++ .../com/velocitypowered/api/util/ModInfo.java | 24 +++ .../api/util/ProxyVersion.java | 15 ++ .../velocitypowered/api/util/ServerLink.java | 32 ++++ gradle/libs.versions.toml | 10 +- .../natives/util/MoreByteBufUtils.java | 4 +- proxy/build.gradle.kts | 8 +- .../velocitypowered/proxy/VelocityServer.java | 2 +- .../handler/ModernResourcePackHandler.java | 2 +- .../handler/ResourcePackHandler.java | 1 + .../proxy/event/VelocityEventManager.java | 62 +++---- .../proxy/protocol/ProtocolUtils.java | 6 +- .../packet/AvailableCommandsPacket.java | 7 + .../proxy/protocol/packet/BossBarPacket.java | 88 ++++++++-- .../packet/BundleDelimiterPacket.java | 8 + .../protocol/packet/ClientSettingsPacket.java | 33 +++- .../ClientboundCookieRequestPacket.java | 5 + .../packet/ClientboundSoundEntityPacket.java | 22 ++- .../packet/ClientboundStopSoundPacket.java | 12 +- .../packet/ClientboundStoreCookiePacket.java | 5 + .../protocol/packet/DialogClearPacket.java | 7 + .../protocol/packet/DialogShowPacket.java | 7 + .../protocol/packet/DisconnectPacket.java | 26 ++- .../packet/EncryptionRequestPacket.java | 6 + .../packet/EncryptionResponsePacket.java | 19 +- .../protocol/packet/HandshakePacket.java | 10 +- .../packet/HeaderAndFooterPacket.java | 8 +- .../proxy/protocol/packet/JoinGamePacket.java | 30 ++-- .../protocol/packet/KeepAlivePacket.java | 5 + .../protocol/packet/LegacyDisconnect.java | 20 ++- .../packet/LegacyHandshakePacket.java | 5 + .../protocol/packet/LegacyPingPacket.java | 5 + .../packet/LegacyPlayerListItemPacket.java | 48 ++++-- .../packet/LoginAcknowledgedPacket.java | 9 +- .../packet/LoginPluginMessagePacket.java | 17 ++ .../packet/LoginPluginResponsePacket.java | 11 ++ .../protocol/packet/PingIdentifyPacket.java | 3 + .../protocol/packet/PluginMessagePacket.java | 12 +- .../packet/RemovePlayerInfoPacket.java | 4 + .../packet/RemoveResourcePackPacket.java | 6 +- .../packet/ResourcePackRequestPacket.java | 26 ++- .../packet/ResourcePackResponsePacket.java | 32 +++- .../proxy/protocol/packet/RespawnPacket.java | 26 +++ .../protocol/packet/ServerDataPacket.java | 15 +- .../protocol/packet/ServerLoginPacket.java | 31 +++- .../packet/ServerLoginSuccessPacket.java | 16 ++ .../ServerboundCookieResponsePacket.java | 5 + .../ServerboundCustomClickActionPacket.java | 6 + .../protocol/packet/SetCompressionPacket.java | 4 + .../protocol/packet/StatusPingPacket.java | 4 + .../protocol/packet/StatusRequestPacket.java | 4 +- .../protocol/packet/StatusResponsePacket.java | 9 + .../packet/TabCompleteRequestPacket.java | 9 + .../packet/TabCompleteResponsePacket.java | 6 + .../proxy/protocol/packet/TransferPacket.java | 14 ++ .../packet/UpsertPlayerInfoPacket.java | 31 ++-- .../packet/brigadier/ArgumentIdentifier.java | 19 +- .../brigadier/ArgumentPropertyRegistry.java | 16 +- .../brigadier/ArgumentPropertySerializer.java | 10 ++ .../packet/brigadier/ModArgumentProperty.java | 11 ++ .../RegistryIdArgumentSerializer.java | 10 ++ .../packet/brigadier/RegistryKeyArgument.java | 9 + .../brigadier/RegistryKeyArgumentList.java | 29 ++++ .../RegistryKeyArgumentSerializer.java | 6 + .../brigadier/TimeArgumentSerializer.java | 6 + .../chat/ChatAcknowledgementPacket.java | 59 ++++--- .../protocol/packet/chat/ChatHandler.java | 16 ++ .../proxy/protocol/packet/chat/ChatQueue.java | 45 ++++- .../protocol/packet/chat/ChatTimeKeeper.java | 17 ++ .../proxy/protocol/packet/chat/ChatType.java | 8 +- .../protocol/packet/chat/CommandHandler.java | 66 +++++-- .../protocol/packet/chat/ComponentHolder.java | 131 ++++++++++---- .../packet/chat/LastSeenMessages.java | 34 +++- .../chat/PlayerChatCompletionPacket.java | 8 + .../chat/RateLimitedCommandHandler.java | 59 ++++--- .../packet/chat/RemoteChatSession.java | 5 + .../packet/chat/SystemChatPacket.java | 7 +- .../chat/builder/ChatBuilderFactory.java | 11 ++ .../packet/chat/builder/ChatBuilderV2.java | 7 + .../packet/chat/keyed/KeyedChatBuilder.java | 6 + .../packet/chat/keyed/KeyedChatHandler.java | 25 +++ .../chat/keyed/KeyedCommandHandler.java | 16 +- .../chat/keyed/KeyedPlayerChatPacket.java | 7 + .../chat/keyed/KeyedPlayerCommandPacket.java | 7 + .../packet/chat/legacy/LegacyChatBuilder.java | 7 + .../packet/chat/legacy/LegacyChatHandler.java | 7 + .../packet/chat/legacy/LegacyChatPacket.java | 8 + .../chat/legacy/LegacyCommandHandler.java | 17 +- .../chat/session/SessionChatBuilder.java | 7 + .../chat/session/SessionChatHandler.java | 10 +- .../chat/session/SessionCommandHandler.java | 16 +- .../chat/session/SessionPlayerChatPacket.java | 16 ++ .../session/SessionPlayerCommandPacket.java | 90 ++++++++-- .../session/UnsignedPlayerCommandPacket.java | 13 +- .../packet/config/ActiveFeaturesPacket.java | 7 + .../ClientboundCustomReportDetailsPacket.java | 66 +++---- .../config/ClientboundServerLinksPacket.java | 123 +++++++------ .../config/CodeOfConductAcceptPacket.java | 6 + .../packet/config/CodeOfConductPacket.java | 8 + .../packet/config/FinishedUpdatePacket.java | 9 +- .../packet/config/KnownPacksPacket.java | 97 ++++++----- .../packet/config/RegistrySyncPacket.java | 12 ++ .../packet/config/StartUpdatePacket.java | 12 +- .../packet/config/TagsUpdatePacket.java | 10 +- .../LegacyMinecraftPingVersion.java | 10 ++ .../packet/title/GenericTitlePacket.java | 20 ++- .../packet/title/LegacyTitlePacket.java | 14 +- .../packet/title/TitleActionbarPacket.java | 10 ++ .../packet/title/TitleClearPacket.java | 9 + .../packet/title/TitleSubtitlePacket.java | 9 + .../packet/title/TitleTextPacket.java | 9 + .../packet/title/TitleTimesPacket.java | 9 + .../src/main/resources/default-velocity.toml | 2 +- 185 files changed, 2990 insertions(+), 502 deletions(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 268a8197..5e503f6a 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { api(libs.guava) // DEPRECATED: Will be removed in Velocity Polymer - api("com.moandjiezana.toml:toml4j:0.7.2") + api("io.hotmoka:toml4j:0.7.3") api(platform(libs.adventure.bom)) api("net.kyori:adventure-api") @@ -55,8 +55,6 @@ tasks { } } withType { - exclude("com/velocitypowered/api/plugin/ap/**") - val o = options as StandardJavadocDocletOptions o.encoding = "UTF-8" o.source = "21" @@ -66,7 +64,7 @@ tasks { "https://www.javadocs.dev/org.slf4j/slf4j-api/${libs.slf4j.get().version}/", "https://guava.dev/releases/${libs.guava.get().version}/api/docs/", "https://google.github.io/guice/api-docs/${libs.guice.get().version}/javadoc/", - "https://docs.oracle.com/en/java/javase/17/docs/api/", + "https://docs.oracle.com/en/java/javase/21/docs/api/", "https://jd.advntr.dev/api/${libs.adventure.bom.get().version}/", "https://jd.advntr.dev/text-minimessage/${libs.adventure.bom.get().version}/", "https://jd.advntr.dev/key/${libs.adventure.bom.get().version}/", @@ -79,8 +77,5 @@ tasks { "implNote:a:Implementation Note:", "sinceMinecraft:a:Since Minecraft:" ) - - // Disable the crazy super-strict doclint tool in Java 8 - o.addStringOption("Xdoclint:none", "-quiet") } } diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java index b44f2847..6424d34e 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java @@ -36,6 +36,15 @@ import javax.tools.StandardLocation; @SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"}) public class PluginAnnotationProcessor extends AbstractProcessor { + /** + * Creates a new {@code PluginAnnotationProcessor}. + * + *

The processor is instantiated by the Java compiler and initialized via + * {@link #init(ProcessingEnvironment)}.

+ */ + public PluginAnnotationProcessor() { + } + private ProcessingEnvironment environment; private String pluginClassFound; private boolean warnedAboutMultiplePlugins; diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java index b712d896..b8a35ec9 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java @@ -24,7 +24,19 @@ import org.checkerframework.checker.nullness.qual.Nullable; */ public final class SerializedPluginDescription { + /** + * The string pattern used to validate plugin IDs. + * + *

Plugin IDs must start with a lowercase letter and may contain lowercase letters, + * digits, hyphens, and underscores. The total length must not exceed 64 characters.

+ */ public static final String ID_PATTERN_STRING = "[a-z][a-z0-9-_]{0,63}"; + /** + * The compiled pattern used to validate plugin IDs. + * + *

Plugin IDs must start with a lowercase letter and may contain lowercase letters, + * digits, hyphens, and underscores. The total length must not exceed 64 characters.

+ */ public static final Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING); // @Nullable is used here to make GSON skip these in the serialized file @@ -64,34 +76,78 @@ public final class SerializedPluginDescription { .collect(Collectors.toList()), dependencies, qualifiedName); } + /** + * Gets the ID of the plugin this dependency refers to. + * + * @return the plugin ID + */ public String getId() { return id; } + /** + * Gets the human-readable name of the plugin. + * + * @return the plugin's name, or {@code null} if not specified + */ public @Nullable String getName() { return name; } + /** + * Gets the version string of the plugin. + * + * @return the plugin version, or {@code null} if not specified + */ public @Nullable String getVersion() { return version; } + /** + * Gets the plugin's description, typically a short summary of its functionality. + * + * @return the description, or {@code null} if not specified + */ public @Nullable String getDescription() { return description; } + /** + * Gets the website URL for the plugin. + * + *

This is often used to link to documentation, support, or the plugin's homepage.

+ * + * @return the plugin URL, or {@code null} if not specified + */ public @Nullable String getUrl() { return url; } + /** + * Gets the list of authors who contributed to the plugin. + * + * @return an immutable list of authors; empty if none were specified + */ public List getAuthors() { return authors == null ? ImmutableList.of() : authors; } + /** + * Gets the list of declared dependencies for the plugin. + * + *

Dependencies may be required or optional and describe other plugins, this one depends.

+ * + * @return an immutable list of plugin dependencies + */ public List getDependencies() { return dependencies == null ? ImmutableList.of() : dependencies; } + /** + * Gets the fully qualified name of the plugin's main class. + * + * @return the main class name + */ public String getMain() { return main; } @@ -142,15 +198,33 @@ public final class SerializedPluginDescription { private final String id; private final boolean optional; + /** + * Constructs a new dependency class. + * + * @param id the ID of the dependent plugin + * @param optional whether the dependency is optional + */ public Dependency(String id, boolean optional) { this.id = id; this.optional = optional; } + /** + * Gets the ID of the plugin this dependency refers to. + * + * @return the plugin ID + */ public String getId() { return id; } + /** + * Indicates whether this dependency is optional. + * + *

Optional dependencies are not required for the plugin to load.

+ * + * @return {@code true} if the dependency is optional; {@code false} otherwise + */ public boolean isOptional() { return optional; } diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandSource.java b/api/src/main/java/com/velocitypowered/api/command/CommandSource.java index 3cc03925..24d5272d 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandSource.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandSource.java @@ -25,20 +25,20 @@ public interface CommandSource extends Audience, PermissionSubject { * @param message MiniMessage content * @see
MiniMessage docs * for more information on the format. - **/ + */ default void sendRichMessage(final @NotNull String message) { this.sendMessage(MiniMessage.miniMessage().deserialize(message, this)); } /** - * Sends a message with the MiniMessage format to this source. - * - * @param message MiniMessage content - * @param resolvers resolvers to use - * @see MiniMessage docs - * and MiniMessage Placeholders docs - * for more information on the format. - **/ + * Sends a message with the MiniMessage format to this source. + * + * @param message MiniMessage content + * @param resolvers resolvers to use + * @see MiniMessage docs + * and MiniMessage Placeholders docs + * for more information on the format. + */ default void sendRichMessage( final @NotNull String message, final @NotNull TagResolver @NotNull... resolvers @@ -47,13 +47,13 @@ public interface CommandSource extends Audience, PermissionSubject { } /** - * Sends a plain message to this source. - * - * @param message plain message - * @apiNote This method will not apply any form of parse to the text provided, - * however, it is recommended not to use legacy color codes as this is a deprecated format + * Sends a plain message to this source. + * + * @param message plain message + * @apiNote This method will not apply any form of parse to the text provided, + * however, it is recommended not to use legacy color codes as this is a deprecated format * and not recommended. - */ + */ default void sendPlainMessage(final @NotNull String message) { this.sendMessage(Component.text(message)); } diff --git a/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java b/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java index 0ae69591..bd6415c3 100644 --- a/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java +++ b/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java @@ -20,6 +20,12 @@ import org.jetbrains.annotations.NotNull; */ public final class VelocityBrigadierMessage implements Message, ComponentLike { + /** + * Creates a new {@link VelocityBrigadierMessage} using the given {@link Component} as the message. + * + * @param message the component to use as the tooltip message + * @return a new instance of {@link VelocityBrigadierMessage} + */ public static VelocityBrigadierMessage tooltip(Component message) { return new VelocityBrigadierMessage(message); } diff --git a/api/src/main/java/com/velocitypowered/api/event/Continuation.java b/api/src/main/java/com/velocitypowered/api/event/Continuation.java index 30672ef6..5c17bf7b 100644 --- a/api/src/main/java/com/velocitypowered/api/event/Continuation.java +++ b/api/src/main/java/com/velocitypowered/api/event/Continuation.java @@ -20,6 +20,8 @@ public interface Continuation { /** * Resumes the continuation after the executed task failed. + * + * @param exception the {@link Throwable} that caused the failure */ void resumeWithException(Throwable exception); -} \ No newline at end of file +} diff --git a/api/src/main/java/com/velocitypowered/api/event/EventHandler.java b/api/src/main/java/com/velocitypowered/api/event/EventHandler.java index 3f0a1aa0..ca8b164b 100644 --- a/api/src/main/java/com/velocitypowered/api/event/EventHandler.java +++ b/api/src/main/java/com/velocitypowered/api/event/EventHandler.java @@ -13,12 +13,28 @@ import org.checkerframework.checker.nullness.qual.Nullable; * Represents an interface to perform direct dispatch of an event. This makes integration easier to * achieve with platforms such as RxJava. While this interface can be used to implement an awaiting * event handler, {@link AwaitingEventExecutor} provides a more idiomatic means to doing so. + * + * @param the event type this handler accepts */ @FunctionalInterface public interface EventHandler { + /** + * Executes this handler synchronously with the given event. + * + * @param event the event to handle + */ void execute(E event); + /** + * Executes this handler asynchronously with the given event. + * + *

If asynchronous handling is not implemented, the event is executed synchronously + * and this method returns {@code null}.

+ * + * @param event the event to handle + * @return an {@link EventTask} representing the async task, or {@code null} if not async + */ default @Nullable EventTask executeAsync(E event) { execute(event); return null; diff --git a/api/src/main/java/com/velocitypowered/api/event/EventManager.java b/api/src/main/java/com/velocitypowered/api/event/EventManager.java index ed11986c..b8d604cf 100644 --- a/api/src/main/java/com/velocitypowered/api/event/EventManager.java +++ b/api/src/main/java/com/velocitypowered/api/event/EventManager.java @@ -73,6 +73,7 @@ public interface EventManager { * servicing connections while a plugin handles a potentially long-running operation such as a * database query. * + * @param the event type * @param event the event to fire * @return a {@link CompletableFuture} representing the posted event */ diff --git a/api/src/main/java/com/velocitypowered/api/event/PostOrder.java b/api/src/main/java/com/velocitypowered/api/event/PostOrder.java index 98fa2e86..21b418cb 100644 --- a/api/src/main/java/com/velocitypowered/api/event/PostOrder.java +++ b/api/src/main/java/com/velocitypowered/api/event/PostOrder.java @@ -12,7 +12,34 @@ package com.velocitypowered.api.event; */ public enum PostOrder { - FIRST, EARLY, NORMAL, LATE, LAST, + /** + * Indicates the listener should be invoked first, before any other listener. + * This order is suitable for listeners that must handle the event before others. + */ + FIRST, + /** + * Indicates the listener should be invoked early, but after listeners with {@link #FIRST}. + * This order is suitable for handling the event before most other listeners. + */ + EARLY, + /** + * Indicates the listener should be invoked in the normal order of execution. + * This is the default and most commonly used order. + */ + NORMAL, + /** + * Indicates the listener should be invoked later in the execution order, + * after listeners with {@link #NORMAL}. + * This order is suitable for listeners that should observe the results of + * earlier listeners. + */ + LATE, + /** + * Indicates the listener should be invoked last, after all other listeners. + * This order is suitable for listeners that should run only after all others + * have completed handling the event. + */ + LAST, /** * Previously used to specify that {@link Subscribe#priority()} should be used. diff --git a/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java b/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java index 0aafd058..d2a33860 100644 --- a/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java @@ -15,6 +15,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** * Indicates an event that has a result attached to it. + * + * @param the type of result associated with the event */ public interface ResultedEvent { @@ -70,10 +72,20 @@ public interface ResultedEvent { return status ? "allowed" : "denied"; } + /** + * Returns a result indicating the event is allowed to proceed. + * + * @return an allowed {@link GenericResult} + */ public static GenericResult allowed() { return ALLOWED; } + /** + * Returns a result indicating the event is denied. + * + * @return a denied {@link GenericResult} + */ public static GenericResult denied() { return DENIED; } @@ -89,6 +101,12 @@ public interface ResultedEvent { private final boolean status; private final @Nullable Component reason; + /** + * Represents an allowed or denied result that may include a denial reason. + * + * @param status whether the result is allowed + * @param reason the component explaining why the result was denied, or {@code null} + */ protected ComponentResult(boolean status, @Nullable Component reason) { this.status = status; this.reason = reason; @@ -99,6 +117,11 @@ public interface ResultedEvent { return status; } + /** + * Returns the denial reason component, if present. + * + * @return an {@link Optional} containing the reason component if the result is denied + */ public Optional getReasonComponent() { return Optional.ofNullable(reason); } @@ -114,10 +137,22 @@ public interface ResultedEvent { return "denied"; } + /** + * Returns a result indicating the event is allowed to proceed. + * + * @return an allowed {@link ComponentResult} + */ public static ComponentResult allowed() { return ALLOWED; } + /** + * Returns a result indicating the event is denied, with the given reason component. + * + * @param reason the denial reason to show + * @return a denied {@link ComponentResult} + * @throws NullPointerException if the reason is null + */ public static ComponentResult denied(Component reason) { Preconditions.checkNotNull(reason, "reason"); return new ComponentResult(false, reason); diff --git a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java index 7ed704fc..6daa62a8 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java @@ -106,6 +106,8 @@ public final class CommandExecuteEvent implements ResultedEvent { /** * Represents information about a command invocation, including its signed state and source. * + * @param signedState the signed state of the command + * @param source the source of the command invocation * @since 3.4.0 */ public record InvocationInfo(SignedState signedState, Source source) { @@ -191,10 +193,22 @@ public final class CommandExecuteEvent implements ResultedEvent { this.command = command; } + /** + * Returns the command to be executed, if it was overridden. + * + * @return an {@link Optional} containing the new command string (without leading slash), + * or empty if no override is present + */ public Optional getCommand() { return Optional.ofNullable(command); } + /** + * Indicates whether this command should be forwarded directly to the backend server + * instead of being processed by the proxy. + * + * @return {@code true} if the command should be forwarded to the server, {@code false} otherwise + */ public boolean isForwardToServer() { return forward; } diff --git a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java index d00cffac..265fbdda 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java @@ -37,10 +37,20 @@ public class PlayerAvailableCommandsEvent { this.rootNode = checkNotNull(rootNode, "rootNode"); } + /** + * Gets the player that the available commands are being sent to. + * + * @return the targeted player + */ public Player getPlayer() { return player; } + /** + * Gets the root command node that represents the available commands. + * + * @return the Brigadier root command node + */ public RootCommandNode getRootNode() { return rootNode; } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java index e344b6c5..d3ddc0e3 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java @@ -21,6 +21,12 @@ public final class ConnectionHandshakeEvent { private final InboundConnection connection; private final HandshakeIntent intent; + /** + * Constructs a new {@link ConnectionHandshakeEvent}. + * + * @param connection the inbound connection from the client + * @param intent the intent of the handshake (e.g., login or status) + */ public ConnectionHandshakeEvent(InboundConnection connection, HandshakeIntent intent) { this.connection = Preconditions.checkNotNull(connection, "connection"); this.intent = Preconditions.checkNotNull(intent, "intent"); @@ -39,10 +45,20 @@ public final class ConnectionHandshakeEvent { this.intent = HandshakeIntent.LOGIN; } + /** + * Returns the inbound connection associated with this handshake. + * + * @return the connection + */ public InboundConnection getConnection() { return connection; } + /** + * Returns the {@link HandshakeIntent} associated with this connection handshake. + * + * @return the intent of the handshake + */ public HandshakeIntent getIntent() { return this.intent; } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java index bec7b745..4a2dba4f 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java @@ -17,12 +17,10 @@ import com.velocitypowered.api.proxy.Player; * Operations on the provided player, aside from basic data retrieval operations, may behave in * undefined ways. * - *

- * Velocity typically fires this event asynchronously and does not wait for a response. However, - * it will wait for all {@link DisconnectEvent}s for every player on the proxy to fire - * successfully before the proxy shuts down. This event is the sole exception to the - * {@link AwaitingEvent} contract. - *

+ *

Velocity typically fires this event asynchronously and does not wait for a response. However, + * it will wait for all {@link DisconnectEvent}s for every player on the proxy to fire + * successfully before the proxy shuts down. This event is the sole exception to the + * {@link AwaitingEvent} contract.

*/ @AwaitingEvent public final class DisconnectEvent { @@ -30,15 +28,31 @@ public final class DisconnectEvent { private final Player player; private final LoginStatus loginStatus; + /** + * Creates a new {@link DisconnectEvent}. + * + * @param player the player who disconnected + * @param loginStatus the status of the player's login at the time of disconnection + */ public DisconnectEvent(Player player, LoginStatus loginStatus) { this.player = Preconditions.checkNotNull(player, "player"); this.loginStatus = Preconditions.checkNotNull(loginStatus, "loginStatus"); } + /** + * Returns the player who disconnected. + * + * @return the player + */ public Player getPlayer() { return player; } + /** + * Returns the login status of the player at the time of disconnection. + * + * @return the login status + */ public LoginStatus getLoginStatus() { return loginStatus; } @@ -56,11 +70,29 @@ public final class DisconnectEvent { */ public enum LoginStatus { + /** + * The player completed a successful login to the proxy. + */ SUCCESSFUL_LOGIN, + /** + * The player was disconnected because another login with the same UUID occurred. + */ CONFLICTING_LOGIN, + /** + * The player voluntarily disconnected before completing the login. + */ CANCELLED_BY_USER, + /** + * The proxy disconnected the player before login completed. + */ CANCELLED_BY_PROXY, + /** + * The player disconnected on their own, but only after starting the login and before completing it. + */ CANCELLED_BY_USER_BEFORE_COMPLETE, + /** + * The player disconnected before joining the initial backend server. + */ PRE_SERVER_JOIN } } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java index 49408897..3ec01264 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java @@ -24,11 +24,21 @@ public final class LoginEvent implements ResultedEventThis value is {@code null} on 1.19.2 and lower, * up to 1.20.1 it is optional and from 1.20.2 it will always be available.

* @@ -129,14 +140,29 @@ public final class PreLoginEvent implements ResultedEvent getReasonComponent() { return Optional.ofNullable(reason); } + /** + * Checks if this result explicitly forces online mode for the connection. + * + * @return true if online mode is forced + */ public boolean isOnlineModeAllowed() { return result == Result.FORCE_ONLINE; } + /** + * Checks if this result explicitly forces offline mode for the connection. + * + * @return true if offline mode is forced + */ public boolean isForceOfflineMode() { return result == Result.FORCE_OFFLINE; } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java index 584ab005..37e96a7d 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java @@ -28,15 +28,31 @@ public final class PreTransferEvent implements ResultedEvent channels; + /** + * Constructs a new PlayerChannelRegisterEvent. + * + * @param player the player who sent the plugin message + * @param channels the list of channels the player is registering + */ public PlayerChannelRegisterEvent(Player player, List channels) { this.player = Preconditions.checkNotNull(player, "player"); this.channels = Preconditions.checkNotNull(channels, "channels"); } + /** + * Gets the player who sent the plugin message to register channels. + * + * @return the player involved in this event + */ public Player getPlayer() { return player; } + /** + * Gets the list of {@link ChannelIdentifier}s that the player registered. + * + * @return the list of registered channels + */ public List getChannels() { return channels; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java index 86eeb2bc..69e59da0 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java @@ -21,15 +21,35 @@ public final class PlayerChannelUnregisterEvent { private final Player player; private final List channels; + /** + * Constructs a new {@link PlayerChannelUnregisterEvent}. + * + * @param player the player that sent the unregister message + * @param channels the list of {@link ChannelIdentifier}s being unregistered + * @throws NullPointerException if {@code player} or {@code channels} is {@code null} + */ public PlayerChannelUnregisterEvent(Player player, List channels) { this.player = Preconditions.checkNotNull(player, "player"); this.channels = Preconditions.checkNotNull(channels, "channels"); } + /** + * Gets the {@link Player} who sent the unregister message. + * + * @return the player involved in this event + */ public Player getPlayer() { return player; } + /** + * Gets the list of {@link ChannelIdentifier}s that the player has unregistered. + * + *

These identifiers correspond to the plugin message channels that the client has + * indicated it will no longer use.

+ * + * @return the list of unregistered channels + */ public List getChannels() { return channels; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java index dd1fae29..6548cf60 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java @@ -38,10 +38,20 @@ public final class PlayerChatEvent implements ResultedEvent getMessage() { return Optional.ofNullable(message); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java index 73d41ecd..587d374a 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java @@ -37,10 +37,20 @@ public class PlayerChooseInitialServerEvent { this.initialServer = initialServer; } + /** + * Gets the player who is choosing the initial server. + * + * @return the connected player + */ public Player getPlayer() { return player; } + /** + * Gets the initial server the player will connect to. + * + * @return an {@link Optional} containing the selected server, or empty if none was set + */ public Optional getInitialServer() { return Optional.ofNullable(initialServer); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java index 268d5b6a..0a45093f 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java @@ -29,10 +29,20 @@ public final class PlayerClientBrandEvent { this.brand = Preconditions.checkNotNull(brand); } + /** + * Gets the player who sent the client brand. + * + * @return the player + */ public Player getPlayer() { return player; } + /** + * Gets the brand string sent by the client. + * + * @return the client brand + */ public String getBrand() { return brand; } @@ -40,9 +50,9 @@ public final class PlayerClientBrandEvent { @Override public String toString() { return "PlayerClientBrandEvent{" - + "player=" + player - + ", brand='" + brand + '\'' - + '}'; + + "player=" + player + + ", brand='" + brand + '\'' + + '}'; } } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java index eb0b4133..377b8b45 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java @@ -21,15 +21,31 @@ public final class PlayerModInfoEvent { private final Player player; private final ModInfo modInfo; + /** + * Constructs a new {@code PlayerModInfoEvent}. + * + * @param player the player sending their mod list + * @param modInfo the mod list information + */ public PlayerModInfoEvent(Player player, ModInfo modInfo) { this.player = Preconditions.checkNotNull(player, "player"); this.modInfo = Preconditions.checkNotNull(modInfo, "modInfo"); } + /** + * Returns the player who sent their mod list. + * + * @return the player + */ public Player getPlayer() { return player; } + /** + * Returns the mod information sent by the player. + * + * @return the mod information + */ public ModInfo getModInfo() { return modInfo; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java index d212666b..9e3f59f2 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java @@ -33,6 +33,8 @@ public class PlayerResourcePackStatusEvent { /** * Instantiates this event. * + * @param player the player affected by the status update + * @param status the status of the resource pack * @deprecated Use {@link PlayerResourcePackStatusEvent#PlayerResourcePackStatusEvent * (Player, UUID, Status, ResourcePackInfo)} instead. */ @@ -44,6 +46,9 @@ public class PlayerResourcePackStatusEvent { /** * Instantiates this event. * + * @param player the player affected by the status update + * @param status the status of the resource pack + * @param packInfo the resource pack metadata * @deprecated Use {@link PlayerResourcePackStatusEvent#PlayerResourcePackStatusEvent * (Player, UUID, Status, ResourcePackInfo)} instead. */ @@ -54,6 +59,11 @@ public class PlayerResourcePackStatusEvent { /** * Instantiates this event. + * + * @param player the player affected by the status update + * @param packId the unique ID of the resource pack + * @param status the status of the resource pack + * @param packInfo the resource pack metadata */ public PlayerResourcePackStatusEvent( Player player, UUID packId, Status status, ResourcePackInfo packInfo) { diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java index cd1bd01c..542633c7 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java @@ -22,15 +22,31 @@ public final class PlayerSettingsChangedEvent { private final Player player; private final PlayerSettings playerSettings; + /** + * Constructs a new PlayerSettingsChangedEvent. + * + * @param player the player who changed settings + * @param playerSettings the new settings sent by the client + */ public PlayerSettingsChangedEvent(Player player, PlayerSettings playerSettings) { this.player = Preconditions.checkNotNull(player, "player"); this.playerSettings = Preconditions.checkNotNull(playerSettings, "playerSettings"); } + /** + * Returns the player whose settings changed. + * + * @return the player + */ public Player getPlayer() { return player; } + /** + * Returns the new client settings sent by the player. + * + * @return the updated player settings + */ public PlayerSettings getPlayerSettings() { return playerSettings; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java index ac4452a0..48e98587 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java @@ -45,14 +45,29 @@ public final class ServerConnectedEvent { this.previousServer = previousServer; } + /** + * Returns the player involved in this event. + * + * @return the {@link Player} who connected + */ public Player getPlayer() { return player; } + /** + * Returns the server the player successfully connected to. + * + * @return the {@link RegisteredServer} the player connected to + */ public RegisteredServer getServer() { return server; } + /** + * Returns the server the player was previously connected to, if any. + * + * @return an {@link Optional} of the previous {@link RegisteredServer}, or empty if none + */ public Optional getPreviousServer() { return Optional.ofNullable(previousServer); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java index 9597e02a..d790d975 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java @@ -63,10 +63,20 @@ public class ServerLoginPluginMessageEvent implements ResultedEvent getServer() { return Optional.ofNullable(server); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java index 96d1bb8e..52901cf4 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java @@ -29,6 +29,9 @@ public class ServerResourcePackRemoveEvent implements ResultedEventVelocity will wait for this event before continuing/ending the configuration state.

* * @param player The player who can be configured. 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 05d6c2af..97a2ded0 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,8 +15,9 @@ import org.jetbrains.annotations.NotNull; /** * 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. - * However due to backend server being unable to keep the connection alive during state changes, + * 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. diff --git a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java index c1677706..6560f7bc 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull; /** * This event is executed when a player has entered the configuration state. + * *

From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed, * the {@linkplain Player#getProtocolState()} method is guaranteed * to return {@link ProtocolState#CONFIGURATION}.

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 50df5a8a..1cd3f283 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 @@ -14,8 +14,9 @@ import org.jetbrains.annotations.NotNull; /** * 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 during state changes, + * 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}.

* diff --git a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java index 517f119c..994a1d41 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java @@ -14,6 +14,7 @@ import org.jetbrains.annotations.NotNull; /** * This event is executed when a player has finished the configuration state. + * *

From this moment on, the {@link Player#getProtocolState()} method * will return {@link ProtocolState#PLAY}.

* diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java index 662e403d..1824a69c 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java @@ -19,15 +19,31 @@ public final class ListenerBoundEvent { private final InetSocketAddress address; private final ListenerType listenerType; + /** + * Constructs a new {@link ListenerBoundEvent}. + * + * @param address the socket address the listener is bound to + * @param listenerType the type of listener that was bound + */ public ListenerBoundEvent(InetSocketAddress address, ListenerType listenerType) { this.address = Preconditions.checkNotNull(address, "address"); this.listenerType = Preconditions.checkNotNull(listenerType, "listenerType"); } + /** + * Returns the socket address the listener is bound to. + * + * @return the bound socket address + */ public InetSocketAddress getAddress() { return address; } + /** + * Returns the type of listener that was bound. + * + * @return the listener type + */ public ListenerType getListenerType() { return listenerType; } diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java index c2551a35..da8c61d6 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java @@ -19,15 +19,31 @@ public final class ListenerCloseEvent { private final InetSocketAddress address; private final ListenerType listenerType; + /** + * Constructs a new {@link ListenerCloseEvent}. + * + * @param address the socket address the listener was bound to + * @param listenerType the type of listener being closed + */ public ListenerCloseEvent(InetSocketAddress address, ListenerType listenerType) { this.address = Preconditions.checkNotNull(address, "address"); this.listenerType = Preconditions.checkNotNull(listenerType, "listenerType"); } + /** + * Returns the socket address the listener was bound to. + * + * @return the bound socket address + */ public InetSocketAddress getAddress() { return address; } + /** + * Returns the type of listener being closed. + * + * @return the listener type + */ public ListenerType getListenerType() { return listenerType; } diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java index d01ce190..7e19f0e1 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java @@ -17,6 +17,12 @@ import com.velocitypowered.api.event.annotation.AwaitingEvent; @AwaitingEvent public final class ProxyInitializeEvent { + /** + * Creates a new {@code ProxyInitializeEvent}. + */ + public ProxyInitializeEvent() { + } + @Override public String toString() { return "ProxyInitializeEvent"; diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java index 63555436..14d40884 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java @@ -28,6 +28,12 @@ public final class ProxyPingEvent implements ResultedEventThis status can be caused by a {@link HandshakeIntent#STATUS}, * {@link HandshakeIntent#LOGIN} or {@link HandshakeIntent#TRANSFER} intent.

* If the intent is LOGIN or TRANSFER, the next state will be {@link #LOGIN}, @@ -24,6 +25,7 @@ public enum ProtocolState { HANDSHAKE, /** * Ping State of a connection. + * *

Connections with the {@link HandshakeIntent#STATUS} intent will pass through this state * and be disconnected after it requests the ping from the server * and the server responds with the respective ping.

@@ -31,11 +33,13 @@ public enum ProtocolState { STATUS, /** * Authentication State of a connection. + * *

At this moment the player is authenticating with the authentication servers.

*/ LOGIN, /** * Configuration State of a connection. + * *

At this point the player allows the server to send information * such as resource packs and plugin messages, at the same time the player * will send his client brand and the respective plugin messages @@ -46,6 +50,7 @@ public enum ProtocolState { CONFIGURATION, /** * Game State of a connection. + * *

In this state is where the whole game runs, the server is able to change * the player's state to {@link #CONFIGURATION} as needed in versions 1.20.2 and higher.

*/ diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index e803c302..c3eba765 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -21,6 +21,9 @@ import java.util.Set; * Represents each Minecraft protocol version. */ public enum ProtocolVersion implements Ordered { + /** + * Represents an unknown protocol version. + */ UNKNOWN(-1, "Unknown") { @Override public boolean isUnknown() { @@ -32,6 +35,9 @@ public enum ProtocolVersion implements Ordered { return false; } }, + /** + * Represents legacy protocol versions before 1.7. + */ LEGACY(-2, "Legacy") { @Override public boolean isLegacy() { @@ -43,57 +49,201 @@ public enum ProtocolVersion implements Ordered { return false; } }, - MINECRAFT_1_7_2(4, - "1.7.2", "1.7.3", "1.7.4", "1.7.5"), - MINECRAFT_1_7_6(5, - "1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10"), - MINECRAFT_1_8(47, - "1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9"), + /** + * Minecraft 1.7.2 to 1.7.5. + */ + MINECRAFT_1_7_2(4, "1.7.2", "1.7.3", "1.7.4", "1.7.5"), + /** + * Minecraft 1.7.6 to 1.7.10. + */ + MINECRAFT_1_7_6(5, "1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10"), + /** + * Minecraft 1.8 to 1.8.9. + */ + MINECRAFT_1_8(47, "1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9"), + /** + * Minecraft 1.9. + */ MINECRAFT_1_9(107, "1.9"), + /** + * Minecraft 1.9.1. + */ MINECRAFT_1_9_1(108, "1.9.1"), + /** + * Minecraft 1.9.2. + */ MINECRAFT_1_9_2(109, "1.9.2"), + /** + * Minecraft 1.9.3 to 1.9.4. + */ MINECRAFT_1_9_4(110, "1.9.3", "1.9.4"), + /** + * Minecraft 1.10 to 1.10.2. + */ MINECRAFT_1_10(210, "1.10", "1.10.1", "1.10.2"), + /** + * Minecraft 1.11. + */ MINECRAFT_1_11(315, "1.11"), + /** + * Minecraft 1.11.1 to 1.11.2. + */ MINECRAFT_1_11_1(316, "1.11.1", "1.11.2"), + /** + * Minecraft 1.12. + */ MINECRAFT_1_12(335, "1.12"), + /** + * Minecraft 1.12.1. + */ MINECRAFT_1_12_1(338, "1.12.1"), + /** + * Minecraft 1.12.2. + */ MINECRAFT_1_12_2(340, "1.12.2"), + /** + * Minecraft 1.13. + */ MINECRAFT_1_13(393, "1.13"), + /** + * Minecraft 1.13.1. + */ MINECRAFT_1_13_1(401, "1.13.1"), + /** + * Minecraft 1.13.2. + */ MINECRAFT_1_13_2(404, "1.13.2"), + /** + * Minecraft 1.14. + */ MINECRAFT_1_14(477, "1.14"), + /** + * Minecraft 1.14.1. + */ MINECRAFT_1_14_1(480, "1.14.1"), + /** + * Minecraft 1.14.2. + */ MINECRAFT_1_14_2(485, "1.14.2"), + /** + * Minecraft 1.14.3. + */ MINECRAFT_1_14_3(490, "1.14.3"), + /** + * Minecraft 1.14.4. + */ MINECRAFT_1_14_4(498, "1.14.4"), + /** + * Minecraft 1.15. + */ MINECRAFT_1_15(573, "1.15"), + /** + * Minecraft 1.15.1. + */ MINECRAFT_1_15_1(575, "1.15.1"), + /** + * Minecraft 1.15.2. + */ MINECRAFT_1_15_2(578, "1.15.2"), + /** + * Minecraft 1.16. + */ MINECRAFT_1_16(735, "1.16"), + /** + * Minecraft 1.16.1. + */ MINECRAFT_1_16_1(736, "1.16.1"), + /** + * Minecraft 1.16.2. + */ MINECRAFT_1_16_2(751, "1.16.2"), + /** + * Minecraft 1.16.3. + */ MINECRAFT_1_16_3(753, "1.16.3"), + /** + * Minecraft 1.16.4 to 1.16.5. + */ MINECRAFT_1_16_4(754, "1.16.4", "1.16.5"), + /** + * Minecraft 1.17. + */ MINECRAFT_1_17(755, "1.17"), + /** + * Minecraft 1.17.1. + */ MINECRAFT_1_17_1(756, "1.17.1"), + /** + * Minecraft 1.18 to 1.18.1. + */ MINECRAFT_1_18(757, "1.18", "1.18.1"), + /** + * Minecraft 1.18.2. + */ MINECRAFT_1_18_2(758, "1.18.2"), + /** + * Minecraft 1.19. + */ MINECRAFT_1_19(759, "1.19"), + /** + * Minecraft 1.19.1 to 1.19.2. + */ MINECRAFT_1_19_1(760, "1.19.1", "1.19.2"), + /** + * Minecraft 1.19.3. + */ MINECRAFT_1_19_3(761, "1.19.3"), + /** + * Minecraft 1.19.4. + */ MINECRAFT_1_19_4(762, "1.19.4"), + /** + * Minecraft 1.20 to 1.20.1. + */ MINECRAFT_1_20(763, "1.20", "1.20.1"), + /** + * Minecraft 1.20.2. + */ MINECRAFT_1_20_2(764, "1.20.2"), + /** + * Minecraft 1.20.3 to 1.20.4. + */ MINECRAFT_1_20_3(765, "1.20.3", "1.20.4"), + /** + * Minecraft 1.20.5 to 1.20.6. + */ MINECRAFT_1_20_5(766, "1.20.5", "1.20.6"), + /** + * Minecraft 1.21 to 1.21.1. + */ MINECRAFT_1_21(767, "1.21", "1.21.1"), + /** + * Minecraft 1.21.2 to 1.21.3. + */ MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"), + /** + * Minecraft 1.21.4. + */ MINECRAFT_1_21_4(769, "1.21.4"), + /** + * Minecraft 1.21.5. + */ MINECRAFT_1_21_5(770, "1.21.5"), + /** + * Minecraft 1.21.6. + */ MINECRAFT_1_21_6(771, "1.21.6"), + /** + * Minecraft 1.21.7 to 1.21.8. + */ MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"), + /** + * Minecraft 1.21.9 to 1.21.10. + */ MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"), + /** + * Minecraft 1.21.11. + */ MINECRAFT_1_21_11(774, "1.21.11"); private static final int SNAPSHOT_BIT = 30; diff --git a/api/src/main/java/com/velocitypowered/api/permission/Tristate.java b/api/src/main/java/com/velocitypowered/api/permission/Tristate.java index ddbe26a8..02f6924b 100644 --- a/api/src/main/java/com/velocitypowered/api/permission/Tristate.java +++ b/api/src/main/java/com/velocitypowered/api/permission/Tristate.java @@ -15,7 +15,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; * Represents three different states of a setting. * *

Possible values:

- *

+ * *
    *
  • {@link #TRUE} - a positive setting
  • *
  • {@link #FALSE} - a negative (negated) setting
  • diff --git a/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java b/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java index 1882d264..bee2a26d 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java @@ -12,18 +12,37 @@ package com.velocitypowered.api.plugin; */ public class InvalidPluginException extends Exception { + /** + * Creates a new exception with no detail message. + */ public InvalidPluginException() { super(); } + /** + * Creates a new exception with the specified detail message. + * + * @param message the detail message + */ public InvalidPluginException(String message) { super(message); } + /** + * Creates a new exception with the specified detail message and cause. + * + * @param message the detail message + * @param cause the cause of the exception + */ public InvalidPluginException(String message, Throwable cause) { super(message, cause); } + /** + * Creates a new exception with the specified cause. + * + * @param cause the cause of the exception + */ public InvalidPluginException(Throwable cause) { super(cause); } diff --git a/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java b/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java index 540b54ea..cbf9b487 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java @@ -96,6 +96,12 @@ public interface PluginDescription { return ImmutableSet.of(); } + /** + * Gets a specific dependency of the {@link Plugin} by its ID. + * + * @param id the ID of the dependency to look up + * @return an {@link Optional} containing the matching {@link PluginDependency}, or empty if not found + */ default Optional getDependency(String id) { return Optional.empty(); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index efe21cd7..456f6541 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -150,6 +150,8 @@ public interface Player extends /** * Returns the player's game profile. + * + * @return the player's profile */ GameProfile getGameProfile(); @@ -242,10 +244,10 @@ public interface Player extends * Gets the {@link ResourcePackInfo} of the currently applied * resource-pack or null if none. * - *

    Note that since 1.20.3 it is no longer recommended to use + *

    Note that since 1.20.3 it is no longer recommended to use * this method as it will only return the last applied * resource pack. To get all applied resource packs, use - * {@link #getAppliedResourcePacks()} instead.

    + * {@link #getAppliedResourcePacks()} instead.

    * * @return the applied resource pack or null if none. */ @@ -258,10 +260,10 @@ public interface Player extends * the user is currently downloading or is currently * prompted to install or null if none. * - *

    Note that since 1.20.3 it is no longer recommended to use + *

    Note that since 1.20.3 it is no longer recommended to use * this method as it will only return the last pending * resource pack. To get all pending resource packs, use - * {@link #getPendingResourcePacks()} instead.

    + * {@link #getPendingResourcePacks()} instead.

    * * @return the pending resource pack or null if none */ @@ -313,6 +315,7 @@ public interface Player extends /** * {@inheritDoc} + * *

    Note that this method does not send a plugin message to the server the player * is connected to. You should only use this method if you are trying to communicate * with a mod that is installed on the player's client.

    @@ -336,7 +339,6 @@ public interface Player extends Component.text(getUsername())))); } - /** * Gets the player's client brand. * @@ -384,12 +386,11 @@ public interface Player extends /** * {@inheritDoc} * - * * @apiNote This method is not currently implemented in Velocity * and will not perform any actions. * @see #playSound(Sound, Sound.Emitter) * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void playSound(@NotNull Sound sound) { @@ -402,7 +403,7 @@ public interface Player extends * and will not perform any actions. * @see #playSound(Sound, Sound.Emitter) * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void playSound(@NotNull Sound sound, double x, double y, double z) { @@ -445,7 +446,7 @@ public interface Player extends * and will not perform any actions. * * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void openBook(@NotNull Book book) { @@ -458,7 +459,7 @@ public interface Player extends * and will not perform any actions. * * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void showDialog(@NotNull DialogLike dialog) { @@ -471,7 +472,7 @@ public interface Player extends * and will not perform any actions. * * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void closeDialog() { @@ -521,4 +522,4 @@ public interface Player extends * @sinceMinecraft 1.21 */ void setServerLinks(@NotNull List links); -} \ No newline at end of file +} diff --git a/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java b/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java index d2a6cc94..b6c01121 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java @@ -28,7 +28,6 @@ public interface IdentifiedKey extends KeySigned { */ PublicKey getSignedPublicKey(); - /** * Validates a signature against this public key. * @@ -59,7 +58,15 @@ public interface IdentifiedKey extends KeySigned { * The different versions of player keys, per Minecraft version. */ enum Revision implements Ordered { + /** + * Represents the original key revision introduced in Minecraft 1.19. + * Keys are not tied to a specific player identity. + */ GENERIC_V1(ImmutableSet.of(), ImmutableSet.of(ProtocolVersion.MINECRAFT_1_19)), + /** + * Represents the key revision introduced in Minecraft 1.19.1. + * Keys are cryptographically linked to player identities. + */ LINKED_V2(ImmutableSet.of(), ImmutableSet.of(ProtocolVersion.MINECRAFT_1_19_1)); final Set backwardsCompatibleTo; @@ -69,11 +76,21 @@ public interface IdentifiedKey extends KeySigned { this.backwardsCompatibleTo = backwardsCompatibleTo; this.applicableTo = applicableTo; } - + + /** + * Returns the set of revisions that this revision is backwards-compatible with. + * + * @return a set of compatible earlier revisions + */ public Set getBackwardsCompatibleTo() { return backwardsCompatibleTo; } - + + /** + * Returns the set of Minecraft protocol versions this revision applies to. + * + * @return a set of applicable protocol versions + */ public Set getApplicableTo() { return applicableTo; } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java b/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java index 8ad64c18..83fd402f 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java @@ -34,7 +34,6 @@ public interface KeySigned { */ Instant getExpiryTemporal(); - /** * Check if the signature has expired. * @@ -56,6 +55,7 @@ public interface KeySigned { * Validates the signature, expiry temporal and key against the * signer public key. Note: This will **not** check for * expiry. You can check for expiry with {@link KeySigned#hasExpired()}. + * *

    DOES NOT WORK YET FOR MESSAGES AND COMMANDS!

    * Addendum: Does not work for 1.19.1 until the user has authenticated. * diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java index 9da9a7b4..eafb484f 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java @@ -31,6 +31,11 @@ public final class LegacyChannelIdentifier implements ChannelIdentifier { this.name = name; } + /** + * Returns the name of this legacy plugin message channel. + * + * @return the channel name + */ public String getName() { return name; } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java index a271a414..92f8ef9f 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java @@ -84,14 +84,29 @@ public final class MinecraftChannelIdentifier implements ChannelIdentifier { return create(key.namespace(), key.value()); } + /** + * Returns the namespace of this channel identifier. + * + * @return the namespace string (e.g., {@code minecraft}) + */ public String getNamespace() { return namespace; } + /** + * Returns the name of the channel within its namespace. + * + * @return the channel name string + */ public String getName() { return name; } + /** + * Converts this channel identifier to a {@link Key} object. + * + * @return a {@link Key} representing this identifier + */ public Key asKey() { return Key.key(namespace, name); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java b/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java index 416cbf15..91cca964 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java @@ -86,8 +86,17 @@ public interface PlayerSettings { * The client's current chat display mode. */ enum ChatMode { + /** + * Chat is fully visible. + */ SHOWN, + /** + * Only command messages are shown. + */ COMMANDS_ONLY, + /** + * Chat is completely hidden. + */ HIDDEN } @@ -95,7 +104,13 @@ public interface PlayerSettings { * The player's selected dominant hand. */ enum MainHand { + /** + * This scope defines the left hand. + */ LEFT, + /** + * This scope defines the right hand. + */ RIGHT } @@ -103,8 +118,17 @@ public interface PlayerSettings { * The client's current "Particles" option state. */ enum ParticleStatus { + /** + * All particles are shown. + */ ALL, + /** + * A reduced number of particles are shown. + */ DECREASED, + /** + * Minimal particle effects are shown. + */ MINIMAL } } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java b/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java index 82937685..7e620185 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java @@ -87,7 +87,6 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { /** * Returns a copy of this {@link ResourcePackInfo} instance as a builder, using the new URL. - *

    * It is not guaranteed that * {@code resourcePackInfo.asBuilder(resourcePackInfo.getUrl()).build().equals(resourcePackInfo)} * is true, because the {@link ResourcePackInfo#getOrigin()} and @@ -108,6 +107,7 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * Sets the id of the resource pack. * * @param id the id the resource-pack + * @return this builder instance */ Builder setId(UUID id); @@ -128,6 +128,7 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * the player will be disconnected from the network * * @param shouldForce whether or not to force the client to accept the resource pack + * @return this builder instance */ Builder setShouldForce(boolean shouldForce); @@ -140,6 +141,7 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * before downloading. * * @param hash the SHA-1 hash of the resource-pack + * @return this builder instance */ Builder setHash(@Nullable byte[] hash); @@ -148,6 +150,7 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * This will only display if the client version is 1.17 or newer. * * @param prompt the component to display + * @return this builder instance */ Builder setPrompt(@Nullable Component prompt); @@ -174,4 +177,4 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { */ PLUGIN_ON_PROXY } -} \ No newline at end of file +} diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java b/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java index 1a5030fe..89355341 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java @@ -17,34 +17,74 @@ public final class SkinParts { private final byte bitmask; + /** + * Constructs a new SkinParts object with the provided bitmask. + * + * @param skinBitmask the bitmask representing which skin parts are enabled + */ public SkinParts(byte skinBitmask) { this.bitmask = skinBitmask; } + /** + * Returns whether the player has a cape enabled. + * + * @return true if the cape is enabled, false otherwise + */ public boolean hasCape() { return (bitmask & 1) == 1; } + /** + * Returns whether the player has a jacket enabled. + * + * @return true if the jacket is enabled, false otherwise + */ public boolean hasJacket() { return ((bitmask >> 1) & 1) == 1; } + /** + * Returns whether the player has a left sleeve enabled. + * + * @return true if the left sleeve is enabled, false otherwise + */ public boolean hasLeftSleeve() { return ((bitmask >> 2) & 1) == 1; } + /** + * Returns whether the player has a right sleeve enabled. + * + * @return true if the right sleeve is enabled, false otherwise + */ public boolean hasRightSleeve() { return ((bitmask >> 3) & 1) == 1; } + /** + * Returns whether the player has their left pants enabled. + * + * @return true if the left pants are enabled, false otherwise + */ public boolean hasLeftPants() { return ((bitmask >> 4) & 1) == 1; } + /** + * Returns whether the player has their right pants enabled. + * + * @return true if the right pants are enabled, false otherwise + */ public boolean hasRightPants() { return ((bitmask >> 5) & 1) == 1; } + /** + * Returns whether the player has a hat enabled. + * + * @return true if the hat is enabled, false otherwise + */ public boolean hasHat() { return ((bitmask >> 6) & 1) == 1; } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java b/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java index aea45287..57a42392 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java @@ -237,8 +237,11 @@ public interface TabListEntry extends KeyIdentifiable { /** * Sets the {@link IdentifiedKey} of the {@link TabListEntry}. + * *

    This only works for players currently not connected to this proxy.

    + * *

    For any player currently connected to this proxy this will be filled automatically.

    + * *

    Will ignore mismatching key revisions data.

    * * @param chatSession session to set diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java b/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java index 6c794bf4..c51765f8 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java @@ -147,7 +147,6 @@ public final class QueryResponse { return plugins; } - /** * Creates a new {@link Builder} instance from data represented by this response, so that you * may create a new {@link QueryResponse} with new data. It is guaranteed that @@ -434,14 +433,31 @@ public final class QueryResponse { this.version = version; } + /** + * Gets the name of the plugin. + * + * @return the plugin name + */ public String getName() { return name; } + /** + * Gets the version of the plugin, if available. + * + * @return an {@link Optional} containing the version if present + */ public Optional getVersion() { return Optional.ofNullable(version); } + /** + * Creates a new {@link PluginInformation} instance with the given name and version. + * + * @param name the name of the plugin + * @param version the version of the plugin (nullable) + * @return a new {@link PluginInformation} instance + */ public static PluginInformation of(String name, @Nullable String version) { return new PluginInformation(name, version); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java index fd686297..9546a662 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java @@ -32,11 +32,21 @@ public final class ServerInfo implements Comparable { this.address = Preconditions.checkNotNull(address, "address"); } - public final String getName() { + /** + * Gets the name of the server. + * + * @return the name of the server + */ + public String getName() { return name; } - public final InetSocketAddress getAddress() { + /** + * Gets the network address of the server. + * + * @return the {@link InetSocketAddress} of the server + */ + public InetSocketAddress getAddress() { return address; } @@ -49,7 +59,7 @@ public final class ServerInfo implements Comparable { } @Override - public final boolean equals(@Nullable Object o) { + public boolean equals(@Nullable Object o) { if (this == o) { return true; } @@ -62,7 +72,7 @@ public final class ServerInfo implements Comparable { } @Override - public final int hashCode() { + public int hashCode() { return Objects.hash(name, address); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java index eb86f93e..98ca3b75 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java @@ -22,7 +22,6 @@ import java.util.UUID; import net.kyori.adventure.text.Component; import org.jspecify.annotations.Nullable; - /** * Represents a 1.7 and above server list ping response. This class is immutable. */ @@ -34,6 +33,14 @@ public final class ServerPing { private final @Nullable Favicon favicon; private final @Nullable ModInfo modinfo; + /** + * Constructs an initial ServerPing instance. + * + * @param version the version of the server + * @param players the players on the server, or {@code null} if not shown + * @param description the MOTD for the server + * @param favicon the server's favicon, or {@code null} if not set + */ public ServerPing(Version version, @Nullable Players players, net.kyori.adventure.text.Component description, @Nullable Favicon favicon) { this(version, players, description, favicon, ModInfo.DEFAULT); @@ -58,23 +65,48 @@ public final class ServerPing { this.modinfo = modinfo; } + /** + * Gets the version shown to the client during the ping. + * + * @return the version + */ public Version getVersion() { return version; } + /** + * Gets the player information shown to the client. + * + * @return the player information, or empty if not shown + */ public Optional getPlayers() { return Optional.ofNullable(players); } + /** + * Gets the description (MOTD) component shown in the ping response. + * + * @return the description component + */ @Nullable public Component getDescriptionComponent() { return description; } + /** + * Gets the favicon sent to the client. + * + * @return the favicon, or empty if not present + */ public Optional getFavicon() { return Optional.ofNullable(favicon); } + /** + * Gets the mod info sent to the client. + * + * @return the mod info, or empty if not present + */ public Optional getModinfo() { return Optional.ofNullable(modinfo); } @@ -139,6 +171,11 @@ public final class ServerPing { return builder; } + /** + * Creates a new {@link Builder} for constructing a {@link ServerPing}. + * + * @return a new ServerPing builder + */ public static Builder builder() { return new Builder(); } @@ -346,34 +383,74 @@ public final class ServerPing { description, favicon, nullOutModinfo ? null : new ModInfo(modType, mods)); } + /** + * Gets the version currently set in the builder. + * + * @return the version + */ public Version getVersion() { return version; } + /** + * Gets the number of players online. + * + * @return the online player count + */ public int getOnlinePlayers() { return onlinePlayers; } + /** + * Gets the maximum player capacity. + * + * @return the max player count + */ public int getMaximumPlayers() { return maximumPlayers; } + /** + * Gets the sample players shown in the ping. + * + * @return the sample player list + */ public List getSamplePlayers() { return samplePlayers; } + /** + * Gets the description component currently set in the builder. + * + * @return the server description, or empty if unset + */ public Optional getDescriptionComponent() { return Optional.ofNullable(description); } + /** + * Gets the favicon currently set in the builder. + * + * @return the favicon, or empty if none + */ public Optional getFavicon() { return Optional.ofNullable(favicon); } + /** + * Gets the type of mod loader (e.g., "FML"). + * + * @return the mod type string + */ public String getModType() { return modType; } + /** + * Gets the list of mods reported in the ping. + * + * @return the mod list + */ public List getMods() { return mods; } @@ -417,10 +494,20 @@ public final class ServerPing { this.name = Preconditions.checkNotNull(name, "name"); } + /** + * Gets the protocol number associated with the server version. + * + * @return the protocol version number + */ public int getProtocol() { return protocol; } + /** + * Gets the user-facing name of the server version. + * + * @return the version name + */ public String getName() { return name; } @@ -474,14 +561,29 @@ public final class ServerPing { this.sample = ImmutableList.copyOf(sample); } + /** + * Gets the number of online players. + * + * @return the number of online players + */ public int getOnline() { return online; } + /** + * Gets the maximum number of players the server claims it can hold. + * + * @return the maximum number of players + */ public int getMax() { return max; } + /** + * Gets a sample list of online players. + * + * @return the sample players + */ public List getSample() { return sample == null ? ImmutableList.of() : sample; } @@ -519,22 +621,47 @@ public final class ServerPing { */ public static final class SamplePlayer { + /** + * A constant representing an anonymous sample player with a null UUID and generic name. + */ public static final SamplePlayer ANONYMOUS = new SamplePlayer( "Anonymous Player", new UUID(0L, 0L) ); + /** + * The legacy string name of the player. + */ private final String name; + /** + * The unique identifier (UUID) of the player. + */ private final UUID id; + /** + * Constructs a SamplePlayer with the given name and UUID. + * + * @param name the name of the player + * @param id the UUID of the player + */ public SamplePlayer(String name, UUID id) { this.name = name; this.id = id; } + /** + * Gets the legacy string name of the sample player. + * + * @return the player name + */ public String getName() { return name; } + /** + * Gets the UUID of the sample player. + * + * @return the player UUID + */ public UUID getId() { return id; } diff --git a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java index 27c42138..e918c8e9 100644 --- a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java +++ b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java @@ -200,14 +200,29 @@ public final class GameProfile { this.signature = Preconditions.checkNotNull(signature, "signature"); } + /** + * Returns the name of this property. + * + * @return the property name + */ public String getName() { return name; } + /** + * Returns the value of this property. + * + * @return the property value + */ public String getValue() { return value; } + /** + * Returns the Mojang-provided signature for this property. + * + * @return the property signature + */ public String getSignature() { return signature; } diff --git a/api/src/main/java/com/velocitypowered/api/util/ModInfo.java b/api/src/main/java/com/velocitypowered/api/util/ModInfo.java index cfc52289..d5e252fa 100644 --- a/api/src/main/java/com/velocitypowered/api/util/ModInfo.java +++ b/api/src/main/java/com/velocitypowered/api/util/ModInfo.java @@ -18,6 +18,10 @@ import java.util.Objects; */ public final class ModInfo { + /** + * The default mod info used when no mods are present. + * Typically used for Forge-compatible connections that require a placeholder. + */ public static final ModInfo DEFAULT = new ModInfo("FML", ImmutableList.of()); private final String type; @@ -34,10 +38,20 @@ public final class ModInfo { this.modList = ImmutableList.copyOf(modList); } + /** + * Returns the Forge mod list type (e.g., "FML"). + * + * @return the mod list type + */ public String getType() { return type; } + /** + * Returns an immutable list of all mods in this mod list. + * + * @return the list of mods + */ public List getMods() { return modList; } @@ -89,10 +103,20 @@ public final class ModInfo { Preconditions.checkArgument(version.length() < 128, "mod version is too long"); } + /** + * Returns the mod ID (identifier string). + * + * @return the mod ID + */ public String getId() { return id; } + /** + * Returns the mod version string. + * + * @return the mod version + */ public String getVersion() { return version; } diff --git a/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java b/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java index abc3a14a..303fbd0f 100644 --- a/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java +++ b/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java @@ -33,14 +33,29 @@ public final class ProxyVersion { this.version = Preconditions.checkNotNull(version, "version"); } + /** + * Gets the name of the proxy implementation. + * + * @return the name of the proxy + */ public String getName() { return name; } + /** + * Gets the vendor of the proxy implementation. + * + * @return the vendor of the proxy + */ public String getVendor() { return vendor; } + /** + * Gets the version of the proxy implementation. + * + * @return the version of the proxy + */ public String getVersion() { return version; } diff --git a/api/src/main/java/com/velocitypowered/api/util/ServerLink.java b/api/src/main/java/com/velocitypowered/api/util/ServerLink.java index 9eb04a98..484833fe 100644 --- a/api/src/main/java/com/velocitypowered/api/util/ServerLink.java +++ b/api/src/main/java/com/velocitypowered/api/util/ServerLink.java @@ -38,6 +38,7 @@ public final class ServerLink { * * @param label a custom component label to display * @param link the URL to open when clicked + * @return a {@link ServerLink} instance with the given label and URL */ public static ServerLink serverLink(Component label, String link) { return new ServerLink(label, link); @@ -48,6 +49,7 @@ public final class ServerLink { * * @param type the {@link Type built-in type} of link * @param link the URL to open when clicked + * @return a {@link ServerLink} instance with the given type and URL */ public static ServerLink serverLink(Type type, String link) { return new ServerLink(type, link); @@ -86,15 +88,45 @@ public final class ServerLink { * @apiNote {@link Type#BUG_REPORT} links are shown on the connection error screen */ public enum Type { + /** + * A link to report bugs related to the server or gameplay. + */ BUG_REPORT, + /** + * A link to the server's community guidelines or rules. + */ COMMUNITY_GUIDELINES, + /** + * A link to the server’s support or help desk. + */ SUPPORT, + /** + * A link showing the current server or service status. + */ STATUS, + /** + * A link to provide feedback to the server staff or developers. + */ FEEDBACK, + /** + * A link to the server’s community hub or Discord. + */ COMMUNITY, + /** + * A link to the server's main website. + */ WEBSITE, + /** + * A link to the server's forums. + */ FORUMS, + /** + * A link to server or game-related news. + */ NEWS, + /** + * A link to announcements from the server team. + */ ANNOUNCEMENTS } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7be8d469..5ad83ecc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,12 +3,12 @@ configurate3 = "3.7.3" configurate4 = "4.2.0" flare = "2.0.1" log4j = "2.25.3" -netty = "4.2.7.Final" +netty = "4.2.9.Final" [plugins] fill = "io.papermc.fill.gradle:1.0.10" shadow = "com.gradleup.shadow:9.3.1" -spotless = "com.diffplug.spotless:8.2.0" +spotless = "com.diffplug.spotless:8.2.1" [libraries] adventure-bom = "net.kyori:adventure-bom:4.26.1" @@ -21,7 +21,7 @@ brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT" bstats = "org.bstats:bstats-base:3.1.0" caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3" checker-qual = "org.checkerframework:checker-qual:3.53.0" -checkstyle = "com.puppycrawl.tools:checkstyle:10.9.3" +checkstyle = "com.puppycrawl.tools:checkstyle:13.0.0" completablefutures = "com.spotify:completable-futures:0.3.6" configurate3-hocon = { module = "org.spongepowered:configurate-hocon", version.ref = "configurate3" } configurate3-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate3" } @@ -30,12 +30,12 @@ configurate4-hocon = { module = "org.spongepowered:configurate-hocon", version.r configurate4-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate4" } configurate4-gson = { module = "org.spongepowered:configurate-gson", version.ref = "configurate4" } disruptor = "com.lmax:disruptor:4.0.0" -fastutil = "it.unimi.dsi:fastutil:8.5.15" +fastutil = "it.unimi.dsi:fastutil:8.5.18" flare-core = { module = "space.vectrix.flare:flare", version.ref = "flare" } flare-fastutil = { module = "space.vectrix.flare:flare-fastutil", version.ref = "flare" } jline = "org.jline:jline-terminal-jansi:3.30.6" jopt = "net.sf.jopt-simple:jopt-simple:5.0.4" -junit = "org.junit.jupiter:junit-jupiter:5.14.2" +junit = "org.junit.jupiter:junit-jupiter:6.0.2" jspecify = "org.jspecify:jspecify:1.0.0" kyori-ansi = "net.kyori:ansi:1.1.1" guava = "com.google.guava:guava:33.5.0-jre" diff --git a/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java b/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java index 13f4f0c5..886f2081 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java +++ b/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java @@ -54,8 +54,8 @@ public class MoreByteBufUtils { BufferPreference preferred = nativeStuff.preferredBufferType(); return switch (preferred) { case DIRECT_PREFERRED, HEAP_PREFERRED -> - // The native prefers this type, but doesn't strictly require we provide it. - true; + // The native prefers this type, but doesn't strictly require we provide it. + true; case DIRECT_REQUIRED -> buf.hasMemoryAddress(); case HEAP_REQUIRED -> buf.hasArray(); }; diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 599baba1..2fb40773 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -14,10 +14,6 @@ application { } tasks { - withType { - exclude("**/com/velocitypowered/proxy/protocol/packet/**") - } - jar { manifest { attributes["Implementation-Title"] = "Velocity" @@ -33,7 +29,7 @@ tasks { transform(Log4j2PluginsCacheFileTransformer::class.java) - // Exclude all the collection types we don"t intend to use + // Exclude all the collection types we don't intend to use exclude("it/unimi/dsi/fastutil/booleans/**") exclude("it/unimi/dsi/fastutil/bytes/**") exclude("it/unimi/dsi/fastutil/chars/**") @@ -42,7 +38,7 @@ tasks { exclude("it/unimi/dsi/fastutil/longs/**") exclude("it/unimi/dsi/fastutil/shorts/**") - // Exclude the fastutil IO utilities - we don"t use them. + // Exclude the fastutil IO utilities - we don't use them. exclude("it/unimi/dsi/fastutil/io/**") // Exclude most of the int types - Object2IntMap have a values() method that returns an diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index 95f10bcb..f44cb99e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -650,7 +650,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { } /** - * Calls {@link #shutdown(boolean, Component)} with the default reason "Proxy shutting down." + * Calls {@link #shutdown(boolean, Component)} with the default reason "Proxy shutting down.". * * @param explicitExit whether the user explicitly shut down the proxy */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java index f0fd5e08..3bef8a4b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java @@ -37,7 +37,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Modern (Minecraft 1.20.3+) ResourcePackHandler + * Modern (Minecraft 1.20.3+) ResourcePackHandler. */ public final class ModernResourcePackHandler extends ResourcePackHandler { private final ListMultimap outstandingResourcePacks = diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java index b3843885..dc04b912 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java @@ -118,6 +118,7 @@ public abstract sealed class ResourcePackHandler /** * Processes a client response to a sent resource-pack. + * *

    Cases in which no action will be taken:

    *
      * diff --git a/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java b/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java index 9d54b2d0..7037ee2a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java @@ -545,6 +545,36 @@ public class VelocityEventManager implements EventManager { } } + private void fire(final @Nullable CompletableFuture future, final E event, + final int offset, final boolean currentlyAsync, final HandlerRegistration[] registrations) { + for (int i = offset; i < registrations.length; i++) { + final HandlerRegistration registration = registrations[i]; + try { + final EventTask eventTask = registration.handler.executeAsync(event); + if (eventTask == null) { + continue; + } + final ContinuationTask continuationTask = new ContinuationTask<>(eventTask, + registrations, future, event, i, currentlyAsync); + if (currentlyAsync || !eventTask.requiresAsync()) { + if (continuationTask.execute()) { + continue; + } + } else { + registration.plugin.getExecutorService().execute(continuationTask); + } + // fire will continue in another thread once the async task is + // executed and the continuation is resumed + return; + } catch (final Throwable t) { + logHandlerException(registration, t); + } + } + if (future != null) { + future.complete(event); + } + } + private static final int TASK_STATE_DEFAULT = 0; private static final int TASK_STATE_EXECUTING = 1; private static final int TASK_STATE_CONTINUE_IMMEDIATELY = 2; @@ -669,40 +699,10 @@ public class VelocityEventManager implements EventManager { } } - private void fire(final @Nullable CompletableFuture future, final E event, - final int offset, final boolean currentlyAsync, final HandlerRegistration[] registrations) { - for (int i = offset; i < registrations.length; i++) { - final HandlerRegistration registration = registrations[i]; - try { - final EventTask eventTask = registration.handler.executeAsync(event); - if (eventTask == null) { - continue; - } - final ContinuationTask continuationTask = new ContinuationTask<>(eventTask, - registrations, future, event, i, currentlyAsync); - if (currentlyAsync || !eventTask.requiresAsync()) { - if (continuationTask.execute()) { - continue; - } - } else { - registration.plugin.getExecutorService().execute(continuationTask); - } - // fire will continue in another thread once the async task is - // executed and the continuation is resumed - return; - } catch (final Throwable t) { - logHandlerException(registration, t); - } - } - if (future != null) { - future.complete(event); - } - } - private static void logHandlerException( final HandlerRegistration registration, final Throwable t) { final PluginDescription pluginDescription = registration.plugin.getDescription(); logger.error("Couldn't pass {} to {} {}", registration.eventType.getSimpleName(), pluginDescription.getId(), pluginDescription.getVersion().orElse(""), t); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index efc0ed17..093256d0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -633,7 +633,7 @@ public enum ProtocolUtils { private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A; /** - * Reads an byte array for legacy version 1.7 from the specified {@code buf} + * Reads an byte array for legacy version 1.7 from the specified {@code buf}. * * @param buf the buffer to read from * @return the read byte array @@ -671,7 +671,7 @@ public enum ProtocolUtils { } /** - * Writes an byte array for legacy version 1.7 to the specified {@code buf} + * Writes an byte array for legacy version 1.7 to the specified {@code buf}. * * @param b array * @param buf buf @@ -695,7 +695,7 @@ public enum ProtocolUtils { } /** - * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf} + * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf}. * * @param b array * @param buf buf diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java index 2746b23f..23cebf61 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java @@ -53,6 +53,13 @@ import java.util.function.Predicate; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a packet that contains the list of available commands, implementing {@link MinecraftPacket}. + * + *

      The {@code AvailableCommandsPacket} is responsible for transmitting the set of commands + * that a player can execute. It provides the necessary information about available commands + * within the current session or game state.

      + */ public class AvailableCommandsPacket implements MinecraftPacket { private static final Command PLACEHOLDER_COMMAND = source -> 0; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java index d7748eff..06cbd861 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java @@ -29,6 +29,10 @@ import java.util.UUID; import net.kyori.adventure.bossbar.BossBar; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a packet used to manage boss bars. + * This packet can add, remove, or update a boss bar. + */ public class BossBarPacket implements MinecraftPacket { private static final Enum2IntMap COLORS_TO_PROTOCOL = @@ -70,6 +74,14 @@ public class BossBarPacket implements MinecraftPacket { private int overlay; private short flags; + /** + * Creates a packet to add a new boss bar. + * + * @param id the UUID of the boss bar + * @param bar the {@link BossBar} instance + * @param name the {@link ComponentHolder} containing the boss bar's name + * @return a {@link BossBarPacket} to add a boss bar + */ public static BossBarPacket createAddPacket( final UUID id, final BossBar bar, @@ -86,6 +98,13 @@ public class BossBarPacket implements MinecraftPacket { return packet; } + /** + * Creates a packet to remove an existing boss bar. + * + * @param id the UUID of the boss bar to remove + * @param bar the {@link BossBar} instance + * @return a {@link BossBarPacket} to remove a boss bar + */ public static BossBarPacket createRemovePacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -93,6 +112,13 @@ public class BossBarPacket implements MinecraftPacket { return packet; } + /** + * Creates a packet to update the progress (percentage) of the boss bar. + * + * @param id the UUID of the boss bar + * @param bar the {@link BossBar} instance + * @return a {@link BossBarPacket} to update the boss bar's progress + */ public static BossBarPacket createUpdateProgressPacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -101,6 +127,14 @@ public class BossBarPacket implements MinecraftPacket { return packet; } + /** + * Creates a packet to update the name of the boss bar. + * + * @param id the UUID of the boss bar + * @param bar the {@link BossBar} instance + * @param name the {@link ComponentHolder} containing the boss bar's new name + * @return a {@link BossBarPacket} to update the boss bar's name + */ public static BossBarPacket createUpdateNamePacket( final UUID id, final BossBar bar, @@ -113,6 +147,13 @@ public class BossBarPacket implements MinecraftPacket { return packet; } + /** + * Creates a packet to update the style (color and overlay) of the boss bar. + * + * @param id the UUID of the boss bar + * @param bar the {@link BossBar} instance + * @return a {@link BossBarPacket} to update the boss bar's style + */ public static BossBarPacket createUpdateStylePacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -122,6 +163,13 @@ public class BossBarPacket implements MinecraftPacket { return packet; } + /** + * Creates a packet to update the properties of the boss bar. + * + * @param id the UUID of the boss bar + * @param bar the {@link BossBar} instance + * @return a {@link BossBarPacket} to update the boss bar's properties + */ public static BossBarPacket createUpdatePropertiesPacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -130,6 +178,12 @@ public class BossBarPacket implements MinecraftPacket { return packet; } + /** + * Retrieves the UUID of the boss bar. + * + * @return the UUID of the boss bar + * @throws IllegalStateException if the UUID has not been set + */ public UUID getUuid() { if (uuid == null) { throw new IllegalStateException("No boss bar UUID specified"); @@ -214,7 +268,8 @@ public class BossBarPacket implements MinecraftPacket { this.overlay = ProtocolUtils.readVarInt(buf); this.flags = buf.readUnsignedByte(); } - case REMOVE -> {} + case REMOVE -> { + } case UPDATE_PERCENT -> this.percent = buf.readFloat(); case UPDATE_NAME -> this.name = ComponentHolder.read(buf, version); case UPDATE_STYLE -> { @@ -235,22 +290,23 @@ public class BossBarPacket implements MinecraftPacket { ProtocolUtils.writeVarInt(buf, action); switch (action) { case ADD -> { - if (name == null) { - throw new IllegalStateException("No name specified!"); - } - name.write(buf); - buf.writeFloat(percent); - ProtocolUtils.writeVarInt(buf, color); - ProtocolUtils.writeVarInt(buf, overlay); - buf.writeByte(flags); + if (name == null) { + throw new IllegalStateException("No name specified!"); + } + name.write(buf); + buf.writeFloat(percent); + ProtocolUtils.writeVarInt(buf, color); + ProtocolUtils.writeVarInt(buf, overlay); + buf.writeByte(flags); + } + case REMOVE -> { } - case REMOVE -> {} case UPDATE_PERCENT -> buf.writeFloat(percent); case UPDATE_NAME -> { - if (name == null) { - throw new IllegalStateException("No name specified!"); - } - name.write(buf); + if (name == null) { + throw new IllegalStateException("No name specified!"); + } + name.write(buf); } case UPDATE_STYLE -> { ProtocolUtils.writeVarInt(buf, color); @@ -264,7 +320,7 @@ public class BossBarPacket implements MinecraftPacket { private static byte serializeFlags(Set flags) { byte val = 0x0; for (BossBar.Flag flag : flags) { - val |= FLAG_BITS_TO_PROTOCOL.get(flag); + val |= (byte) FLAG_BITS_TO_PROTOCOL.get(flag); } return val; } @@ -273,4 +329,4 @@ public class BossBarPacket implements MinecraftPacket { public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java index 4da691c7..5c6827f3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java @@ -23,6 +23,14 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet used as a delimiter for bundling multiple packets together. + * The {@code BundleDelimiterPacket} marks the beginning or end of a packet bundle, + * allowing the server and client to process groups of packets as a single logical unit. + * + *

      This packet is typically used to signal the start or end of a packet sequence that + * are sent together, enabling efficient transmission and processing of related data.

      + */ public final class BundleDelimiterPacket implements MinecraftPacket { public static final BundleDelimiterPacket INSTANCE = new BundleDelimiterPacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java index 39e6fde0..743fb2ba 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java @@ -23,9 +23,13 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import java.util.Objects; - import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents the client settings packet in Minecraft, which is sent by the client + * to the server to communicate its settings such as locale, view distance, chat preferences, + * skin customization, and other client-side configurations. + */ public class ClientSettingsPacket implements MinecraftPacket { private @Nullable String locale; private byte viewDistance; @@ -41,6 +45,19 @@ public class ClientSettingsPacket implements MinecraftPacket { public ClientSettingsPacket() { } + /** + * Constructs a new {@code ClientSettingsPacket} with the specified settings. + * + * @param locale the client's locale setting + * @param viewDistance the view distance + * @param chatVisibility the client's chat visibility setting + * @param chatColors whether chat colors are enabled + * @param skinParts the customization for skin parts + * @param mainHand the client's main hand preference + * @param textFilteringEnabled whether text filtering is enabled + * @param clientListingAllowed whether the client allows listing + * @param particleStatus whether particles are enabled + */ public ClientSettingsPacket(String locale, byte viewDistance, int chatVisibility, boolean chatColors, short skinParts, int mainHand, boolean textFilteringEnabled, boolean clientListingAllowed, int particleStatus) { @@ -55,6 +72,12 @@ public class ClientSettingsPacket implements MinecraftPacket { this.particleStatus = particleStatus; } + /** + * Gets the client's locale. + * + * @return the locale + * @throws IllegalStateException if no locale is specified + */ public String getLocale() { if (locale == null) { throw new IllegalStateException("No locale specified"); @@ -132,10 +155,10 @@ public class ClientSettingsPacket implements MinecraftPacket { @Override public String toString() { - return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance + - ", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" + - skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + textFilteringEnabled + - ", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}'; + return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance + + ", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" + + skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + textFilteringEnabled + + ", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java index fd558b29..0e7c2a7a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java @@ -25,6 +25,11 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; +/** + * Represents a packet sent from the server to the client to request cookies. + * This packet can be used to initiate a request for cookie-related data from the client, + * typically for authentication or tracking purposes. + */ public class ClientboundCookieRequestPacket implements MinecraftPacket { private Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java index 459f1430..9ccebf3b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java @@ -22,11 +22,16 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +import java.util.Random; import net.kyori.adventure.sound.Sound; import org.jetbrains.annotations.Nullable; -import java.util.Random; - +/** + * A clientbound packet that instructs the client to play a sound tied to an entity. + * + *

      This is sent by the server when a sound should be played at the location of a + * specific entity, with optional fixed range and seed.

      + */ public class ClientboundSoundEntityPacket implements MinecraftPacket { private static final Random SEEDS_RANDOM = new Random(); @@ -35,8 +40,16 @@ public class ClientboundSoundEntityPacket implements MinecraftPacket { private @Nullable Float fixedRange; private int emitterEntityId; - public ClientboundSoundEntityPacket() {} + public ClientboundSoundEntityPacket() { + } + /** + * Constructs a new sound entity packet. + * + * @param sound the sound to play + * @param fixedRange the fixed attenuation range, or {@code null} to use the default + * @param emitterEntityId the entity ID of the sound emitter + */ public ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange, int emitterEntityId) { this.sound = sound; this.fixedRange = fixedRange; @@ -55,8 +68,9 @@ public class ClientboundSoundEntityPacket implements MinecraftPacket { ProtocolUtils.writeMinimalKey(buf, sound.name()); buf.writeBoolean(fixedRange != null); - if (fixedRange != null) + if (fixedRange != null) { buf.writeFloat(fixedRange); + } ProtocolUtils.writeSoundSource(buf, protocolVersion, sound.source()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java index 3e085d38..ecf14c5a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java @@ -22,18 +22,24 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +import javax.annotation.Nullable; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.sound.SoundStop; -import javax.annotation.Nullable; - +/** + * A clientbound packet instructing the client to stop one or more sounds. + * + *

      This packet supports specifying a {@link Sound.Source}, a {@link Key} sound identifier, + * or both together. If neither is specified, the client will stop all currently playing sounds.

      + */ public class ClientboundStopSoundPacket implements MinecraftPacket { private @Nullable Sound.Source source; private @Nullable Key soundName; - public ClientboundStopSoundPacket() {} + public ClientboundStopSoundPacket() { + } public ClientboundStopSoundPacket(SoundStop soundStop) { this(soundStop.source(), soundStop.sound()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java index 7823b558..e551473a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java @@ -25,6 +25,11 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; +/** + * Represents a packet sent from the server to the client to store a cookie. + * This packet can be used to send cookie-related data from the server to be stored or processed + * by the client. + */ public class ClientboundStoreCookiePacket implements MinecraftPacket { private Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java index 4188abfd..e64e1ada 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java @@ -23,6 +23,13 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +/** + * Represents the packet sent by the server to the client to clear any + * currently displayed configuration dialog. + * + *

      This packet is used during the configuration phase (1.21.6+) to + * instruct the client to dismiss an active dialog window.

      + */ public class DialogClearPacket implements MinecraftPacket { public static final DialogClearPacket INSTANCE = new DialogClearPacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java index 67d4b8f8..21a69cc2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java @@ -27,6 +27,13 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.BinaryTagIO; +/** + * Represents the packet sent by the server to the client to display a configuration dialog + * during the configuration phase in Minecraft 1.21.6+. + * + *

      This packet is only relevant in the CONFIG and PLAY states. If the ID is {@code 0}, + * a dialog is to be shown and the accompanying {@link BinaryTag} contains its data.

      + */ public class DialogShowPacket implements MinecraftPacket { private final StateRegistry state; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java index dd16cb61..7074e8fd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java @@ -28,6 +28,12 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a packet sent by the server to disconnect the client. This packet contains + * a reason for the disconnection, which is sent to the client and displayed to the player. + * The packet can be sent in different states (e.g., login, play), which affects how the + * reason is processed. + */ public class DisconnectPacket implements MinecraftPacket { private @Nullable ComponentHolder reason; @@ -42,6 +48,12 @@ public class DisconnectPacket implements MinecraftPacket { this.reason = Preconditions.checkNotNull(reason, "reason"); } + /** + * Retrieves the reason for the disconnection, which will be sent to the client. + * + * @return the reason for the disconnection as a {@link ComponentHolder} + * @throws IllegalStateException if no reason is specified + */ public ComponentHolder getReason() { if (reason == null) { throw new IllegalStateException("No reason specified"); @@ -62,8 +74,8 @@ public class DisconnectPacket implements MinecraftPacket { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - reason = ComponentHolder.read(buf, state == StateRegistry.LOGIN - ? ProtocolVersion.MINECRAFT_1_20_2 : version); + reason = ComponentHolder.read(buf, state == StateRegistry.LOGIN + ? ProtocolVersion.MINECRAFT_1_20_2 : version); } @Override @@ -76,9 +88,17 @@ public class DisconnectPacket implements MinecraftPacket { return handler.handle(this); } + /** + * Creates a new {@code DisconnectPacket} with the specified reason and version. + * + * @param component the component explaining the disconnection reason + * @param version the protocol version in use + * @param state the state in which the disconnection occurs + * @return the created {@code DisconnectPacket} + */ public static DisconnectPacket create(Component component, ProtocolVersion version, StateRegistry state) { Preconditions.checkNotNull(component, "component"); return new DisconnectPacket(state, new ComponentHolder(state == StateRegistry.LOGIN ? ProtocolVersion.MINECRAFT_1_20_2 : version, component)); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java index 422d5e11..66af05e0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java @@ -26,6 +26,12 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import java.util.Arrays; +/** + * Represents the encryption request packet in Minecraft, which is sent by the server + * during the encryption handshake process. This packet is used to initiate secure + * communication by providing the client with the server's public key and a verified token. + * The client must respond with the encrypted shared secret and verify token. + */ public class EncryptionRequestPacket implements MinecraftPacket { private String serverId = ""; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java index fedb67a5..eed2ab1f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java @@ -26,10 +26,18 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; +import java.util.Arrays; import org.checkerframework.checker.nullness.qual.Nullable; -import java.util.Arrays; - +/** + * Represents the encryption response packet in Minecraft, which is sent by the client + * during the encryption handshake process. This packet contains the shared secret + * and verifies the token used to establish secure communication between the client + * and the server. + * + *

      The packet structure varies depending on the Minecraft protocol version, with additional + * fields such as a salt being present in versions 1.19 and above.

      + */ public class EncryptionResponsePacket implements MinecraftPacket { private static final QuietDecoderException NO_SALT = new QuietDecoderException( @@ -47,6 +55,13 @@ public class EncryptionResponsePacket implements MinecraftPacket { return verifyToken.clone(); } + /** + * Retrieves the salt used in the encryption response. The salt is introduced in + * Minecraft version 1.19 and is optional in certain protocol versions. + * + * @return the salt used in the encryption response + * @throws QuietDecoderException if the salt is not present + */ public long getSalt() { if (salt == null) { throw NO_SALT; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java index 88cb3688..5deaf395 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java @@ -27,6 +27,12 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +/** + * Represents a handshake packet in Minecraft, which is used during the initial connection process. + * This packet contains information such as the protocol version, server address, port, and the intent + * of the handshake (e.g., login or status request). This packet is crucial for establishing a connection + * between the client and the server. + */ public class HandshakePacket implements MinecraftPacket { // This size was chosen to ensure Forge clients can still connect even with very long hostnames. @@ -110,13 +116,13 @@ public class HandshakePacket implements MinecraftPacket { @Override public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 7; } @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java index 339d026f..55eb3ebc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java @@ -26,6 +26,10 @@ import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; import net.kyori.adventure.text.Component; +/** + * Represents a packet that contains both the header and footer for the player list screen (tab list) in Minecraft. + * This packet allows the server to set or update the header and footer text that is displayed on the client's tab list. + */ public class HeaderAndFooterPacket implements MinecraftPacket { private final ComponentHolder header; @@ -67,11 +71,11 @@ public class HeaderAndFooterPacket implements MinecraftPacket { public static HeaderAndFooterPacket create(Component header, Component footer, ProtocolVersion protocolVersion) { return new HeaderAndFooterPacket(new ComponentHolder(protocolVersion, header), - new ComponentHolder(protocolVersion, footer)); + new ComponentHolder(protocolVersion, footer)); } public static HeaderAndFooterPacket reset(ProtocolVersion version) { ComponentHolder empty = new ComponentHolder(version, Component.empty()); return new HeaderAndFooterPacket(empty, empty); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java index 787d858e..81ac98ae 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java @@ -21,13 +21,19 @@ import com.google.common.collect.ImmutableSet; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.registry.DimensionInfo; -import com.velocitypowered.proxy.protocol.*; +import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.Pair; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a packet sent to the client when they successfully join a game in Minecraft. + * This packet contains all the necessary information to initialize the client state, + * including the player's entity ID, game mode, dimension, world settings, and more. + */ public class JoinGamePacket implements MinecraftPacket { private static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024); @@ -204,17 +210,17 @@ public class JoinGamePacket implements MinecraftPacket { @Override public String toString() { - return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" + - dimension + ", partialHashedSeed=" + partialHashedSeed + ", difficulty=" + difficulty + - ", isHardcore=" + isHardcore + ", maxPlayers=" + maxPlayers + ", levelType='" + levelType + - '\'' + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo + - ", showRespawnScreen=" + showRespawnScreen + ", doLimitedCrafting=" + doLimitedCrafting + - ", levelNames=" + levelNames + ", registry='" + registry + '\'' + ", dimensionInfo='" + - dimensionInfo + '\'' + ", currentDimensionData='" + currentDimensionData + '\'' + - ", previousGamemode=" + previousGamemode + ", simulationDistance=" + simulationDistance + - ", lastDeathPosition='" + lastDeathPosition + '\'' + ", portalCooldown=" + portalCooldown + - ", seaLevel=" + seaLevel + - '}'; + return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" + + dimension + ", partialHashedSeed=" + partialHashedSeed + ", difficulty=" + difficulty + + ", isHardcore=" + isHardcore + ", maxPlayers=" + maxPlayers + ", levelType='" + levelType + + '\'' + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo + + ", showRespawnScreen=" + showRespawnScreen + ", doLimitedCrafting=" + doLimitedCrafting + + ", levelNames=" + levelNames + ", registry='" + registry + '\'' + ", dimensionInfo='" + + dimensionInfo + '\'' + ", currentDimensionData='" + currentDimensionData + '\'' + + ", previousGamemode=" + previousGamemode + ", simulationDistance=" + simulationDistance + + ", lastDeathPosition='" + lastDeathPosition + '\'' + ", portalCooldown=" + portalCooldown + + ", seaLevel=" + seaLevel + + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java index a44e50ee..3ae2d89d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java @@ -23,6 +23,11 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a KeepAlive packet in Minecraft. This packet is used to ensure that the connection + * between the client and the server shall still be active by sending a randomly generated ID that + * the client must respond to. + */ public class KeepAlivePacket implements MinecraftPacket { private long randomId; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java index e8f8deef..952dfe28 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java @@ -25,7 +25,13 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -@SuppressWarnings("checkstyle:MissingJavadocType") +/** + * Represents a legacy disconnect packet that contains a reason for disconnection. + * This class is used to convert modern server ping responses into the legacy format, + * which is compatible with older Minecraft versions. + * + * @param reason the string reason for disconnection + */ public record LegacyDisconnect(String reason) { private static final ServerPing.Players FAKE_PLAYERS = new ServerPing.Players(0, 0, @@ -46,17 +52,17 @@ public record LegacyDisconnect(String reason) { return switch (version) { case MINECRAFT_1_3 -> - // Minecraft 1.3 and below use the section symbol as a delimiter. Accordingly, we must - // remove all section symbols, along with fetching just the first line of an (unformatted) - // MOTD. - new LegacyDisconnect(String.join(LEGACY_COLOR_CODE, + // Minecraft 1.3 and below use the section symbol as a delimiter. Accordingly, we must + // remove all section symbols, along with fetching just the first line of an (unformatted) + // MOTD. + new LegacyDisconnect(String.join(LEGACY_COLOR_CODE, cleanSectionSymbol(getFirstLine(PlainTextComponentSerializer.plainText().serialize( response.getDescriptionComponent()))), Integer.toString(players.getOnline()), Integer.toString(players.getMax()))); case MINECRAFT_1_4, MINECRAFT_1_6 -> - // Minecraft 1.4-1.6 provide support for more fields, and additionally support color codes. - new LegacyDisconnect(String.join("\0", + // Minecraft 1.4-1.6 provide support for more fields, and additionally support color codes. + new LegacyDisconnect(String.join("\0", LEGACY_COLOR_CODE + "1", Integer.toString(response.getVersion().getProtocol()), response.getVersion().getName(), diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java index 38483ed8..8a9aba27 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java @@ -23,6 +23,11 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a legacy handshake packet in Minecraft, which is typically used + * during the initial connection process for older versions of the Minecraft protocol. + * This class currently does not support decoding of the handshake packet. + */ public class LegacyHandshakePacket implements MinecraftPacket { @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java index 656d3222..c81c4722 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java @@ -26,6 +26,11 @@ import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a legacy ping packet in Minecraft, commonly used in the server list ping process. + * This packet handles compatibility with older Minecraft versions and contains information + * such as the ping protocol version and optionally a virtual host address. + */ public class LegacyPingPacket implements MinecraftPacket { private final LegacyMinecraftPingVersion version; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java index 9dbe9cbc..cdffabcc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java @@ -33,6 +33,10 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a legacy player list item packet, which is used to modify the player list in a Minecraft client. + * The packet can add, remove, or update player entries (e.g., updating gamemode, latency, or display names). + */ public class LegacyPlayerListItemPacket implements MinecraftPacket { public static final int ADD_PLAYER = 0; @@ -76,16 +80,16 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { item.setLatency(ProtocolUtils.readVarInt(buf)); item.setDisplayName(readOptionalComponent(buf, version)); if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) { - if (buf.readBoolean()) { - item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf)); - } + if (buf.readBoolean()) { + item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf)); + } } } case UPDATE_GAMEMODE -> item.setGameMode(ProtocolUtils.readVarInt(buf)); case UPDATE_LATENCY -> item.setLatency(ProtocolUtils.readVarInt(buf)); case UPDATE_DISPLAY_NAME -> item.setDisplayName(readOptionalComponent(buf, version)); case REMOVE_PLAYER -> { - //Do nothing, all that is needed is the uuid + // Do nothing, all that is needed is the uuid } default -> throw new UnsupportedOperationException("Unknown action " + action); } @@ -107,6 +111,17 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { return null; } + /** + * Encodes this packet's contents into the given {@link ByteBuf}. + * + *

      This method serializes the packet data based on the current protocol version. + * Subclasses overriding this method should preserve compatibility with legacy + * and modern formats as needed.

      + * + * @param buf the buffer to write to + * @param direction the direction of the packet (clientbound or serverbound) + * @param version the Minecraft protocol version + */ @Override public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) { @@ -125,12 +140,12 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { ProtocolUtils.writeVarInt(buf, item.getLatency()); writeDisplayName(buf, item.getDisplayName(), version); if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) { - if (item.getPlayerKey() != null) { - buf.writeBoolean(true); - ProtocolUtils.writePlayerKey(buf, item.getPlayerKey()); - } else { - buf.writeBoolean(false); - } + if (item.getPlayerKey() != null) { + buf.writeBoolean(true); + ProtocolUtils.writePlayerKey(buf, item.getPlayerKey()); + } else { + buf.writeBoolean(false); + } } } case UPDATE_GAMEMODE -> ProtocolUtils.writeVarInt(buf, item.getGameMode()); @@ -172,6 +187,10 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { } } + /** + * Represents an individual item in the player list, containing the player's details such as UUID, name, + * game mode, latency, and optionally a display name and player key. + */ public static class Item { private final UUID uuid; @@ -190,6 +209,15 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { this.uuid = uuid; } + /** + * Creates an {@link Item} instance from a {@link TabListEntry}. + * This method extracts relevant data from the {@link TabListEntry} such as + * the player's profile ID, name, properties, latency, game mode, player key, + * and display name, and uses them to populate a new {@code Item}. + * + * @param entry the {@link TabListEntry} from which to extract data + * @return an {@link Item} populated with data from the {@link TabListEntry} + */ public static Item from(TabListEntry entry) { return new Item(entry.getProfile().getId()) .setName(entry.getProfile().getName()) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java index 16cf519b..15bbb2c3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java @@ -23,6 +23,13 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet that acknowledges a successful login, implementing {@link MinecraftPacket}. + * + *

      The {@code LoginAcknowledgedPacket} is sent by the server to confirm that the player's login + * process has been successfully completed. It signals the transition from the login phase to the + * game or session phase.

      + */ public class LoginAcknowledgedPacket implements MinecraftPacket { @Override @@ -37,7 +44,7 @@ public class LoginAcknowledgedPacket implements MinecraftPacket { @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java index 2fa82e92..5833ea03 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java @@ -27,6 +27,10 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a login plugin message packet sent during the login phase. This packet allows custom + * plugin messages to be sent from the server to the client before login is complete. + */ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket { private int id; @@ -36,6 +40,13 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M super(null); } + /** + * Constructs a new {@code LoginPluginMessagePacket} with the specified ID, channel, and data buffer. + * + * @param id the plugin message ID + * @param channel the channel name, or {@code null} if not specified + * @param data the data buffer + */ public LoginPluginMessagePacket(int id, @Nullable String channel, ByteBuf data) { super(data); this.id = id; @@ -46,6 +57,12 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M return id; } + /** + * Gets the plugin message channel. + * + * @return the channel name + * @throws IllegalStateException if the channel is not specified + */ public String getChannel() { if (channel == null) { throw new IllegalStateException("Channel is not specified!"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java index e7d9443d..1a8c1066 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java @@ -27,6 +27,10 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +/** + * Represents the response packet to a plugin message sent during the login phase. + * The packet contains the plugin message ID, a success flag, and any additional data. + */ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements MinecraftPacket { private int id; @@ -36,6 +40,13 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements super(Unpooled.EMPTY_BUFFER); } + /** + * Constructs a new {@code LoginPluginResponsePacket} with the specified ID, success status, and data buffer. + * + * @param id the plugin message ID + * @param success {@code true} if the plugin message was successful, {@code false} otherwise + * @param buf the data buffer + */ public LoginPluginResponsePacket(int id, boolean success, @MonotonicNonNull ByteBuf buf) { super(buf); this.id = id; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java index 27c1351d..7d870dcf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java @@ -23,6 +23,9 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet used for ping identification with a unique ID. + */ public class PingIdentifyPacket implements MinecraftPacket { private int id; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java index ecf2887f..bb8abf57 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java @@ -29,6 +29,10 @@ import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a plugin message packet, which allows for custom communication between + * a Minecraft server and a client via custom channels. + */ public class PluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket { private @Nullable String channel; @@ -43,6 +47,12 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr this.channel = channel; } + /** + * Gets the channel for this plugin message. + * + * @return the channel name + * @throws IllegalStateException if the channel is not set + */ public String getChannel() { if (channel == null) { throw new IllegalStateException("Channel is not specified."); @@ -73,7 +83,6 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr } else { this.replace(ProtocolUtils.readRetainedByteBufSlice17(buf)); } - } @Override @@ -97,7 +106,6 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr } else { ProtocolUtils.writeByteBuf17(content(), buf, true); // True for Forge support } - } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java index 90ab3871..255769d8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java @@ -27,6 +27,10 @@ import java.util.ArrayList; import java.util.Collection; import java.util.UUID; +/** + * Represents a packet sent to remove player information from the player list. + * The packet contains a collection of {@link UUID}s representing the profiles to be removed. + */ public class RemovePlayerInfoPacket implements MinecraftPacket { private Collection profilesToRemove; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java index d003a0a9..8d6ef276 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java @@ -25,6 +25,10 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import java.util.UUID; +/** + * Represents a packet sent to remove a previously applied resource pack from the client. + * The packet contains an optional UUID that identifies the resource pack to be removed. + */ public class RemoveResourcePackPacket implements MinecraftPacket { private UUID id; @@ -60,4 +64,4 @@ public class RemoveResourcePackPacket implements MinecraftPacket { public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java index a0f86aed..b5e7e63f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java @@ -33,6 +33,10 @@ import java.util.regex.Pattern; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a resource pack request packet sent by the server to prompt the client to download a resource pack. + * The packet includes the resource pack URL, SHA1 hash, and optional prompt. + */ public class ResourcePackRequestPacket implements MinecraftPacket { private @MonotonicNonNull UUID id; // 1.20.3+ @@ -124,6 +128,12 @@ public class ResourcePackRequestPacket implements MinecraftPacket { } } + /** + * Converts this packet into a {@link VelocityResourcePackInfo} object, which contains the information + * about the resource pack being requested. + * + * @return a {@code VelocityResourcePackInfo} representing the resource pack information + */ public VelocityResourcePackInfo toServerPromptedPack() { final ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url)) @@ -145,12 +155,12 @@ public class ResourcePackRequestPacket implements MinecraftPacket { @Override public String toString() { - return "ResourcePackRequestPacket{" + - "id=" + id + - ", url='" + url + '\'' + - ", hash='" + hash + '\'' + - ", isRequired=" + isRequired + - ", prompt=" + prompt + - '}'; + return "ResourcePackRequestPacket{" + + "id=" + id + + ", url='" + url + '\'' + + ", hash='" + hash + '\'' + + ", isRequired=" + isRequired + + ", prompt=" + prompt + + '}'; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java index 020c3530..de5d0882 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java @@ -24,10 +24,13 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +import java.util.UUID; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import java.util.UUID; - +/** + * Represents the response packet sent by the client after receiving a resource pack request from the server. + * The packet contains information about the client's response, including the resource pack status. + */ public class ResourcePackResponsePacket implements MinecraftPacket { private UUID id; @@ -37,12 +40,25 @@ public class ResourcePackResponsePacket implements MinecraftPacket { public ResourcePackResponsePacket() { } + /** + * Constructs a new {@code ResourcePackResponsePacket} with the specified parameters. + * + * @param id the unique identifier for the response + * @param hash the hash of the resource pack + * @param status the status of the resource pack + */ public ResourcePackResponsePacket(UUID id, String hash, @MonotonicNonNull Status status) { this.id = id; this.hash = hash; this.status = status; } + /** + * Gets the status of the resource pack response. + * + * @return the status of the response + * @throws IllegalStateException if the packet has not been deserialized yet + */ public Status getStatus() { if (status == null) { throw new IllegalStateException("Packet not yet deserialized"); @@ -87,10 +103,10 @@ public class ResourcePackResponsePacket implements MinecraftPacket { @Override public String toString() { - return "ResourcePackResponsePacket{" + - "id=" + id + - ", hash='" + hash + '\'' + - ", status=" + status + - '}'; + return "ResourcePackResponsePacket{" + + "id=" + id + + ", hash='" + hash + '\'' + + ", status=" + status + + '}'; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java index fd9c8ca7..2e13fcad 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java @@ -28,6 +28,10 @@ import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a respawn packet sent by the server when the player changes dimensions or respawns. + * The packet contains information about the new dimension, difficulty, gamemode, and more. + */ public class RespawnPacket implements MinecraftPacket { private int dimension; @@ -46,6 +50,22 @@ public class RespawnPacket implements MinecraftPacket { public RespawnPacket() { } + /** + * Constructs a new {@code RespawnPacket} with the specified parameters. + * + * @param dimension the dimension the player is respawning or teleporting to + * @param partialHashedSeed the partial hashed seed + * @param difficulty the difficulty of the server + * @param gamemode the player's current gamemode + * @param levelType the type of level (e.g., "default", "flat") + * @param dataToKeep a byte flag indicating whether certain data should be kept + * @param dimensionInfo additional information about the dimension (for 1.16-1.16.1) + * @param previousGamemode the player's previous gamemode + * @param currentDimensionData data about the current dimension (for 1.16.2+) + * @param lastDeathPosition optional last death position (for 1.19+) + * @param portalCooldown the cooldown for portal usage (for 1.20+) + * @param seaLevel a determinable spawn point for a user (for 1.21.2+) + */ public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode, String levelType, byte dataToKeep, DimensionInfo dimensionInfo, short previousGamemode, CompoundBinaryTag currentDimensionData, @@ -65,6 +85,12 @@ public class RespawnPacket implements MinecraftPacket { this.seaLevel = seaLevel; } + /** + * Creates a new {@code RespawnPacket} from a {@link JoinGamePacket}. + * + * @param joinGame the {@code JoinGamePacket} to use + * @return a new {@code RespawnPacket} based on the provided {@code JoinGamePacket} + */ public static RespawnPacket fromJoinGame(JoinGamePacket joinGame) { return new RespawnPacket(joinGame.getDimension(), joinGame.getPartialHashedSeed(), joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType(), diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java index 325a3c9d..e1430aae 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java @@ -25,10 +25,14 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.Nullable; import java.nio.charset.StandardCharsets; import java.util.Base64; +import org.jetbrains.annotations.Nullable; +/** + * Represents the server data packet sent from the server to the client, which contains information + * such as the server description, favicon, and secure chat enforcement status. + */ public class ServerDataPacket implements MinecraftPacket { private @Nullable ComponentHolder description; @@ -38,6 +42,13 @@ public class ServerDataPacket implements MinecraftPacket { public ServerDataPacket() { } + /** + * Constructs a new {@code ServerDataPacket} with the given server description, favicon, and secure chat enforcement status. + * + * @param description the server description (maybe null) + * @param favicon the server favicon (maybe null) + * @param secureChatEnforced whether secure chat is enforced (for versions 1.19.1 to 1.20.5) + */ public ServerDataPacket(@Nullable ComponentHolder description, @Nullable Favicon favicon, boolean secureChatEnforced) { this.description = description; @@ -127,4 +138,4 @@ public class ServerDataPacket implements MinecraftPacket { public int encodeSizeHint(Direction direction, ProtocolVersion version) { return 8 * 1024; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java index 65693cd8..8c8bec60 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java @@ -29,6 +29,11 @@ import io.netty.buffer.ByteBuf; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents the packet sent from the client to the server during the login phase. + * This packet contains the player's username, optionally a cryptographic key for + * authentication, and the holder UUID depending on the Minecraft protocol version. + */ public class ServerLoginPacket implements MinecraftPacket { private static final QuietDecoderException EMPTY_USERNAME = new QuietDecoderException( @@ -41,17 +46,35 @@ public class ServerLoginPacket implements MinecraftPacket { public ServerLoginPacket() { } + /** + * Constructs a {@code ServerLoginPacket} with a username and optional player key. + * + * @param username the player's username + * @param playerKey the player's cryptographic key, or {@code null} if not present + */ public ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey) { this.username = Preconditions.checkNotNull(username, "username"); this.playerKey = playerKey; } + /** + * Constructs a new {@code ServerLoginPacket} with the specified username and holder UUID. + * + * @param username the player's username + * @param holderUuid the holder UUID (optional) + */ public ServerLoginPacket(String username, @Nullable UUID holderUuid) { this.username = Preconditions.checkNotNull(username, "username"); this.holderUuid = holderUuid; this.playerKey = null; } + /** + * Gets the player's username from the login packet. + * + * @return the player's username + * @throws IllegalStateException if the username is not specified + */ public String getUsername() { if (username == null) { throw new IllegalStateException("No username found!"); @@ -74,10 +97,10 @@ public class ServerLoginPacket implements MinecraftPacket { @Override public String toString() { return "ServerLogin{" - + "username='" + username + '\'' - + "playerKey='" + playerKey + '\'' - + "holderUUID='" + holderUuid + '\'' - + '}'; + + "username='" + username + '\'' + + "playerKey='" + playerKey + '\'' + + "holderUUID='" + holderUuid + '\'' + + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java index 322cd9b1..86893cc0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java @@ -30,6 +30,10 @@ import java.util.List; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents the packet sent from the server to the client to indicate successful login. + * This packet contains the player's UUID, username, and properties associated with their profile. + */ public class ServerLoginSuccessPacket implements MinecraftPacket { private @Nullable UUID uuid; @@ -38,6 +42,12 @@ public class ServerLoginSuccessPacket implements MinecraftPacket { private static final boolean strictErrorHandling = VelocityProperties .readBoolean("velocity.strictErrorHandling", true); + /** + * Gets the player's UUID from the login success packet. + * + * @return the player's UUID + * @throws IllegalStateException if the UUID is not specified + */ public UUID getUuid() { if (uuid == null) { throw new IllegalStateException("No UUID specified!"); @@ -49,6 +59,12 @@ public class ServerLoginSuccessPacket implements MinecraftPacket { this.uuid = uuid; } + /** + * Gets the player's username from the login success packet. + * + * @return the player's username + * @throws IllegalStateException if the username is not specified + */ public String getUsername() { if (username == null) { throw new IllegalStateException("No username specified!"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java index bee12b80..2191ae09 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java @@ -26,6 +26,11 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a server-bound packet sent by the client containing a key and an optional payload. + * This packet is typically used for exchanging metadata or other information between the client + * and server. + */ public class ServerboundCookieResponsePacket implements MinecraftPacket { private Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java index 6b846c23..9b5665fc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java @@ -25,6 +25,12 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; +/** + * Represents a serverbound packet carrying an opaque custom click action payload. + * + *

      The payload is retained as-is and forwarded to the session handler without + * interpretation by the proxy.

      + */ public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder implements MinecraftPacket { public ServerboundCustomClickActionPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java index 6710bf85..7bba5645 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java @@ -23,6 +23,10 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet that sets the compression threshold for network communication. + * When the size of a packet exceeds the threshold, the packet will be compressed. + */ public class SetCompressionPacket implements MinecraftPacket { private int threshold; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java index 30236704..554e8793 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java @@ -24,6 +24,10 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +/** + * Represents a status ping packet sent by the client to the server, which is used to measure the latency + * between the client and server. + */ public class StatusPingPacket implements MinecraftPacket { private long randomId; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java index 870d9909..cbf901cf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java @@ -24,12 +24,14 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +/** + * Represents a status request packet sent by the client to the server to request the server's status. + */ public class StatusRequestPacket implements MinecraftPacket { public static final StatusRequestPacket INSTANCE = new StatusRequestPacket(); private StatusRequestPacket() { - } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java index 20fada4b..08dcb3db 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java @@ -25,6 +25,9 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a status response packet sent from the server to the client. + */ public class StatusResponsePacket implements MinecraftPacket { private @Nullable CharSequence status; @@ -36,6 +39,12 @@ public class StatusResponsePacket implements MinecraftPacket { this.status = status; } + /** + * Gets the status message from the packet. + * + * @return the status message as a {@link String} + * @throws IllegalStateException if the status is not specified + */ public String getStatus() { if (status == null) { throw new IllegalStateException("Status is not specified"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java index dda4695b..5bdbcc6b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java @@ -29,6 +29,9 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a packet sent by the client when a tab-completion request is initiated. + */ public class TabCompleteRequestPacket implements MinecraftPacket { private static final int VANILLA_MAX_TAB_COMPLETE_LEN = 2048; @@ -39,6 +42,12 @@ public class TabCompleteRequestPacket implements MinecraftPacket { private boolean hasPosition; private long position; + /** + * Gets the command string to be completed. + * + * @return the command string + * @throws IllegalStateException if the command is not set + */ public String getCommand() { if (command == null) { throw new IllegalStateException("Command is not specified"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java index a22fff0b..dddad82f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java @@ -30,6 +30,9 @@ import java.util.ArrayList; import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents the packet used to send tab-completion suggestions to the client. + */ public class TabCompleteResponsePacket implements MinecraftPacket { private int transactionId; @@ -122,6 +125,9 @@ public class TabCompleteResponsePacket implements MinecraftPacket { return handler.handle(this); } + /** + * Represents an individual tab-completion suggestion (offer) sent to the client. + */ public static class Offer implements Comparable { private final String text; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java index b5a74e49..6f94c6c9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java @@ -25,6 +25,9 @@ import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; import org.jetbrains.annotations.Nullable; +/** + * Represents a packet used to transfer a player to another server. + */ public class TransferPacket implements MinecraftPacket { private String host; private int port; @@ -32,11 +35,22 @@ public class TransferPacket implements MinecraftPacket { public TransferPacket() { } + /** + * Constructs a {@code TransferPacket} with the specified host and port. + * + * @param host the hostname of the destination server + * @param port the port of the destination server + */ public TransferPacket(final String host, final int port) { this.host = host; this.port = port; } + /** + * Gets the {@link InetSocketAddress} representing the transfer address. + * + * @return the {@code InetSocketAddress}, or {@code null} if the host is not set + */ @Nullable public InetSocketAddress address() { if (host == null) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java index 9ef40ef0..b86b8bd1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java @@ -34,6 +34,9 @@ import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; +/** + * Represents the packet for updating or inserting player information. + */ public class UpsertPlayerInfoPacket implements MinecraftPacket { private static final Action[] ALL_ACTIONS = Action.class.getEnumConstants(); @@ -133,6 +136,9 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket { return handler.handle(this); } + /** + * Represents the possible actions in the player info packet. + */ public enum Action { ADD_PLAYER((ignored, buf, info) -> { // read info.profile = new GameProfile( @@ -213,6 +219,9 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket { } } + /** + * Represents an entry in the player info packet. + */ public static class Entry { private final UUID profileId; @@ -303,16 +312,16 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket { @Override public String toString() { - return "Entry{" + - "profileId=" + profileId + - ", profile=" + profile + - ", listed=" + listed + - ", latency=" + latency + - ", gameMode=" + gameMode + - ", displayName=" + displayName + - ", listOrder=" + listOrder + - ", chatSession=" + chatSession + - '}'; + return "Entry{" + + "profileId=" + profileId + + ", profile=" + profile + + ", listed=" + listed + + ", latency=" + latency + + ", gameMode=" + gameMode + + ", displayName=" + displayName + + ", listOrder=" + listOrder + + ", chatSession=" + chatSession + + '}'; } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java index 6441f6f7..fe43f5d0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java @@ -24,6 +24,14 @@ import java.util.HashMap; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents an identifier for a Brigadier command argument, mapping the argument to + * different protocol versions. + * + *

      The {@code ArgumentIdentifier} is responsible for holding an identifier string for + * an argument and a map that associates protocol versions with their respective IDs. + * It ensures that the protocol version is compatible with the Minecraft 1.19 protocol or later.

      + */ public class ArgumentIdentifier { private final String identifier; @@ -37,8 +45,8 @@ public class ArgumentIdentifier { Map temp = new HashMap<>(); ProtocolVersion previous = null; - for (int i = 0; i < versions.length; i++) { - VersionSet current = Preconditions.checkNotNull(versions[i]); + for (VersionSet version : versions) { + VersionSet current = Preconditions.checkNotNull(version); Preconditions.checkArgument( current.getVersion().noLessThan(ProtocolVersion.MINECRAFT_1_19), @@ -60,9 +68,9 @@ public class ArgumentIdentifier { @Override public String toString() { - return "ArgumentIdentifier{" + - "identifier='" + identifier + '\'' + - '}'; + return "ArgumentIdentifier{" + + "identifier='" + identifier + '\'' + + '}'; } public String getIdentifier() { @@ -101,7 +109,6 @@ public class ArgumentIdentifier { public ProtocolVersion getVersion() { return version; } - } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java index 203ab375..ba7ab86b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java @@ -45,11 +45,18 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -import org.jetbrains.annotations.NotNull; - import java.util.HashMap; import java.util.Map; +import org.jetbrains.annotations.NotNull; +/** + * The {@code ArgumentPropertyRegistry} is responsible for managing the registration and + * retrieval of argument properties used in command parsing and execution. + * + *

      This class functions as a registry, allowing different argument properties to be registered + * and later retrieved or used when processing commands within the system. The properties + * might be tied to argument types, validation rules, or transformations.

      + */ public class ArgumentPropertyRegistry { private ArgumentPropertyRegistry() { @@ -145,7 +152,6 @@ public class ArgumentPropertyRegistry { } else { ProtocolUtils.writeString(buf, identifier.getIdentifier()); } - } /** @@ -272,7 +278,7 @@ public class ArgumentPropertyRegistry { empty(id("minecraft:heightmap", mapSet(MINECRAFT_1_21_6, 51), mapSet(MINECRAFT_1_21_5, 50), mapSet(MINECRAFT_1_20_3, 49), mapSet(MINECRAFT_1_19_4, 47))); // 1.19.4 - empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54),mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48), + empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54), mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48), mapSet(MINECRAFT_1_19_4, 48), mapSet(MINECRAFT_1_19, 47))); // added in 1.16 empty(id("minecraft:loot_table", mapSet(MINECRAFT_1_21_6, 52), mapSet(MINECRAFT_1_21_5, 51), mapSet(MINECRAFT_1_20_5, 50))); @@ -287,4 +293,4 @@ public class ArgumentPropertyRegistry { empty(id("minecraft:nbt")); // No longer in 1.19+ } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java index 25dcfd76..3649fec1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java @@ -21,6 +21,16 @@ import com.velocitypowered.api.network.ProtocolVersion; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * The {@code ArgumentPropertySerializer} interface defines a contract for serializing and + * deserializing argument properties to and from a specific format. + * + *

      This interface allows implementations to convert argument properties into a serialized form, + * which can later be deserialized and restored to their original form. This is particularly useful + * for persisting command argument configurations or sending them across a network.

      + * + * @param the type of the argument property being serialized + */ public interface ArgumentPropertySerializer { @Nullable T deserialize(ByteBuf buf, ProtocolVersion protocolVersion); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java index 15416f86..950f3784 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java @@ -28,6 +28,17 @@ import io.netty.buffer.Unpooled; import java.util.Collection; import java.util.concurrent.CompletableFuture; +/** + * Represents a mod-specific argument type with custom binary data attached. + * + *

      This class allows external mods or extensions to define their own command argument + * types, identified by a namespaced {@link ArgumentIdentifier} and accompanied by + * serialized {@link ByteBuf} data.

      + * + *

      Note: This type is not parseable or suggestible through Brigadier and exists primarily + * to preserve compatibility with extended command metadata during serialization and + * deserialization.

      + */ public class ModArgumentProperty implements ArgumentType { private final ArgumentIdentifier identifier; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java index 5e8e1daf..eff680c4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java @@ -21,6 +21,16 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * The {@code RegistryIdArgumentSerializer} handles serialization and deserialization + * of integer-based registry ID arguments. + * + *

      This serializer is used for command arguments that refer to elements in Minecraft + * registries (e.g., items, entities, dimensions) by their numerical registry ID.

      + * + *

      Values are encoded as variable-length integers using {@link ProtocolUtils} + * for compact transmission.

      + */ public class RegistryIdArgumentSerializer implements ArgumentPropertySerializer { static final RegistryIdArgumentSerializer REGISTRY_ID = new RegistryIdArgumentSerializer(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java index 6d55b246..1c554e21 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java @@ -28,6 +28,15 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; +/** + * Represents a Brigadier {@link ArgumentType} for registry keys, which are typically + * namespaced resource locations (e.g., {@code minecraft:diamond_sword}). + * + *

      This argument type reads an unquoted string from input and treats it as a raw registry + * key. It does not validate the format or resolve the key against a known registry.

      + * + *

      Examples include simple strings, namespaced keys, or numeric-like identifiers.

      + */ public class RegistryKeyArgument implements ArgumentType { private static final List EXAMPLES = Arrays.asList("foo", "foo:bar", "012"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java index 2bf5f345..86fe95f1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java @@ -21,14 +21,25 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a list of {@link RegistryKeyArgument} objects. + * + *

      Used to manage and store multiple registry key arguments.

      + */ public final class RegistryKeyArgumentList { + /** + * Represents a registry key argument that can either be a resource or a tag. + */ public static class ResourceOrTag extends RegistryKeyArgument { public ResourceOrTag(String identifier) { super(identifier); } + /** + * Serializer for {@link ResourceOrTag}. + */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceOrTag.Serializer REGISTRY = new ResourceOrTag.Serializer(); @@ -45,12 +56,18 @@ public final class RegistryKeyArgumentList { } } + /** + * Represents a registry key argument specifically for a resource or tag key. + */ public static class ResourceOrTagKey extends RegistryKeyArgument { public ResourceOrTagKey(String identifier) { super(identifier); } + /** + * Serializer for {@link ResourceOrTagKey}. + */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceOrTagKey.Serializer REGISTRY = new ResourceOrTagKey.Serializer(); @@ -67,12 +84,18 @@ public final class RegistryKeyArgumentList { } } + /** + * Represents a registry key argument for a resource. + */ public static class ResourceSelector extends RegistryKeyArgument { public ResourceSelector(String identifier) { super(identifier); } + /** + * Serializer for {@link ResourceSelector}. + */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceSelector.Serializer REGISTRY = new ResourceSelector.Serializer(); @@ -89,12 +112,18 @@ public final class RegistryKeyArgumentList { } } + /** + * Represents a registry key argument for a resource key. + */ public static class ResourceKey extends RegistryKeyArgument { public ResourceKey(String identifier) { super(identifier); } + /** + * Serializer for {@link ResourceKey}. + */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceKey.Serializer REGISTRY = new ResourceKey.Serializer(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java index 6ada6157..e2562c85 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java @@ -21,6 +21,12 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Serializer for {@link RegistryKeyArgument} objects. + * + *

      This class handles the serialization and deserialization of {@code RegistryKeyArgument} + * objects to and from a {@link ByteBuf} using the specified {@link ProtocolVersion}.

      + */ public class RegistryKeyArgumentSerializer implements ArgumentPropertySerializer { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java index b026e8cc..5e4d9ced 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java @@ -20,6 +20,12 @@ package com.velocitypowered.proxy.protocol.packet.brigadier; import com.velocitypowered.api.network.ProtocolVersion; import io.netty.buffer.ByteBuf; +/** + * Serializer for time-based arguments represented as {@link Integer}. + * + *

      This class handles the serialization and deserialization of time-related arguments, + * converting them to and from an {@link Integer} format.

      + */ public class TimeArgumentSerializer implements ArgumentPropertySerializer { static final TimeArgumentSerializer TIME = new TimeArgumentSerializer(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java index b0718090..c27c7199 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java @@ -23,39 +23,44 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet sent to acknowledge the receipt of a chat message. + * This packet is used to confirm that a player or client has received and processed + * a chat message from the server. + */ public class ChatAcknowledgementPacket implements MinecraftPacket { - int offset; + int offset; - public ChatAcknowledgementPacket(int offset) { - this.offset = offset; - } + public ChatAcknowledgementPacket(int offset) { + this.offset = offset; + } - public ChatAcknowledgementPacket() { - } + public ChatAcknowledgementPacket() { + } - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - offset = ProtocolUtils.readVarInt(buf); - } + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + offset = ProtocolUtils.readVarInt(buf); + } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, offset); - } + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, offset); + } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } - @Override - public String toString() { - return "ChatAcknowledgement{" + - "offset=" + offset + - '}'; - } + @Override + public String toString() { + return "ChatAcknowledgement{" + + "offset=" + offset + + '}'; + } - public int offset() { - return offset; - } + public int offset() { + return offset; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java index 0cd2f44a..af67506b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java @@ -19,12 +19,28 @@ package com.velocitypowered.proxy.protocol.packet.chat; import com.velocitypowered.proxy.protocol.MinecraftPacket; +/** + * Represents a handler for processing chat-related packets in the game. + * This interface is generic and can handle different types of Minecraft packets that + * extend {@link MinecraftPacket}. + * + * @param the type of packet that this chat handler processes, which must + * extend {@link MinecraftPacket} + */ public interface ChatHandler { Class packetClass(); void handlePlayerChatInternal(T packet); + /** + * Handles a player chat event represented by the given {@link MinecraftPacket}. + * This default method provides a basic mechanism for processing chat-related packets that + * involve player messages. + * + * @param packet the {@link MinecraftPacket} representing the player chat event to handle + * @return {@code true} if the chat event was successfully handled, {@code false} otherwise + */ default boolean handlePlayerChat(MinecraftPacket packet) { if (packetClass().isInstance(packet)) { handlePlayerChatInternal(packetClass().cast(packet)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java index 14a56336..0869ab99 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java @@ -21,12 +21,12 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import io.netty.channel.ChannelFuture; -import org.checkerframework.checker.nullness.qual.Nullable; import java.time.Instant; import java.util.BitSet; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; +import org.checkerframework.checker.nullness.qual.Nullable; /** * A precisely ordered queue which allows for outside entries into the ordered queue through @@ -79,7 +79,8 @@ public class ChatQueue implements AutoCloseable { * @param timestamp the new {@link Instant} timestamp of this packet to update the internal chat state. * @param lastSeenMessages the new {@link LastSeenMessages} last seen messages to update the internal chat state. */ - public void queuePacket(Function> nextPacket, @Nullable Instant timestamp, @Nullable LastSeenMessages lastSeenMessages) { + public void queuePacket(Function> nextPacket, @Nullable Instant timestamp, + @Nullable LastSeenMessages lastSeenMessages) { queueTask((chatState, smc) -> { LastSeenMessages newLastSeenMessages = chatState.updateFromMessage(timestamp, lastSeenMessages); return nextPacket.apply(newLastSeenMessages).thenCompose(packet -> writePacket(packet, smc)); @@ -100,6 +101,12 @@ public class ChatQueue implements AutoCloseable { }); } + /** + * Handles the acknowledgement of a chat message or event by processing the given offset. + * This method is typically called when a chat message or command is acknowledged by the client or server. + * + * @param offset the offset representing the specific message or event being acknowledged + */ public void handleAcknowledgement(int offset) { queueTask((chatState, smc) -> { int ackCountToForward = chatState.accumulateAckCount(offset); @@ -138,16 +145,16 @@ public class ChatQueue implements AutoCloseable { *
    • If we last forwarded a chat or command packet from the client, we have a known 'last seen' that we can * reuse.
    • *
    • If we last forwarded a {@link ChatAcknowledgementPacket}, the previous 'last seen' cannot be reused. We - * cannot predict an up-to-date 'last seen', as we do not know which messages the client actually saw.
    • + * cannot predict an up to date 'last seen', as we do not know which messages the client actually saw. *
    • Therefore, we need to hold back any acknowledgement packets so that we can continue to reuse the last valid * 'last seen' state.
    • *
    • However, there is a limit to the number of messages that can remain unacknowledged on the server.
    • *
    • To address this, we know that if the client has moved its 'last seen' window far enough, we can fill in the - * gap with dummy 'last seen', and it will never be checked.
    • + * gap with stub 'last seen', and it will never be checked. *
    * - * Note that this is effectively unused for 1.20.5+ clients, as commands without any signature do not send 'last seen' - * updates. + *

    Note that this is effectively unused for 1.20.5+ clients, as commands without any signature do not send 'last seen' + * updates.

    */ public static class ChatState { private static final int MINIMUM_DELAYED_ACK_COUNT = LastSeenMessages.WINDOW_SIZE; @@ -160,6 +167,17 @@ public class ChatQueue implements AutoCloseable { private ChatState() { } + /** + * Updates the state of the {@link LastSeenMessages} and the timestamp based on a new message or event. + * This method processes the given timestamp and last seen messages to ensure the internal state is up to date. + * - If the provided {@link Instant} is not null, it updates the last known timestamp. + * - If the provided {@link LastSeenMessages} is not null, it flushes any delayed acknowledgements and updates the + * internal acknowledged messages, returning an adjusted {@link LastSeenMessages} with the offset applied. + * + * @param timestamp the optional {@link Instant} representing the new timestamp for the message or event + * @param lastSeenMessages the optional {@link LastSeenMessages} representing the last seen messages by the player + * @return the updated {@link LastSeenMessages} with the applied offset, or {@code null} if no updates were made + */ @Nullable public LastSeenMessages updateFromMessage(@Nullable Instant timestamp, @Nullable LastSeenMessages lastSeenMessages) { if (timestamp != null) { @@ -174,6 +192,16 @@ public class ChatQueue implements AutoCloseable { return null; } + /** + * Accumulates the given acknowledgement count and determines if enough acknowledgements have been gathered to forward. + * - Adds the provided `ackCount` to the current delayed acknowledgement count. + * - If the accumulated acknowledgements exceed the {@link LastSeenMessages#WINDOW_SIZE}, the method resets the delayed + * acknowledgement count and returns the number of acknowledgements that should be forwarded. + * - If the threshold is not met, the method returns 0, indicating that no acknowledgements need to be forwarded yet. + * + * @param ackCount the number of acknowledgements to add to the accumulated count + * @return the number of acknowledgements that should be forwarded, or 0 if the threshold has not been reached + */ public int accumulateAckCount(int ackCount) { int delayedAckCount = this.delayedAckCount.addAndGet(ackCount); int ackCountToForward = delayedAckCount - MINIMUM_DELAYED_ACK_COUNT; @@ -186,6 +214,11 @@ public class ChatQueue implements AutoCloseable { return 0; } + /** + * Creates a snapshot of the current {@link LastSeenMessages} state. + * + * @return a new {@link LastSeenMessages} representing the current view + */ public LastSeenMessages createLastSeen() { return new LastSeenMessages(0, lastSeenMessages, (byte) 0); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java index 94fc5356..9409a86f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java @@ -19,6 +19,11 @@ package com.velocitypowered.proxy.protocol.packet.chat; import java.time.Instant; +/** + * Manages the timing and duration of chat messages within the game. + * The {@code ChatTimeKeeper} class tracks when chat messages are sent and provides mechanisms + * to determine how long a message has been displayed or to manage message expiration. + */ public class ChatTimeKeeper { private Instant lastTimestamp; @@ -27,6 +32,18 @@ public class ChatTimeKeeper { this.lastTimestamp = Instant.MIN; } + /** + * Updates the internal timestamp of the chat message or session. + * This method checks if the provided {@link Instant} is before the current stored timestamp. + * If it is, the internal timestamp is updated, and the method returns {@code false} to + * indicate that the update was not successful. + * If the provided {@link Instant} is valid, the timestamp is updated, + * and the method may return {@code true}. + * + * @param instant the {@link Instant} representing the new timestamp to update + * @return {@code true} if the timestamp was successfully updated, {@code false} + * if the provided instant is before the current timestamp + */ public boolean update(Instant instant) { if (instant.isBefore(this.lastTimestamp)) { this.lastTimestamp = instant; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java index 66e4e988..04706615 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java @@ -17,6 +17,12 @@ package com.velocitypowered.proxy.protocol.packet.chat; +/** + * Represents different types of chat messages in the game, defining how a message should be + * handled and displayed. + * This enum categorizes various chat message types such as system messages, player chat, + * or game info. + */ public enum ChatType { CHAT((byte) 0), SYSTEM((byte) 1), @@ -31,4 +37,4 @@ public enum ChatType { public byte getId() { return raw; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java index 8e39d78a..31cd85c3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java @@ -31,6 +31,14 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a handler for processing commands associated with specific types of Minecraft packets. + * This interface is generic and allows for handling different packet types that extend + * {@link MinecraftPacket}. + * + * @param the type of packet that this handler is responsible for, which + * must extend {@link MinecraftPacket} + */ public interface CommandHandler { Logger logger = LogManager.getLogger(CommandHandler.class); @@ -39,6 +47,14 @@ public interface CommandHandler { void handlePlayerCommandInternal(T packet); + /** + * Handles a player command associated with a given {@link MinecraftPacket}. + * This default method provides a mechanism for processing commands related to player + * actions within the game. + * + * @param packet the {@link MinecraftPacket} representing the player command to be handled + * @return {@code true} if the command was successfully handled, {@code false} otherwise + */ default boolean handlePlayerCommand(MinecraftPacket packet) { if (packetClass().isInstance(packet)) { handlePlayerCommandInternal(packetClass().cast(packet)); @@ -54,25 +70,45 @@ public interface CommandHandler { .thenApply(hasRunPacketFunction); } + /** + * Queues the result of a player command for execution, managing the future result of the command. + * This method is designed to interact with the {@link VelocityServer} + * and {@link ConnectedPlayer} to + * handle the process of command execution, queuing, and response handling. + * + * @param server the {@link VelocityServer} instance responsible for managing the + * command execution + * @param player the {@link ConnectedPlayer} who initiated the command + * @param futurePacketCreator a {@link BiFunction} that creates a future packet based on + * the {@link CommandExecuteEvent} + * and {@link LastSeenMessages}, which will be used for sending + * a command result + * @param message the command message that the player sent + * @param timestamp the {@link Instant} when the command was executed + * @param lastSeenMessages the {@link LastSeenMessages} object containing the messages last + * seen by the player, + * or {@code null} if not applicable + * @param invocationInfo signing metadata for the event dispatch + */ default void queueCommandResult(VelocityServer server, ConnectedPlayer player, BiFunction> futurePacketCreator, String message, Instant timestamp, @Nullable LastSeenMessages lastSeenMessages, CommandExecuteEvent.InvocationInfo invocationInfo) { - CompletableFuture eventFuture = server.getCommandManager().callCommandEvent(player, message, - invocationInfo); - player.getChatQueue().queuePacket( + CompletableFuture eventFuture = server.getCommandManager().callCommandEvent(player, message, + invocationInfo); + player.getChatQueue().queuePacket( newLastSeenMessages -> eventFuture - .thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages)) - .thenApply(pkt -> { - if (server.getConfiguration().isLogCommandExecutions()) { - logger.info("{} -> executed command /{}", player, message); - } - return pkt; - }).exceptionally(e -> { - logger.info("Exception occurred while running command for {}", player.getUsername(), e); - player.sendMessage( - Component.translatable("velocity.command.generic-error", NamedTextColor.RED)); - return null; - }), timestamp, lastSeenMessages); + .thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages)) + .thenApply(pkt -> { + if (server.getConfiguration().isLogCommandExecutions()) { + logger.info("{} -> executed command /{}", player, message); + } + return pkt; + }).exceptionally(e -> { + logger.info("Exception occurred while running command for {}", player.getUsername(), e); + player.sendMessage( + Component.translatable("velocity.command.generic-error", NamedTextColor.RED)); + return null; + }), timestamp, lastSeenMessages); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java index 0b003326..087756e1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java @@ -25,6 +25,9 @@ import com.google.gson.internal.LazilyParsedNumber; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.BinaryTagType; @@ -47,10 +50,12 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - +/** + * Represents a holder for components used in chat or other text-based data in the Minecraft + * protocol. + * This class supports various formats including JSON and NBT (Named Binary Tag) for storing and + * transmitting text components. + */ public class ComponentHolder { private static final Logger logger = LogManager.getLogger(ComponentHolder.class); public static final int DEFAULT_MAX_STRING_SIZE = 262143; @@ -75,6 +80,14 @@ public class ComponentHolder { this.binaryTag = binaryTag; } + /** + * Retrieves the {@link Component} stored in this {@link ComponentHolder}. + * If the component is not yet initialized, it will attempt to deserialize it from either + * the JSON or NBT representation, depending on which is available. + * + * @return the {@link Component} stored in this holder + * @throws IllegalStateException if both the JSON and binary representations fail to deserialize + */ public Component getComponent() { if (component == null) { if (json != null) { @@ -95,6 +108,13 @@ public class ComponentHolder { return component; } + /** + * Retrieves the JSON representation of the {@link Component} stored in this + * {@link ComponentHolder}. + * If the JSON string is not yet initialized, it will serialize the component into a JSON string. + * + * @return the JSON string representing the {@link Component} + */ public String getJson() { if (json == null) { json = ProtocolUtils.getJsonChatSerializer(version).serialize(getComponent()); @@ -102,6 +122,14 @@ public class ComponentHolder { return json; } + /** + * Retrieves the NBT (Named Binary Tag) representation of the {@link Component} stored in this + * {@link ComponentHolder}. + * If the NBT tag is not yet initialized, it will serialize the component into an NBT + * representation. + * + * @return the {@link BinaryTag} representing the {@link Component} + */ public BinaryTag getBinaryTag() { if (binaryTag == null) { // TODO: replace this with adventure-text-serializer-nbt @@ -110,6 +138,16 @@ public class ComponentHolder { return binaryTag; } + /** + * Serializes a {@link JsonElement} into a {@link BinaryTag} format. + * This method converts JSON primitives (numbers, strings, booleans) and complex structures + * (arrays, objects) + * into their corresponding NBT representations. + * + * @param json the {@link JsonElement} to be serialized into a {@link BinaryTag} + * @return the {@link BinaryTag} representing the serialized JSON element + * @throws IllegalArgumentException if the JSON element is of an unsupported or unknown type + */ public static BinaryTag serialize(JsonElement json) { if (json instanceof JsonPrimitive jsonPrimitive) { if (jsonPrimitive.isNumber()) { @@ -162,36 +200,40 @@ public class ComponentHolder { } switch (listType.id()) { - case 1://BinaryTagTypes.BYTE: + case 1 -> { // BinaryTagTypes.BYTE: byte[] bytes = new byte[jsonArray.size()]; for (int i = 0; i < bytes.length; i++) { bytes[i] = jsonArray.get(i).getAsNumber().byteValue(); } return ByteArrayBinaryTag.byteArrayBinaryTag(bytes); - case 3://BinaryTagTypes.INT: + } + case 3 -> { // BinaryTagTypes.INT: int[] ints = new int[jsonArray.size()]; for (int i = 0; i < ints.length; i++) { ints[i] = jsonArray.get(i).getAsNumber().intValue(); } return IntArrayBinaryTag.intArrayBinaryTag(ints); - case 4://BinaryTagTypes.LONG: + } + case 4 -> { // BinaryTagTypes.LONG: long[] longs = new long[jsonArray.size()]; for (int i = 0; i < longs.length; i++) { longs[i] = jsonArray.get(i).getAsNumber().longValue(); } return LongArrayBinaryTag.longArrayBinaryTag(longs); - case 10://BinaryTagTypes.COMPOUND: - tagItems.replaceAll(tag -> { - if (tag.type() == BinaryTagTypes.COMPOUND) { - return tag; - } else { - return CompoundBinaryTag.builder().put("", tag).build(); - } - }); - break; + } + case 10 -> // BinaryTagTypes.COMPOUND: + tagItems.replaceAll(tag -> { + if (tag.type() == BinaryTagTypes.COMPOUND) { + return tag; + } else { + return CompoundBinaryTag.builder().put("", tag).build(); + } + }); + default -> { + } } return ListBinaryTag.listBinaryTag(listType, tagItems); @@ -200,21 +242,30 @@ public class ComponentHolder { return EndBinaryTag.endBinaryTag(); } + /** + * Deserializes a {@link BinaryTag} into a {@link JsonElement}. + * This method converts NBT (Named Binary Tag) data into its corresponding JSON representation, + * including handling of primitive types, arrays, and compound structures. + * + * @param tag the {@link BinaryTag} to be deserialized into a {@link JsonElement} + * @return the {@link JsonElement} representing the deserialized NBT data + * @throws IllegalArgumentException if the NBT tag type is unsupported or unknown + */ public static JsonElement deserialize(BinaryTag tag) { return switch (tag.type().id()) { - //BinaryTagTypes.BYTE + // BinaryTagTypes.BYTE case 1 -> new JsonPrimitive(((ByteBinaryTag) tag).value()); - //BinaryTagTypes.SHORT + // BinaryTagTypes.SHORT case 2 -> new JsonPrimitive(((ShortBinaryTag) tag).value()); - //BinaryTagTypes.INT: + // BinaryTagTypes.INT: case 3 -> new JsonPrimitive(((IntBinaryTag) tag).value()); - //BinaryTagTypes.LONG: + // BinaryTagTypes.LONG: case 4 -> new JsonPrimitive(((LongBinaryTag) tag).value()); - //BinaryTagTypes.FLOAT: + // BinaryTagTypes.FLOAT: case 5 -> new JsonPrimitive(((FloatBinaryTag) tag).value()); - //BinaryTagTypes.DOUBLE: + // BinaryTagTypes.DOUBLE: case 6 -> new JsonPrimitive(((DoubleBinaryTag) tag).value()); - //BinaryTagTypes.BYTE_ARRAY: + // BinaryTagTypes.BYTE_ARRAY: case 7 -> { byte[] byteArray = ((ByteArrayBinaryTag) tag).value(); @@ -225,9 +276,9 @@ public class ComponentHolder { yield jsonByteArray; } - //BinaryTagTypes.STRING: + // BinaryTagTypes.STRING: case 8 -> new JsonPrimitive(((StringBinaryTag) tag).value()); - //BinaryTagTypes.LIST: + // BinaryTagTypes.LIST: case 9 -> { ListBinaryTag items = (ListBinaryTag) tag; JsonArray jsonList = new JsonArray(items.size()); @@ -238,7 +289,7 @@ public class ComponentHolder { yield jsonList; } - //BinaryTagTypes.COMPOUND: + // BinaryTagTypes.COMPOUND: case 10 -> { CompoundBinaryTag compound = (CompoundBinaryTag) tag; JsonObject jsonObject = new JsonObject(); @@ -254,7 +305,7 @@ public class ComponentHolder { yield jsonObject; } - //BinaryTagTypes.INT_ARRAY: + // BinaryTagTypes.INT_ARRAY: case 11 -> { int[] intArray = ((IntArrayBinaryTag) tag).value(); @@ -265,7 +316,7 @@ public class ComponentHolder { yield jsonIntArray; } - //BinaryTagTypes.LONG_ARRAY: + // BinaryTagTypes.LONG_ARRAY: case 12 -> { long[] longArray = ((LongArrayBinaryTag) tag).value(); @@ -280,6 +331,19 @@ public class ComponentHolder { }; } + /** + * Reads a {@link ComponentHolder} from the provided {@link ByteBuf} using the specified + * {@link ProtocolVersion}. + * This method deserializes a component from either its binary (NBT) or JSON representation, + * depending on the protocol version. + * - For Minecraft versions 1.20.3 and later, it reads a binary tag. + * - For Minecraft versions 1.13 and later, it reads a JSON string with a size limit. + * - For earlier versions, it reads a standard JSON string. + * + * @param buf the {@link ByteBuf} containing the serialized component data + * @param version the {@link ProtocolVersion} indicating how the component should be deserialized + * @return a {@link ComponentHolder} containing the deserialized component + */ public static ComponentHolder read(ByteBuf buf, ProtocolVersion version) { if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) { return new ComponentHolder(version, @@ -291,6 +355,15 @@ public class ComponentHolder { } } + /** + * Writes the {@link ComponentHolder}'s data to the provided {@link ByteBuf}. + * This method serializes the component into either its binary (NBT) or JSON representation + * based on the protocol version. + * - For Minecraft versions 1.20.3 and later, it writes the component as a binary tag (NBT). + * - For earlier versions, it writes the component as a JSON string. + * + * @param buf the {@link ByteBuf} where the component data will be written + */ public void write(ByteBuf buf) { if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) { ProtocolUtils.writeBinaryTag(buf, version, getBinaryTag()); @@ -298,4 +371,4 @@ public class ComponentHolder { ProtocolUtils.writeString(buf, getJson()); } } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java index c03e5f8c..8f41a6c8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java @@ -23,6 +23,10 @@ import io.netty.buffer.ByteBuf; import java.util.Arrays; import java.util.BitSet; +/** + * Represents a collection of the last seen messages by a player or client. + * This class tracks the recent chat messages that the player has viewed. + */ public class LastSeenMessages { public static final int WINDOW_SIZE = 20; @@ -35,12 +39,26 @@ public class LastSeenMessages { this(0, new BitSet(), (byte) 0); } + /** + * Creates a new {@link LastSeenMessages} instance with the specified offset, acknowledged messages, and checksum. + * + * @param offset the starting index of the message window + * @param acknowledged a BitSet representing which messages have been acknowledged + * @param checksum the checksum for the message window data + */ public LastSeenMessages(int offset, BitSet acknowledged, byte checksum) { this.offset = offset; this.acknowledged = acknowledged; this.checksum = checksum; } + /** + * Constructs a new {@link LastSeenMessages} instance by decoding data from the provided + * {@link ByteBuf}. + * + * @param buf the buffer containing the serialized last seen messages data + * @param protocolVersion the protocol version (determines if checksum is written) + */ public LastSeenMessages(ByteBuf buf, ProtocolVersion protocolVersion) { this.offset = ProtocolUtils.readVarInt(buf); @@ -53,6 +71,12 @@ public class LastSeenMessages { } } + /** + * Encodes this {@link LastSeenMessages} instance into the provided {@link ByteBuf}. + * + * @param buf the buffer to write the data to + * @param protocolVersion the protocol version used for encoding + */ public void encode(ByteBuf buf, ProtocolVersion protocolVersion) { ProtocolUtils.writeVarInt(buf, offset); buf.writeBytes(Arrays.copyOf(acknowledged.toByteArray(), DIV_FLOOR)); @@ -75,10 +99,10 @@ public class LastSeenMessages { @Override public String toString() { - return "LastSeenMessages{" + - "offset=" + offset + - ", acknowledged=" + acknowledged + - ", checksum=" + checksum + - '}'; + return "LastSeenMessages{" + + "offset=" + offset + + ", acknowledged=" + acknowledged + + ", checksum=" + checksum + + '}'; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java index d07b798a..41b6f6cb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java @@ -23,6 +23,11 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet sent between the server and client to handle chat completion suggestions. + * This packet allows the server to send chat message completions or suggestions to the client, + * helping users complete commands or chat messages. + */ public class PlayerChatCompletionPacket implements MinecraftPacket { private String[] completions; @@ -71,6 +76,9 @@ public class PlayerChatCompletionPacket implements MinecraftPacket { return handler.handle(this); } + /** + * Represents the different actions that can be taken with chat completions. + */ public enum Action { ADD, REMOVE, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java index e5823643..4bddf35f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java @@ -22,37 +22,46 @@ import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import net.kyori.adventure.text.Component; +/** + * Abstract base class for handling rate-limited player command packets. + * + *

    Subclasses should implement {@link #handlePlayerCommandInternal(MinecraftPacket)} to define + * how individual command packets are processed. Rate limiting is enforced to prevent abuse.

    + * + * @param the type of {@link MinecraftPacket} this handler processes + */ public abstract class RateLimitedCommandHandler implements CommandHandler { - private final Player player; - private final VelocityServer velocityServer; + private final Player player; + private final VelocityServer velocityServer; - private int failedAttempts; + private int failedAttempts; - protected RateLimitedCommandHandler(Player player, VelocityServer velocityServer) { - this.player = player; - this.velocityServer = velocityServer; - } + protected RateLimitedCommandHandler(Player player, VelocityServer velocityServer) { + this.player = player; + this.velocityServer = velocityServer; + } - @Override - public boolean handlePlayerCommand(MinecraftPacket packet) { - if (packetClass().isInstance(packet)) { - if (!velocityServer.getCommandRateLimiter().attempt(player.getUniqueId())) { - if (velocityServer.getConfiguration().isKickOnCommandRateLimit() && failedAttempts++ >= velocityServer.getConfiguration().getKickAfterRateLimitedCommands()) { - player.disconnect(Component.translatable("velocity.kick.command-rate-limit")); - } - - if (velocityServer.getConfiguration().isForwardCommandsIfRateLimited()) { - return false; // Send the packet to the server - } - } else { - failedAttempts = 0; - } - - handlePlayerCommandInternal(packetClass().cast(packet)); - return true; + @Override + public boolean handlePlayerCommand(MinecraftPacket packet) { + if (packetClass().isInstance(packet)) { + if (!velocityServer.getCommandRateLimiter().attempt(player.getUniqueId())) { + if (velocityServer.getConfiguration().isKickOnCommandRateLimit() + && failedAttempts++ >= velocityServer.getConfiguration().getKickAfterRateLimitedCommands()) { + player.disconnect(Component.translatable("velocity.kick.command-rate-limit")); } - return false; + if (velocityServer.getConfiguration().isForwardCommandsIfRateLimited()) { + return false; // Send the packet to the server + } + } else { + failedAttempts = 0; + } + + handlePlayerCommandInternal(packetClass().cast(packet)); + return true; } + + return false; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java index 9dd5950a..13421cfb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java @@ -26,6 +26,11 @@ import java.util.Objects; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a remote chat session that implements the {@link ChatSession} interface. + * This session is used for handling chat interactions that occur remotely, typically between + * a client and server, allowing for communication and session tracking. + */ public class RemoteChatSession implements ChatSession { private final @Nullable UUID sessionId; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java index 1a26affd..a15aac01 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java @@ -23,6 +23,11 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * Represents a packet sent from the server to the client to display system chat messages. + * This packet handles the communication of messages that are not player-generated, but instead + * come from the system or server itself. + */ public class SystemChatPacket implements MinecraftPacket { public SystemChatPacket() { @@ -47,7 +52,7 @@ public class SystemChatPacket implements MinecraftPacket { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { component = ComponentHolder.read(buf, version); - if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)){ + if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) { type = buf.readBoolean() ? ChatType.GAME_INFO : ChatType.SYSTEM; } else { type = ChatType.values()[ProtocolUtils.readVarInt(buf)]; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java index b0d2f12a..ac889a52 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java @@ -23,11 +23,22 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatBuilder; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionChatBuilder; import java.util.function.Function; +/** + * Factory class for creating instances of chat builders. + * + *

    The {@code ChatBuilderFactory} is responsible for providing various builder instances + * used to construct chat-related components, such as messages, chat formats, or text components.

    + */ public class ChatBuilderFactory { private final ProtocolVersion version; private final Function builderFunction; + /** + * Creates a new {@code ChatBuilderFactory} for the specified protocol version. + * + * @param version the protocol version to be used by the chat builder factory + */ public ChatBuilderFactory(ProtocolVersion version) { this.version = version; if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java index 9ac02864..18cea35a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java @@ -28,6 +28,13 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * An abstract class for building chat components in version 2 of the chat system. + * + *

    The {@code ChatBuilderV2} class provides the foundation for creating and formatting + * chat components, allowing subclasses to implement specific behaviors for constructing + * chat messages or text components.

    + */ public abstract class ChatBuilderV2 { protected final ProtocolVersion version; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java index d654c619..b8cd4f79 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java @@ -26,6 +26,12 @@ import com.velocitypowered.proxy.protocol.packet.chat.SystemChatPacket; import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderV2; import net.kyori.adventure.text.Component; +/** + * A concrete implementation of {@link ChatBuilderV2} that uses keys to build chat components. + * + *

    The {@code KeyedChatBuilder} class extends the functionality of {@link ChatBuilderV2} by allowing + * chat components to be built using specific keys, enabling dynamic message construction.

    + */ public class KeyedChatBuilder extends ChatBuilderV2 { public KeyedChatBuilder(ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java index f8fc906a..edc2268b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java @@ -30,6 +30,13 @@ import net.kyori.adventure.text.Component; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +/** + * A handler for processing chat components based on specific keys. + * + *

    The {@code KeyedChatHandler} class is responsible for managing chat interactions or + * messages that keys identify. It implements the required interface or class + * to handle key-based chat processing.

    + */ public class KeyedChatHandler implements com.velocitypowered.proxy.protocol.packet.chat.ChatHandler { @@ -48,6 +55,15 @@ public class KeyedChatHandler implements return KeyedPlayerChatPacket.class; } + /** + * Logs an error and disconnects the player when a plugin attempts to cancel a signed chat message. + * + *

    This method handles the invalid behavior of canceling signed chat messages, which is no longer allowed + * starting from Minecraft version 1.19.1.

    + * + * @param logger the logger used to log the error + * @param player the player to disconnect due to the illegal action + */ public static void invalidCancel(Logger logger, ConnectedPlayer player) { logger.fatal("A plugin tried to cancel a signed chat message." + " This is no longer possible in 1.19.1 and newer. " @@ -56,6 +72,15 @@ public class KeyedChatHandler implements + "Contact your network administrator.")); } + /** + * Logs an error and disconnects the player when a plugin attempts to modify a signed chat message. + * + *

    This method handles the invalid behavior of modifying signed chat messages, which is no longer allowed + * starting from Minecraft version 1.19.1.

    + * + * @param logger the logger used to log the error + * @param player the player to disconnect due to the illegal action + */ public static void invalidChange(Logger logger, ConnectedPlayer player) { logger.fatal("A plugin tried to change a signed chat message. " + "This is no longer possible in 1.19.1 and newer. " diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java index b10332f0..e52f4c9a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java @@ -26,11 +26,24 @@ import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderV2; import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; +/** + * Handles keyed player commands by implementing {@link RateLimitedCommandHandler}. + * + *

    The {@code KeyedCommandHandler} processes commands that are sent using + * {@link KeyedPlayerCommandPacket}. It provides the necessary logic for handling + * and executing commands associated with specific keys.

    + */ public class KeyedCommandHandler extends RateLimitedCommandHandler { private final ConnectedPlayer player; private final VelocityServer server; + /** + * Constructs a new {@code KeyedCommandHandler}. + * + * @param player the player sending the command + * @param server the proxy server instance + */ public KeyedCommandHandler(ConnectedPlayer player, VelocityServer server) { super(player, server); this.player = player; @@ -112,6 +125,7 @@ public class KeyedCommandHandler extends RateLimitedCommandHandlerThe {@code KeyedPlayerChatPacket} handles player chat messages, supporting signed previews, + * message signatures, and previous message validation. It includes fields for tracking message + * signatures and handling expired messages.

    + */ public class KeyedPlayerChatPacket implements MinecraftPacket { private String message; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java index 0bb43ec8..9978243f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java @@ -35,6 +35,13 @@ import java.util.List; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a player command packet with support for keyed commands. + * + *

    The {@code KeyedPlayerCommandPacket} handles player commands sent to the server, + * allowing for command execution based on specific keys. This packet can include additional + * information such as arguments and key-based identifiers for the command.

    + */ public class KeyedPlayerCommandPacket implements MinecraftPacket { private static final int MAX_NUM_ARGUMENTS = 8; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java index 77df43bb..f61661e2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java @@ -25,6 +25,13 @@ import java.util.UUID; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; +/** + * A concrete implementation of {@link ChatBuilderV2} for handling legacy chat formats. + * + *

    The {@code LegacyChatBuilder} is designed to support and build chat components + * using legacy chat formatting, such as the formats used in earlier versions of Minecraft. + * It extends the functionality of {@link ChatBuilderV2} to cater to older chat systems.

    + */ public class LegacyChatBuilder extends ChatBuilderV2 { public LegacyChatBuilder(ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java index b7a641ca..71dc842a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java @@ -23,6 +23,13 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.packet.chat.ChatHandler; +/** + * A handler for processing legacy chat packets, implementing {@link ChatHandler}. + * + *

    The {@code LegacyChatHandler} is responsible for handling and processing chat messages + * sent using {@link LegacyChatPacket}. This class provides the necessary logic for + * processing chat data using legacy Minecraft chat formats.

    + */ public class LegacyChatHandler implements ChatHandler { private final VelocityServer server; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java index f5bb6b4f..942dc6ca 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java @@ -25,6 +25,13 @@ import io.netty.buffer.ByteBuf; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a legacy chat packet used in older versions of Minecraft. + * + *

    The {@code LegacyChatPacket} is responsible for holding and transmitting chat messages + * in the format used by legacy versions of Minecraft. It implements {@link MinecraftPacket} + * to ensure compatibility with the packet-handling system.

    + */ public class LegacyChatPacket implements MinecraftPacket { public static final byte CHAT_TYPE = (byte) 0; @@ -45,6 +52,7 @@ public class LegacyChatPacket implements MinecraftPacket { try { return Integer.parseInt(value.trim()); } catch (final NumberFormatException e) { + // Exception has been handled } } return 100; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java index 4f88ee34..68ff4f45 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java @@ -21,15 +21,27 @@ import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.packet.chat.RateLimitedCommandHandler; - import java.time.Instant; import java.util.concurrent.CompletableFuture; +/** + * A handler for processing legacy commands, implementing {@link RateLimitedCommandHandler}. + * + *

    The {@code LegacyCommandHandler} processes and handles command packets that are sent + * using {@link LegacyChatPacket}. It provides the necessary logic to support legacy + * command formats and ensure compatibility with older Minecraft versions.

    + */ public class LegacyCommandHandler extends RateLimitedCommandHandler { private final ConnectedPlayer player; private final VelocityServer server; + /** + * Constructs a new {@code LegacyCommandHandler} for handling legacy command packets. + * + * @param player the connected player issuing the command + * @param server the Velocity server instance + */ public LegacyCommandHandler(ConnectedPlayer player, VelocityServer server) { super(player, server); this.player = player; @@ -64,6 +76,7 @@ public class LegacyCommandHandler extends RateLimitedCommandHandlerThe {@code SessionChatBuilder} is designed to build chat components that are specific to + * a player's session, allowing customization and context-specific formatting of chat messages + * within the current session.

    + */ public class SessionChatBuilder extends ChatBuilderV2 { public SessionChatBuilder(ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java index 74b5747f..621564a1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java @@ -26,11 +26,17 @@ import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.packet.chat.ChatHandler; import com.velocitypowered.proxy.protocol.packet.chat.ChatQueue; +import java.util.concurrent.CompletableFuture; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.concurrent.CompletableFuture; - +/** + * A handler for processing session-based chat packets, implementing {@link ChatHandler}. + * + *

    The {@code SessionChatHandler} processes and handles chat messages sent during a player's + * session using {@link SessionPlayerChatPacket}. It provides the logic for handling session-specific + * chat messages, ensuring the correct context and formatting within the session.

    + */ public class SessionChatHandler implements ChatHandler { private static final Logger logger = LogManager.getLogger(SessionChatHandler.class); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java index 6978f8ee..83d10b5d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java @@ -22,17 +22,29 @@ import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket; -import java.util.concurrent.CompletableFuture; - import com.velocitypowered.proxy.protocol.packet.chat.RateLimitedCommandHandler; +import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * A handler for processing session-based commands, implementing {@link RateLimitedCommandHandler}. + * + *

    The {@code SessionCommandHandler} is responsible for handling commands that are specific + * to a player's session, using {@link SessionPlayerCommandPacket}. It provides logic to + * process commands that are tied to the context of the current session.

    + */ public class SessionCommandHandler extends RateLimitedCommandHandler { private final ConnectedPlayer player; private final VelocityServer server; + /** + * Constructs a new {@link SessionCommandHandler} for the specified player and server. + * + * @param player the connected player associated with this handler + * @param server the Velocity server instance + */ public SessionCommandHandler(ConnectedPlayer player, VelocityServer server) { super(player, server); this.player = player; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java index 8a00452c..4a63665c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java @@ -25,6 +25,13 @@ import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages; import io.netty.buffer.ByteBuf; import java.time.Instant; +/** + * Represents a player chat packet specific to a session, implementing {@link MinecraftPacket}. + * + *

    The {@code SessionPlayerChatPacket} handles chat messages sent by a player during a session, + * and may include session-specific context, such as timestamps, message formatting, or other + * relevant session data.

    + */ public class SessionPlayerChatPacket implements MinecraftPacket { protected String message; @@ -100,6 +107,15 @@ public class SessionPlayerChatPacket implements MinecraftPacket { return signature; } + /** + * Creates a new {@code SessionPlayerChatPacket} with the specified last-seen messages. + * + *

    This method constructs a new {@code SessionPlayerChatPacket} instance that retains the + * current packet's properties, while updating the last seen messages.

    + * + * @param lastSeenMessages the last seen messages to associate with the new packet + * @return a new {@code SessionPlayerChatPacket} with the updated last seen messages + */ public SessionPlayerChatPacket withLastSeenMessages(LastSeenMessages lastSeenMessages) { SessionPlayerChatPacket packet = new SessionPlayerChatPacket(); packet.message = message; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java index f4ea3a1e..8a7ddd0d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java @@ -26,11 +26,17 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; -import org.checkerframework.checker.nullness.qual.Nullable; - import java.time.Instant; import java.util.List; +import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents a packet that handles player commands in a Minecraft session. + * + *

    This packet contains information about the player's command, timestamp, + * salt, argument signatures, and last seen messages for verification and + * processing.

    + */ public class SessionPlayerCommandPacket implements MinecraftPacket { protected String command; @@ -71,7 +77,8 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { } public CommandExecuteEvent.SignedState getEventSignedState() { - return !this.argumentSignatures.isEmpty() ? CommandExecuteEvent.SignedState.SIGNED_WITH_ARGS : CommandExecuteEvent.SignedState.SIGNED_WITHOUT_ARGS; + return !this.argumentSignatures.isEmpty() ? CommandExecuteEvent.SignedState.SIGNED_WITH_ARGS + : CommandExecuteEvent.SignedState.SIGNED_WITHOUT_ARGS; } @Override @@ -81,15 +88,26 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { @Override public String toString() { - return "SessionPlayerCommand{" + - "command='" + command + '\'' + - ", timeStamp=" + timeStamp + - ", salt=" + salt + - ", argumentSignatures=" + argumentSignatures + - ", lastSeenMessages=" + lastSeenMessages + - '}'; + return "SessionPlayerCommand{" + + "command='" + command + '\'' + + ", timeStamp=" + timeStamp + + ", salt=" + salt + + ", argumentSignatures=" + argumentSignatures + + ", lastSeenMessages=" + lastSeenMessages + + '}'; } + /** + * Returns a new instance of {@code SessionPlayerCommandPacket} with the specified + * {@code LastSeenMessages}. + * + *

    If {@code lastSeenMessages} is null, it creates an {@code UnsignedPlayerCommandPacket} + * instead. Otherwise, it creates a new {@code SessionPlayerCommandPacket} with the + * provided {@code lastSeenMessages}.

    + * + * @param lastSeenMessages the last seen messages to include in the packet, may be {@code null} + * @return a new instance of {@code SessionPlayerCommandPacket} or {@code UnsignedPlayerCommandPacket} + */ public SessionPlayerCommandPacket withLastSeenMessages(@Nullable LastSeenMessages lastSeenMessages) { if (lastSeenMessages == null) { UnsignedPlayerCommandPacket packet = new UnsignedPlayerCommandPacket(); @@ -105,6 +123,12 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { return packet; } + /** + * Represents a collection of argument signatures for commands. + * + *

    This class is responsible for handling the encoding and decoding of + * argument signatures associated with a player command in a Minecraft session.

    + */ public static class ArgumentSignatures { private final List entries; @@ -113,6 +137,16 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { this.entries = List.of(); } + /** + * Constructs an {@code ArgumentSignatures} instance by decoding the signatures + * from the provided {@code ByteBuf}. + * + *

    This constructor reads the argument signatures from the buffer and ensures + * that the number of signatures does not exceed the allowed limit.

    + * + * @param buf the {@code ByteBuf} to decode the argument signatures from + * @throws QuietDecoderException if the number of argument signatures exceeds the allowed limit + */ public ArgumentSignatures(ByteBuf buf) { int size = ProtocolUtils.readVarInt(buf); if (size > 8) { @@ -130,20 +164,44 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { return this.entries.isEmpty(); } + /** + * Encodes the argument signatures into the provided {@code ByteBuf}. + * + *

    This method writes the number of argument signatures and each signature's + * details into the buffer for transmission.

    + * + * @param buf the {@code ByteBuf} to encode the argument signatures into + */ public void encode(ByteBuf buf) { ProtocolUtils.writeVarInt(buf, entries.size()); for (ArgumentSignature entry : entries) { entry.encode(buf); } } + + /** + * Returns a string representation of this {@code ArgumentSignatures} instance. + * + *

    The output includes a list of individual {@link ArgumentSignature} entries + * attached to this command packet.

    + * + * @return a human-readable string describing the argument signatures + */ @Override public String toString() { - return "ArgumentSignatures{" + - "entries=" + entries + - '}'; + return "ArgumentSignatures{" + + "entries=" + entries + + '}'; } } + /** + * Represents a single argument signature associated with a command. + * + *

    This class is responsible for handling the encoding and decoding of + * individual argument signatures, which consist of a name and a signature + * (byte array).

    + */ public static class ArgumentSignature { private final String name; @@ -161,9 +219,9 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { @Override public String toString() { - return "ArgumentSignature{" + - "name='" + name + '\'' + - '}'; + return "ArgumentSignature{" + + "name='" + name + '\'' + + '}'; } } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java index 915f0cfb..1953b07f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java @@ -24,6 +24,13 @@ import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * Represents an unsigned player command packet, extending {@link SessionPlayerCommandPacket}. + * + *

    The {@code UnsignedPlayerCommandPacket} is used to handle player commands that are not + * signed. It inherits session-specific behavior from {@link SessionPlayerCommandPacket} + * while indicating that the command is unsigned.

    + */ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket { @Override @@ -52,8 +59,8 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket { @Override public String toString() { - return "UnsignedPlayerCommandPacket{" + - "command='" + command + '\'' + - '}'; + return "UnsignedPlayerCommandPacket{" + + "command='" + command + '\'' + + '}'; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java index 79c94b64..50052654 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java @@ -24,6 +24,13 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; +/** + * The {@code ActiveFeaturesPacket} class represents a packet that communicates the currently + * active features between the client and server in the Minecraft protocol. + * + *

    This packet is used to inform the client about which features are enabled or active, + * potentially based on server configurations or gameplay states.

    + */ public class ActiveFeaturesPacket implements MinecraftPacket { private Key[] activeFeatures; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java index 6a3618cb..a9b415e9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java @@ -25,43 +25,47 @@ import io.netty.buffer.ByteBuf; import java.util.HashMap; import java.util.Map; +/** + * Represents a packet sent from the server to the client, containing custom report details. + * This packet carries a map of key-value pairs, where each key and value are strings. + */ public class ClientboundCustomReportDetailsPacket implements MinecraftPacket { - private Map details; + private Map details; - public ClientboundCustomReportDetailsPacket() { + public ClientboundCustomReportDetailsPacket() { + } + + public ClientboundCustomReportDetailsPacket(Map details) { + this.details = details; + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + int detailsCount = ProtocolUtils.readVarInt(buf); + + this.details = new HashMap<>(detailsCount); + for (int i = 0; i < detailsCount; i++) { + details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); } + } - public ClientboundCustomReportDetailsPacket(Map details) { - this.details = details; - } + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, details.size()); - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - int detailsCount = ProtocolUtils.readVarInt(buf); + details.forEach((key, detail) -> { + ProtocolUtils.writeString(buf, key); + ProtocolUtils.writeString(buf, detail); + }); + } - this.details = new HashMap<>(detailsCount); - for (int i = 0; i < detailsCount; i++) { - details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); - } - } + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, details.size()); - - details.forEach((key, detail) -> { - ProtocolUtils.writeString(buf, key); - ProtocolUtils.writeString(buf, detail); - }); - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } - - public Map getDetails() { - return details; - } + public Map getDetails() { + return details; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java index d37866d8..58b531c2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java @@ -18,7 +18,6 @@ package com.velocitypowered.proxy.protocol.packet.config; import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.api.util.ServerLink; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; @@ -27,64 +26,78 @@ import io.netty.buffer.ByteBuf; import java.util.ArrayList; import java.util.List; +/** + * Represents a packet sent from the server to the client, containing server-related links. + * This packet carries a list of links (e.g., URLs or other resources) associated with the server. + */ public class ClientboundServerLinksPacket implements MinecraftPacket { - private List serverLinks; + private List serverLinks; - public ClientboundServerLinksPacket() { + public ClientboundServerLinksPacket() { + } + + public ClientboundServerLinksPacket(List serverLinks) { + this.serverLinks = serverLinks; + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + int linksCount = ProtocolUtils.readVarInt(buf); + + this.serverLinks = new ArrayList<>(linksCount); + for (int i = 0; i < linksCount; i++) { + serverLinks.add(ServerLink.read(buf, version)); + } + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, serverLinks.size()); + + for (ServerLink serverLink : serverLinks) { + serverLink.write(buf); + } + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } + + public List getServerLinks() { + return serverLinks; + } + + /** + * Represents a link to a server with an ID, display name, and URL. + * + *

    This record holds the server's identification number, a display name + * encapsulated in a {@code ComponentHolder}, and the server's URL as a string.

    + * + * @param id the unique identifier for the server + * @param displayName the display name of the server, represented by a {@code ComponentHolder} + * @param url the URL of the server + */ + public record ServerLink(int id, ComponentHolder displayName, String url) { + + private static ServerLink read(ByteBuf buf, ProtocolVersion version) { + if (buf.readBoolean()) { + return new ServerLink(ProtocolUtils.readVarInt(buf), null, ProtocolUtils.readString(buf)); + } else { + return new ServerLink(-1, ComponentHolder.read(buf, version), ProtocolUtils.readString(buf)); + } } - public ClientboundServerLinksPacket(List serverLinks) { - this.serverLinks = serverLinks; - } - - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - int linksCount = ProtocolUtils.readVarInt(buf); - - this.serverLinks = new ArrayList<>(linksCount); - for (int i = 0; i < linksCount; i++) { - serverLinks.add(ServerLink.read(buf, version)); - } - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, serverLinks.size()); - - for (ServerLink serverLink : serverLinks) { - serverLink.write(buf); - } - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } - - public List getServerLinks() { - return serverLinks; - } - - public record ServerLink(int id, ComponentHolder displayName, String url) { - - private static ServerLink read(ByteBuf buf, ProtocolVersion version) { - if (buf.readBoolean()) { - return new ServerLink(ProtocolUtils.readVarInt(buf), null, ProtocolUtils.readString(buf)); - } else { - return new ServerLink(-1, ComponentHolder.read(buf, version), ProtocolUtils.readString(buf)); - } - } - - private void write(ByteBuf buf) { - if (id >= 0) { - buf.writeBoolean(true); - ProtocolUtils.writeVarInt(buf, id); - } else { - buf.writeBoolean(false); - displayName.write(buf); - } - ProtocolUtils.writeString(buf, url); - } + private void write(ByteBuf buf) { + if (id >= 0) { + buf.writeBoolean(true); + ProtocolUtils.writeVarInt(buf, id); + } else { + buf.writeBoolean(false); + displayName.write(buf); + } + ProtocolUtils.writeString(buf, url); } + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java index e9811f9f..07ca9c4b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java @@ -23,6 +23,12 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; +/** + * A client-to-server packet indicating the player has accepted the server's + * code of conduct during the configuration stage. + * + *

    This packet has no payload and is represented as a singleton.

    + */ public class CodeOfConductAcceptPacket implements MinecraftPacket { public static final CodeOfConductAcceptPacket INSTANCE = new CodeOfConductAcceptPacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java index 41433307..37fdd926 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java @@ -24,6 +24,14 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; +/** + * A server-to-client packet containing the server's code of conduct. + * + *

    This packet is sent during the configuration stage to present the + * server-defined conduct rules to the client. The client may later + * respond with a {@link CodeOfConductAcceptPacket} to indicate + * acceptance.

    + */ public class CodeOfConductPacket extends DeferredByteBufHolder implements MinecraftPacket { public CodeOfConductPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java index 20d40fd4..5a2afea5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java @@ -23,6 +23,13 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * The {@code FinishedUpdatePacket} class represents a packet that signals the completion + * of an update process between the client and server in the Minecraft protocol. + * + *

    This packet is used to indicate that the client has finished receiving and processing + * an update, ensuring that further operations can proceed.

    + */ public class FinishedUpdatePacket implements MinecraftPacket { public static final FinishedUpdatePacket INSTANCE = new FinishedUpdatePacket(); @@ -41,7 +48,7 @@ public class FinishedUpdatePacket implements MinecraftPacket { @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java index b3fb0de4..08e90baf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java @@ -24,55 +24,74 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; +/** + * The {@code KnownPacksPacket} class represents a packet that handles the synchronization + * of known resource packs between the client and server in the Minecraft protocol. + * + *

    This packet contains a list of {@link KnownPack} instances, each representing a resource + * pack with a namespace, identifier, and version. It allows the server to inform the client + * about available resource packs.

    + */ public class KnownPacksPacket implements MinecraftPacket { - private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64); - private static final QuietDecoderException TOO_MANY_PACKS = - new QuietDecoderException("too many known packs"); + private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64); + private static final QuietDecoderException TOO_MANY_PACKS = + new QuietDecoderException("too many known packs"); - private KnownPack[] packs; + private KnownPack[] packs; - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion protocolVersion) { - final int packCount = ProtocolUtils.readVarInt(buf); - if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) { - throw TOO_MANY_PACKS; - } - - final KnownPack[] packs = new KnownPack[packCount]; - - for (int i = 0; i < packCount; i++) { - packs[i] = KnownPack.read(buf); - } - - this.packs = packs; + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + final int packCount = ProtocolUtils.readVarInt(buf); + if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) { + throw TOO_MANY_PACKS; } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, packs.length); + final KnownPack[] packs = new KnownPack[packCount]; - for (KnownPack pack : packs) { - pack.write(buf); - } + for (int i = 0; i < packCount; i++) { + packs[i] = KnownPack.read(buf); } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); + this.packs = packs; + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, packs.length); + + for (KnownPack pack : packs) { + pack.write(buf); + } + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } + + /** + * The {@code KnownPack} record represents a known resource pack with a namespace, + * identifier, and version in the Minecraft protocol. + * + *

    It encapsulates the information needed to identify a resource pack, typically used + * for managing or synchronizing resource packs between the client and server.

    + * + * @param namespace the namespace of the resource pack (e.g., "minecraft" or a mod name) + * @param id the unique identifier of the resource pack within the namespace + * @param version the version of the resource pack + */ + public record KnownPack(String namespace, String id, String version) { + private static KnownPack read(ByteBuf buf) { + return new KnownPack(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); } - public record KnownPack(String namespace, String id, String version) { - private static KnownPack read(ByteBuf buf) { - return new KnownPack(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); - } - - private void write(ByteBuf buf) { - ProtocolUtils.writeString(buf, namespace); - ProtocolUtils.writeString(buf, id); - ProtocolUtils.writeString(buf, version); - } + private void write(ByteBuf buf) { + ProtocolUtils.writeString(buf, namespace); + ProtocolUtils.writeString(buf, id); + ProtocolUtils.writeString(buf, version); } + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java index 2d9ed230..e7dc200e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java @@ -25,6 +25,18 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; +/** + * The {@code RegistrySyncPacket} class is responsible for synchronizing registry data + * between the server and client in Minecraft. + * + *

    This packet is used to ensure that the client has the same registry information as + * the server, covering aspects like blocks, items, entities, and other game elements + * that are part of Minecraft's internal registries.

    + * + *

    It extends the {@link DeferredByteBufHolder} class to handle deferred buffering + * operations for potentially large sets of registry data, which may include + * complex serialization processes.

    + */ public class RegistrySyncPacket extends DeferredByteBufHolder implements MinecraftPacket { public RegistrySyncPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java index d41265ce..8820c025 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java @@ -23,6 +23,16 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * The {@code StartUpdatePacket} class represents a packet that signals the + * start of an update process in the Minecraft protocol. + * + *

    This packet may be used to notify the client or server that a certain update + * process, such as data synchronization or gameplay changes, is about to begin.

    + * + *

    Its specific use depends on the version and context of the update, + * typically handled in the Minecraft networking layer.

    + */ public class StartUpdatePacket implements MinecraftPacket { public static final StartUpdatePacket INSTANCE = new StartUpdatePacket(); @@ -41,7 +51,7 @@ public class StartUpdatePacket implements MinecraftPacket { @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java index c0cf414e..5e0f9777 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java @@ -24,9 +24,17 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; - import java.util.Map; +/** + * The {@code TagsUpdatePacket} class represents a packet sent to update the tags + * used by the Minecraft client. Tags are used in various parts of the game to group + * blocks, items, entities, and other objects under common categories. + * + *

    This packet is typically sent to clients when they join a server or when + * the server needs to update the list of tags for the client, ensuring that + * the client has the most up-to-date tag information.

    + */ public class TagsUpdatePacket implements MinecraftPacket { private Map> tags; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java index d5ef296a..cad00691 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java @@ -17,6 +17,16 @@ package com.velocitypowered.proxy.protocol.packet.legacyping; +/** + * The {@code LegacyMinecraftPingVersion} enum represents the various protocol versions + * used by older Minecraft clients during the server ping process. + * + *

    This enum is used to distinguish between the different legacy versions of Minecraft + * that have unique ping formats, ensuring compatibility with those older clients.

    + * + *

    Each constant in this enum corresponds to a specific version of Minecraft that + * requires a legacy server ping format.

    + */ public enum LegacyMinecraftPingVersion { MINECRAFT_1_3, MINECRAFT_1_4, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java index 8641173e..d8c0e8d7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java @@ -23,8 +23,21 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; +/** + * The {@code GenericTitlePacket} class serves as the base class for all title-related packets + * in Minecraft. This class provides common functionality and properties for handling title, subtitle, + * action bar, and timing-related packets. + * + *

    Subclasses of {@code GenericTitlePacket} implement specific behavior for different types of title + * packets, such as titles, subtitles, and action bars.

    + */ public abstract class GenericTitlePacket implements MinecraftPacket { + /** + * The {@code ActionType} enum represents the different actions that can be performed with a title packet. + * Each action corresponds to a specific type of title operation, such as setting a title or subtitle, + * updating timing information, or resetting and hiding titles. + */ public enum ActionType { SET_TITLE(0), SET_SUBTITLE(1), @@ -45,7 +58,6 @@ public abstract class GenericTitlePacket implements MinecraftPacket { } } - private ActionType action; protected void setAction(ActionType action) { @@ -88,10 +100,9 @@ public abstract class GenericTitlePacket implements MinecraftPacket { throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); } - @Override public final void decode(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { throw new UnsupportedOperationException(); // encode only } @@ -103,7 +114,7 @@ public abstract class GenericTitlePacket implements MinecraftPacket { * @return GenericTitlePacket instance that follows the invoker type/version */ public static GenericTitlePacket constructTitlePacket(ActionType type, ProtocolVersion version) { - GenericTitlePacket packet = null; + GenericTitlePacket packet; if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) { packet = switch (type) { case SET_ACTION_BAR -> new TitleActionbarPacket(); @@ -111,7 +122,6 @@ public abstract class GenericTitlePacket implements MinecraftPacket { case SET_TIMES -> new TitleTimesPacket(); case SET_TITLE -> new TitleTextPacket(); case HIDE, RESET -> new TitleClearPacket(); - default -> throw new IllegalArgumentException("Invalid ActionType"); }; } else { packet = new LegacyTitlePacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java index ebae8a9e..5b5b8b0f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java @@ -24,6 +24,16 @@ import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; +/** + * The {@code LegacyTitlePacket} class represents a packet that handles title-related functionality + * for older versions of Minecraft where title handling differs. + * + *

    This packet is used to send title and subtitle information using legacy methods for clients + * that do not support the newer title packet format.

    + * + *

    It extends the {@link GenericTitlePacket}, inheriting basic title properties but is specifically + * focused on legacy title implementations.

    + */ public class LegacyTitlePacket extends GenericTitlePacket { private @Nullable ComponentHolder component; @@ -51,10 +61,10 @@ public class LegacyTitlePacket extends GenericTitlePacket { buf.writeInt(stay); buf.writeInt(fadeOut); } - case HIDE, RESET -> {} + case HIDE, RESET -> { + } default -> throw new UnsupportedOperationException("Unknown action " + getAction()); } - } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java index f34983ea..5fb3c9a8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java @@ -23,6 +23,16 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; +/** + * The {@code TitleActionbarPacket} class represents a packet that handles the content of an action bar + * displayed to the player in Minecraft. + * + *

    This packet is used to send the text that appears in the action bar, which is a separate text line + * displayed above the hotbar on the player's screen.

    + * + *

    It extends the {@link GenericTitlePacket}, inheriting basic title properties and focusing on + * the content of the action bar.

    + */ public class TitleActionbarPacket extends GenericTitlePacket { private ComponentHolder component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java index 1b348969..077ca594 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java @@ -22,6 +22,15 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * The {@code TitleClearPacket} class represents a packet that handles the clearing or removal of a title + * from the player's screen in Minecraft. + * + *

    This packet is used to instruct the client to clear any currently displayed title and subtitle.

    + * + *

    It extends the {@link GenericTitlePacket}, inheriting basic title properties but is specifically + * focused on clearing the title display.

    + */ public class TitleClearPacket extends GenericTitlePacket { public TitleClearPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java index 0f375ae2..3f44f3e9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java @@ -23,6 +23,15 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; +/** + * The {@code TitleSubtitlePacket} class represents a packet that handles the subtitle content for a title + * displayed to the player in Minecraft. + * + *

    This packet is used to send the subtitle text that appears below the main title on the player's screen.

    + * + *

    It extends the {@link GenericTitlePacket}, inheriting basic title properties and focusing + * on the subtitle content of the title.

    + */ public class TitleSubtitlePacket extends GenericTitlePacket { private ComponentHolder component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java index ae75f5d6..17179075 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java @@ -23,6 +23,15 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; +/** + * The {@code TitleTextPacket} class represents a packet that handles the text content for a title + * displayed to the player in Minecraft. + * + *

    This packet is used to send the main title text to be displayed on the player's screen.

    + * + *

    It extends the {@link GenericTitlePacket}, inheriting basic title properties and focusing + * on the specific text content of the title.

    + */ public class TitleTextPacket extends GenericTitlePacket { private ComponentHolder component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java index 8764a12f..5b737af4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java @@ -22,6 +22,15 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +/** + * The {@code TitleTimesPacket} class represents a packet that handles the timing settings for a title in + * Minecraft, such as fade-in, stay, and fade-out durations. + * + *

    This packet is used to set the timing properties for a title displayed to the player.

    + * + *

    It extends the {@link GenericTitlePacket} to inherit basic title properties and adds specific timing + * controls for the title display.

    + */ public class TitleTimesPacket extends GenericTitlePacket { private int fadeIn; diff --git a/proxy/src/main/resources/default-velocity.toml b/proxy/src/main/resources/default-velocity.toml index 4d71e589..28de5297 100644 --- a/proxy/src/main/resources/default-velocity.toml +++ b/proxy/src/main/resources/default-velocity.toml @@ -42,7 +42,7 @@ forwarding-secret-file = "forwarding.secret" # Announce whether or not your server supports Forge. If you run a modded server, we # suggest turning this on. -# +# # If your network runs one modpack consistently, consider using ping-passthrough = "mods" # instead for a nicer display in the server list. announce-forge = false From 9bfe19f795b610a8abd5ac0fbf9879fdd24de7ca Mon Sep 17 00:00:00 2001 From: Pedro <3602279+Doc94@users.noreply.github.com> Date: Fri, 30 Jan 2026 14:58:44 -0300 Subject: [PATCH 19/48] [ci skip] Replace docs.advntr.dev to docs.papermc.io in jd (#1720) --- .../java/com/velocitypowered/api/command/CommandSource.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandSource.java b/api/src/main/java/com/velocitypowered/api/command/CommandSource.java index 24d5272d..dcc57431 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandSource.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandSource.java @@ -23,7 +23,7 @@ public interface CommandSource extends Audience, PermissionSubject { * Sends a message with the MiniMessage format to this source. * * @param message MiniMessage content - * @see MiniMessage docs + * @see MiniMessage docs * for more information on the format. */ default void sendRichMessage(final @NotNull String message) { @@ -35,8 +35,8 @@ public interface CommandSource extends Audience, PermissionSubject { * * @param message MiniMessage content * @param resolvers resolvers to use - * @see MiniMessage docs - * and MiniMessage Placeholders docs + * @see MiniMessage docs + * and MiniMessage Placeholders docs * for more information on the format. */ default void sendRichMessage( From 14160e1988a704a3ed78580116679fbe98c840b6 Mon Sep 17 00:00:00 2001 From: Emil <12966472+Emilxyz@users.noreply.github.com> Date: Fri, 30 Jan 2026 19:09:27 +0100 Subject: [PATCH 20/48] feat: Implement SkinSource for Player and GameProfile (#1721) --- .../com/velocitypowered/api/proxy/Player.java | 14 +++++++++++- .../velocitypowered/api/util/GameProfile.java | 22 ++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index 456f6541..0fd295ac 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -39,6 +39,7 @@ import net.kyori.adventure.sound.SoundStop; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.event.HoverEventSource; +import net.kyori.adventure.text.object.PlayerHeadObjectContents; import org.checkerframework.checker.nullness.qual.Nullable; import org.jetbrains.annotations.NotNull; @@ -49,7 +50,8 @@ public interface Player extends /* Fundamental Velocity interfaces */ CommandSource, InboundConnection, ChannelMessageSource, ChannelMessageSink, /* Adventure-specific interfaces */ - Identified, HoverEventSource, Keyed, KeyIdentifiable, Sound.Emitter { + Identified, HoverEventSource, Keyed, KeyIdentifiable, Sound.Emitter, + PlayerHeadObjectContents.SkinSource { /** * Returns the player's current username. @@ -339,6 +341,16 @@ public interface Player extends Component.text(getUsername())))); } + @SuppressWarnings("UnstableApiUsage") // permitted implementation + @Override + default void applySkinToPlayerHeadContents( + final PlayerHeadObjectContents.@NotNull Builder builder) { + builder.skin(this.getGameProfile()); + if (this.hasSentPlayerSettings()) { + builder.hat(this.getPlayerSettings().getSkinParts().hasHat()); + } + } + /** * Gets the player's client brand. * diff --git a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java index e918c8e9..c99ffe7d 100644 --- a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java +++ b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java @@ -11,11 +11,14 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; +import net.kyori.adventure.text.object.PlayerHeadObjectContents; +import org.jetbrains.annotations.NotNull; /** * Represents a Mojang game profile. This class is immutable. */ -public final class GameProfile { +public final class GameProfile implements PlayerHeadObjectContents.SkinSource { private final UUID id; private final String undashedId; @@ -169,6 +172,23 @@ public final class GameProfile { ImmutableList.of()); } + @SuppressWarnings("UnstableApiUsage") // permitted implementation + @Override + public void applySkinToPlayerHeadContents( + final PlayerHeadObjectContents.@NotNull Builder builder) { + if (this.properties.isEmpty()) { + builder.id(this.id); + return; + } + + builder.id(this.id) + .name(this.name) + .profileProperties(this.properties.stream() + .map(property -> PlayerHeadObjectContents.property(property.getName(), + property.getValue(), property.getSignature())) + .collect(Collectors.toList())); + } + @Override public String toString() { return "GameProfile{" From 7e01491e2f7952a3d2d798ddaaf0ffd396921329 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sat, 31 Jan 2026 11:34:51 +0100 Subject: [PATCH 21/48] Promote build channel to stable --- proxy/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index 2fb40773..d78a7a3b 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -115,7 +115,7 @@ fill { project("velocity") build { - channel = BuildChannel.BETA + channel = BuildChannel.STABLE versionFamily("3.0.0") version(projectVersion) From 2535751cd9f61cbc880032decb3c20c3dac32f7e Mon Sep 17 00:00:00 2001 From: Rocco Date: Tue, 10 Feb 2026 18:59:34 +0000 Subject: [PATCH 22/48] Add server-id hash to LoginEvent (#1027) --- .../api/event/connection/LoginEvent.java | 28 ++++++++++++++++++- .../connection/client/AuthSessionHandler.java | 6 ++-- .../client/InitialLoginSessionHandler.java | 4 +-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java index 3ec01264..29997670 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java @@ -11,6 +11,7 @@ import com.google.common.base.Preconditions; import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.event.annotation.AwaitingEvent; import com.velocitypowered.api.proxy.Player; +import org.checkerframework.checker.nullness.qual.Nullable; /** * This event is fired once the player has been authenticated, but before they connect to a server. @@ -22,18 +23,33 @@ import com.velocitypowered.api.proxy.Player; public final class LoginEvent implements ResultedEvent { private final Player player; + private final String serverIdHash; private ComponentResult result; /** * Constructs a new {@link LoginEvent}. * * @param player the player who has completed authentication + * @param serverIdHash the server ID hash sent to Mojang for authentication, + * or {@code null} if the connection is in offline-mode */ - public LoginEvent(Player player) { + public LoginEvent(Player player, @Nullable String serverIdHash) { this.player = Preconditions.checkNotNull(player, "player"); + this.serverIdHash = serverIdHash; this.result = ComponentResult.allowed(); } + /** + * Constructs a new {@link LoginEvent}. + * + * @param player the player who has completed authentication + * @deprecated Use {@link #LoginEvent(Player, String)}. + */ + @Deprecated(forRemoval = true) + public LoginEvent(Player player) { + this(player, null); + } + /** * Returns the player who has completed authentication. * @@ -43,6 +59,16 @@ public final class LoginEvent implements ResultedEvent { + server.getEventManager().fire(new LoginEvent(player, serverIdHash)).thenAcceptAsync(event -> { if (mcConnection.isClosed()) { // The player was disconnected server.getEventManager().fireAndForget(new DisconnectEvent(player, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java index 92f14191..482fb76e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/InitialLoginSessionHandler.java @@ -152,7 +152,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { } else { mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, new AuthSessionHandler(server, inbound, - GameProfile.forOfflinePlayer(login.getUsername()), false)); + GameProfile.forOfflinePlayer(login.getUsername()), false, null)); } }); }); @@ -255,7 +255,7 @@ public class InitialLoginSessionHandler implements MinecraftSessionHandler { } // All went well, initialize the session. mcConnection.setActiveSessionHandler(StateRegistry.LOGIN, - new AuthSessionHandler(server, inbound, profile, true)); + new AuthSessionHandler(server, inbound, profile, true, serverId)); } else if (response.statusCode() == 204) { // Apparently an offline-mode user logged onto this online-mode proxy. inbound.disconnect( From c2fd3c07ac1f317e2700aead1a2338fe11152ce2 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Wed, 11 Feb 2026 22:21:03 +0100 Subject: [PATCH 23/48] Introduce SchedulerBackend to fix VelocitySchedulerTest intermittent failure (#1728) --- .../scheduler/ExecutorSchedulerBackend.java | 70 +++++ .../proxy/scheduler/SchedulerBackend.java | 56 ++++ .../proxy/scheduler/VelocityScheduler.java | 24 +- .../DeterministicSchedulerBackend.java | 257 ++++++++++++++++++ .../scheduler/VelocitySchedulerTest.java | 58 ++-- 5 files changed, 433 insertions(+), 32 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/scheduler/ExecutorSchedulerBackend.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/scheduler/SchedulerBackend.java create mode 100644 proxy/src/test/java/com/velocitypowered/proxy/scheduler/DeterministicSchedulerBackend.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/ExecutorSchedulerBackend.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/ExecutorSchedulerBackend.java new file mode 100644 index 00000000..d10eab6f --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/ExecutorSchedulerBackend.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018-2026 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.scheduler; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * A {@link SchedulerBackend} backed by a real {@link ScheduledExecutorService}. + */ +public class ExecutorSchedulerBackend implements SchedulerBackend { + + private final ScheduledExecutorService executor; + + /** + * Creates a ExecutorSchedulerBackend with a default executor. + */ + public ExecutorSchedulerBackend() { + this(Executors.newSingleThreadScheduledExecutor( + new ThreadFactoryBuilder() + .setDaemon(true) + .setNameFormat("Velocity Task Scheduler Timer") + .build() + )); + } + + /** + * Creates a ExecutorSchedulerBackend with a given executor. + * + * @param executor The executor to use. + */ + public ExecutorSchedulerBackend(ScheduledExecutorService executor) { + this.executor = checkNotNull(executor, "executor"); + } + + @Override + public ScheduledFuture schedule(Runnable task, long delay, TimeUnit unit) { + return executor.schedule(task, delay, unit); + } + + @Override + public ScheduledFuture scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) { + return executor.scheduleAtFixedRate(task, initialDelay, period, unit); + } + + @Override + public void shutdown() { + executor.shutdown(); + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/SchedulerBackend.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/SchedulerBackend.java new file mode 100644 index 00000000..ab251ca2 --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/SchedulerBackend.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018-2026 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.scheduler; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * Backend interface used by {@link VelocityScheduler} to schedule timer callbacks. + * + *

    This is an internal abstraction that allows tests to replace the real-time scheduler + * with a deterministic implementation. + */ +interface SchedulerBackend { + + /** + * Schedules a task to run once after the given delay. + * + * @param task the task to run + * @param delay the delay + * @param unit the delay unit + * @return a future representing the scheduled task + */ + ScheduledFuture schedule(Runnable task, long delay, TimeUnit unit); + + /** + * Schedules a task to run at a fixed rate. + * + * @param task the task to run + * @param initialDelay the initial delay + * @param period the period between runs + * @param unit the time unit + * @return a future representing the scheduled task + */ + ScheduledFuture scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit); + + /** + * Shuts down the backend. + */ + void shutdown(); +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java index 727832bd..0a38582a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/scheduler/VelocityScheduler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2023 Velocity Contributors + * Copyright (C) 2018-2026 Velocity Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +23,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; -import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.plugin.PluginManager; import com.velocitypowered.api.scheduler.ScheduledTask; @@ -40,7 +39,6 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -60,20 +58,23 @@ import org.jetbrains.annotations.VisibleForTesting; public class VelocityScheduler implements Scheduler { private final PluginManager pluginManager; - private final ScheduledExecutorService timerExecutionService; + private final SchedulerBackend backend; private final Multimap tasksByPlugin = Multimaps.synchronizedMultimap( Multimaps.newSetMultimap(new IdentityHashMap<>(), HashSet::new)); /** - * Initalizes the scheduler. + * Initializes the scheduler. * * @param pluginManager the Velocity plugin manager */ public VelocityScheduler(PluginManager pluginManager) { + this(pluginManager, new ExecutorSchedulerBackend()); + } + + @VisibleForTesting + VelocityScheduler(PluginManager pluginManager, SchedulerBackend backend) { this.pluginManager = pluginManager; - this.timerExecutionService = Executors - .newSingleThreadScheduledExecutor(new ThreadFactoryBuilder().setDaemon(true) - .setNameFormat("Velocity Task Scheduler Timer").build()); + this.backend = backend; } @Override @@ -118,7 +119,7 @@ public class VelocityScheduler implements Scheduler { for (ScheduledTask task : terminating) { task.cancel(); } - timerExecutionService.shutdown(); + backend.shutdown(); final List plugins = new ArrayList<>(this.pluginManager.getPlugins()); final Iterator pluginIterator = plugins.iterator(); while (pluginIterator.hasNext()) { @@ -232,10 +233,9 @@ public class VelocityScheduler implements Scheduler { void schedule() { if (repeat == 0) { - this.future = timerExecutionService.schedule(this, delay, TimeUnit.MILLISECONDS); + this.future = backend.schedule(this, delay, TimeUnit.MILLISECONDS); } else { - this.future = timerExecutionService - .scheduleAtFixedRate(this, delay, repeat, TimeUnit.MILLISECONDS); + this.future = backend.scheduleAtFixedRate(this, delay, repeat, TimeUnit.MILLISECONDS); } } diff --git a/proxy/src/test/java/com/velocitypowered/proxy/scheduler/DeterministicSchedulerBackend.java b/proxy/src/test/java/com/velocitypowered/proxy/scheduler/DeterministicSchedulerBackend.java new file mode 100644 index 00000000..8a472ceb --- /dev/null +++ b/proxy/src/test/java/com/velocitypowered/proxy/scheduler/DeterministicSchedulerBackend.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2018-2026 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.scheduler; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.time.Duration; +import java.util.PriorityQueue; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Delayed; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +/** + * A deterministic {@link SchedulerBackend} for tests. + * + *

    This backend does not use the wall clock. Tests manually advance time, and all due tasks + * are executed deterministically on the calling thread. + */ +class DeterministicSchedulerBackend implements SchedulerBackend { + + private final Object lock = new Object(); + private final PriorityQueue queue = new PriorityQueue<>(); + private boolean shutdown; + private long nowNanos; + private long seq; + + @Override + public ScheduledFuture schedule(Runnable task, long delay, TimeUnit unit) { + checkNotNull(task, "task"); + checkNotNull(unit, "unit"); + return enqueue(task, unit.toNanos(delay), 0); + } + + @Override + public ScheduledFuture scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) { + checkNotNull(task, "task"); + checkNotNull(unit, "unit"); + checkArgument(period > 0, "period must be > 0"); + return enqueue(task, unit.toNanos(initialDelay), unit.toNanos(period)); + } + + @Override + public void shutdown() { + synchronized (lock) { + shutdown = true; + queue.clear(); + } + } + + /** + * Runs all tasks that are due "now" without advancing time. + */ + void runUntilIdle() { + drainDueTasks(); + } + + /** + * Advances virtual time and runs all tasks that become due. + * + * @param duration the amount of time to advance + */ + void advance(Duration duration) { + checkNotNull(duration, "duration"); + advance(duration.toNanos()); + } + + /** + * Advances virtual time and runs all tasks that become due. + * + * @param time the time to advance + * @param unit the unit + */ + void advance(long time, TimeUnit unit) { + checkNotNull(unit, "unit"); + advance(unit.toNanos(time)); + } + + private void advance(long nanos) { + if (nanos < 0) { + throw new IllegalArgumentException("nanos must be >= 0"); + } + synchronized (lock) { + nowNanos += nanos; + } + drainDueTasks(); + } + + private ScheduledFuture enqueue(Runnable task, long delayNanos, long periodNanos) { + synchronized (lock) { + if (shutdown) { + throw new java.util.concurrent.RejectedExecutionException("backend is shut down"); + } + Entry entry = new Entry(task, nowNanos + Math.max(0, delayNanos), periodNanos, seq++); + entry.future = new FutureImpl(entry); + queue.add(entry); + return entry.future; + } + } + + private void drainDueTasks() { + while (true) { + Entry entry; + synchronized (lock) { + entry = queue.peek(); + if (entry == null || entry.nextRunNanos > nowNanos) { + return; + } + queue.poll(); + } + + // Run outside the lock to avoid deadlocks if tasks schedule more work. + if (!entry.future.isCancelled()) { + try { + entry.task.run(); + } finally { + // no-op + } + } + + synchronized (lock) { + if (entry.future.isCancelled()) { + // Cancelled tasks are not re-queued. + continue; + } + + if (entry.periodNanos == 0) { + entry.future.complete(); + } else { + // Fixed-rate semantics: next run time is based on the scheduled time, not completion time. + entry.nextRunNanos = entry.nextRunNanos + entry.periodNanos; + queue.add(entry); + } + } + } + } + + private final class FutureImpl implements ScheduledFuture { + + private final Entry entry; + private final CountDownLatch completion = new CountDownLatch(1); + private volatile boolean cancelled; + private volatile boolean done; + + private FutureImpl(Entry entry) { + this.entry = entry; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + synchronized (lock) { + if (done) { + return false; + } + cancelled = true; + done = true; + queue.remove(entry); + } + completion.countDown(); + return true; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public boolean isDone() { + return done; + } + + void complete() { + if (!done) { + done = true; + completion.countDown(); + } + } + + @Override + public Object get() throws InterruptedException { + completion.await(); + if (cancelled) { + throw new CancellationException(); + } + return null; + } + + @Override + public Object get(long timeout, TimeUnit unit) throws InterruptedException, java.util.concurrent.TimeoutException { + if (!completion.await(timeout, unit)) { + throw new java.util.concurrent.TimeoutException(); + } + if (cancelled) { + throw new CancellationException(); + } + return null; + } + + @Override + public long getDelay(TimeUnit unit) { + synchronized (lock) { + long remaining = Math.max(0, entry.nextRunNanos - nowNanos); + return unit.convert(remaining, TimeUnit.NANOSECONDS); + } + } + + @Override + public int compareTo(Delayed o) { + long d1 = getDelay(TimeUnit.NANOSECONDS); + long d2 = o.getDelay(TimeUnit.NANOSECONDS); + return Long.compare(d1, d2); + } + } + + private static final class Entry implements Comparable { + + private final Runnable task; + private final long periodNanos; + private final long sequence; + private long nextRunNanos; + private FutureImpl future; + + private Entry(Runnable task, long nextRunNanos, long periodNanos, long sequence) { + this.task = task; + this.nextRunNanos = nextRunNanos; + this.periodNanos = periodNanos; + this.sequence = sequence; + } + + @Override + public int compareTo(Entry other) { + int cmp = Long.compare(this.nextRunNanos, other.nextRunNanos); + if (cmp != 0) { + return cmp; + } + return Long.compare(this.sequence, other.sequence); + } + } +} diff --git a/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java b/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java index e31a8a7e..15b8f1e9 100644 --- a/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java +++ b/proxy/src/test/java/com/velocitypowered/proxy/scheduler/VelocitySchedulerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2023 Velocity Contributors + * Copyright (C) 2018-2026 Velocity Contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,6 +18,7 @@ package com.velocitypowered.proxy.scheduler; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.velocitypowered.api.scheduler.ScheduledTask; import com.velocitypowered.api.scheduler.TaskStatus; @@ -31,22 +32,26 @@ import java.util.concurrent.atomic.AtomicReference; import org.junit.jupiter.api.Test; class VelocitySchedulerTest { - // TODO: The timings here will be inaccurate on slow systems. @Test void buildTask() throws Exception { - VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager()); + DeterministicSchedulerBackend backend = new DeterministicSchedulerBackend(); + VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager(), backend); + CountDownLatch latch = new CountDownLatch(1); - ScheduledTask task = scheduler.buildTask(FakePluginManager.PLUGIN_A, latch::countDown) - .schedule(); - latch.await(); + ScheduledTask task = scheduler.buildTask(FakePluginManager.PLUGIN_A, latch::countDown).schedule(); + + backend.runUntilIdle(); // runs tasks due at t=0 + assertTrue(latch.await(5, TimeUnit.SECONDS)); + ((VelocityTask) task).awaitCompletion(); assertEquals(TaskStatus.FINISHED, task.status()); } @Test - void cancelWorks() throws Exception { - VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager()); + void cancelWorks() { + DeterministicSchedulerBackend backend = new DeterministicSchedulerBackend(); + VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager(), backend); AtomicInteger i = new AtomicInteger(3); ScheduledTask task = scheduler.buildTask(FakePluginManager.PLUGIN_A, i::decrementAndGet) .delay(100, TimeUnit.SECONDS) @@ -58,19 +63,26 @@ class VelocitySchedulerTest { @Test void repeatTaskWorks() throws Exception { - VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager()); + DeterministicSchedulerBackend backend = new DeterministicSchedulerBackend(); + VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager(), backend); + CountDownLatch latch = new CountDownLatch(3); ScheduledTask task = scheduler.buildTask(FakePluginManager.PLUGIN_A, latch::countDown) .delay(100, TimeUnit.MILLISECONDS) .repeat(100, TimeUnit.MILLISECONDS) .schedule(); - latch.await(); + + backend.advance(300, TimeUnit.MILLISECONDS); // triggers 3 timer firings deterministically + assertTrue(latch.await(5, TimeUnit.SECONDS)); + task.cancel(); } @Test void obtainTasksFromPlugin() throws Exception { - VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager()); + DeterministicSchedulerBackend backend = new DeterministicSchedulerBackend(); + VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager(), backend); + CountDownLatch runningLatch = new CountDownLatch(1); CountDownLatch endingLatch = new CountDownLatch(1); @@ -86,16 +98,19 @@ class VelocitySchedulerTest { .repeat(Duration.ofMillis(5)) .schedule(); - runningLatch.await(); + backend.advance(50, TimeUnit.MILLISECONDS); // run first tick only (no wall clock) + assertTrue(runningLatch.await(5, TimeUnit.SECONDS)); - assertEquals(scheduler.tasksByPlugin(FakePluginManager.PLUGIN_A).size(), 1); + assertEquals(1, scheduler.tasksByPlugin(FakePluginManager.PLUGIN_A).size()); endingLatch.countDown(); } @Test void testConsumerCancel() throws Exception { - VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager()); + DeterministicSchedulerBackend backend = new DeterministicSchedulerBackend(); + VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager(), backend); + CountDownLatch latch = new CountDownLatch(1); ScheduledTask task = scheduler.buildTask( @@ -108,14 +123,17 @@ class VelocitySchedulerTest { assertEquals(TaskStatus.SCHEDULED, task.status()); - latch.await(); + backend.runUntilIdle(); // initialDelay is 0 -> due immediately in virtual time + assertTrue(latch.await(5, TimeUnit.SECONDS)); assertEquals(TaskStatus.CANCELLED, task.status()); } @Test void testConsumerEquality() throws Exception { - VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager()); + DeterministicSchedulerBackend backend = new DeterministicSchedulerBackend(); + VelocityScheduler scheduler = new VelocityScheduler(new FakePluginManager(), backend); + CountDownLatch latch = new CountDownLatch(1); AtomicReference consumerTask = new AtomicReference<>(); @@ -127,10 +145,10 @@ class VelocitySchedulerTest { }).delay(60, TimeUnit.MILLISECONDS).schedule(); initialTask.set(task); - latch.await(); + + backend.advance(60, TimeUnit.MILLISECONDS); + assertTrue(latch.await(5, TimeUnit.SECONDS)); assertEquals(consumerTask.get(), initialTask.get()); - } - -} \ No newline at end of file +} From 6aff78728c267bbb67b07298b8cf4580fb79fc6f Mon Sep 17 00:00:00 2001 From: Noah <59799222+Leguan16@users.noreply.github.com> Date: Sat, 21 Feb 2026 20:26:49 +0100 Subject: [PATCH 24/48] [ci skip] fix: typo in ServerPreConnectEvent.ServerResult#denied javadoc (#1735) --- .../velocitypowered/api/event/player/ServerPreConnectEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java index 593a824e..7eb0abb2 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerPreConnectEvent.java @@ -148,7 +148,7 @@ public final class ServerPreConnectEvent implements * is used, then {@link ConnectionRequestBuilder#connect()}'s result will have the status * {@link Status#CONNECTION_CANCELLED}. * - * @return a result to deny conneections + * @return a result to deny connections */ public static ServerResult denied() { return DENIED; From e0db25664fc82eabd9fde5aac22a2311a9765975 Mon Sep 17 00:00:00 2001 From: Riley Park Date: Tue, 3 Mar 2026 05:39:25 -0800 Subject: [PATCH 25/48] Revert "Add various missing jd, bump remaining deps (#1718)" This reverts commit 7d0c002f89d1cc916fd7525bcb4f2a0f4bc31649. --- api/build.gradle.kts | 9 +- .../plugin/ap/PluginAnnotationProcessor.java | 9 - .../ap/SerializedPluginDescription.java | 74 -------- .../api/command/CommandSource.java | 14 +- .../api/command/VelocityBrigadierMessage.java | 6 - .../api/event/Continuation.java | 4 +- .../api/event/EventHandler.java | 16 -- .../api/event/EventManager.java | 1 - .../velocitypowered/api/event/PostOrder.java | 29 +--- .../api/event/ResultedEvent.java | 35 ---- .../event/command/CommandExecuteEvent.java | 14 -- .../command/PlayerAvailableCommandsEvent.java | 10 -- .../connection/ConnectionHandshakeEvent.java | 16 -- .../api/event/connection/DisconnectEvent.java | 44 +---- .../api/event/connection/LoginEvent.java | 21 +-- .../event/connection/PluginMessageEvent.java | 41 ----- .../api/event/connection/PostLoginEvent.java | 10 -- .../api/event/connection/PreLoginEvent.java | 26 --- .../event/connection/PreTransferEvent.java | 37 ---- .../permission/PermissionsSetupEvent.java | 16 -- .../api/event/player/CookieReceiveEvent.java | 25 --- .../api/event/player/CookieRequestEvent.java | 15 -- .../api/event/player/CookieStoreEvent.java | 27 --- .../event/player/GameProfileRequestEvent.java | 21 +-- .../event/player/KickedFromServerEvent.java | 22 --- .../player/PlayerChannelRegisterEvent.java | 16 -- .../player/PlayerChannelUnregisterEvent.java | 20 --- .../api/event/player/PlayerChatEvent.java | 15 -- .../PlayerChooseInitialServerEvent.java | 10 -- .../event/player/PlayerClientBrandEvent.java | 16 +- .../api/event/player/PlayerModInfoEvent.java | 16 -- .../player/PlayerResourcePackStatusEvent.java | 10 -- .../player/PlayerSettingsChangedEvent.java | 16 -- .../event/player/ServerConnectedEvent.java | 15 -- .../player/ServerLoginPluginMessageEvent.java | 26 --- .../event/player/ServerPostConnectEvent.java | 7 - .../event/player/ServerPreConnectEvent.java | 5 - .../player/ServerResourcePackRemoveEvent.java | 3 - .../player/ServerResourcePackSendEvent.java | 21 --- .../PlayerConfigurationEvent.java | 1 - .../PlayerEnterConfigurationEvent.java | 3 +- .../PlayerEnteredConfigurationEvent.java | 1 - .../PlayerFinishConfigurationEvent.java | 3 +- .../PlayerFinishedConfigurationEvent.java | 1 - .../api/event/proxy/ListenerBoundEvent.java | 16 -- .../api/event/proxy/ListenerCloseEvent.java | 16 -- .../api/event/proxy/ProxyInitializeEvent.java | 6 - .../api/event/proxy/ProxyPingEvent.java | 6 - .../event/proxy/ProxyPreShutdownEvent.java | 6 - .../api/event/proxy/ProxyReloadEvent.java | 6 - .../api/event/proxy/ProxyShutdownEvent.java | 6 - .../proxy/server/ServerRegisteredEvent.java | 6 - .../proxy/server/ServerUnregisteredEvent.java | 6 - .../api/network/HandshakeIntent.java | 17 -- .../api/network/ListenerType.java | 6 - .../api/network/ProtocolState.java | 5 - .../api/network/ProtocolVersion.java | 162 +----------------- .../api/permission/Tristate.java | 2 +- .../api/plugin/InvalidPluginException.java | 19 -- .../api/plugin/PluginDescription.java | 6 - .../com/velocitypowered/api/proxy/Player.java | 24 ++- .../api/proxy/crypto/IdentifiedKey.java | 23 +-- .../api/proxy/crypto/KeySigned.java | 2 +- .../messages/LegacyChannelIdentifier.java | 5 - .../messages/MinecraftChannelIdentifier.java | 15 -- .../api/proxy/player/PlayerSettings.java | 24 --- .../api/proxy/player/ResourcePackInfo.java | 7 +- .../api/proxy/player/SkinParts.java | 40 ----- .../api/proxy/player/TabListEntry.java | 3 - .../api/proxy/server/QueryResponse.java | 18 +- .../api/proxy/server/ServerInfo.java | 18 +- .../api/proxy/server/ServerPing.java | 129 +------------- .../velocitypowered/api/util/GameProfile.java | 15 -- .../com/velocitypowered/api/util/ModInfo.java | 24 --- .../api/util/ProxyVersion.java | 15 -- .../velocitypowered/api/util/ServerLink.java | 32 ---- gradle/libs.versions.toml | 10 +- .../natives/util/MoreByteBufUtils.java | 4 +- proxy/build.gradle.kts | 8 +- .../velocitypowered/proxy/VelocityServer.java | 2 +- .../handler/ModernResourcePackHandler.java | 2 +- .../handler/ResourcePackHandler.java | 1 - .../proxy/event/VelocityEventManager.java | 62 +++---- .../proxy/protocol/ProtocolUtils.java | 6 +- .../packet/AvailableCommandsPacket.java | 7 - .../proxy/protocol/packet/BossBarPacket.java | 88 ++-------- .../packet/BundleDelimiterPacket.java | 8 - .../protocol/packet/ClientSettingsPacket.java | 33 +--- .../ClientboundCookieRequestPacket.java | 5 - .../packet/ClientboundSoundEntityPacket.java | 22 +-- .../packet/ClientboundStopSoundPacket.java | 12 +- .../packet/ClientboundStoreCookiePacket.java | 5 - .../protocol/packet/DialogClearPacket.java | 7 - .../protocol/packet/DialogShowPacket.java | 7 - .../protocol/packet/DisconnectPacket.java | 26 +-- .../packet/EncryptionRequestPacket.java | 6 - .../packet/EncryptionResponsePacket.java | 19 +- .../protocol/packet/HandshakePacket.java | 10 +- .../packet/HeaderAndFooterPacket.java | 8 +- .../proxy/protocol/packet/JoinGamePacket.java | 30 ++-- .../protocol/packet/KeepAlivePacket.java | 5 - .../protocol/packet/LegacyDisconnect.java | 20 +-- .../packet/LegacyHandshakePacket.java | 5 - .../protocol/packet/LegacyPingPacket.java | 5 - .../packet/LegacyPlayerListItemPacket.java | 48 ++---- .../packet/LoginAcknowledgedPacket.java | 9 +- .../packet/LoginPluginMessagePacket.java | 17 -- .../packet/LoginPluginResponsePacket.java | 11 -- .../protocol/packet/PingIdentifyPacket.java | 3 - .../protocol/packet/PluginMessagePacket.java | 12 +- .../packet/RemovePlayerInfoPacket.java | 4 - .../packet/RemoveResourcePackPacket.java | 6 +- .../packet/ResourcePackRequestPacket.java | 26 +-- .../packet/ResourcePackResponsePacket.java | 32 +--- .../proxy/protocol/packet/RespawnPacket.java | 26 --- .../protocol/packet/ServerDataPacket.java | 15 +- .../protocol/packet/ServerLoginPacket.java | 31 +--- .../packet/ServerLoginSuccessPacket.java | 16 -- .../ServerboundCookieResponsePacket.java | 5 - .../ServerboundCustomClickActionPacket.java | 6 - .../protocol/packet/SetCompressionPacket.java | 4 - .../protocol/packet/StatusPingPacket.java | 4 - .../protocol/packet/StatusRequestPacket.java | 4 +- .../protocol/packet/StatusResponsePacket.java | 9 - .../packet/TabCompleteRequestPacket.java | 9 - .../packet/TabCompleteResponsePacket.java | 6 - .../proxy/protocol/packet/TransferPacket.java | 14 -- .../packet/UpsertPlayerInfoPacket.java | 31 ++-- .../packet/brigadier/ArgumentIdentifier.java | 19 +- .../brigadier/ArgumentPropertyRegistry.java | 18 +- .../brigadier/ArgumentPropertySerializer.java | 10 -- .../packet/brigadier/ModArgumentProperty.java | 11 -- .../RegistryIdArgumentSerializer.java | 10 -- .../packet/brigadier/RegistryKeyArgument.java | 9 - .../brigadier/RegistryKeyArgumentList.java | 29 ---- .../RegistryKeyArgumentSerializer.java | 6 - .../brigadier/TimeArgumentSerializer.java | 6 - .../chat/ChatAcknowledgementPacket.java | 59 +++---- .../protocol/packet/chat/ChatHandler.java | 16 -- .../proxy/protocol/packet/chat/ChatQueue.java | 45 +---- .../protocol/packet/chat/ChatTimeKeeper.java | 17 -- .../proxy/protocol/packet/chat/ChatType.java | 8 +- .../protocol/packet/chat/CommandHandler.java | 66 ++----- .../protocol/packet/chat/ComponentHolder.java | 131 ++++---------- .../packet/chat/LastSeenMessages.java | 34 +--- .../chat/PlayerChatCompletionPacket.java | 8 - .../chat/RateLimitedCommandHandler.java | 63 +++---- .../packet/chat/RemoteChatSession.java | 5 - .../packet/chat/SystemChatPacket.java | 7 +- .../chat/builder/ChatBuilderFactory.java | 11 -- .../packet/chat/builder/ChatBuilderV2.java | 7 - .../packet/chat/keyed/KeyedChatBuilder.java | 6 - .../packet/chat/keyed/KeyedChatHandler.java | 25 --- .../chat/keyed/KeyedCommandHandler.java | 16 +- .../chat/keyed/KeyedPlayerChatPacket.java | 7 - .../chat/keyed/KeyedPlayerCommandPacket.java | 7 - .../packet/chat/legacy/LegacyChatBuilder.java | 7 - .../packet/chat/legacy/LegacyChatHandler.java | 7 - .../packet/chat/legacy/LegacyChatPacket.java | 8 - .../chat/legacy/LegacyCommandHandler.java | 17 +- .../chat/session/SessionChatBuilder.java | 7 - .../chat/session/SessionChatHandler.java | 10 +- .../chat/session/SessionCommandHandler.java | 16 +- .../chat/session/SessionPlayerChatPacket.java | 16 -- .../session/SessionPlayerCommandPacket.java | 92 ++-------- .../session/UnsignedPlayerCommandPacket.java | 13 +- .../packet/config/ActiveFeaturesPacket.java | 7 - .../ClientboundCustomReportDetailsPacket.java | 66 ++++--- .../config/ClientboundServerLinksPacket.java | 123 ++++++------- .../config/CodeOfConductAcceptPacket.java | 6 - .../packet/config/CodeOfConductPacket.java | 8 - .../packet/config/FinishedUpdatePacket.java | 9 +- .../packet/config/KnownPacksPacket.java | 97 +++++------ .../packet/config/RegistrySyncPacket.java | 12 -- .../packet/config/StartUpdatePacket.java | 12 +- .../packet/config/TagsUpdatePacket.java | 10 +- .../LegacyMinecraftPingVersion.java | 10 -- .../packet/title/GenericTitlePacket.java | 20 +-- .../packet/title/LegacyTitlePacket.java | 14 +- .../packet/title/TitleActionbarPacket.java | 10 -- .../packet/title/TitleClearPacket.java | 9 - .../packet/title/TitleSubtitlePacket.java | 9 - .../packet/title/TitleTextPacket.java | 9 - .../packet/title/TitleTimesPacket.java | 9 - .../src/main/resources/default-velocity.toml | 2 +- 185 files changed, 502 insertions(+), 2992 deletions(-) diff --git a/api/build.gradle.kts b/api/build.gradle.kts index 5e503f6a..268a8197 100644 --- a/api/build.gradle.kts +++ b/api/build.gradle.kts @@ -24,7 +24,7 @@ dependencies { api(libs.guava) // DEPRECATED: Will be removed in Velocity Polymer - api("io.hotmoka:toml4j:0.7.3") + api("com.moandjiezana.toml:toml4j:0.7.2") api(platform(libs.adventure.bom)) api("net.kyori:adventure-api") @@ -55,6 +55,8 @@ tasks { } } withType { + exclude("com/velocitypowered/api/plugin/ap/**") + val o = options as StandardJavadocDocletOptions o.encoding = "UTF-8" o.source = "21" @@ -64,7 +66,7 @@ tasks { "https://www.javadocs.dev/org.slf4j/slf4j-api/${libs.slf4j.get().version}/", "https://guava.dev/releases/${libs.guava.get().version}/api/docs/", "https://google.github.io/guice/api-docs/${libs.guice.get().version}/javadoc/", - "https://docs.oracle.com/en/java/javase/21/docs/api/", + "https://docs.oracle.com/en/java/javase/17/docs/api/", "https://jd.advntr.dev/api/${libs.adventure.bom.get().version}/", "https://jd.advntr.dev/text-minimessage/${libs.adventure.bom.get().version}/", "https://jd.advntr.dev/key/${libs.adventure.bom.get().version}/", @@ -77,5 +79,8 @@ tasks { "implNote:a:Implementation Note:", "sinceMinecraft:a:Since Minecraft:" ) + + // Disable the crazy super-strict doclint tool in Java 8 + o.addStringOption("Xdoclint:none", "-quiet") } } diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java index 6424d34e..b44f2847 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/PluginAnnotationProcessor.java @@ -36,15 +36,6 @@ import javax.tools.StandardLocation; @SupportedAnnotationTypes({"com.velocitypowered.api.plugin.Plugin"}) public class PluginAnnotationProcessor extends AbstractProcessor { - /** - * Creates a new {@code PluginAnnotationProcessor}. - * - *

    The processor is instantiated by the Java compiler and initialized via - * {@link #init(ProcessingEnvironment)}.

    - */ - public PluginAnnotationProcessor() { - } - private ProcessingEnvironment environment; private String pluginClassFound; private boolean warnedAboutMultiplePlugins; diff --git a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java index b8a35ec9..b712d896 100644 --- a/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java +++ b/api/src/ap/java/com/velocitypowered/api/plugin/ap/SerializedPluginDescription.java @@ -24,19 +24,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; */ public final class SerializedPluginDescription { - /** - * The string pattern used to validate plugin IDs. - * - *

    Plugin IDs must start with a lowercase letter and may contain lowercase letters, - * digits, hyphens, and underscores. The total length must not exceed 64 characters.

    - */ public static final String ID_PATTERN_STRING = "[a-z][a-z0-9-_]{0,63}"; - /** - * The compiled pattern used to validate plugin IDs. - * - *

    Plugin IDs must start with a lowercase letter and may contain lowercase letters, - * digits, hyphens, and underscores. The total length must not exceed 64 characters.

    - */ public static final Pattern ID_PATTERN = Pattern.compile(ID_PATTERN_STRING); // @Nullable is used here to make GSON skip these in the serialized file @@ -76,78 +64,34 @@ public final class SerializedPluginDescription { .collect(Collectors.toList()), dependencies, qualifiedName); } - /** - * Gets the ID of the plugin this dependency refers to. - * - * @return the plugin ID - */ public String getId() { return id; } - /** - * Gets the human-readable name of the plugin. - * - * @return the plugin's name, or {@code null} if not specified - */ public @Nullable String getName() { return name; } - /** - * Gets the version string of the plugin. - * - * @return the plugin version, or {@code null} if not specified - */ public @Nullable String getVersion() { return version; } - /** - * Gets the plugin's description, typically a short summary of its functionality. - * - * @return the description, or {@code null} if not specified - */ public @Nullable String getDescription() { return description; } - /** - * Gets the website URL for the plugin. - * - *

    This is often used to link to documentation, support, or the plugin's homepage.

    - * - * @return the plugin URL, or {@code null} if not specified - */ public @Nullable String getUrl() { return url; } - /** - * Gets the list of authors who contributed to the plugin. - * - * @return an immutable list of authors; empty if none were specified - */ public List getAuthors() { return authors == null ? ImmutableList.of() : authors; } - /** - * Gets the list of declared dependencies for the plugin. - * - *

    Dependencies may be required or optional and describe other plugins, this one depends.

    - * - * @return an immutable list of plugin dependencies - */ public List getDependencies() { return dependencies == null ? ImmutableList.of() : dependencies; } - /** - * Gets the fully qualified name of the plugin's main class. - * - * @return the main class name - */ public String getMain() { return main; } @@ -198,33 +142,15 @@ public final class SerializedPluginDescription { private final String id; private final boolean optional; - /** - * Constructs a new dependency class. - * - * @param id the ID of the dependent plugin - * @param optional whether the dependency is optional - */ public Dependency(String id, boolean optional) { this.id = id; this.optional = optional; } - /** - * Gets the ID of the plugin this dependency refers to. - * - * @return the plugin ID - */ public String getId() { return id; } - /** - * Indicates whether this dependency is optional. - * - *

    Optional dependencies are not required for the plugin to load.

    - * - * @return {@code true} if the dependency is optional; {@code false} otherwise - */ public boolean isOptional() { return optional; } diff --git a/api/src/main/java/com/velocitypowered/api/command/CommandSource.java b/api/src/main/java/com/velocitypowered/api/command/CommandSource.java index dcc57431..c94dec4c 100644 --- a/api/src/main/java/com/velocitypowered/api/command/CommandSource.java +++ b/api/src/main/java/com/velocitypowered/api/command/CommandSource.java @@ -25,7 +25,7 @@ public interface CommandSource extends Audience, PermissionSubject { * @param message MiniMessage content * @see MiniMessage docs * for more information on the format. - */ + **/ default void sendRichMessage(final @NotNull String message) { this.sendMessage(MiniMessage.miniMessage().deserialize(message, this)); } @@ -47,13 +47,13 @@ public interface CommandSource extends Audience, PermissionSubject { } /** - * Sends a plain message to this source. - * - * @param message plain message - * @apiNote This method will not apply any form of parse to the text provided, - * however, it is recommended not to use legacy color codes as this is a deprecated format + * Sends a plain message to this source. + * + * @param message plain message + * @apiNote This method will not apply any form of parse to the text provided, + * however, it is recommended not to use legacy color codes as this is a deprecated format * and not recommended. - */ + */ default void sendPlainMessage(final @NotNull String message) { this.sendMessage(Component.text(message)); } diff --git a/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java b/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java index bd6415c3..0ae69591 100644 --- a/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java +++ b/api/src/main/java/com/velocitypowered/api/command/VelocityBrigadierMessage.java @@ -20,12 +20,6 @@ import org.jetbrains.annotations.NotNull; */ public final class VelocityBrigadierMessage implements Message, ComponentLike { - /** - * Creates a new {@link VelocityBrigadierMessage} using the given {@link Component} as the message. - * - * @param message the component to use as the tooltip message - * @return a new instance of {@link VelocityBrigadierMessage} - */ public static VelocityBrigadierMessage tooltip(Component message) { return new VelocityBrigadierMessage(message); } diff --git a/api/src/main/java/com/velocitypowered/api/event/Continuation.java b/api/src/main/java/com/velocitypowered/api/event/Continuation.java index 5c17bf7b..30672ef6 100644 --- a/api/src/main/java/com/velocitypowered/api/event/Continuation.java +++ b/api/src/main/java/com/velocitypowered/api/event/Continuation.java @@ -20,8 +20,6 @@ public interface Continuation { /** * Resumes the continuation after the executed task failed. - * - * @param exception the {@link Throwable} that caused the failure */ void resumeWithException(Throwable exception); -} +} \ No newline at end of file diff --git a/api/src/main/java/com/velocitypowered/api/event/EventHandler.java b/api/src/main/java/com/velocitypowered/api/event/EventHandler.java index ca8b164b..3f0a1aa0 100644 --- a/api/src/main/java/com/velocitypowered/api/event/EventHandler.java +++ b/api/src/main/java/com/velocitypowered/api/event/EventHandler.java @@ -13,28 +13,12 @@ import org.checkerframework.checker.nullness.qual.Nullable; * Represents an interface to perform direct dispatch of an event. This makes integration easier to * achieve with platforms such as RxJava. While this interface can be used to implement an awaiting * event handler, {@link AwaitingEventExecutor} provides a more idiomatic means to doing so. - * - * @param the event type this handler accepts */ @FunctionalInterface public interface EventHandler { - /** - * Executes this handler synchronously with the given event. - * - * @param event the event to handle - */ void execute(E event); - /** - * Executes this handler asynchronously with the given event. - * - *

    If asynchronous handling is not implemented, the event is executed synchronously - * and this method returns {@code null}.

    - * - * @param event the event to handle - * @return an {@link EventTask} representing the async task, or {@code null} if not async - */ default @Nullable EventTask executeAsync(E event) { execute(event); return null; diff --git a/api/src/main/java/com/velocitypowered/api/event/EventManager.java b/api/src/main/java/com/velocitypowered/api/event/EventManager.java index b8d604cf..ed11986c 100644 --- a/api/src/main/java/com/velocitypowered/api/event/EventManager.java +++ b/api/src/main/java/com/velocitypowered/api/event/EventManager.java @@ -73,7 +73,6 @@ public interface EventManager { * servicing connections while a plugin handles a potentially long-running operation such as a * database query. * - * @param the event type * @param event the event to fire * @return a {@link CompletableFuture} representing the posted event */ diff --git a/api/src/main/java/com/velocitypowered/api/event/PostOrder.java b/api/src/main/java/com/velocitypowered/api/event/PostOrder.java index 21b418cb..98fa2e86 100644 --- a/api/src/main/java/com/velocitypowered/api/event/PostOrder.java +++ b/api/src/main/java/com/velocitypowered/api/event/PostOrder.java @@ -12,34 +12,7 @@ package com.velocitypowered.api.event; */ public enum PostOrder { - /** - * Indicates the listener should be invoked first, before any other listener. - * This order is suitable for listeners that must handle the event before others. - */ - FIRST, - /** - * Indicates the listener should be invoked early, but after listeners with {@link #FIRST}. - * This order is suitable for handling the event before most other listeners. - */ - EARLY, - /** - * Indicates the listener should be invoked in the normal order of execution. - * This is the default and most commonly used order. - */ - NORMAL, - /** - * Indicates the listener should be invoked later in the execution order, - * after listeners with {@link #NORMAL}. - * This order is suitable for listeners that should observe the results of - * earlier listeners. - */ - LATE, - /** - * Indicates the listener should be invoked last, after all other listeners. - * This order is suitable for listeners that should run only after all others - * have completed handling the event. - */ - LAST, + FIRST, EARLY, NORMAL, LATE, LAST, /** * Previously used to specify that {@link Subscribe#priority()} should be used. diff --git a/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java b/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java index d2a33860..0aafd058 100644 --- a/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/ResultedEvent.java @@ -15,8 +15,6 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** * Indicates an event that has a result attached to it. - * - * @param the type of result associated with the event */ public interface ResultedEvent { @@ -72,20 +70,10 @@ public interface ResultedEvent { return status ? "allowed" : "denied"; } - /** - * Returns a result indicating the event is allowed to proceed. - * - * @return an allowed {@link GenericResult} - */ public static GenericResult allowed() { return ALLOWED; } - /** - * Returns a result indicating the event is denied. - * - * @return a denied {@link GenericResult} - */ public static GenericResult denied() { return DENIED; } @@ -101,12 +89,6 @@ public interface ResultedEvent { private final boolean status; private final @Nullable Component reason; - /** - * Represents an allowed or denied result that may include a denial reason. - * - * @param status whether the result is allowed - * @param reason the component explaining why the result was denied, or {@code null} - */ protected ComponentResult(boolean status, @Nullable Component reason) { this.status = status; this.reason = reason; @@ -117,11 +99,6 @@ public interface ResultedEvent { return status; } - /** - * Returns the denial reason component, if present. - * - * @return an {@link Optional} containing the reason component if the result is denied - */ public Optional getReasonComponent() { return Optional.ofNullable(reason); } @@ -137,22 +114,10 @@ public interface ResultedEvent { return "denied"; } - /** - * Returns a result indicating the event is allowed to proceed. - * - * @return an allowed {@link ComponentResult} - */ public static ComponentResult allowed() { return ALLOWED; } - /** - * Returns a result indicating the event is denied, with the given reason component. - * - * @param reason the denial reason to show - * @return a denied {@link ComponentResult} - * @throws NullPointerException if the reason is null - */ public static ComponentResult denied(Component reason) { Preconditions.checkNotNull(reason, "reason"); return new ComponentResult(false, reason); diff --git a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java index 6daa62a8..7ed704fc 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/CommandExecuteEvent.java @@ -106,8 +106,6 @@ public final class CommandExecuteEvent implements ResultedEvent { /** * Represents information about a command invocation, including its signed state and source. * - * @param signedState the signed state of the command - * @param source the source of the command invocation * @since 3.4.0 */ public record InvocationInfo(SignedState signedState, Source source) { @@ -193,22 +191,10 @@ public final class CommandExecuteEvent implements ResultedEvent { this.command = command; } - /** - * Returns the command to be executed, if it was overridden. - * - * @return an {@link Optional} containing the new command string (without leading slash), - * or empty if no override is present - */ public Optional getCommand() { return Optional.ofNullable(command); } - /** - * Indicates whether this command should be forwarded directly to the backend server - * instead of being processed by the proxy. - * - * @return {@code true} if the command should be forwarded to the server, {@code false} otherwise - */ public boolean isForwardToServer() { return forward; } diff --git a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java index 265fbdda..d00cffac 100644 --- a/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/command/PlayerAvailableCommandsEvent.java @@ -37,20 +37,10 @@ public class PlayerAvailableCommandsEvent { this.rootNode = checkNotNull(rootNode, "rootNode"); } - /** - * Gets the player that the available commands are being sent to. - * - * @return the targeted player - */ public Player getPlayer() { return player; } - /** - * Gets the root command node that represents the available commands. - * - * @return the Brigadier root command node - */ public RootCommandNode getRootNode() { return rootNode; } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java index d3ddc0e3..e344b6c5 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/ConnectionHandshakeEvent.java @@ -21,12 +21,6 @@ public final class ConnectionHandshakeEvent { private final InboundConnection connection; private final HandshakeIntent intent; - /** - * Constructs a new {@link ConnectionHandshakeEvent}. - * - * @param connection the inbound connection from the client - * @param intent the intent of the handshake (e.g., login or status) - */ public ConnectionHandshakeEvent(InboundConnection connection, HandshakeIntent intent) { this.connection = Preconditions.checkNotNull(connection, "connection"); this.intent = Preconditions.checkNotNull(intent, "intent"); @@ -45,20 +39,10 @@ public final class ConnectionHandshakeEvent { this.intent = HandshakeIntent.LOGIN; } - /** - * Returns the inbound connection associated with this handshake. - * - * @return the connection - */ public InboundConnection getConnection() { return connection; } - /** - * Returns the {@link HandshakeIntent} associated with this connection handshake. - * - * @return the intent of the handshake - */ public HandshakeIntent getIntent() { return this.intent; } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java index 4a2dba4f..bec7b745 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/DisconnectEvent.java @@ -17,10 +17,12 @@ import com.velocitypowered.api.proxy.Player; * Operations on the provided player, aside from basic data retrieval operations, may behave in * undefined ways. * - *

    Velocity typically fires this event asynchronously and does not wait for a response. However, - * it will wait for all {@link DisconnectEvent}s for every player on the proxy to fire - * successfully before the proxy shuts down. This event is the sole exception to the - * {@link AwaitingEvent} contract.

    + *

    + * Velocity typically fires this event asynchronously and does not wait for a response. However, + * it will wait for all {@link DisconnectEvent}s for every player on the proxy to fire + * successfully before the proxy shuts down. This event is the sole exception to the + * {@link AwaitingEvent} contract. + *

    */ @AwaitingEvent public final class DisconnectEvent { @@ -28,31 +30,15 @@ public final class DisconnectEvent { private final Player player; private final LoginStatus loginStatus; - /** - * Creates a new {@link DisconnectEvent}. - * - * @param player the player who disconnected - * @param loginStatus the status of the player's login at the time of disconnection - */ public DisconnectEvent(Player player, LoginStatus loginStatus) { this.player = Preconditions.checkNotNull(player, "player"); this.loginStatus = Preconditions.checkNotNull(loginStatus, "loginStatus"); } - /** - * Returns the player who disconnected. - * - * @return the player - */ public Player getPlayer() { return player; } - /** - * Returns the login status of the player at the time of disconnection. - * - * @return the login status - */ public LoginStatus getLoginStatus() { return loginStatus; } @@ -70,29 +56,11 @@ public final class DisconnectEvent { */ public enum LoginStatus { - /** - * The player completed a successful login to the proxy. - */ SUCCESSFUL_LOGIN, - /** - * The player was disconnected because another login with the same UUID occurred. - */ CONFLICTING_LOGIN, - /** - * The player voluntarily disconnected before completing the login. - */ CANCELLED_BY_USER, - /** - * The proxy disconnected the player before login completed. - */ CANCELLED_BY_PROXY, - /** - * The player disconnected on their own, but only after starting the login and before completing it. - */ CANCELLED_BY_USER_BEFORE_COMPLETE, - /** - * The player disconnected before joining the initial backend server. - */ PRE_SERVER_JOIN } } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java index 29997670..454da839 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/LoginEvent.java @@ -26,6 +26,11 @@ public final class LoginEvent implements ResultedEventThis value is {@code null} on 1.19.2 and lower, * up to 1.20.1 it is optional and from 1.20.2 it will always be available.

    * @@ -140,29 +129,14 @@ public final class PreLoginEvent implements ResultedEvent getReasonComponent() { return Optional.ofNullable(reason); } - /** - * Checks if this result explicitly forces online mode for the connection. - * - * @return true if online mode is forced - */ public boolean isOnlineModeAllowed() { return result == Result.FORCE_ONLINE; } - /** - * Checks if this result explicitly forces offline mode for the connection. - * - * @return true if offline mode is forced - */ public boolean isForceOfflineMode() { return result == Result.FORCE_OFFLINE; } diff --git a/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java b/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java index 37e96a7d..584ab005 100644 --- a/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/connection/PreTransferEvent.java @@ -28,31 +28,15 @@ public final class PreTransferEvent implements ResultedEvent channels; - /** - * Constructs a new PlayerChannelRegisterEvent. - * - * @param player the player who sent the plugin message - * @param channels the list of channels the player is registering - */ public PlayerChannelRegisterEvent(Player player, List channels) { this.player = Preconditions.checkNotNull(player, "player"); this.channels = Preconditions.checkNotNull(channels, "channels"); } - /** - * Gets the player who sent the plugin message to register channels. - * - * @return the player involved in this event - */ public Player getPlayer() { return player; } - /** - * Gets the list of {@link ChannelIdentifier}s that the player registered. - * - * @return the list of registered channels - */ public List getChannels() { return channels; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java index 69e59da0..86eeb2bc 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChannelUnregisterEvent.java @@ -21,35 +21,15 @@ public final class PlayerChannelUnregisterEvent { private final Player player; private final List channels; - /** - * Constructs a new {@link PlayerChannelUnregisterEvent}. - * - * @param player the player that sent the unregister message - * @param channels the list of {@link ChannelIdentifier}s being unregistered - * @throws NullPointerException if {@code player} or {@code channels} is {@code null} - */ public PlayerChannelUnregisterEvent(Player player, List channels) { this.player = Preconditions.checkNotNull(player, "player"); this.channels = Preconditions.checkNotNull(channels, "channels"); } - /** - * Gets the {@link Player} who sent the unregister message. - * - * @return the player involved in this event - */ public Player getPlayer() { return player; } - /** - * Gets the list of {@link ChannelIdentifier}s that the player has unregistered. - * - *

    These identifiers correspond to the plugin message channels that the client has - * indicated it will no longer use.

    - * - * @return the list of unregistered channels - */ public List getChannels() { return channels; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java index 6548cf60..dd1fae29 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChatEvent.java @@ -38,20 +38,10 @@ public final class PlayerChatEvent implements ResultedEvent getMessage() { return Optional.ofNullable(message); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java index 587d374a..73d41ecd 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerChooseInitialServerEvent.java @@ -37,20 +37,10 @@ public class PlayerChooseInitialServerEvent { this.initialServer = initialServer; } - /** - * Gets the player who is choosing the initial server. - * - * @return the connected player - */ public Player getPlayer() { return player; } - /** - * Gets the initial server the player will connect to. - * - * @return an {@link Optional} containing the selected server, or empty if none was set - */ public Optional getInitialServer() { return Optional.ofNullable(initialServer); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java index 0a45093f..268d5b6a 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerClientBrandEvent.java @@ -29,20 +29,10 @@ public final class PlayerClientBrandEvent { this.brand = Preconditions.checkNotNull(brand); } - /** - * Gets the player who sent the client brand. - * - * @return the player - */ public Player getPlayer() { return player; } - /** - * Gets the brand string sent by the client. - * - * @return the client brand - */ public String getBrand() { return brand; } @@ -50,9 +40,9 @@ public final class PlayerClientBrandEvent { @Override public String toString() { return "PlayerClientBrandEvent{" - + "player=" + player - + ", brand='" + brand + '\'' - + '}'; + + "player=" + player + + ", brand='" + brand + '\'' + + '}'; } } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java index 377b8b45..eb0b4133 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerModInfoEvent.java @@ -21,31 +21,15 @@ public final class PlayerModInfoEvent { private final Player player; private final ModInfo modInfo; - /** - * Constructs a new {@code PlayerModInfoEvent}. - * - * @param player the player sending their mod list - * @param modInfo the mod list information - */ public PlayerModInfoEvent(Player player, ModInfo modInfo) { this.player = Preconditions.checkNotNull(player, "player"); this.modInfo = Preconditions.checkNotNull(modInfo, "modInfo"); } - /** - * Returns the player who sent their mod list. - * - * @return the player - */ public Player getPlayer() { return player; } - /** - * Returns the mod information sent by the player. - * - * @return the mod information - */ public ModInfo getModInfo() { return modInfo; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java index 9e3f59f2..d212666b 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerResourcePackStatusEvent.java @@ -33,8 +33,6 @@ public class PlayerResourcePackStatusEvent { /** * Instantiates this event. * - * @param player the player affected by the status update - * @param status the status of the resource pack * @deprecated Use {@link PlayerResourcePackStatusEvent#PlayerResourcePackStatusEvent * (Player, UUID, Status, ResourcePackInfo)} instead. */ @@ -46,9 +44,6 @@ public class PlayerResourcePackStatusEvent { /** * Instantiates this event. * - * @param player the player affected by the status update - * @param status the status of the resource pack - * @param packInfo the resource pack metadata * @deprecated Use {@link PlayerResourcePackStatusEvent#PlayerResourcePackStatusEvent * (Player, UUID, Status, ResourcePackInfo)} instead. */ @@ -59,11 +54,6 @@ public class PlayerResourcePackStatusEvent { /** * Instantiates this event. - * - * @param player the player affected by the status update - * @param packId the unique ID of the resource pack - * @param status the status of the resource pack - * @param packInfo the resource pack metadata */ public PlayerResourcePackStatusEvent( Player player, UUID packId, Status status, ResourcePackInfo packInfo) { diff --git a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java index 542633c7..cd1bd01c 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/PlayerSettingsChangedEvent.java @@ -22,31 +22,15 @@ public final class PlayerSettingsChangedEvent { private final Player player; private final PlayerSettings playerSettings; - /** - * Constructs a new PlayerSettingsChangedEvent. - * - * @param player the player who changed settings - * @param playerSettings the new settings sent by the client - */ public PlayerSettingsChangedEvent(Player player, PlayerSettings playerSettings) { this.player = Preconditions.checkNotNull(player, "player"); this.playerSettings = Preconditions.checkNotNull(playerSettings, "playerSettings"); } - /** - * Returns the player whose settings changed. - * - * @return the player - */ public Player getPlayer() { return player; } - /** - * Returns the new client settings sent by the player. - * - * @return the updated player settings - */ public PlayerSettings getPlayerSettings() { return playerSettings; } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java index 48e98587..ac4452a0 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerConnectedEvent.java @@ -45,29 +45,14 @@ public final class ServerConnectedEvent { this.previousServer = previousServer; } - /** - * Returns the player involved in this event. - * - * @return the {@link Player} who connected - */ public Player getPlayer() { return player; } - /** - * Returns the server the player successfully connected to. - * - * @return the {@link RegisteredServer} the player connected to - */ public RegisteredServer getServer() { return server; } - /** - * Returns the server the player was previously connected to, if any. - * - * @return an {@link Optional} of the previous {@link RegisteredServer}, or empty if none - */ public Optional getPreviousServer() { return Optional.ofNullable(previousServer); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java index d790d975..9597e02a 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerLoginPluginMessageEvent.java @@ -63,20 +63,10 @@ public class ServerLoginPluginMessageEvent implements ResultedEvent getServer() { return Optional.ofNullable(server); } diff --git a/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java index 52901cf4..96d1bb8e 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/ServerResourcePackRemoveEvent.java @@ -29,9 +29,6 @@ public class ServerResourcePackRemoveEvent implements ResultedEventVelocity will wait for this event before continuing/ending the configuration state.

    * * @param player The player who can be configured. 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 97a2ded0..05d6c2af 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,9 +15,8 @@ import org.jetbrains.annotations.NotNull; /** * 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. - * However, due to backend server being unable to keep the connection alive during state changes, + * 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. diff --git a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java index 6560f7bc..c1677706 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerEnteredConfigurationEvent.java @@ -14,7 +14,6 @@ import org.jetbrains.annotations.NotNull; /** * This event is executed when a player has entered the configuration state. - * *

    From this moment on, until the {@link PlayerFinishedConfigurationEvent} is executed, * the {@linkplain Player#getProtocolState()} method is guaranteed * to return {@link ProtocolState#CONFIGURATION}.

    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 1cd3f283..50df5a8a 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 @@ -14,9 +14,8 @@ import org.jetbrains.annotations.NotNull; /** * 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 during state changes, + * 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}.

    * diff --git a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java index 994a1d41..517f119c 100644 --- a/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/player/configuration/PlayerFinishedConfigurationEvent.java @@ -14,7 +14,6 @@ import org.jetbrains.annotations.NotNull; /** * This event is executed when a player has finished the configuration state. - * *

    From this moment on, the {@link Player#getProtocolState()} method * will return {@link ProtocolState#PLAY}.

    * diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java index 1824a69c..662e403d 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerBoundEvent.java @@ -19,31 +19,15 @@ public final class ListenerBoundEvent { private final InetSocketAddress address; private final ListenerType listenerType; - /** - * Constructs a new {@link ListenerBoundEvent}. - * - * @param address the socket address the listener is bound to - * @param listenerType the type of listener that was bound - */ public ListenerBoundEvent(InetSocketAddress address, ListenerType listenerType) { this.address = Preconditions.checkNotNull(address, "address"); this.listenerType = Preconditions.checkNotNull(listenerType, "listenerType"); } - /** - * Returns the socket address the listener is bound to. - * - * @return the bound socket address - */ public InetSocketAddress getAddress() { return address; } - /** - * Returns the type of listener that was bound. - * - * @return the listener type - */ public ListenerType getListenerType() { return listenerType; } diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java index da8c61d6..c2551a35 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ListenerCloseEvent.java @@ -19,31 +19,15 @@ public final class ListenerCloseEvent { private final InetSocketAddress address; private final ListenerType listenerType; - /** - * Constructs a new {@link ListenerCloseEvent}. - * - * @param address the socket address the listener was bound to - * @param listenerType the type of listener being closed - */ public ListenerCloseEvent(InetSocketAddress address, ListenerType listenerType) { this.address = Preconditions.checkNotNull(address, "address"); this.listenerType = Preconditions.checkNotNull(listenerType, "listenerType"); } - /** - * Returns the socket address the listener was bound to. - * - * @return the bound socket address - */ public InetSocketAddress getAddress() { return address; } - /** - * Returns the type of listener being closed. - * - * @return the listener type - */ public ListenerType getListenerType() { return listenerType; } diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java index 7e19f0e1..d01ce190 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyInitializeEvent.java @@ -17,12 +17,6 @@ import com.velocitypowered.api.event.annotation.AwaitingEvent; @AwaitingEvent public final class ProxyInitializeEvent { - /** - * Creates a new {@code ProxyInitializeEvent}. - */ - public ProxyInitializeEvent() { - } - @Override public String toString() { return "ProxyInitializeEvent"; diff --git a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java index 14d40884..63555436 100644 --- a/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java +++ b/api/src/main/java/com/velocitypowered/api/event/proxy/ProxyPingEvent.java @@ -28,12 +28,6 @@ public final class ProxyPingEvent implements ResultedEventThis status can be caused by a {@link HandshakeIntent#STATUS}, * {@link HandshakeIntent#LOGIN} or {@link HandshakeIntent#TRANSFER} intent.

    * If the intent is LOGIN or TRANSFER, the next state will be {@link #LOGIN}, @@ -25,7 +24,6 @@ public enum ProtocolState { HANDSHAKE, /** * Ping State of a connection. - * *

    Connections with the {@link HandshakeIntent#STATUS} intent will pass through this state * and be disconnected after it requests the ping from the server * and the server responds with the respective ping.

    @@ -33,13 +31,11 @@ public enum ProtocolState { STATUS, /** * Authentication State of a connection. - * *

    At this moment the player is authenticating with the authentication servers.

    */ LOGIN, /** * Configuration State of a connection. - * *

    At this point the player allows the server to send information * such as resource packs and plugin messages, at the same time the player * will send his client brand and the respective plugin messages @@ -50,7 +46,6 @@ public enum ProtocolState { CONFIGURATION, /** * Game State of a connection. - * *

    In this state is where the whole game runs, the server is able to change * the player's state to {@link #CONFIGURATION} as needed in versions 1.20.2 and higher.

    */ diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index c3eba765..e803c302 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -21,9 +21,6 @@ import java.util.Set; * Represents each Minecraft protocol version. */ public enum ProtocolVersion implements Ordered { - /** - * Represents an unknown protocol version. - */ UNKNOWN(-1, "Unknown") { @Override public boolean isUnknown() { @@ -35,9 +32,6 @@ public enum ProtocolVersion implements Ordered { return false; } }, - /** - * Represents legacy protocol versions before 1.7. - */ LEGACY(-2, "Legacy") { @Override public boolean isLegacy() { @@ -49,201 +43,57 @@ public enum ProtocolVersion implements Ordered { return false; } }, - /** - * Minecraft 1.7.2 to 1.7.5. - */ - MINECRAFT_1_7_2(4, "1.7.2", "1.7.3", "1.7.4", "1.7.5"), - /** - * Minecraft 1.7.6 to 1.7.10. - */ - MINECRAFT_1_7_6(5, "1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10"), - /** - * Minecraft 1.8 to 1.8.9. - */ - MINECRAFT_1_8(47, "1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9"), - /** - * Minecraft 1.9. - */ + MINECRAFT_1_7_2(4, + "1.7.2", "1.7.3", "1.7.4", "1.7.5"), + MINECRAFT_1_7_6(5, + "1.7.6", "1.7.7", "1.7.8", "1.7.9", "1.7.10"), + MINECRAFT_1_8(47, + "1.8", "1.8.1", "1.8.2", "1.8.3", "1.8.4", "1.8.5", "1.8.6", "1.8.7", "1.8.8", "1.8.9"), MINECRAFT_1_9(107, "1.9"), - /** - * Minecraft 1.9.1. - */ MINECRAFT_1_9_1(108, "1.9.1"), - /** - * Minecraft 1.9.2. - */ MINECRAFT_1_9_2(109, "1.9.2"), - /** - * Minecraft 1.9.3 to 1.9.4. - */ MINECRAFT_1_9_4(110, "1.9.3", "1.9.4"), - /** - * Minecraft 1.10 to 1.10.2. - */ MINECRAFT_1_10(210, "1.10", "1.10.1", "1.10.2"), - /** - * Minecraft 1.11. - */ MINECRAFT_1_11(315, "1.11"), - /** - * Minecraft 1.11.1 to 1.11.2. - */ MINECRAFT_1_11_1(316, "1.11.1", "1.11.2"), - /** - * Minecraft 1.12. - */ MINECRAFT_1_12(335, "1.12"), - /** - * Minecraft 1.12.1. - */ MINECRAFT_1_12_1(338, "1.12.1"), - /** - * Minecraft 1.12.2. - */ MINECRAFT_1_12_2(340, "1.12.2"), - /** - * Minecraft 1.13. - */ MINECRAFT_1_13(393, "1.13"), - /** - * Minecraft 1.13.1. - */ MINECRAFT_1_13_1(401, "1.13.1"), - /** - * Minecraft 1.13.2. - */ MINECRAFT_1_13_2(404, "1.13.2"), - /** - * Minecraft 1.14. - */ MINECRAFT_1_14(477, "1.14"), - /** - * Minecraft 1.14.1. - */ MINECRAFT_1_14_1(480, "1.14.1"), - /** - * Minecraft 1.14.2. - */ MINECRAFT_1_14_2(485, "1.14.2"), - /** - * Minecraft 1.14.3. - */ MINECRAFT_1_14_3(490, "1.14.3"), - /** - * Minecraft 1.14.4. - */ MINECRAFT_1_14_4(498, "1.14.4"), - /** - * Minecraft 1.15. - */ MINECRAFT_1_15(573, "1.15"), - /** - * Minecraft 1.15.1. - */ MINECRAFT_1_15_1(575, "1.15.1"), - /** - * Minecraft 1.15.2. - */ MINECRAFT_1_15_2(578, "1.15.2"), - /** - * Minecraft 1.16. - */ MINECRAFT_1_16(735, "1.16"), - /** - * Minecraft 1.16.1. - */ MINECRAFT_1_16_1(736, "1.16.1"), - /** - * Minecraft 1.16.2. - */ MINECRAFT_1_16_2(751, "1.16.2"), - /** - * Minecraft 1.16.3. - */ MINECRAFT_1_16_3(753, "1.16.3"), - /** - * Minecraft 1.16.4 to 1.16.5. - */ MINECRAFT_1_16_4(754, "1.16.4", "1.16.5"), - /** - * Minecraft 1.17. - */ MINECRAFT_1_17(755, "1.17"), - /** - * Minecraft 1.17.1. - */ MINECRAFT_1_17_1(756, "1.17.1"), - /** - * Minecraft 1.18 to 1.18.1. - */ MINECRAFT_1_18(757, "1.18", "1.18.1"), - /** - * Minecraft 1.18.2. - */ MINECRAFT_1_18_2(758, "1.18.2"), - /** - * Minecraft 1.19. - */ MINECRAFT_1_19(759, "1.19"), - /** - * Minecraft 1.19.1 to 1.19.2. - */ MINECRAFT_1_19_1(760, "1.19.1", "1.19.2"), - /** - * Minecraft 1.19.3. - */ MINECRAFT_1_19_3(761, "1.19.3"), - /** - * Minecraft 1.19.4. - */ MINECRAFT_1_19_4(762, "1.19.4"), - /** - * Minecraft 1.20 to 1.20.1. - */ MINECRAFT_1_20(763, "1.20", "1.20.1"), - /** - * Minecraft 1.20.2. - */ MINECRAFT_1_20_2(764, "1.20.2"), - /** - * Minecraft 1.20.3 to 1.20.4. - */ MINECRAFT_1_20_3(765, "1.20.3", "1.20.4"), - /** - * Minecraft 1.20.5 to 1.20.6. - */ MINECRAFT_1_20_5(766, "1.20.5", "1.20.6"), - /** - * Minecraft 1.21 to 1.21.1. - */ MINECRAFT_1_21(767, "1.21", "1.21.1"), - /** - * Minecraft 1.21.2 to 1.21.3. - */ MINECRAFT_1_21_2(768, "1.21.2", "1.21.3"), - /** - * Minecraft 1.21.4. - */ MINECRAFT_1_21_4(769, "1.21.4"), - /** - * Minecraft 1.21.5. - */ MINECRAFT_1_21_5(770, "1.21.5"), - /** - * Minecraft 1.21.6. - */ MINECRAFT_1_21_6(771, "1.21.6"), - /** - * Minecraft 1.21.7 to 1.21.8. - */ MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"), - /** - * Minecraft 1.21.9 to 1.21.10. - */ MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"), - /** - * Minecraft 1.21.11. - */ MINECRAFT_1_21_11(774, "1.21.11"); private static final int SNAPSHOT_BIT = 30; diff --git a/api/src/main/java/com/velocitypowered/api/permission/Tristate.java b/api/src/main/java/com/velocitypowered/api/permission/Tristate.java index 02f6924b..ddbe26a8 100644 --- a/api/src/main/java/com/velocitypowered/api/permission/Tristate.java +++ b/api/src/main/java/com/velocitypowered/api/permission/Tristate.java @@ -15,7 +15,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; * Represents three different states of a setting. * *

    Possible values:

    - * + *

    *
      *
    • {@link #TRUE} - a positive setting
    • *
    • {@link #FALSE} - a negative (negated) setting
    • diff --git a/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java b/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java index bee2a26d..1882d264 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/InvalidPluginException.java @@ -12,37 +12,18 @@ package com.velocitypowered.api.plugin; */ public class InvalidPluginException extends Exception { - /** - * Creates a new exception with no detail message. - */ public InvalidPluginException() { super(); } - /** - * Creates a new exception with the specified detail message. - * - * @param message the detail message - */ public InvalidPluginException(String message) { super(message); } - /** - * Creates a new exception with the specified detail message and cause. - * - * @param message the detail message - * @param cause the cause of the exception - */ public InvalidPluginException(String message, Throwable cause) { super(message, cause); } - /** - * Creates a new exception with the specified cause. - * - * @param cause the cause of the exception - */ public InvalidPluginException(Throwable cause) { super(cause); } diff --git a/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java b/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java index cbf9b487..540b54ea 100644 --- a/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java +++ b/api/src/main/java/com/velocitypowered/api/plugin/PluginDescription.java @@ -96,12 +96,6 @@ public interface PluginDescription { return ImmutableSet.of(); } - /** - * Gets a specific dependency of the {@link Plugin} by its ID. - * - * @param id the ID of the dependency to look up - * @return an {@link Optional} containing the matching {@link PluginDependency}, or empty if not found - */ default Optional getDependency(String id) { return Optional.empty(); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/Player.java b/api/src/main/java/com/velocitypowered/api/proxy/Player.java index 0fd295ac..057b8a23 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/Player.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/Player.java @@ -152,8 +152,6 @@ public interface Player extends /** * Returns the player's game profile. - * - * @return the player's profile */ GameProfile getGameProfile(); @@ -246,10 +244,10 @@ public interface Player extends * Gets the {@link ResourcePackInfo} of the currently applied * resource-pack or null if none. * - *

      Note that since 1.20.3 it is no longer recommended to use + *

      Note that since 1.20.3 it is no longer recommended to use * this method as it will only return the last applied * resource pack. To get all applied resource packs, use - * {@link #getAppliedResourcePacks()} instead.

      + * {@link #getAppliedResourcePacks()} instead.

      * * @return the applied resource pack or null if none. */ @@ -262,10 +260,10 @@ public interface Player extends * the user is currently downloading or is currently * prompted to install or null if none. * - *

      Note that since 1.20.3 it is no longer recommended to use + *

      Note that since 1.20.3 it is no longer recommended to use * this method as it will only return the last pending * resource pack. To get all pending resource packs, use - * {@link #getPendingResourcePacks()} instead.

      + * {@link #getPendingResourcePacks()} instead.

      * * @return the pending resource pack or null if none */ @@ -317,7 +315,6 @@ public interface Player extends /** * {@inheritDoc} - * *

      Note that this method does not send a plugin message to the server the player * is connected to. You should only use this method if you are trying to communicate * with a mod that is installed on the player's client.

      @@ -398,11 +395,12 @@ public interface Player extends /** * {@inheritDoc} * + * * @apiNote This method is not currently implemented in Velocity * and will not perform any actions. * @see #playSound(Sound, Sound.Emitter) * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void playSound(@NotNull Sound sound) { @@ -415,7 +413,7 @@ public interface Player extends * and will not perform any actions. * @see #playSound(Sound, Sound.Emitter) * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void playSound(@NotNull Sound sound, double x, double y, double z) { @@ -458,7 +456,7 @@ public interface Player extends * and will not perform any actions. * * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void openBook(@NotNull Book book) { @@ -471,7 +469,7 @@ public interface Player extends * and will not perform any actions. * * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void showDialog(@NotNull DialogLike dialog) { @@ -484,7 +482,7 @@ public interface Player extends * and will not perform any actions. * * @see - * Unsupported Adventure Operations + * Unsupported Adventure Operations */ @Override default void closeDialog() { @@ -534,4 +532,4 @@ public interface Player extends * @sinceMinecraft 1.21 */ void setServerLinks(@NotNull List links); -} +} \ No newline at end of file diff --git a/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java b/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java index b6c01121..d2a6cc94 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/crypto/IdentifiedKey.java @@ -28,6 +28,7 @@ public interface IdentifiedKey extends KeySigned { */ PublicKey getSignedPublicKey(); + /** * Validates a signature against this public key. * @@ -58,15 +59,7 @@ public interface IdentifiedKey extends KeySigned { * The different versions of player keys, per Minecraft version. */ enum Revision implements Ordered { - /** - * Represents the original key revision introduced in Minecraft 1.19. - * Keys are not tied to a specific player identity. - */ GENERIC_V1(ImmutableSet.of(), ImmutableSet.of(ProtocolVersion.MINECRAFT_1_19)), - /** - * Represents the key revision introduced in Minecraft 1.19.1. - * Keys are cryptographically linked to player identities. - */ LINKED_V2(ImmutableSet.of(), ImmutableSet.of(ProtocolVersion.MINECRAFT_1_19_1)); final Set backwardsCompatibleTo; @@ -76,21 +69,11 @@ public interface IdentifiedKey extends KeySigned { this.backwardsCompatibleTo = backwardsCompatibleTo; this.applicableTo = applicableTo; } - - /** - * Returns the set of revisions that this revision is backwards-compatible with. - * - * @return a set of compatible earlier revisions - */ + public Set getBackwardsCompatibleTo() { return backwardsCompatibleTo; } - - /** - * Returns the set of Minecraft protocol versions this revision applies to. - * - * @return a set of applicable protocol versions - */ + public Set getApplicableTo() { return applicableTo; } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java b/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java index 83fd402f..8ad64c18 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/crypto/KeySigned.java @@ -34,6 +34,7 @@ public interface KeySigned { */ Instant getExpiryTemporal(); + /** * Check if the signature has expired. * @@ -55,7 +56,6 @@ public interface KeySigned { * Validates the signature, expiry temporal and key against the * signer public key. Note: This will **not** check for * expiry. You can check for expiry with {@link KeySigned#hasExpired()}. - * *

      DOES NOT WORK YET FOR MESSAGES AND COMMANDS!

      * Addendum: Does not work for 1.19.1 until the user has authenticated. * diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java index eafb484f..9da9a7b4 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/LegacyChannelIdentifier.java @@ -31,11 +31,6 @@ public final class LegacyChannelIdentifier implements ChannelIdentifier { this.name = name; } - /** - * Returns the name of this legacy plugin message channel. - * - * @return the channel name - */ public String getName() { return name; } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java index 92f8ef9f..a271a414 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/messages/MinecraftChannelIdentifier.java @@ -84,29 +84,14 @@ public final class MinecraftChannelIdentifier implements ChannelIdentifier { return create(key.namespace(), key.value()); } - /** - * Returns the namespace of this channel identifier. - * - * @return the namespace string (e.g., {@code minecraft}) - */ public String getNamespace() { return namespace; } - /** - * Returns the name of the channel within its namespace. - * - * @return the channel name string - */ public String getName() { return name; } - /** - * Converts this channel identifier to a {@link Key} object. - * - * @return a {@link Key} representing this identifier - */ public Key asKey() { return Key.key(namespace, name); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java b/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java index 91cca964..416cbf15 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/PlayerSettings.java @@ -86,17 +86,8 @@ public interface PlayerSettings { * The client's current chat display mode. */ enum ChatMode { - /** - * Chat is fully visible. - */ SHOWN, - /** - * Only command messages are shown. - */ COMMANDS_ONLY, - /** - * Chat is completely hidden. - */ HIDDEN } @@ -104,13 +95,7 @@ public interface PlayerSettings { * The player's selected dominant hand. */ enum MainHand { - /** - * This scope defines the left hand. - */ LEFT, - /** - * This scope defines the right hand. - */ RIGHT } @@ -118,17 +103,8 @@ public interface PlayerSettings { * The client's current "Particles" option state. */ enum ParticleStatus { - /** - * All particles are shown. - */ ALL, - /** - * A reduced number of particles are shown. - */ DECREASED, - /** - * Minimal particle effects are shown. - */ MINIMAL } } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java b/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java index 7e620185..82937685 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/ResourcePackInfo.java @@ -87,6 +87,7 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { /** * Returns a copy of this {@link ResourcePackInfo} instance as a builder, using the new URL. + *

      * It is not guaranteed that * {@code resourcePackInfo.asBuilder(resourcePackInfo.getUrl()).build().equals(resourcePackInfo)} * is true, because the {@link ResourcePackInfo#getOrigin()} and @@ -107,7 +108,6 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * Sets the id of the resource pack. * * @param id the id the resource-pack - * @return this builder instance */ Builder setId(UUID id); @@ -128,7 +128,6 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * the player will be disconnected from the network * * @param shouldForce whether or not to force the client to accept the resource pack - * @return this builder instance */ Builder setShouldForce(boolean shouldForce); @@ -141,7 +140,6 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * before downloading. * * @param hash the SHA-1 hash of the resource-pack - * @return this builder instance */ Builder setHash(@Nullable byte[] hash); @@ -150,7 +148,6 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { * This will only display if the client version is 1.17 or newer. * * @param prompt the component to display - * @return this builder instance */ Builder setPrompt(@Nullable Component prompt); @@ -177,4 +174,4 @@ public interface ResourcePackInfo extends ResourcePackRequestLike { */ PLUGIN_ON_PROXY } -} +} \ No newline at end of file diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java b/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java index 89355341..1a5030fe 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/SkinParts.java @@ -17,74 +17,34 @@ public final class SkinParts { private final byte bitmask; - /** - * Constructs a new SkinParts object with the provided bitmask. - * - * @param skinBitmask the bitmask representing which skin parts are enabled - */ public SkinParts(byte skinBitmask) { this.bitmask = skinBitmask; } - /** - * Returns whether the player has a cape enabled. - * - * @return true if the cape is enabled, false otherwise - */ public boolean hasCape() { return (bitmask & 1) == 1; } - /** - * Returns whether the player has a jacket enabled. - * - * @return true if the jacket is enabled, false otherwise - */ public boolean hasJacket() { return ((bitmask >> 1) & 1) == 1; } - /** - * Returns whether the player has a left sleeve enabled. - * - * @return true if the left sleeve is enabled, false otherwise - */ public boolean hasLeftSleeve() { return ((bitmask >> 2) & 1) == 1; } - /** - * Returns whether the player has a right sleeve enabled. - * - * @return true if the right sleeve is enabled, false otherwise - */ public boolean hasRightSleeve() { return ((bitmask >> 3) & 1) == 1; } - /** - * Returns whether the player has their left pants enabled. - * - * @return true if the left pants are enabled, false otherwise - */ public boolean hasLeftPants() { return ((bitmask >> 4) & 1) == 1; } - /** - * Returns whether the player has their right pants enabled. - * - * @return true if the right pants are enabled, false otherwise - */ public boolean hasRightPants() { return ((bitmask >> 5) & 1) == 1; } - /** - * Returns whether the player has a hat enabled. - * - * @return true if the hat is enabled, false otherwise - */ public boolean hasHat() { return ((bitmask >> 6) & 1) == 1; } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java b/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java index 57a42392..aea45287 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/player/TabListEntry.java @@ -237,11 +237,8 @@ public interface TabListEntry extends KeyIdentifiable { /** * Sets the {@link IdentifiedKey} of the {@link TabListEntry}. - * *

      This only works for players currently not connected to this proxy.

      - * *

      For any player currently connected to this proxy this will be filled automatically.

      - * *

      Will ignore mismatching key revisions data.

      * * @param chatSession session to set diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java b/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java index c51765f8..6c794bf4 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/QueryResponse.java @@ -147,6 +147,7 @@ public final class QueryResponse { return plugins; } + /** * Creates a new {@link Builder} instance from data represented by this response, so that you * may create a new {@link QueryResponse} with new data. It is guaranteed that @@ -433,31 +434,14 @@ public final class QueryResponse { this.version = version; } - /** - * Gets the name of the plugin. - * - * @return the plugin name - */ public String getName() { return name; } - /** - * Gets the version of the plugin, if available. - * - * @return an {@link Optional} containing the version if present - */ public Optional getVersion() { return Optional.ofNullable(version); } - /** - * Creates a new {@link PluginInformation} instance with the given name and version. - * - * @param name the name of the plugin - * @param version the version of the plugin (nullable) - * @return a new {@link PluginInformation} instance - */ public static PluginInformation of(String name, @Nullable String version) { return new PluginInformation(name, version); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java index 9546a662..fd686297 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerInfo.java @@ -32,21 +32,11 @@ public final class ServerInfo implements Comparable { this.address = Preconditions.checkNotNull(address, "address"); } - /** - * Gets the name of the server. - * - * @return the name of the server - */ - public String getName() { + public final String getName() { return name; } - /** - * Gets the network address of the server. - * - * @return the {@link InetSocketAddress} of the server - */ - public InetSocketAddress getAddress() { + public final InetSocketAddress getAddress() { return address; } @@ -59,7 +49,7 @@ public final class ServerInfo implements Comparable { } @Override - public boolean equals(@Nullable Object o) { + public final boolean equals(@Nullable Object o) { if (this == o) { return true; } @@ -72,7 +62,7 @@ public final class ServerInfo implements Comparable { } @Override - public int hashCode() { + public final int hashCode() { return Objects.hash(name, address); } diff --git a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java index 98ca3b75..eb86f93e 100644 --- a/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java +++ b/api/src/main/java/com/velocitypowered/api/proxy/server/ServerPing.java @@ -22,6 +22,7 @@ import java.util.UUID; import net.kyori.adventure.text.Component; import org.jspecify.annotations.Nullable; + /** * Represents a 1.7 and above server list ping response. This class is immutable. */ @@ -33,14 +34,6 @@ public final class ServerPing { private final @Nullable Favicon favicon; private final @Nullable ModInfo modinfo; - /** - * Constructs an initial ServerPing instance. - * - * @param version the version of the server - * @param players the players on the server, or {@code null} if not shown - * @param description the MOTD for the server - * @param favicon the server's favicon, or {@code null} if not set - */ public ServerPing(Version version, @Nullable Players players, net.kyori.adventure.text.Component description, @Nullable Favicon favicon) { this(version, players, description, favicon, ModInfo.DEFAULT); @@ -65,48 +58,23 @@ public final class ServerPing { this.modinfo = modinfo; } - /** - * Gets the version shown to the client during the ping. - * - * @return the version - */ public Version getVersion() { return version; } - /** - * Gets the player information shown to the client. - * - * @return the player information, or empty if not shown - */ public Optional getPlayers() { return Optional.ofNullable(players); } - /** - * Gets the description (MOTD) component shown in the ping response. - * - * @return the description component - */ @Nullable public Component getDescriptionComponent() { return description; } - /** - * Gets the favicon sent to the client. - * - * @return the favicon, or empty if not present - */ public Optional getFavicon() { return Optional.ofNullable(favicon); } - /** - * Gets the mod info sent to the client. - * - * @return the mod info, or empty if not present - */ public Optional getModinfo() { return Optional.ofNullable(modinfo); } @@ -171,11 +139,6 @@ public final class ServerPing { return builder; } - /** - * Creates a new {@link Builder} for constructing a {@link ServerPing}. - * - * @return a new ServerPing builder - */ public static Builder builder() { return new Builder(); } @@ -383,74 +346,34 @@ public final class ServerPing { description, favicon, nullOutModinfo ? null : new ModInfo(modType, mods)); } - /** - * Gets the version currently set in the builder. - * - * @return the version - */ public Version getVersion() { return version; } - /** - * Gets the number of players online. - * - * @return the online player count - */ public int getOnlinePlayers() { return onlinePlayers; } - /** - * Gets the maximum player capacity. - * - * @return the max player count - */ public int getMaximumPlayers() { return maximumPlayers; } - /** - * Gets the sample players shown in the ping. - * - * @return the sample player list - */ public List getSamplePlayers() { return samplePlayers; } - /** - * Gets the description component currently set in the builder. - * - * @return the server description, or empty if unset - */ public Optional getDescriptionComponent() { return Optional.ofNullable(description); } - /** - * Gets the favicon currently set in the builder. - * - * @return the favicon, or empty if none - */ public Optional getFavicon() { return Optional.ofNullable(favicon); } - /** - * Gets the type of mod loader (e.g., "FML"). - * - * @return the mod type string - */ public String getModType() { return modType; } - /** - * Gets the list of mods reported in the ping. - * - * @return the mod list - */ public List getMods() { return mods; } @@ -494,20 +417,10 @@ public final class ServerPing { this.name = Preconditions.checkNotNull(name, "name"); } - /** - * Gets the protocol number associated with the server version. - * - * @return the protocol version number - */ public int getProtocol() { return protocol; } - /** - * Gets the user-facing name of the server version. - * - * @return the version name - */ public String getName() { return name; } @@ -561,29 +474,14 @@ public final class ServerPing { this.sample = ImmutableList.copyOf(sample); } - /** - * Gets the number of online players. - * - * @return the number of online players - */ public int getOnline() { return online; } - /** - * Gets the maximum number of players the server claims it can hold. - * - * @return the maximum number of players - */ public int getMax() { return max; } - /** - * Gets a sample list of online players. - * - * @return the sample players - */ public List getSample() { return sample == null ? ImmutableList.of() : sample; } @@ -621,47 +519,22 @@ public final class ServerPing { */ public static final class SamplePlayer { - /** - * A constant representing an anonymous sample player with a null UUID and generic name. - */ public static final SamplePlayer ANONYMOUS = new SamplePlayer( "Anonymous Player", new UUID(0L, 0L) ); - /** - * The legacy string name of the player. - */ private final String name; - /** - * The unique identifier (UUID) of the player. - */ private final UUID id; - /** - * Constructs a SamplePlayer with the given name and UUID. - * - * @param name the name of the player - * @param id the UUID of the player - */ public SamplePlayer(String name, UUID id) { this.name = name; this.id = id; } - /** - * Gets the legacy string name of the sample player. - * - * @return the player name - */ public String getName() { return name; } - /** - * Gets the UUID of the sample player. - * - * @return the player UUID - */ public UUID getId() { return id; } diff --git a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java index c99ffe7d..5fd60e5b 100644 --- a/api/src/main/java/com/velocitypowered/api/util/GameProfile.java +++ b/api/src/main/java/com/velocitypowered/api/util/GameProfile.java @@ -220,29 +220,14 @@ public final class GameProfile implements PlayerHeadObjectContents.SkinSource { this.signature = Preconditions.checkNotNull(signature, "signature"); } - /** - * Returns the name of this property. - * - * @return the property name - */ public String getName() { return name; } - /** - * Returns the value of this property. - * - * @return the property value - */ public String getValue() { return value; } - /** - * Returns the Mojang-provided signature for this property. - * - * @return the property signature - */ public String getSignature() { return signature; } diff --git a/api/src/main/java/com/velocitypowered/api/util/ModInfo.java b/api/src/main/java/com/velocitypowered/api/util/ModInfo.java index d5e252fa..cfc52289 100644 --- a/api/src/main/java/com/velocitypowered/api/util/ModInfo.java +++ b/api/src/main/java/com/velocitypowered/api/util/ModInfo.java @@ -18,10 +18,6 @@ import java.util.Objects; */ public final class ModInfo { - /** - * The default mod info used when no mods are present. - * Typically used for Forge-compatible connections that require a placeholder. - */ public static final ModInfo DEFAULT = new ModInfo("FML", ImmutableList.of()); private final String type; @@ -38,20 +34,10 @@ public final class ModInfo { this.modList = ImmutableList.copyOf(modList); } - /** - * Returns the Forge mod list type (e.g., "FML"). - * - * @return the mod list type - */ public String getType() { return type; } - /** - * Returns an immutable list of all mods in this mod list. - * - * @return the list of mods - */ public List getMods() { return modList; } @@ -103,20 +89,10 @@ public final class ModInfo { Preconditions.checkArgument(version.length() < 128, "mod version is too long"); } - /** - * Returns the mod ID (identifier string). - * - * @return the mod ID - */ public String getId() { return id; } - /** - * Returns the mod version string. - * - * @return the mod version - */ public String getVersion() { return version; } diff --git a/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java b/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java index 303fbd0f..abc3a14a 100644 --- a/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java +++ b/api/src/main/java/com/velocitypowered/api/util/ProxyVersion.java @@ -33,29 +33,14 @@ public final class ProxyVersion { this.version = Preconditions.checkNotNull(version, "version"); } - /** - * Gets the name of the proxy implementation. - * - * @return the name of the proxy - */ public String getName() { return name; } - /** - * Gets the vendor of the proxy implementation. - * - * @return the vendor of the proxy - */ public String getVendor() { return vendor; } - /** - * Gets the version of the proxy implementation. - * - * @return the version of the proxy - */ public String getVersion() { return version; } diff --git a/api/src/main/java/com/velocitypowered/api/util/ServerLink.java b/api/src/main/java/com/velocitypowered/api/util/ServerLink.java index 484833fe..9eb04a98 100644 --- a/api/src/main/java/com/velocitypowered/api/util/ServerLink.java +++ b/api/src/main/java/com/velocitypowered/api/util/ServerLink.java @@ -38,7 +38,6 @@ public final class ServerLink { * * @param label a custom component label to display * @param link the URL to open when clicked - * @return a {@link ServerLink} instance with the given label and URL */ public static ServerLink serverLink(Component label, String link) { return new ServerLink(label, link); @@ -49,7 +48,6 @@ public final class ServerLink { * * @param type the {@link Type built-in type} of link * @param link the URL to open when clicked - * @return a {@link ServerLink} instance with the given type and URL */ public static ServerLink serverLink(Type type, String link) { return new ServerLink(type, link); @@ -88,45 +86,15 @@ public final class ServerLink { * @apiNote {@link Type#BUG_REPORT} links are shown on the connection error screen */ public enum Type { - /** - * A link to report bugs related to the server or gameplay. - */ BUG_REPORT, - /** - * A link to the server's community guidelines or rules. - */ COMMUNITY_GUIDELINES, - /** - * A link to the server’s support or help desk. - */ SUPPORT, - /** - * A link showing the current server or service status. - */ STATUS, - /** - * A link to provide feedback to the server staff or developers. - */ FEEDBACK, - /** - * A link to the server’s community hub or Discord. - */ COMMUNITY, - /** - * A link to the server's main website. - */ WEBSITE, - /** - * A link to the server's forums. - */ FORUMS, - /** - * A link to server or game-related news. - */ NEWS, - /** - * A link to announcements from the server team. - */ ANNOUNCEMENTS } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5ad83ecc..7be8d469 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,12 +3,12 @@ configurate3 = "3.7.3" configurate4 = "4.2.0" flare = "2.0.1" log4j = "2.25.3" -netty = "4.2.9.Final" +netty = "4.2.7.Final" [plugins] fill = "io.papermc.fill.gradle:1.0.10" shadow = "com.gradleup.shadow:9.3.1" -spotless = "com.diffplug.spotless:8.2.1" +spotless = "com.diffplug.spotless:8.2.0" [libraries] adventure-bom = "net.kyori:adventure-bom:4.26.1" @@ -21,7 +21,7 @@ brigadier = "com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT" bstats = "org.bstats:bstats-base:3.1.0" caffeine = "com.github.ben-manes.caffeine:caffeine:3.2.3" checker-qual = "org.checkerframework:checker-qual:3.53.0" -checkstyle = "com.puppycrawl.tools:checkstyle:13.0.0" +checkstyle = "com.puppycrawl.tools:checkstyle:10.9.3" completablefutures = "com.spotify:completable-futures:0.3.6" configurate3-hocon = { module = "org.spongepowered:configurate-hocon", version.ref = "configurate3" } configurate3-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate3" } @@ -30,12 +30,12 @@ configurate4-hocon = { module = "org.spongepowered:configurate-hocon", version.r configurate4-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate4" } configurate4-gson = { module = "org.spongepowered:configurate-gson", version.ref = "configurate4" } disruptor = "com.lmax:disruptor:4.0.0" -fastutil = "it.unimi.dsi:fastutil:8.5.18" +fastutil = "it.unimi.dsi:fastutil:8.5.15" flare-core = { module = "space.vectrix.flare:flare", version.ref = "flare" } flare-fastutil = { module = "space.vectrix.flare:flare-fastutil", version.ref = "flare" } jline = "org.jline:jline-terminal-jansi:3.30.6" jopt = "net.sf.jopt-simple:jopt-simple:5.0.4" -junit = "org.junit.jupiter:junit-jupiter:6.0.2" +junit = "org.junit.jupiter:junit-jupiter:5.14.2" jspecify = "org.jspecify:jspecify:1.0.0" kyori-ansi = "net.kyori:ansi:1.1.1" guava = "com.google.guava:guava:33.5.0-jre" diff --git a/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java b/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java index 886f2081..13f4f0c5 100644 --- a/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java +++ b/native/src/main/java/com/velocitypowered/natives/util/MoreByteBufUtils.java @@ -54,8 +54,8 @@ public class MoreByteBufUtils { BufferPreference preferred = nativeStuff.preferredBufferType(); return switch (preferred) { case DIRECT_PREFERRED, HEAP_PREFERRED -> - // The native prefers this type, but doesn't strictly require we provide it. - true; + // The native prefers this type, but doesn't strictly require we provide it. + true; case DIRECT_REQUIRED -> buf.hasMemoryAddress(); case HEAP_REQUIRED -> buf.hasArray(); }; diff --git a/proxy/build.gradle.kts b/proxy/build.gradle.kts index d78a7a3b..c7164c15 100644 --- a/proxy/build.gradle.kts +++ b/proxy/build.gradle.kts @@ -14,6 +14,10 @@ application { } tasks { + withType { + exclude("**/com/velocitypowered/proxy/protocol/packet/**") + } + jar { manifest { attributes["Implementation-Title"] = "Velocity" @@ -29,7 +33,7 @@ tasks { transform(Log4j2PluginsCacheFileTransformer::class.java) - // Exclude all the collection types we don't intend to use + // Exclude all the collection types we don"t intend to use exclude("it/unimi/dsi/fastutil/booleans/**") exclude("it/unimi/dsi/fastutil/bytes/**") exclude("it/unimi/dsi/fastutil/chars/**") @@ -38,7 +42,7 @@ tasks { exclude("it/unimi/dsi/fastutil/longs/**") exclude("it/unimi/dsi/fastutil/shorts/**") - // Exclude the fastutil IO utilities - we don't use them. + // Exclude the fastutil IO utilities - we don"t use them. exclude("it/unimi/dsi/fastutil/io/**") // Exclude most of the int types - Object2IntMap have a values() method that returns an diff --git a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java index f44cb99e..95f10bcb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/VelocityServer.java @@ -650,7 +650,7 @@ public class VelocityServer implements ProxyServer, ForwardingAudience { } /** - * Calls {@link #shutdown(boolean, Component)} with the default reason "Proxy shutting down.". + * Calls {@link #shutdown(boolean, Component)} with the default reason "Proxy shutting down." * * @param explicitExit whether the user explicitly shut down the proxy */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java index 3bef8a4b..f0fd5e08 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ModernResourcePackHandler.java @@ -37,7 +37,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** - * Modern (Minecraft 1.20.3+) ResourcePackHandler. + * Modern (Minecraft 1.20.3+) ResourcePackHandler */ public final class ModernResourcePackHandler extends ResourcePackHandler { private final ListMultimap outstandingResourcePacks = diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java index dc04b912..b3843885 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/resourcepack/handler/ResourcePackHandler.java @@ -118,7 +118,6 @@ public abstract sealed class ResourcePackHandler /** * Processes a client response to a sent resource-pack. - * *

      Cases in which no action will be taken:

      *
        * diff --git a/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java b/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java index 7037ee2a..9d54b2d0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/event/VelocityEventManager.java @@ -545,36 +545,6 @@ public class VelocityEventManager implements EventManager { } } - private void fire(final @Nullable CompletableFuture future, final E event, - final int offset, final boolean currentlyAsync, final HandlerRegistration[] registrations) { - for (int i = offset; i < registrations.length; i++) { - final HandlerRegistration registration = registrations[i]; - try { - final EventTask eventTask = registration.handler.executeAsync(event); - if (eventTask == null) { - continue; - } - final ContinuationTask continuationTask = new ContinuationTask<>(eventTask, - registrations, future, event, i, currentlyAsync); - if (currentlyAsync || !eventTask.requiresAsync()) { - if (continuationTask.execute()) { - continue; - } - } else { - registration.plugin.getExecutorService().execute(continuationTask); - } - // fire will continue in another thread once the async task is - // executed and the continuation is resumed - return; - } catch (final Throwable t) { - logHandlerException(registration, t); - } - } - if (future != null) { - future.complete(event); - } - } - private static final int TASK_STATE_DEFAULT = 0; private static final int TASK_STATE_EXECUTING = 1; private static final int TASK_STATE_CONTINUE_IMMEDIATELY = 2; @@ -699,10 +669,40 @@ public class VelocityEventManager implements EventManager { } } + private void fire(final @Nullable CompletableFuture future, final E event, + final int offset, final boolean currentlyAsync, final HandlerRegistration[] registrations) { + for (int i = offset; i < registrations.length; i++) { + final HandlerRegistration registration = registrations[i]; + try { + final EventTask eventTask = registration.handler.executeAsync(event); + if (eventTask == null) { + continue; + } + final ContinuationTask continuationTask = new ContinuationTask<>(eventTask, + registrations, future, event, i, currentlyAsync); + if (currentlyAsync || !eventTask.requiresAsync()) { + if (continuationTask.execute()) { + continue; + } + } else { + registration.plugin.getExecutorService().execute(continuationTask); + } + // fire will continue in another thread once the async task is + // executed and the continuation is resumed + return; + } catch (final Throwable t) { + logHandlerException(registration, t); + } + } + if (future != null) { + future.complete(event); + } + } + private static void logHandlerException( final HandlerRegistration registration, final Throwable t) { final PluginDescription pluginDescription = registration.plugin.getDescription(); logger.error("Couldn't pass {} to {} {}", registration.eventType.getSimpleName(), pluginDescription.getId(), pluginDescription.getVersion().orElse(""), t); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 093256d0..efc0ed17 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -633,7 +633,7 @@ public enum ProtocolUtils { private static final int FORGE_MAX_ARRAY_LENGTH = Integer.MAX_VALUE & 0x1FFF9A; /** - * Reads an byte array for legacy version 1.7 from the specified {@code buf}. + * Reads an byte array for legacy version 1.7 from the specified {@code buf} * * @param buf the buffer to read from * @return the read byte array @@ -671,7 +671,7 @@ public enum ProtocolUtils { } /** - * Writes an byte array for legacy version 1.7 to the specified {@code buf}. + * Writes an byte array for legacy version 1.7 to the specified {@code buf} * * @param b array * @param buf buf @@ -695,7 +695,7 @@ public enum ProtocolUtils { } /** - * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf}. + * Writes an {@link ByteBuf} for legacy version 1.7 to the specified {@code buf} * * @param b array * @param buf buf diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java index 23cebf61..2746b23f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java @@ -53,13 +53,6 @@ import java.util.function.Predicate; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a packet that contains the list of available commands, implementing {@link MinecraftPacket}. - * - *

        The {@code AvailableCommandsPacket} is responsible for transmitting the set of commands - * that a player can execute. It provides the necessary information about available commands - * within the current session or game state.

        - */ public class AvailableCommandsPacket implements MinecraftPacket { private static final Command PLACEHOLDER_COMMAND = source -> 0; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java index 06cbd861..d7748eff 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BossBarPacket.java @@ -29,10 +29,6 @@ import java.util.UUID; import net.kyori.adventure.bossbar.BossBar; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a packet used to manage boss bars. - * This packet can add, remove, or update a boss bar. - */ public class BossBarPacket implements MinecraftPacket { private static final Enum2IntMap COLORS_TO_PROTOCOL = @@ -74,14 +70,6 @@ public class BossBarPacket implements MinecraftPacket { private int overlay; private short flags; - /** - * Creates a packet to add a new boss bar. - * - * @param id the UUID of the boss bar - * @param bar the {@link BossBar} instance - * @param name the {@link ComponentHolder} containing the boss bar's name - * @return a {@link BossBarPacket} to add a boss bar - */ public static BossBarPacket createAddPacket( final UUID id, final BossBar bar, @@ -98,13 +86,6 @@ public class BossBarPacket implements MinecraftPacket { return packet; } - /** - * Creates a packet to remove an existing boss bar. - * - * @param id the UUID of the boss bar to remove - * @param bar the {@link BossBar} instance - * @return a {@link BossBarPacket} to remove a boss bar - */ public static BossBarPacket createRemovePacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -112,13 +93,6 @@ public class BossBarPacket implements MinecraftPacket { return packet; } - /** - * Creates a packet to update the progress (percentage) of the boss bar. - * - * @param id the UUID of the boss bar - * @param bar the {@link BossBar} instance - * @return a {@link BossBarPacket} to update the boss bar's progress - */ public static BossBarPacket createUpdateProgressPacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -127,14 +101,6 @@ public class BossBarPacket implements MinecraftPacket { return packet; } - /** - * Creates a packet to update the name of the boss bar. - * - * @param id the UUID of the boss bar - * @param bar the {@link BossBar} instance - * @param name the {@link ComponentHolder} containing the boss bar's new name - * @return a {@link BossBarPacket} to update the boss bar's name - */ public static BossBarPacket createUpdateNamePacket( final UUID id, final BossBar bar, @@ -147,13 +113,6 @@ public class BossBarPacket implements MinecraftPacket { return packet; } - /** - * Creates a packet to update the style (color and overlay) of the boss bar. - * - * @param id the UUID of the boss bar - * @param bar the {@link BossBar} instance - * @return a {@link BossBarPacket} to update the boss bar's style - */ public static BossBarPacket createUpdateStylePacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -163,13 +122,6 @@ public class BossBarPacket implements MinecraftPacket { return packet; } - /** - * Creates a packet to update the properties of the boss bar. - * - * @param id the UUID of the boss bar - * @param bar the {@link BossBar} instance - * @return a {@link BossBarPacket} to update the boss bar's properties - */ public static BossBarPacket createUpdatePropertiesPacket(final UUID id, final BossBar bar) { final BossBarPacket packet = new BossBarPacket(); packet.setUuid(id); @@ -178,12 +130,6 @@ public class BossBarPacket implements MinecraftPacket { return packet; } - /** - * Retrieves the UUID of the boss bar. - * - * @return the UUID of the boss bar - * @throws IllegalStateException if the UUID has not been set - */ public UUID getUuid() { if (uuid == null) { throw new IllegalStateException("No boss bar UUID specified"); @@ -268,8 +214,7 @@ public class BossBarPacket implements MinecraftPacket { this.overlay = ProtocolUtils.readVarInt(buf); this.flags = buf.readUnsignedByte(); } - case REMOVE -> { - } + case REMOVE -> {} case UPDATE_PERCENT -> this.percent = buf.readFloat(); case UPDATE_NAME -> this.name = ComponentHolder.read(buf, version); case UPDATE_STYLE -> { @@ -290,23 +235,22 @@ public class BossBarPacket implements MinecraftPacket { ProtocolUtils.writeVarInt(buf, action); switch (action) { case ADD -> { - if (name == null) { - throw new IllegalStateException("No name specified!"); - } - name.write(buf); - buf.writeFloat(percent); - ProtocolUtils.writeVarInt(buf, color); - ProtocolUtils.writeVarInt(buf, overlay); - buf.writeByte(flags); - } - case REMOVE -> { + if (name == null) { + throw new IllegalStateException("No name specified!"); + } + name.write(buf); + buf.writeFloat(percent); + ProtocolUtils.writeVarInt(buf, color); + ProtocolUtils.writeVarInt(buf, overlay); + buf.writeByte(flags); } + case REMOVE -> {} case UPDATE_PERCENT -> buf.writeFloat(percent); case UPDATE_NAME -> { - if (name == null) { - throw new IllegalStateException("No name specified!"); - } - name.write(buf); + if (name == null) { + throw new IllegalStateException("No name specified!"); + } + name.write(buf); } case UPDATE_STYLE -> { ProtocolUtils.writeVarInt(buf, color); @@ -320,7 +264,7 @@ public class BossBarPacket implements MinecraftPacket { private static byte serializeFlags(Set flags) { byte val = 0x0; for (BossBar.Flag flag : flags) { - val |= (byte) FLAG_BITS_TO_PROTOCOL.get(flag); + val |= FLAG_BITS_TO_PROTOCOL.get(flag); } return val; } @@ -329,4 +273,4 @@ public class BossBarPacket implements MinecraftPacket { public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java index 5c6827f3..4da691c7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/BundleDelimiterPacket.java @@ -23,14 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet used as a delimiter for bundling multiple packets together. - * The {@code BundleDelimiterPacket} marks the beginning or end of a packet bundle, - * allowing the server and client to process groups of packets as a single logical unit. - * - *

        This packet is typically used to signal the start or end of a packet sequence that - * are sent together, enabling efficient transmission and processing of related data.

        - */ public final class BundleDelimiterPacket implements MinecraftPacket { public static final BundleDelimiterPacket INSTANCE = new BundleDelimiterPacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java index 743fb2ba..39e6fde0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java @@ -23,13 +23,9 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import java.util.Objects; + import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents the client settings packet in Minecraft, which is sent by the client - * to the server to communicate its settings such as locale, view distance, chat preferences, - * skin customization, and other client-side configurations. - */ public class ClientSettingsPacket implements MinecraftPacket { private @Nullable String locale; private byte viewDistance; @@ -45,19 +41,6 @@ public class ClientSettingsPacket implements MinecraftPacket { public ClientSettingsPacket() { } - /** - * Constructs a new {@code ClientSettingsPacket} with the specified settings. - * - * @param locale the client's locale setting - * @param viewDistance the view distance - * @param chatVisibility the client's chat visibility setting - * @param chatColors whether chat colors are enabled - * @param skinParts the customization for skin parts - * @param mainHand the client's main hand preference - * @param textFilteringEnabled whether text filtering is enabled - * @param clientListingAllowed whether the client allows listing - * @param particleStatus whether particles are enabled - */ public ClientSettingsPacket(String locale, byte viewDistance, int chatVisibility, boolean chatColors, short skinParts, int mainHand, boolean textFilteringEnabled, boolean clientListingAllowed, int particleStatus) { @@ -72,12 +55,6 @@ public class ClientSettingsPacket implements MinecraftPacket { this.particleStatus = particleStatus; } - /** - * Gets the client's locale. - * - * @return the locale - * @throws IllegalStateException if no locale is specified - */ public String getLocale() { if (locale == null) { throw new IllegalStateException("No locale specified"); @@ -155,10 +132,10 @@ public class ClientSettingsPacket implements MinecraftPacket { @Override public String toString() { - return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance - + ", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" - + skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + textFilteringEnabled - + ", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}'; + return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance + + ", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" + + skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + textFilteringEnabled + + ", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java index 0e7c2a7a..fd558b29 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundCookieRequestPacket.java @@ -25,11 +25,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; -/** - * Represents a packet sent from the server to the client to request cookies. - * This packet can be used to initiate a request for cookie-related data from the client, - * typically for authentication or tracking purposes. - */ public class ClientboundCookieRequestPacket implements MinecraftPacket { private Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java index 9ccebf3b..459f1430 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java @@ -22,16 +22,11 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -import java.util.Random; import net.kyori.adventure.sound.Sound; import org.jetbrains.annotations.Nullable; -/** - * A clientbound packet that instructs the client to play a sound tied to an entity. - * - *

        This is sent by the server when a sound should be played at the location of a - * specific entity, with optional fixed range and seed.

        - */ +import java.util.Random; + public class ClientboundSoundEntityPacket implements MinecraftPacket { private static final Random SEEDS_RANDOM = new Random(); @@ -40,16 +35,8 @@ public class ClientboundSoundEntityPacket implements MinecraftPacket { private @Nullable Float fixedRange; private int emitterEntityId; - public ClientboundSoundEntityPacket() { - } + public ClientboundSoundEntityPacket() {} - /** - * Constructs a new sound entity packet. - * - * @param sound the sound to play - * @param fixedRange the fixed attenuation range, or {@code null} to use the default - * @param emitterEntityId the entity ID of the sound emitter - */ public ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange, int emitterEntityId) { this.sound = sound; this.fixedRange = fixedRange; @@ -68,9 +55,8 @@ public class ClientboundSoundEntityPacket implements MinecraftPacket { ProtocolUtils.writeMinimalKey(buf, sound.name()); buf.writeBoolean(fixedRange != null); - if (fixedRange != null) { + if (fixedRange != null) buf.writeFloat(fixedRange); - } ProtocolUtils.writeSoundSource(buf, protocolVersion, sound.source()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java index ecf14c5a..3e085d38 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java @@ -22,24 +22,18 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -import javax.annotation.Nullable; import net.kyori.adventure.key.Key; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.sound.SoundStop; -/** - * A clientbound packet instructing the client to stop one or more sounds. - * - *

        This packet supports specifying a {@link Sound.Source}, a {@link Key} sound identifier, - * or both together. If neither is specified, the client will stop all currently playing sounds.

        - */ +import javax.annotation.Nullable; + public class ClientboundStopSoundPacket implements MinecraftPacket { private @Nullable Sound.Source source; private @Nullable Key soundName; - public ClientboundStopSoundPacket() { - } + public ClientboundStopSoundPacket() {} public ClientboundStopSoundPacket(SoundStop soundStop) { this(soundStop.source(), soundStop.sound()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java index e551473a..7823b558 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStoreCookiePacket.java @@ -25,11 +25,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; -/** - * Represents a packet sent from the server to the client to store a cookie. - * This packet can be used to send cookie-related data from the server to be stored or processed - * by the client. - */ public class ClientboundStoreCookiePacket implements MinecraftPacket { private Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java index e64e1ada..4188abfd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogClearPacket.java @@ -23,13 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; -/** - * Represents the packet sent by the server to the client to clear any - * currently displayed configuration dialog. - * - *

        This packet is used during the configuration phase (1.21.6+) to - * instruct the client to dismiss an active dialog window.

        - */ public class DialogClearPacket implements MinecraftPacket { public static final DialogClearPacket INSTANCE = new DialogClearPacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java index 21a69cc2..67d4b8f8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DialogShowPacket.java @@ -27,13 +27,6 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.BinaryTagIO; -/** - * Represents the packet sent by the server to the client to display a configuration dialog - * during the configuration phase in Minecraft 1.21.6+. - * - *

        This packet is only relevant in the CONFIG and PLAY states. If the ID is {@code 0}, - * a dialog is to be shown and the accompanying {@link BinaryTag} contains its data.

        - */ public class DialogShowPacket implements MinecraftPacket { private final StateRegistry state; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java index 7074e8fd..dd16cb61 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/DisconnectPacket.java @@ -28,12 +28,6 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a packet sent by the server to disconnect the client. This packet contains - * a reason for the disconnection, which is sent to the client and displayed to the player. - * The packet can be sent in different states (e.g., login, play), which affects how the - * reason is processed. - */ public class DisconnectPacket implements MinecraftPacket { private @Nullable ComponentHolder reason; @@ -48,12 +42,6 @@ public class DisconnectPacket implements MinecraftPacket { this.reason = Preconditions.checkNotNull(reason, "reason"); } - /** - * Retrieves the reason for the disconnection, which will be sent to the client. - * - * @return the reason for the disconnection as a {@link ComponentHolder} - * @throws IllegalStateException if no reason is specified - */ public ComponentHolder getReason() { if (reason == null) { throw new IllegalStateException("No reason specified"); @@ -74,8 +62,8 @@ public class DisconnectPacket implements MinecraftPacket { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - reason = ComponentHolder.read(buf, state == StateRegistry.LOGIN - ? ProtocolVersion.MINECRAFT_1_20_2 : version); + reason = ComponentHolder.read(buf, state == StateRegistry.LOGIN + ? ProtocolVersion.MINECRAFT_1_20_2 : version); } @Override @@ -88,17 +76,9 @@ public class DisconnectPacket implements MinecraftPacket { return handler.handle(this); } - /** - * Creates a new {@code DisconnectPacket} with the specified reason and version. - * - * @param component the component explaining the disconnection reason - * @param version the protocol version in use - * @param state the state in which the disconnection occurs - * @return the created {@code DisconnectPacket} - */ public static DisconnectPacket create(Component component, ProtocolVersion version, StateRegistry state) { Preconditions.checkNotNull(component, "component"); return new DisconnectPacket(state, new ComponentHolder(state == StateRegistry.LOGIN ? ProtocolVersion.MINECRAFT_1_20_2 : version, component)); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java index 66af05e0..422d5e11 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionRequestPacket.java @@ -26,12 +26,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import java.util.Arrays; -/** - * Represents the encryption request packet in Minecraft, which is sent by the server - * during the encryption handshake process. This packet is used to initiate secure - * communication by providing the client with the server's public key and a verified token. - * The client must respond with the encrypted shared secret and verify token. - */ public class EncryptionRequestPacket implements MinecraftPacket { private String serverId = ""; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java index eed2ab1f..fedb67a5 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/EncryptionResponsePacket.java @@ -26,18 +26,10 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; -import java.util.Arrays; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents the encryption response packet in Minecraft, which is sent by the client - * during the encryption handshake process. This packet contains the shared secret - * and verifies the token used to establish secure communication between the client - * and the server. - * - *

        The packet structure varies depending on the Minecraft protocol version, with additional - * fields such as a salt being present in versions 1.19 and above.

        - */ +import java.util.Arrays; + public class EncryptionResponsePacket implements MinecraftPacket { private static final QuietDecoderException NO_SALT = new QuietDecoderException( @@ -55,13 +47,6 @@ public class EncryptionResponsePacket implements MinecraftPacket { return verifyToken.clone(); } - /** - * Retrieves the salt used in the encryption response. The salt is introduced in - * Minecraft version 1.19 and is optional in certain protocol versions. - * - * @return the salt used in the encryption response - * @throws QuietDecoderException if the salt is not present - */ public long getSalt() { if (salt == null) { throw NO_SALT; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java index 5deaf395..88cb3688 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HandshakePacket.java @@ -27,12 +27,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; -/** - * Represents a handshake packet in Minecraft, which is used during the initial connection process. - * This packet contains information such as the protocol version, server address, port, and the intent - * of the handshake (e.g., login or status request). This packet is crucial for establishing a connection - * between the client and the server. - */ public class HandshakePacket implements MinecraftPacket { // This size was chosen to ensure Forge clients can still connect even with very long hostnames. @@ -116,13 +110,13 @@ public class HandshakePacket implements MinecraftPacket { @Override public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 7; } @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java index 55eb3ebc..339d026f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/HeaderAndFooterPacket.java @@ -26,10 +26,6 @@ import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; import net.kyori.adventure.text.Component; -/** - * Represents a packet that contains both the header and footer for the player list screen (tab list) in Minecraft. - * This packet allows the server to set or update the header and footer text that is displayed on the client's tab list. - */ public class HeaderAndFooterPacket implements MinecraftPacket { private final ComponentHolder header; @@ -71,11 +67,11 @@ public class HeaderAndFooterPacket implements MinecraftPacket { public static HeaderAndFooterPacket create(Component header, Component footer, ProtocolVersion protocolVersion) { return new HeaderAndFooterPacket(new ComponentHolder(protocolVersion, header), - new ComponentHolder(protocolVersion, footer)); + new ComponentHolder(protocolVersion, footer)); } public static HeaderAndFooterPacket reset(ProtocolVersion version) { ComponentHolder empty = new ComponentHolder(version, Component.empty()); return new HeaderAndFooterPacket(empty, empty); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java index 81ac98ae..787d858e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGamePacket.java @@ -21,19 +21,13 @@ import com.google.common.collect.ImmutableSet; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.connection.registry.DimensionInfo; -import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.ProtocolUtils; +import com.velocitypowered.proxy.protocol.*; import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.Pair; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a packet sent to the client when they successfully join a game in Minecraft. - * This packet contains all the necessary information to initialize the client state, - * including the player's entity ID, game mode, dimension, world settings, and more. - */ public class JoinGamePacket implements MinecraftPacket { private static final BinaryTagIO.Reader JOINGAME_READER = BinaryTagIO.reader(4 * 1024 * 1024); @@ -210,17 +204,17 @@ public class JoinGamePacket implements MinecraftPacket { @Override public String toString() { - return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" - + dimension + ", partialHashedSeed=" + partialHashedSeed + ", difficulty=" + difficulty - + ", isHardcore=" + isHardcore + ", maxPlayers=" + maxPlayers + ", levelType='" + levelType - + '\'' + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo - + ", showRespawnScreen=" + showRespawnScreen + ", doLimitedCrafting=" + doLimitedCrafting - + ", levelNames=" + levelNames + ", registry='" + registry + '\'' + ", dimensionInfo='" - + dimensionInfo + '\'' + ", currentDimensionData='" + currentDimensionData + '\'' - + ", previousGamemode=" + previousGamemode + ", simulationDistance=" + simulationDistance - + ", lastDeathPosition='" + lastDeathPosition + '\'' + ", portalCooldown=" + portalCooldown - + ", seaLevel=" + seaLevel - + '}'; + return "JoinGame{" + "entityId=" + entityId + ", gamemode=" + gamemode + ", dimension=" + + dimension + ", partialHashedSeed=" + partialHashedSeed + ", difficulty=" + difficulty + + ", isHardcore=" + isHardcore + ", maxPlayers=" + maxPlayers + ", levelType='" + levelType + + '\'' + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo + + ", showRespawnScreen=" + showRespawnScreen + ", doLimitedCrafting=" + doLimitedCrafting + + ", levelNames=" + levelNames + ", registry='" + registry + '\'' + ", dimensionInfo='" + + dimensionInfo + '\'' + ", currentDimensionData='" + currentDimensionData + '\'' + + ", previousGamemode=" + previousGamemode + ", simulationDistance=" + simulationDistance + + ", lastDeathPosition='" + lastDeathPosition + '\'' + ", portalCooldown=" + portalCooldown + + ", seaLevel=" + seaLevel + + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java index 3ae2d89d..a44e50ee 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java @@ -23,11 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a KeepAlive packet in Minecraft. This packet is used to ensure that the connection - * between the client and the server shall still be active by sending a randomly generated ID that - * the client must respond to. - */ public class KeepAlivePacket implements MinecraftPacket { private long randomId; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java index 952dfe28..e8f8deef 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyDisconnect.java @@ -25,13 +25,7 @@ import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; -/** - * Represents a legacy disconnect packet that contains a reason for disconnection. - * This class is used to convert modern server ping responses into the legacy format, - * which is compatible with older Minecraft versions. - * - * @param reason the string reason for disconnection - */ +@SuppressWarnings("checkstyle:MissingJavadocType") public record LegacyDisconnect(String reason) { private static final ServerPing.Players FAKE_PLAYERS = new ServerPing.Players(0, 0, @@ -52,17 +46,17 @@ public record LegacyDisconnect(String reason) { return switch (version) { case MINECRAFT_1_3 -> - // Minecraft 1.3 and below use the section symbol as a delimiter. Accordingly, we must - // remove all section symbols, along with fetching just the first line of an (unformatted) - // MOTD. - new LegacyDisconnect(String.join(LEGACY_COLOR_CODE, + // Minecraft 1.3 and below use the section symbol as a delimiter. Accordingly, we must + // remove all section symbols, along with fetching just the first line of an (unformatted) + // MOTD. + new LegacyDisconnect(String.join(LEGACY_COLOR_CODE, cleanSectionSymbol(getFirstLine(PlainTextComponentSerializer.plainText().serialize( response.getDescriptionComponent()))), Integer.toString(players.getOnline()), Integer.toString(players.getMax()))); case MINECRAFT_1_4, MINECRAFT_1_6 -> - // Minecraft 1.4-1.6 provide support for more fields, and additionally support color codes. - new LegacyDisconnect(String.join("\0", + // Minecraft 1.4-1.6 provide support for more fields, and additionally support color codes. + new LegacyDisconnect(String.join("\0", LEGACY_COLOR_CODE + "1", Integer.toString(response.getVersion().getProtocol()), response.getVersion().getName(), diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java index 8a9aba27..38483ed8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyHandshakePacket.java @@ -23,11 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a legacy handshake packet in Minecraft, which is typically used - * during the initial connection process for older versions of the Minecraft protocol. - * This class currently does not support decoding of the handshake packet. - */ public class LegacyHandshakePacket implements MinecraftPacket { @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java index c81c4722..656d3222 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPingPacket.java @@ -26,11 +26,6 @@ import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a legacy ping packet in Minecraft, commonly used in the server list ping process. - * This packet handles compatibility with older Minecraft versions and contains information - * such as the ping protocol version and optionally a virtual host address. - */ public class LegacyPingPacket implements MinecraftPacket { private final LegacyMinecraftPingVersion version; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java index cdffabcc..9dbe9cbc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LegacyPlayerListItemPacket.java @@ -33,10 +33,6 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a legacy player list item packet, which is used to modify the player list in a Minecraft client. - * The packet can add, remove, or update player entries (e.g., updating gamemode, latency, or display names). - */ public class LegacyPlayerListItemPacket implements MinecraftPacket { public static final int ADD_PLAYER = 0; @@ -80,16 +76,16 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { item.setLatency(ProtocolUtils.readVarInt(buf)); item.setDisplayName(readOptionalComponent(buf, version)); if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) { - if (buf.readBoolean()) { - item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf)); - } + if (buf.readBoolean()) { + item.setPlayerKey(ProtocolUtils.readPlayerKey(version, buf)); + } } } case UPDATE_GAMEMODE -> item.setGameMode(ProtocolUtils.readVarInt(buf)); case UPDATE_LATENCY -> item.setLatency(ProtocolUtils.readVarInt(buf)); case UPDATE_DISPLAY_NAME -> item.setDisplayName(readOptionalComponent(buf, version)); case REMOVE_PLAYER -> { - // Do nothing, all that is needed is the uuid + //Do nothing, all that is needed is the uuid } default -> throw new UnsupportedOperationException("Unknown action " + action); } @@ -111,17 +107,6 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { return null; } - /** - * Encodes this packet's contents into the given {@link ByteBuf}. - * - *

        This method serializes the packet data based on the current protocol version. - * Subclasses overriding this method should preserve compatibility with legacy - * and modern formats as needed.

        - * - * @param buf the buffer to write to - * @param direction the direction of the packet (clientbound or serverbound) - * @param version the Minecraft protocol version - */ @Override public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) { @@ -140,12 +125,12 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { ProtocolUtils.writeVarInt(buf, item.getLatency()); writeDisplayName(buf, item.getDisplayName(), version); if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) { - if (item.getPlayerKey() != null) { - buf.writeBoolean(true); - ProtocolUtils.writePlayerKey(buf, item.getPlayerKey()); - } else { - buf.writeBoolean(false); - } + if (item.getPlayerKey() != null) { + buf.writeBoolean(true); + ProtocolUtils.writePlayerKey(buf, item.getPlayerKey()); + } else { + buf.writeBoolean(false); + } } } case UPDATE_GAMEMODE -> ProtocolUtils.writeVarInt(buf, item.getGameMode()); @@ -187,10 +172,6 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { } } - /** - * Represents an individual item in the player list, containing the player's details such as UUID, name, - * game mode, latency, and optionally a display name and player key. - */ public static class Item { private final UUID uuid; @@ -209,15 +190,6 @@ public class LegacyPlayerListItemPacket implements MinecraftPacket { this.uuid = uuid; } - /** - * Creates an {@link Item} instance from a {@link TabListEntry}. - * This method extracts relevant data from the {@link TabListEntry} such as - * the player's profile ID, name, properties, latency, game mode, player key, - * and display name, and uses them to populate a new {@code Item}. - * - * @param entry the {@link TabListEntry} from which to extract data - * @return an {@link Item} populated with data from the {@link TabListEntry} - */ public static Item from(TabListEntry entry) { return new Item(entry.getProfile().getId()) .setName(entry.getProfile().getName()) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java index 15bbb2c3..16cf519b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginAcknowledgedPacket.java @@ -23,13 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet that acknowledges a successful login, implementing {@link MinecraftPacket}. - * - *

        The {@code LoginAcknowledgedPacket} is sent by the server to confirm that the player's login - * process has been successfully completed. It signals the transition from the login phase to the - * game or session phase.

        - */ public class LoginAcknowledgedPacket implements MinecraftPacket { @Override @@ -44,7 +37,7 @@ public class LoginAcknowledgedPacket implements MinecraftPacket { @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java index 5833ea03..2fa82e92 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginMessagePacket.java @@ -27,10 +27,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a login plugin message packet sent during the login phase. This packet allows custom - * plugin messages to be sent from the server to the client before login is complete. - */ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket { private int id; @@ -40,13 +36,6 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M super(null); } - /** - * Constructs a new {@code LoginPluginMessagePacket} with the specified ID, channel, and data buffer. - * - * @param id the plugin message ID - * @param channel the channel name, or {@code null} if not specified - * @param data the data buffer - */ public LoginPluginMessagePacket(int id, @Nullable String channel, ByteBuf data) { super(data); this.id = id; @@ -57,12 +46,6 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M return id; } - /** - * Gets the plugin message channel. - * - * @return the channel name - * @throws IllegalStateException if the channel is not specified - */ public String getChannel() { if (channel == null) { throw new IllegalStateException("Channel is not specified!"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java index 1a8c1066..e7d9443d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/LoginPluginResponsePacket.java @@ -27,10 +27,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** - * Represents the response packet to a plugin message sent during the login phase. - * The packet contains the plugin message ID, a success flag, and any additional data. - */ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements MinecraftPacket { private int id; @@ -40,13 +36,6 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements super(Unpooled.EMPTY_BUFFER); } - /** - * Constructs a new {@code LoginPluginResponsePacket} with the specified ID, success status, and data buffer. - * - * @param id the plugin message ID - * @param success {@code true} if the plugin message was successful, {@code false} otherwise - * @param buf the data buffer - */ public LoginPluginResponsePacket(int id, boolean success, @MonotonicNonNull ByteBuf buf) { super(buf); this.id = id; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java index 7d870dcf..27c1351d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java @@ -23,9 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet used for ping identification with a unique ID. - */ public class PingIdentifyPacket implements MinecraftPacket { private int id; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java index bb8abf57..ecf2887f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java @@ -29,10 +29,6 @@ import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a plugin message packet, which allows for custom communication between - * a Minecraft server and a client via custom channels. - */ public class PluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket { private @Nullable String channel; @@ -47,12 +43,6 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr this.channel = channel; } - /** - * Gets the channel for this plugin message. - * - * @return the channel name - * @throws IllegalStateException if the channel is not set - */ public String getChannel() { if (channel == null) { throw new IllegalStateException("Channel is not specified."); @@ -83,6 +73,7 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr } else { this.replace(ProtocolUtils.readRetainedByteBufSlice17(buf)); } + } @Override @@ -106,6 +97,7 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr } else { ProtocolUtils.writeByteBuf17(content(), buf, true); // True for Forge support } + } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java index 255769d8..90ab3871 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java @@ -27,10 +27,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.UUID; -/** - * Represents a packet sent to remove player information from the player list. - * The packet contains a collection of {@link UUID}s representing the profiles to be removed. - */ public class RemovePlayerInfoPacket implements MinecraftPacket { private Collection profilesToRemove; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java index 8d6ef276..d003a0a9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemoveResourcePackPacket.java @@ -25,10 +25,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import java.util.UUID; -/** - * Represents a packet sent to remove a previously applied resource pack from the client. - * The packet contains an optional UUID that identifies the resource pack to be removed. - */ public class RemoveResourcePackPacket implements MinecraftPacket { private UUID id; @@ -64,4 +60,4 @@ public class RemoveResourcePackPacket implements MinecraftPacket { public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java index b5e7e63f..a0f86aed 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackRequestPacket.java @@ -33,10 +33,6 @@ import java.util.regex.Pattern; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a resource pack request packet sent by the server to prompt the client to download a resource pack. - * The packet includes the resource pack URL, SHA1 hash, and optional prompt. - */ public class ResourcePackRequestPacket implements MinecraftPacket { private @MonotonicNonNull UUID id; // 1.20.3+ @@ -128,12 +124,6 @@ public class ResourcePackRequestPacket implements MinecraftPacket { } } - /** - * Converts this packet into a {@link VelocityResourcePackInfo} object, which contains the information - * about the resource pack being requested. - * - * @return a {@code VelocityResourcePackInfo} representing the resource pack information - */ public VelocityResourcePackInfo toServerPromptedPack() { final ResourcePackInfo.Builder builder = new VelocityResourcePackInfo.BuilderImpl(Preconditions.checkNotNull(url)) @@ -155,12 +145,12 @@ public class ResourcePackRequestPacket implements MinecraftPacket { @Override public String toString() { - return "ResourcePackRequestPacket{" - + "id=" + id - + ", url='" + url + '\'' - + ", hash='" + hash + '\'' - + ", isRequired=" + isRequired - + ", prompt=" + prompt - + '}'; + return "ResourcePackRequestPacket{" + + "id=" + id + + ", url='" + url + '\'' + + ", hash='" + hash + '\'' + + ", isRequired=" + isRequired + + ", prompt=" + prompt + + '}'; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java index de5d0882..020c3530 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java @@ -24,13 +24,10 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; -import java.util.UUID; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** - * Represents the response packet sent by the client after receiving a resource pack request from the server. - * The packet contains information about the client's response, including the resource pack status. - */ +import java.util.UUID; + public class ResourcePackResponsePacket implements MinecraftPacket { private UUID id; @@ -40,25 +37,12 @@ public class ResourcePackResponsePacket implements MinecraftPacket { public ResourcePackResponsePacket() { } - /** - * Constructs a new {@code ResourcePackResponsePacket} with the specified parameters. - * - * @param id the unique identifier for the response - * @param hash the hash of the resource pack - * @param status the status of the resource pack - */ public ResourcePackResponsePacket(UUID id, String hash, @MonotonicNonNull Status status) { this.id = id; this.hash = hash; this.status = status; } - /** - * Gets the status of the resource pack response. - * - * @return the status of the response - * @throws IllegalStateException if the packet has not been deserialized yet - */ public Status getStatus() { if (status == null) { throw new IllegalStateException("Packet not yet deserialized"); @@ -103,10 +87,10 @@ public class ResourcePackResponsePacket implements MinecraftPacket { @Override public String toString() { - return "ResourcePackResponsePacket{" - + "id=" + id - + ", hash='" + hash + '\'' - + ", status=" + status - + '}'; + return "ResourcePackResponsePacket{" + + "id=" + id + + ", hash='" + hash + '\'' + + ", status=" + status + + '}'; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java index 2e13fcad..fd9c8ca7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RespawnPacket.java @@ -28,10 +28,6 @@ import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.CompoundBinaryTag; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a respawn packet sent by the server when the player changes dimensions or respawns. - * The packet contains information about the new dimension, difficulty, gamemode, and more. - */ public class RespawnPacket implements MinecraftPacket { private int dimension; @@ -50,22 +46,6 @@ public class RespawnPacket implements MinecraftPacket { public RespawnPacket() { } - /** - * Constructs a new {@code RespawnPacket} with the specified parameters. - * - * @param dimension the dimension the player is respawning or teleporting to - * @param partialHashedSeed the partial hashed seed - * @param difficulty the difficulty of the server - * @param gamemode the player's current gamemode - * @param levelType the type of level (e.g., "default", "flat") - * @param dataToKeep a byte flag indicating whether certain data should be kept - * @param dimensionInfo additional information about the dimension (for 1.16-1.16.1) - * @param previousGamemode the player's previous gamemode - * @param currentDimensionData data about the current dimension (for 1.16.2+) - * @param lastDeathPosition optional last death position (for 1.19+) - * @param portalCooldown the cooldown for portal usage (for 1.20+) - * @param seaLevel a determinable spawn point for a user (for 1.21.2+) - */ public RespawnPacket(int dimension, long partialHashedSeed, short difficulty, short gamemode, String levelType, byte dataToKeep, DimensionInfo dimensionInfo, short previousGamemode, CompoundBinaryTag currentDimensionData, @@ -85,12 +65,6 @@ public class RespawnPacket implements MinecraftPacket { this.seaLevel = seaLevel; } - /** - * Creates a new {@code RespawnPacket} from a {@link JoinGamePacket}. - * - * @param joinGame the {@code JoinGamePacket} to use - * @return a new {@code RespawnPacket} based on the provided {@code JoinGamePacket} - */ public static RespawnPacket fromJoinGame(JoinGamePacket joinGame) { return new RespawnPacket(joinGame.getDimension(), joinGame.getPartialHashedSeed(), joinGame.getDifficulty(), joinGame.getGamemode(), joinGame.getLevelType(), diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java index e1430aae..325a3c9d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerDataPacket.java @@ -25,14 +25,10 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; +import org.jetbrains.annotations.Nullable; import java.nio.charset.StandardCharsets; import java.util.Base64; -import org.jetbrains.annotations.Nullable; -/** - * Represents the server data packet sent from the server to the client, which contains information - * such as the server description, favicon, and secure chat enforcement status. - */ public class ServerDataPacket implements MinecraftPacket { private @Nullable ComponentHolder description; @@ -42,13 +38,6 @@ public class ServerDataPacket implements MinecraftPacket { public ServerDataPacket() { } - /** - * Constructs a new {@code ServerDataPacket} with the given server description, favicon, and secure chat enforcement status. - * - * @param description the server description (maybe null) - * @param favicon the server favicon (maybe null) - * @param secureChatEnforced whether secure chat is enforced (for versions 1.19.1 to 1.20.5) - */ public ServerDataPacket(@Nullable ComponentHolder description, @Nullable Favicon favicon, boolean secureChatEnforced) { this.description = description; @@ -138,4 +127,4 @@ public class ServerDataPacket implements MinecraftPacket { public int encodeSizeHint(Direction direction, ProtocolVersion version) { return 8 * 1024; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java index 8c8bec60..65693cd8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginPacket.java @@ -29,11 +29,6 @@ import io.netty.buffer.ByteBuf; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents the packet sent from the client to the server during the login phase. - * This packet contains the player's username, optionally a cryptographic key for - * authentication, and the holder UUID depending on the Minecraft protocol version. - */ public class ServerLoginPacket implements MinecraftPacket { private static final QuietDecoderException EMPTY_USERNAME = new QuietDecoderException( @@ -46,35 +41,17 @@ public class ServerLoginPacket implements MinecraftPacket { public ServerLoginPacket() { } - /** - * Constructs a {@code ServerLoginPacket} with a username and optional player key. - * - * @param username the player's username - * @param playerKey the player's cryptographic key, or {@code null} if not present - */ public ServerLoginPacket(String username, @Nullable IdentifiedKey playerKey) { this.username = Preconditions.checkNotNull(username, "username"); this.playerKey = playerKey; } - /** - * Constructs a new {@code ServerLoginPacket} with the specified username and holder UUID. - * - * @param username the player's username - * @param holderUuid the holder UUID (optional) - */ public ServerLoginPacket(String username, @Nullable UUID holderUuid) { this.username = Preconditions.checkNotNull(username, "username"); this.holderUuid = holderUuid; this.playerKey = null; } - /** - * Gets the player's username from the login packet. - * - * @return the player's username - * @throws IllegalStateException if the username is not specified - */ public String getUsername() { if (username == null) { throw new IllegalStateException("No username found!"); @@ -97,10 +74,10 @@ public class ServerLoginPacket implements MinecraftPacket { @Override public String toString() { return "ServerLogin{" - + "username='" + username + '\'' - + "playerKey='" + playerKey + '\'' - + "holderUUID='" + holderUuid + '\'' - + '}'; + + "username='" + username + '\'' + + "playerKey='" + playerKey + '\'' + + "holderUUID='" + holderUuid + '\'' + + '}'; } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java index 86893cc0..322cd9b1 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerLoginSuccessPacket.java @@ -30,10 +30,6 @@ import java.util.List; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents the packet sent from the server to the client to indicate successful login. - * This packet contains the player's UUID, username, and properties associated with their profile. - */ public class ServerLoginSuccessPacket implements MinecraftPacket { private @Nullable UUID uuid; @@ -42,12 +38,6 @@ public class ServerLoginSuccessPacket implements MinecraftPacket { private static final boolean strictErrorHandling = VelocityProperties .readBoolean("velocity.strictErrorHandling", true); - /** - * Gets the player's UUID from the login success packet. - * - * @return the player's UUID - * @throws IllegalStateException if the UUID is not specified - */ public UUID getUuid() { if (uuid == null) { throw new IllegalStateException("No UUID specified!"); @@ -59,12 +49,6 @@ public class ServerLoginSuccessPacket implements MinecraftPacket { this.uuid = uuid; } - /** - * Gets the player's username from the login success packet. - * - * @return the player's username - * @throws IllegalStateException if the username is not specified - */ public String getUsername() { if (username == null) { throw new IllegalStateException("No username specified!"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java index 2191ae09..bee12b80 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java @@ -26,11 +26,6 @@ import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a server-bound packet sent by the client containing a key and an optional payload. - * This packet is typically used for exchanging metadata or other information between the client - * and server. - */ public class ServerboundCookieResponsePacket implements MinecraftPacket { private Key key; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java index 9b5665fc..6b846c23 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java @@ -25,12 +25,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; -/** - * Represents a serverbound packet carrying an opaque custom click action payload. - * - *

        The payload is retained as-is and forwarded to the session handler without - * interpretation by the proxy.

        - */ public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder implements MinecraftPacket { public ServerboundCustomClickActionPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java index 7bba5645..6710bf85 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/SetCompressionPacket.java @@ -23,10 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet that sets the compression threshold for network communication. - * When the size of a packet exceeds the threshold, the packet will be compressed. - */ public class SetCompressionPacket implements MinecraftPacket { private int threshold; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java index 554e8793..30236704 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusPingPacket.java @@ -24,10 +24,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; -/** - * Represents a status ping packet sent by the client to the server, which is used to measure the latency - * between the client and server. - */ public class StatusPingPacket implements MinecraftPacket { private long randomId; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java index cbf901cf..870d9909 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusRequestPacket.java @@ -24,14 +24,12 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; -/** - * Represents a status request packet sent by the client to the server to request the server's status. - */ public class StatusRequestPacket implements MinecraftPacket { public static final StatusRequestPacket INSTANCE = new StatusRequestPacket(); private StatusRequestPacket() { + } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java index 08dcb3db..20fada4b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/StatusResponsePacket.java @@ -25,9 +25,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a status response packet sent from the server to the client. - */ public class StatusResponsePacket implements MinecraftPacket { private @Nullable CharSequence status; @@ -39,12 +36,6 @@ public class StatusResponsePacket implements MinecraftPacket { this.status = status; } - /** - * Gets the status message from the packet. - * - * @return the status message as a {@link String} - * @throws IllegalStateException if the status is not specified - */ public String getStatus() { if (status == null) { throw new IllegalStateException("Status is not specified"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java index 5bdbcc6b..dda4695b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteRequestPacket.java @@ -29,9 +29,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a packet sent by the client when a tab-completion request is initiated. - */ public class TabCompleteRequestPacket implements MinecraftPacket { private static final int VANILLA_MAX_TAB_COMPLETE_LEN = 2048; @@ -42,12 +39,6 @@ public class TabCompleteRequestPacket implements MinecraftPacket { private boolean hasPosition; private long position; - /** - * Gets the command string to be completed. - * - * @return the command string - * @throws IllegalStateException if the command is not set - */ public String getCommand() { if (command == null) { throw new IllegalStateException("Command is not specified"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java index dddad82f..a22fff0b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TabCompleteResponsePacket.java @@ -30,9 +30,6 @@ import java.util.ArrayList; import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents the packet used to send tab-completion suggestions to the client. - */ public class TabCompleteResponsePacket implements MinecraftPacket { private int transactionId; @@ -125,9 +122,6 @@ public class TabCompleteResponsePacket implements MinecraftPacket { return handler.handle(this); } - /** - * Represents an individual tab-completion suggestion (offer) sent to the client. - */ public static class Offer implements Comparable { private final String text; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java index 6f94c6c9..b5a74e49 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/TransferPacket.java @@ -25,9 +25,6 @@ import io.netty.buffer.ByteBuf; import java.net.InetSocketAddress; import org.jetbrains.annotations.Nullable; -/** - * Represents a packet used to transfer a player to another server. - */ public class TransferPacket implements MinecraftPacket { private String host; private int port; @@ -35,22 +32,11 @@ public class TransferPacket implements MinecraftPacket { public TransferPacket() { } - /** - * Constructs a {@code TransferPacket} with the specified host and port. - * - * @param host the hostname of the destination server - * @param port the port of the destination server - */ public TransferPacket(final String host, final int port) { this.host = host; this.port = port; } - /** - * Gets the {@link InetSocketAddress} representing the transfer address. - * - * @return the {@code InetSocketAddress}, or {@code null} if the host is not set - */ @Nullable public InetSocketAddress address() { if (host == null) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java index b86b8bd1..9ef40ef0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/UpsertPlayerInfoPacket.java @@ -34,9 +34,6 @@ import java.util.List; import java.util.UUID; import org.jetbrains.annotations.Nullable; -/** - * Represents the packet for updating or inserting player information. - */ public class UpsertPlayerInfoPacket implements MinecraftPacket { private static final Action[] ALL_ACTIONS = Action.class.getEnumConstants(); @@ -136,9 +133,6 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket { return handler.handle(this); } - /** - * Represents the possible actions in the player info packet. - */ public enum Action { ADD_PLAYER((ignored, buf, info) -> { // read info.profile = new GameProfile( @@ -219,9 +213,6 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket { } } - /** - * Represents an entry in the player info packet. - */ public static class Entry { private final UUID profileId; @@ -312,16 +303,16 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket { @Override public String toString() { - return "Entry{" - + "profileId=" + profileId - + ", profile=" + profile - + ", listed=" + listed - + ", latency=" + latency - + ", gameMode=" + gameMode - + ", displayName=" + displayName - + ", listOrder=" + listOrder - + ", chatSession=" + chatSession - + '}'; + return "Entry{" + + "profileId=" + profileId + + ", profile=" + profile + + ", listed=" + listed + + ", latency=" + latency + + ", gameMode=" + gameMode + + ", displayName=" + displayName + + ", listOrder=" + listOrder + + ", chatSession=" + chatSession + + '}'; } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java index fe43f5d0..6441f6f7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentIdentifier.java @@ -24,14 +24,6 @@ import java.util.HashMap; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents an identifier for a Brigadier command argument, mapping the argument to - * different protocol versions. - * - *

        The {@code ArgumentIdentifier} is responsible for holding an identifier string for - * an argument and a map that associates protocol versions with their respective IDs. - * It ensures that the protocol version is compatible with the Minecraft 1.19 protocol or later.

        - */ public class ArgumentIdentifier { private final String identifier; @@ -45,8 +37,8 @@ public class ArgumentIdentifier { Map temp = new HashMap<>(); ProtocolVersion previous = null; - for (VersionSet version : versions) { - VersionSet current = Preconditions.checkNotNull(version); + for (int i = 0; i < versions.length; i++) { + VersionSet current = Preconditions.checkNotNull(versions[i]); Preconditions.checkArgument( current.getVersion().noLessThan(ProtocolVersion.MINECRAFT_1_19), @@ -68,9 +60,9 @@ public class ArgumentIdentifier { @Override public String toString() { - return "ArgumentIdentifier{" - + "identifier='" + identifier + '\'' - + '}'; + return "ArgumentIdentifier{" + + "identifier='" + identifier + '\'' + + '}'; } public String getIdentifier() { @@ -109,6 +101,7 @@ public class ArgumentIdentifier { public ProtocolVersion getVersion() { return version; } + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java index ba7ab86b..203ab375 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertyRegistry.java @@ -45,18 +45,11 @@ import com.mojang.brigadier.arguments.StringArgumentType; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -import java.util.HashMap; -import java.util.Map; import org.jetbrains.annotations.NotNull; -/** - * The {@code ArgumentPropertyRegistry} is responsible for managing the registration and - * retrieval of argument properties used in command parsing and execution. - * - *

        This class functions as a registry, allowing different argument properties to be registered - * and later retrieved or used when processing commands within the system. The properties - * might be tied to argument types, validation rules, or transformations.

        - */ +import java.util.HashMap; +import java.util.Map; + public class ArgumentPropertyRegistry { private ArgumentPropertyRegistry() { @@ -152,6 +145,7 @@ public class ArgumentPropertyRegistry { } else { ProtocolUtils.writeString(buf, identifier.getIdentifier()); } + } /** @@ -278,7 +272,7 @@ public class ArgumentPropertyRegistry { empty(id("minecraft:heightmap", mapSet(MINECRAFT_1_21_6, 51), mapSet(MINECRAFT_1_21_5, 50), mapSet(MINECRAFT_1_20_3, 49), mapSet(MINECRAFT_1_19_4, 47))); // 1.19.4 - empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54), mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48), + empty(id("minecraft:uuid", mapSet(MINECRAFT_1_21_6, 56), mapSet(MINECRAFT_1_21_5, 54),mapSet(MINECRAFT_1_20_5, 53), mapSet(MINECRAFT_1_20_3, 48), mapSet(MINECRAFT_1_19_4, 48), mapSet(MINECRAFT_1_19, 47))); // added in 1.16 empty(id("minecraft:loot_table", mapSet(MINECRAFT_1_21_6, 52), mapSet(MINECRAFT_1_21_5, 51), mapSet(MINECRAFT_1_20_5, 50))); @@ -293,4 +287,4 @@ public class ArgumentPropertyRegistry { empty(id("minecraft:nbt")); // No longer in 1.19+ } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java index 3649fec1..25dcfd76 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ArgumentPropertySerializer.java @@ -21,16 +21,6 @@ import com.velocitypowered.api.network.ProtocolVersion; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * The {@code ArgumentPropertySerializer} interface defines a contract for serializing and - * deserializing argument properties to and from a specific format. - * - *

        This interface allows implementations to convert argument properties into a serialized form, - * which can later be deserialized and restored to their original form. This is particularly useful - * for persisting command argument configurations or sending them across a network.

        - * - * @param the type of the argument property being serialized - */ public interface ArgumentPropertySerializer { @Nullable T deserialize(ByteBuf buf, ProtocolVersion protocolVersion); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java index 950f3784..15416f86 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/ModArgumentProperty.java @@ -28,17 +28,6 @@ import io.netty.buffer.Unpooled; import java.util.Collection; import java.util.concurrent.CompletableFuture; -/** - * Represents a mod-specific argument type with custom binary data attached. - * - *

        This class allows external mods or extensions to define their own command argument - * types, identified by a namespaced {@link ArgumentIdentifier} and accompanied by - * serialized {@link ByteBuf} data.

        - * - *

        Note: This type is not parseable or suggestible through Brigadier and exists primarily - * to preserve compatibility with extended command metadata during serialization and - * deserialization.

        - */ public class ModArgumentProperty implements ArgumentType { private final ArgumentIdentifier identifier; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java index eff680c4..5e8e1daf 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryIdArgumentSerializer.java @@ -21,16 +21,6 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * The {@code RegistryIdArgumentSerializer} handles serialization and deserialization - * of integer-based registry ID arguments. - * - *

        This serializer is used for command arguments that refer to elements in Minecraft - * registries (e.g., items, entities, dimensions) by their numerical registry ID.

        - * - *

        Values are encoded as variable-length integers using {@link ProtocolUtils} - * for compact transmission.

        - */ public class RegistryIdArgumentSerializer implements ArgumentPropertySerializer { static final RegistryIdArgumentSerializer REGISTRY_ID = new RegistryIdArgumentSerializer(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java index 1c554e21..6d55b246 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgument.java @@ -28,15 +28,6 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.CompletableFuture; -/** - * Represents a Brigadier {@link ArgumentType} for registry keys, which are typically - * namespaced resource locations (e.g., {@code minecraft:diamond_sword}). - * - *

        This argument type reads an unquoted string from input and treats it as a raw registry - * key. It does not validate the format or resolve the key against a known registry.

        - * - *

        Examples include simple strings, namespaced keys, or numeric-like identifiers.

        - */ public class RegistryKeyArgument implements ArgumentType { private static final List EXAMPLES = Arrays.asList("foo", "foo:bar", "012"); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java index 86fe95f1..2bf5f345 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentList.java @@ -21,25 +21,14 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a list of {@link RegistryKeyArgument} objects. - * - *

        Used to manage and store multiple registry key arguments.

        - */ public final class RegistryKeyArgumentList { - /** - * Represents a registry key argument that can either be a resource or a tag. - */ public static class ResourceOrTag extends RegistryKeyArgument { public ResourceOrTag(String identifier) { super(identifier); } - /** - * Serializer for {@link ResourceOrTag}. - */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceOrTag.Serializer REGISTRY = new ResourceOrTag.Serializer(); @@ -56,18 +45,12 @@ public final class RegistryKeyArgumentList { } } - /** - * Represents a registry key argument specifically for a resource or tag key. - */ public static class ResourceOrTagKey extends RegistryKeyArgument { public ResourceOrTagKey(String identifier) { super(identifier); } - /** - * Serializer for {@link ResourceOrTagKey}. - */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceOrTagKey.Serializer REGISTRY = new ResourceOrTagKey.Serializer(); @@ -84,18 +67,12 @@ public final class RegistryKeyArgumentList { } } - /** - * Represents a registry key argument for a resource. - */ public static class ResourceSelector extends RegistryKeyArgument { public ResourceSelector(String identifier) { super(identifier); } - /** - * Serializer for {@link ResourceSelector}. - */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceSelector.Serializer REGISTRY = new ResourceSelector.Serializer(); @@ -112,18 +89,12 @@ public final class RegistryKeyArgumentList { } } - /** - * Represents a registry key argument for a resource key. - */ public static class ResourceKey extends RegistryKeyArgument { public ResourceKey(String identifier) { super(identifier); } - /** - * Serializer for {@link ResourceKey}. - */ public static class Serializer implements ArgumentPropertySerializer { static final ResourceKey.Serializer REGISTRY = new ResourceKey.Serializer(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java index e2562c85..6ada6157 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/RegistryKeyArgumentSerializer.java @@ -21,12 +21,6 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Serializer for {@link RegistryKeyArgument} objects. - * - *

        This class handles the serialization and deserialization of {@code RegistryKeyArgument} - * objects to and from a {@link ByteBuf} using the specified {@link ProtocolVersion}.

        - */ public class RegistryKeyArgumentSerializer implements ArgumentPropertySerializer { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java index 5e4d9ced..b026e8cc 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/brigadier/TimeArgumentSerializer.java @@ -20,12 +20,6 @@ package com.velocitypowered.proxy.protocol.packet.brigadier; import com.velocitypowered.api.network.ProtocolVersion; import io.netty.buffer.ByteBuf; -/** - * Serializer for time-based arguments represented as {@link Integer}. - * - *

        This class handles the serialization and deserialization of time-related arguments, - * converting them to and from an {@link Integer} format.

        - */ public class TimeArgumentSerializer implements ArgumentPropertySerializer { static final TimeArgumentSerializer TIME = new TimeArgumentSerializer(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java index c27c7199..b0718090 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatAcknowledgementPacket.java @@ -23,44 +23,39 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet sent to acknowledge the receipt of a chat message. - * This packet is used to confirm that a player or client has received and processed - * a chat message from the server. - */ public class ChatAcknowledgementPacket implements MinecraftPacket { - int offset; + int offset; - public ChatAcknowledgementPacket(int offset) { - this.offset = offset; - } + public ChatAcknowledgementPacket(int offset) { + this.offset = offset; + } - public ChatAcknowledgementPacket() { - } + public ChatAcknowledgementPacket() { + } - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - offset = ProtocolUtils.readVarInt(buf); - } + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + offset = ProtocolUtils.readVarInt(buf); + } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, offset); - } + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, offset); + } - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } - @Override - public String toString() { - return "ChatAcknowledgement{" - + "offset=" + offset - + '}'; - } + @Override + public String toString() { + return "ChatAcknowledgement{" + + "offset=" + offset + + '}'; + } - public int offset() { - return offset; - } + public int offset() { + return offset; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java index af67506b..0cd2f44a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatHandler.java @@ -19,28 +19,12 @@ package com.velocitypowered.proxy.protocol.packet.chat; import com.velocitypowered.proxy.protocol.MinecraftPacket; -/** - * Represents a handler for processing chat-related packets in the game. - * This interface is generic and can handle different types of Minecraft packets that - * extend {@link MinecraftPacket}. - * - * @param the type of packet that this chat handler processes, which must - * extend {@link MinecraftPacket} - */ public interface ChatHandler { Class packetClass(); void handlePlayerChatInternal(T packet); - /** - * Handles a player chat event represented by the given {@link MinecraftPacket}. - * This default method provides a basic mechanism for processing chat-related packets that - * involve player messages. - * - * @param packet the {@link MinecraftPacket} representing the player chat event to handle - * @return {@code true} if the chat event was successfully handled, {@code false} otherwise - */ default boolean handlePlayerChat(MinecraftPacket packet) { if (packetClass().isInstance(packet)) { handlePlayerChatInternal(packetClass().cast(packet)); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java index 0869ab99..14a56336 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatQueue.java @@ -21,12 +21,12 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import io.netty.channel.ChannelFuture; +import org.checkerframework.checker.nullness.qual.Nullable; import java.time.Instant; import java.util.BitSet; import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; -import org.checkerframework.checker.nullness.qual.Nullable; /** * A precisely ordered queue which allows for outside entries into the ordered queue through @@ -79,8 +79,7 @@ public class ChatQueue implements AutoCloseable { * @param timestamp the new {@link Instant} timestamp of this packet to update the internal chat state. * @param lastSeenMessages the new {@link LastSeenMessages} last seen messages to update the internal chat state. */ - public void queuePacket(Function> nextPacket, @Nullable Instant timestamp, - @Nullable LastSeenMessages lastSeenMessages) { + public void queuePacket(Function> nextPacket, @Nullable Instant timestamp, @Nullable LastSeenMessages lastSeenMessages) { queueTask((chatState, smc) -> { LastSeenMessages newLastSeenMessages = chatState.updateFromMessage(timestamp, lastSeenMessages); return nextPacket.apply(newLastSeenMessages).thenCompose(packet -> writePacket(packet, smc)); @@ -101,12 +100,6 @@ public class ChatQueue implements AutoCloseable { }); } - /** - * Handles the acknowledgement of a chat message or event by processing the given offset. - * This method is typically called when a chat message or command is acknowledged by the client or server. - * - * @param offset the offset representing the specific message or event being acknowledged - */ public void handleAcknowledgement(int offset) { queueTask((chatState, smc) -> { int ackCountToForward = chatState.accumulateAckCount(offset); @@ -145,16 +138,16 @@ public class ChatQueue implements AutoCloseable { *
      • If we last forwarded a chat or command packet from the client, we have a known 'last seen' that we can * reuse.
      • *
      • If we last forwarded a {@link ChatAcknowledgementPacket}, the previous 'last seen' cannot be reused. We - * cannot predict an up to date 'last seen', as we do not know which messages the client actually saw.
      • + * cannot predict an up-to-date 'last seen', as we do not know which messages the client actually saw. *
      • Therefore, we need to hold back any acknowledgement packets so that we can continue to reuse the last valid * 'last seen' state.
      • *
      • However, there is a limit to the number of messages that can remain unacknowledged on the server.
      • *
      • To address this, we know that if the client has moved its 'last seen' window far enough, we can fill in the - * gap with stub 'last seen', and it will never be checked.
      • + * gap with dummy 'last seen', and it will never be checked. *
      * - *

      Note that this is effectively unused for 1.20.5+ clients, as commands without any signature do not send 'last seen' - * updates.

      + * Note that this is effectively unused for 1.20.5+ clients, as commands without any signature do not send 'last seen' + * updates. */ public static class ChatState { private static final int MINIMUM_DELAYED_ACK_COUNT = LastSeenMessages.WINDOW_SIZE; @@ -167,17 +160,6 @@ public class ChatQueue implements AutoCloseable { private ChatState() { } - /** - * Updates the state of the {@link LastSeenMessages} and the timestamp based on a new message or event. - * This method processes the given timestamp and last seen messages to ensure the internal state is up to date. - * - If the provided {@link Instant} is not null, it updates the last known timestamp. - * - If the provided {@link LastSeenMessages} is not null, it flushes any delayed acknowledgements and updates the - * internal acknowledged messages, returning an adjusted {@link LastSeenMessages} with the offset applied. - * - * @param timestamp the optional {@link Instant} representing the new timestamp for the message or event - * @param lastSeenMessages the optional {@link LastSeenMessages} representing the last seen messages by the player - * @return the updated {@link LastSeenMessages} with the applied offset, or {@code null} if no updates were made - */ @Nullable public LastSeenMessages updateFromMessage(@Nullable Instant timestamp, @Nullable LastSeenMessages lastSeenMessages) { if (timestamp != null) { @@ -192,16 +174,6 @@ public class ChatQueue implements AutoCloseable { return null; } - /** - * Accumulates the given acknowledgement count and determines if enough acknowledgements have been gathered to forward. - * - Adds the provided `ackCount` to the current delayed acknowledgement count. - * - If the accumulated acknowledgements exceed the {@link LastSeenMessages#WINDOW_SIZE}, the method resets the delayed - * acknowledgement count and returns the number of acknowledgements that should be forwarded. - * - If the threshold is not met, the method returns 0, indicating that no acknowledgements need to be forwarded yet. - * - * @param ackCount the number of acknowledgements to add to the accumulated count - * @return the number of acknowledgements that should be forwarded, or 0 if the threshold has not been reached - */ public int accumulateAckCount(int ackCount) { int delayedAckCount = this.delayedAckCount.addAndGet(ackCount); int ackCountToForward = delayedAckCount - MINIMUM_DELAYED_ACK_COUNT; @@ -214,11 +186,6 @@ public class ChatQueue implements AutoCloseable { return 0; } - /** - * Creates a snapshot of the current {@link LastSeenMessages} state. - * - * @return a new {@link LastSeenMessages} representing the current view - */ public LastSeenMessages createLastSeen() { return new LastSeenMessages(0, lastSeenMessages, (byte) 0); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java index 9409a86f..94fc5356 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatTimeKeeper.java @@ -19,11 +19,6 @@ package com.velocitypowered.proxy.protocol.packet.chat; import java.time.Instant; -/** - * Manages the timing and duration of chat messages within the game. - * The {@code ChatTimeKeeper} class tracks when chat messages are sent and provides mechanisms - * to determine how long a message has been displayed or to manage message expiration. - */ public class ChatTimeKeeper { private Instant lastTimestamp; @@ -32,18 +27,6 @@ public class ChatTimeKeeper { this.lastTimestamp = Instant.MIN; } - /** - * Updates the internal timestamp of the chat message or session. - * This method checks if the provided {@link Instant} is before the current stored timestamp. - * If it is, the internal timestamp is updated, and the method returns {@code false} to - * indicate that the update was not successful. - * If the provided {@link Instant} is valid, the timestamp is updated, - * and the method may return {@code true}. - * - * @param instant the {@link Instant} representing the new timestamp to update - * @return {@code true} if the timestamp was successfully updated, {@code false} - * if the provided instant is before the current timestamp - */ public boolean update(Instant instant) { if (instant.isBefore(this.lastTimestamp)) { this.lastTimestamp = instant; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java index 04706615..66e4e988 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ChatType.java @@ -17,12 +17,6 @@ package com.velocitypowered.proxy.protocol.packet.chat; -/** - * Represents different types of chat messages in the game, defining how a message should be - * handled and displayed. - * This enum categorizes various chat message types such as system messages, player chat, - * or game info. - */ public enum ChatType { CHAT((byte) 0), SYSTEM((byte) 1), @@ -37,4 +31,4 @@ public enum ChatType { public byte getId() { return raw; } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java index 31cd85c3..8e39d78a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/CommandHandler.java @@ -31,14 +31,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a handler for processing commands associated with specific types of Minecraft packets. - * This interface is generic and allows for handling different packet types that extend - * {@link MinecraftPacket}. - * - * @param the type of packet that this handler is responsible for, which - * must extend {@link MinecraftPacket} - */ public interface CommandHandler { Logger logger = LogManager.getLogger(CommandHandler.class); @@ -47,14 +39,6 @@ public interface CommandHandler { void handlePlayerCommandInternal(T packet); - /** - * Handles a player command associated with a given {@link MinecraftPacket}. - * This default method provides a mechanism for processing commands related to player - * actions within the game. - * - * @param packet the {@link MinecraftPacket} representing the player command to be handled - * @return {@code true} if the command was successfully handled, {@code false} otherwise - */ default boolean handlePlayerCommand(MinecraftPacket packet) { if (packetClass().isInstance(packet)) { handlePlayerCommandInternal(packetClass().cast(packet)); @@ -70,45 +54,25 @@ public interface CommandHandler { .thenApply(hasRunPacketFunction); } - /** - * Queues the result of a player command for execution, managing the future result of the command. - * This method is designed to interact with the {@link VelocityServer} - * and {@link ConnectedPlayer} to - * handle the process of command execution, queuing, and response handling. - * - * @param server the {@link VelocityServer} instance responsible for managing the - * command execution - * @param player the {@link ConnectedPlayer} who initiated the command - * @param futurePacketCreator a {@link BiFunction} that creates a future packet based on - * the {@link CommandExecuteEvent} - * and {@link LastSeenMessages}, which will be used for sending - * a command result - * @param message the command message that the player sent - * @param timestamp the {@link Instant} when the command was executed - * @param lastSeenMessages the {@link LastSeenMessages} object containing the messages last - * seen by the player, - * or {@code null} if not applicable - * @param invocationInfo signing metadata for the event dispatch - */ default void queueCommandResult(VelocityServer server, ConnectedPlayer player, BiFunction> futurePacketCreator, String message, Instant timestamp, @Nullable LastSeenMessages lastSeenMessages, CommandExecuteEvent.InvocationInfo invocationInfo) { - CompletableFuture eventFuture = server.getCommandManager().callCommandEvent(player, message, - invocationInfo); - player.getChatQueue().queuePacket( + CompletableFuture eventFuture = server.getCommandManager().callCommandEvent(player, message, + invocationInfo); + player.getChatQueue().queuePacket( newLastSeenMessages -> eventFuture - .thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages)) - .thenApply(pkt -> { - if (server.getConfiguration().isLogCommandExecutions()) { - logger.info("{} -> executed command /{}", player, message); - } - return pkt; - }).exceptionally(e -> { - logger.info("Exception occurred while running command for {}", player.getUsername(), e); - player.sendMessage( - Component.translatable("velocity.command.generic-error", NamedTextColor.RED)); - return null; - }), timestamp, lastSeenMessages); + .thenComposeAsync(event -> futurePacketCreator.apply(event, newLastSeenMessages)) + .thenApply(pkt -> { + if (server.getConfiguration().isLogCommandExecutions()) { + logger.info("{} -> executed command /{}", player, message); + } + return pkt; + }).exceptionally(e -> { + logger.info("Exception occurred while running command for {}", player.getUsername(), e); + player.sendMessage( + Component.translatable("velocity.command.generic-error", NamedTextColor.RED)); + return null; + }), timestamp, lastSeenMessages); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java index 087756e1..0b003326 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/ComponentHolder.java @@ -25,9 +25,6 @@ import com.google.gson.internal.LazilyParsedNumber; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import net.kyori.adventure.nbt.BinaryTag; import net.kyori.adventure.nbt.BinaryTagIO; import net.kyori.adventure.nbt.BinaryTagType; @@ -50,12 +47,10 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -/** - * Represents a holder for components used in chat or other text-based data in the Minecraft - * protocol. - * This class supports various formats including JSON and NBT (Named Binary Tag) for storing and - * transmitting text components. - */ +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + public class ComponentHolder { private static final Logger logger = LogManager.getLogger(ComponentHolder.class); public static final int DEFAULT_MAX_STRING_SIZE = 262143; @@ -80,14 +75,6 @@ public class ComponentHolder { this.binaryTag = binaryTag; } - /** - * Retrieves the {@link Component} stored in this {@link ComponentHolder}. - * If the component is not yet initialized, it will attempt to deserialize it from either - * the JSON or NBT representation, depending on which is available. - * - * @return the {@link Component} stored in this holder - * @throws IllegalStateException if both the JSON and binary representations fail to deserialize - */ public Component getComponent() { if (component == null) { if (json != null) { @@ -108,13 +95,6 @@ public class ComponentHolder { return component; } - /** - * Retrieves the JSON representation of the {@link Component} stored in this - * {@link ComponentHolder}. - * If the JSON string is not yet initialized, it will serialize the component into a JSON string. - * - * @return the JSON string representing the {@link Component} - */ public String getJson() { if (json == null) { json = ProtocolUtils.getJsonChatSerializer(version).serialize(getComponent()); @@ -122,14 +102,6 @@ public class ComponentHolder { return json; } - /** - * Retrieves the NBT (Named Binary Tag) representation of the {@link Component} stored in this - * {@link ComponentHolder}. - * If the NBT tag is not yet initialized, it will serialize the component into an NBT - * representation. - * - * @return the {@link BinaryTag} representing the {@link Component} - */ public BinaryTag getBinaryTag() { if (binaryTag == null) { // TODO: replace this with adventure-text-serializer-nbt @@ -138,16 +110,6 @@ public class ComponentHolder { return binaryTag; } - /** - * Serializes a {@link JsonElement} into a {@link BinaryTag} format. - * This method converts JSON primitives (numbers, strings, booleans) and complex structures - * (arrays, objects) - * into their corresponding NBT representations. - * - * @param json the {@link JsonElement} to be serialized into a {@link BinaryTag} - * @return the {@link BinaryTag} representing the serialized JSON element - * @throws IllegalArgumentException if the JSON element is of an unsupported or unknown type - */ public static BinaryTag serialize(JsonElement json) { if (json instanceof JsonPrimitive jsonPrimitive) { if (jsonPrimitive.isNumber()) { @@ -200,40 +162,36 @@ public class ComponentHolder { } switch (listType.id()) { - case 1 -> { // BinaryTagTypes.BYTE: + case 1://BinaryTagTypes.BYTE: byte[] bytes = new byte[jsonArray.size()]; for (int i = 0; i < bytes.length; i++) { bytes[i] = jsonArray.get(i).getAsNumber().byteValue(); } return ByteArrayBinaryTag.byteArrayBinaryTag(bytes); - } - case 3 -> { // BinaryTagTypes.INT: + case 3://BinaryTagTypes.INT: int[] ints = new int[jsonArray.size()]; for (int i = 0; i < ints.length; i++) { ints[i] = jsonArray.get(i).getAsNumber().intValue(); } return IntArrayBinaryTag.intArrayBinaryTag(ints); - } - case 4 -> { // BinaryTagTypes.LONG: + case 4://BinaryTagTypes.LONG: long[] longs = new long[jsonArray.size()]; for (int i = 0; i < longs.length; i++) { longs[i] = jsonArray.get(i).getAsNumber().longValue(); } return LongArrayBinaryTag.longArrayBinaryTag(longs); - } - case 10 -> // BinaryTagTypes.COMPOUND: - tagItems.replaceAll(tag -> { - if (tag.type() == BinaryTagTypes.COMPOUND) { - return tag; - } else { - return CompoundBinaryTag.builder().put("", tag).build(); - } - }); - default -> { - } + case 10://BinaryTagTypes.COMPOUND: + tagItems.replaceAll(tag -> { + if (tag.type() == BinaryTagTypes.COMPOUND) { + return tag; + } else { + return CompoundBinaryTag.builder().put("", tag).build(); + } + }); + break; } return ListBinaryTag.listBinaryTag(listType, tagItems); @@ -242,30 +200,21 @@ public class ComponentHolder { return EndBinaryTag.endBinaryTag(); } - /** - * Deserializes a {@link BinaryTag} into a {@link JsonElement}. - * This method converts NBT (Named Binary Tag) data into its corresponding JSON representation, - * including handling of primitive types, arrays, and compound structures. - * - * @param tag the {@link BinaryTag} to be deserialized into a {@link JsonElement} - * @return the {@link JsonElement} representing the deserialized NBT data - * @throws IllegalArgumentException if the NBT tag type is unsupported or unknown - */ public static JsonElement deserialize(BinaryTag tag) { return switch (tag.type().id()) { - // BinaryTagTypes.BYTE + //BinaryTagTypes.BYTE case 1 -> new JsonPrimitive(((ByteBinaryTag) tag).value()); - // BinaryTagTypes.SHORT + //BinaryTagTypes.SHORT case 2 -> new JsonPrimitive(((ShortBinaryTag) tag).value()); - // BinaryTagTypes.INT: + //BinaryTagTypes.INT: case 3 -> new JsonPrimitive(((IntBinaryTag) tag).value()); - // BinaryTagTypes.LONG: + //BinaryTagTypes.LONG: case 4 -> new JsonPrimitive(((LongBinaryTag) tag).value()); - // BinaryTagTypes.FLOAT: + //BinaryTagTypes.FLOAT: case 5 -> new JsonPrimitive(((FloatBinaryTag) tag).value()); - // BinaryTagTypes.DOUBLE: + //BinaryTagTypes.DOUBLE: case 6 -> new JsonPrimitive(((DoubleBinaryTag) tag).value()); - // BinaryTagTypes.BYTE_ARRAY: + //BinaryTagTypes.BYTE_ARRAY: case 7 -> { byte[] byteArray = ((ByteArrayBinaryTag) tag).value(); @@ -276,9 +225,9 @@ public class ComponentHolder { yield jsonByteArray; } - // BinaryTagTypes.STRING: + //BinaryTagTypes.STRING: case 8 -> new JsonPrimitive(((StringBinaryTag) tag).value()); - // BinaryTagTypes.LIST: + //BinaryTagTypes.LIST: case 9 -> { ListBinaryTag items = (ListBinaryTag) tag; JsonArray jsonList = new JsonArray(items.size()); @@ -289,7 +238,7 @@ public class ComponentHolder { yield jsonList; } - // BinaryTagTypes.COMPOUND: + //BinaryTagTypes.COMPOUND: case 10 -> { CompoundBinaryTag compound = (CompoundBinaryTag) tag; JsonObject jsonObject = new JsonObject(); @@ -305,7 +254,7 @@ public class ComponentHolder { yield jsonObject; } - // BinaryTagTypes.INT_ARRAY: + //BinaryTagTypes.INT_ARRAY: case 11 -> { int[] intArray = ((IntArrayBinaryTag) tag).value(); @@ -316,7 +265,7 @@ public class ComponentHolder { yield jsonIntArray; } - // BinaryTagTypes.LONG_ARRAY: + //BinaryTagTypes.LONG_ARRAY: case 12 -> { long[] longArray = ((LongArrayBinaryTag) tag).value(); @@ -331,19 +280,6 @@ public class ComponentHolder { }; } - /** - * Reads a {@link ComponentHolder} from the provided {@link ByteBuf} using the specified - * {@link ProtocolVersion}. - * This method deserializes a component from either its binary (NBT) or JSON representation, - * depending on the protocol version. - * - For Minecraft versions 1.20.3 and later, it reads a binary tag. - * - For Minecraft versions 1.13 and later, it reads a JSON string with a size limit. - * - For earlier versions, it reads a standard JSON string. - * - * @param buf the {@link ByteBuf} containing the serialized component data - * @param version the {@link ProtocolVersion} indicating how the component should be deserialized - * @return a {@link ComponentHolder} containing the deserialized component - */ public static ComponentHolder read(ByteBuf buf, ProtocolVersion version) { if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) { return new ComponentHolder(version, @@ -355,15 +291,6 @@ public class ComponentHolder { } } - /** - * Writes the {@link ComponentHolder}'s data to the provided {@link ByteBuf}. - * This method serializes the component into either its binary (NBT) or JSON representation - * based on the protocol version. - * - For Minecraft versions 1.20.3 and later, it writes the component as a binary tag (NBT). - * - For earlier versions, it writes the component as a JSON string. - * - * @param buf the {@link ByteBuf} where the component data will be written - */ public void write(ByteBuf buf) { if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) { ProtocolUtils.writeBinaryTag(buf, version, getBinaryTag()); @@ -371,4 +298,4 @@ public class ComponentHolder { ProtocolUtils.writeString(buf, getJson()); } } -} +} \ No newline at end of file diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java index 8f41a6c8..c03e5f8c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/LastSeenMessages.java @@ -23,10 +23,6 @@ import io.netty.buffer.ByteBuf; import java.util.Arrays; import java.util.BitSet; -/** - * Represents a collection of the last seen messages by a player or client. - * This class tracks the recent chat messages that the player has viewed. - */ public class LastSeenMessages { public static final int WINDOW_SIZE = 20; @@ -39,26 +35,12 @@ public class LastSeenMessages { this(0, new BitSet(), (byte) 0); } - /** - * Creates a new {@link LastSeenMessages} instance with the specified offset, acknowledged messages, and checksum. - * - * @param offset the starting index of the message window - * @param acknowledged a BitSet representing which messages have been acknowledged - * @param checksum the checksum for the message window data - */ public LastSeenMessages(int offset, BitSet acknowledged, byte checksum) { this.offset = offset; this.acknowledged = acknowledged; this.checksum = checksum; } - /** - * Constructs a new {@link LastSeenMessages} instance by decoding data from the provided - * {@link ByteBuf}. - * - * @param buf the buffer containing the serialized last seen messages data - * @param protocolVersion the protocol version (determines if checksum is written) - */ public LastSeenMessages(ByteBuf buf, ProtocolVersion protocolVersion) { this.offset = ProtocolUtils.readVarInt(buf); @@ -71,12 +53,6 @@ public class LastSeenMessages { } } - /** - * Encodes this {@link LastSeenMessages} instance into the provided {@link ByteBuf}. - * - * @param buf the buffer to write the data to - * @param protocolVersion the protocol version used for encoding - */ public void encode(ByteBuf buf, ProtocolVersion protocolVersion) { ProtocolUtils.writeVarInt(buf, offset); buf.writeBytes(Arrays.copyOf(acknowledged.toByteArray(), DIV_FLOOR)); @@ -99,10 +75,10 @@ public class LastSeenMessages { @Override public String toString() { - return "LastSeenMessages{" - + "offset=" + offset - + ", acknowledged=" + acknowledged - + ", checksum=" + checksum - + '}'; + return "LastSeenMessages{" + + "offset=" + offset + + ", acknowledged=" + acknowledged + + ", checksum=" + checksum + + '}'; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java index 41b6f6cb..d07b798a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/PlayerChatCompletionPacket.java @@ -23,11 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet sent between the server and client to handle chat completion suggestions. - * This packet allows the server to send chat message completions or suggestions to the client, - * helping users complete commands or chat messages. - */ public class PlayerChatCompletionPacket implements MinecraftPacket { private String[] completions; @@ -76,9 +71,6 @@ public class PlayerChatCompletionPacket implements MinecraftPacket { return handler.handle(this); } - /** - * Represents the different actions that can be taken with chat completions. - */ public enum Action { ADD, REMOVE, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java index 4bddf35f..e5823643 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RateLimitedCommandHandler.java @@ -22,46 +22,37 @@ import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import net.kyori.adventure.text.Component; -/** - * Abstract base class for handling rate-limited player command packets. - * - *

      Subclasses should implement {@link #handlePlayerCommandInternal(MinecraftPacket)} to define - * how individual command packets are processed. Rate limiting is enforced to prevent abuse.

      - * - * @param the type of {@link MinecraftPacket} this handler processes - */ public abstract class RateLimitedCommandHandler implements CommandHandler { - private final Player player; - private final VelocityServer velocityServer; + private final Player player; + private final VelocityServer velocityServer; - private int failedAttempts; + private int failedAttempts; - protected RateLimitedCommandHandler(Player player, VelocityServer velocityServer) { - this.player = player; - this.velocityServer = velocityServer; - } - - @Override - public boolean handlePlayerCommand(MinecraftPacket packet) { - if (packetClass().isInstance(packet)) { - if (!velocityServer.getCommandRateLimiter().attempt(player.getUniqueId())) { - if (velocityServer.getConfiguration().isKickOnCommandRateLimit() - && failedAttempts++ >= velocityServer.getConfiguration().getKickAfterRateLimitedCommands()) { - player.disconnect(Component.translatable("velocity.kick.command-rate-limit")); - } - - if (velocityServer.getConfiguration().isForwardCommandsIfRateLimited()) { - return false; // Send the packet to the server - } - } else { - failedAttempts = 0; - } - - handlePlayerCommandInternal(packetClass().cast(packet)); - return true; + protected RateLimitedCommandHandler(Player player, VelocityServer velocityServer) { + this.player = player; + this.velocityServer = velocityServer; } - return false; - } + @Override + public boolean handlePlayerCommand(MinecraftPacket packet) { + if (packetClass().isInstance(packet)) { + if (!velocityServer.getCommandRateLimiter().attempt(player.getUniqueId())) { + if (velocityServer.getConfiguration().isKickOnCommandRateLimit() && failedAttempts++ >= velocityServer.getConfiguration().getKickAfterRateLimitedCommands()) { + player.disconnect(Component.translatable("velocity.kick.command-rate-limit")); + } + + if (velocityServer.getConfiguration().isForwardCommandsIfRateLimited()) { + return false; // Send the packet to the server + } + } else { + failedAttempts = 0; + } + + handlePlayerCommandInternal(packetClass().cast(packet)); + return true; + } + + return false; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java index 13421cfb..9dd5950a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/RemoteChatSession.java @@ -26,11 +26,6 @@ import java.util.Objects; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a remote chat session that implements the {@link ChatSession} interface. - * This session is used for handling chat interactions that occur remotely, typically between - * a client and server, allowing for communication and session tracking. - */ public class RemoteChatSession implements ChatSession { private final @Nullable UUID sessionId; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java index a15aac01..1a26affd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/SystemChatPacket.java @@ -23,11 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * Represents a packet sent from the server to the client to display system chat messages. - * This packet handles the communication of messages that are not player-generated, but instead - * come from the system or server itself. - */ public class SystemChatPacket implements MinecraftPacket { public SystemChatPacket() { @@ -52,7 +47,7 @@ public class SystemChatPacket implements MinecraftPacket { @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { component = ComponentHolder.read(buf, version); - if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)) { + if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_1)){ type = buf.readBoolean() ? ChatType.GAME_INFO : ChatType.SYSTEM; } else { type = ChatType.values()[ProtocolUtils.readVarInt(buf)]; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java index ac889a52..b0d2f12a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderFactory.java @@ -23,22 +23,11 @@ import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatBuilder; import com.velocitypowered.proxy.protocol.packet.chat.session.SessionChatBuilder; import java.util.function.Function; -/** - * Factory class for creating instances of chat builders. - * - *

      The {@code ChatBuilderFactory} is responsible for providing various builder instances - * used to construct chat-related components, such as messages, chat formats, or text components.

      - */ public class ChatBuilderFactory { private final ProtocolVersion version; private final Function builderFunction; - /** - * Creates a new {@code ChatBuilderFactory} for the specified protocol version. - * - * @param version the protocol version to be used by the chat builder factory - */ public ChatBuilderFactory(ProtocolVersion version) { this.version = version; if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19_3)) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java index 18cea35a..9ac02864 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/builder/ChatBuilderV2.java @@ -28,13 +28,6 @@ import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * An abstract class for building chat components in version 2 of the chat system. - * - *

      The {@code ChatBuilderV2} class provides the foundation for creating and formatting - * chat components, allowing subclasses to implement specific behaviors for constructing - * chat messages or text components.

      - */ public abstract class ChatBuilderV2 { protected final ProtocolVersion version; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java index b8cd4f79..d654c619 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatBuilder.java @@ -26,12 +26,6 @@ import com.velocitypowered.proxy.protocol.packet.chat.SystemChatPacket; import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderV2; import net.kyori.adventure.text.Component; -/** - * A concrete implementation of {@link ChatBuilderV2} that uses keys to build chat components. - * - *

      The {@code KeyedChatBuilder} class extends the functionality of {@link ChatBuilderV2} by allowing - * chat components to be built using specific keys, enabling dynamic message construction.

      - */ public class KeyedChatBuilder extends ChatBuilderV2 { public KeyedChatBuilder(ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java index edc2268b..f8fc906a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedChatHandler.java @@ -30,13 +30,6 @@ import net.kyori.adventure.text.Component; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** - * A handler for processing chat components based on specific keys. - * - *

      The {@code KeyedChatHandler} class is responsible for managing chat interactions or - * messages that keys identify. It implements the required interface or class - * to handle key-based chat processing.

      - */ public class KeyedChatHandler implements com.velocitypowered.proxy.protocol.packet.chat.ChatHandler { @@ -55,15 +48,6 @@ public class KeyedChatHandler implements return KeyedPlayerChatPacket.class; } - /** - * Logs an error and disconnects the player when a plugin attempts to cancel a signed chat message. - * - *

      This method handles the invalid behavior of canceling signed chat messages, which is no longer allowed - * starting from Minecraft version 1.19.1.

      - * - * @param logger the logger used to log the error - * @param player the player to disconnect due to the illegal action - */ public static void invalidCancel(Logger logger, ConnectedPlayer player) { logger.fatal("A plugin tried to cancel a signed chat message." + " This is no longer possible in 1.19.1 and newer. " @@ -72,15 +56,6 @@ public class KeyedChatHandler implements + "Contact your network administrator.")); } - /** - * Logs an error and disconnects the player when a plugin attempts to modify a signed chat message. - * - *

      This method handles the invalid behavior of modifying signed chat messages, which is no longer allowed - * starting from Minecraft version 1.19.1.

      - * - * @param logger the logger used to log the error - * @param player the player to disconnect due to the illegal action - */ public static void invalidChange(Logger logger, ConnectedPlayer player) { logger.fatal("A plugin tried to change a signed chat message. " + "This is no longer possible in 1.19.1 and newer. " diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java index e52f4c9a..b10332f0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedCommandHandler.java @@ -26,24 +26,11 @@ import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderV2; import java.util.concurrent.CompletableFuture; import net.kyori.adventure.text.Component; -/** - * Handles keyed player commands by implementing {@link RateLimitedCommandHandler}. - * - *

      The {@code KeyedCommandHandler} processes commands that are sent using - * {@link KeyedPlayerCommandPacket}. It provides the necessary logic for handling - * and executing commands associated with specific keys.

      - */ public class KeyedCommandHandler extends RateLimitedCommandHandler { private final ConnectedPlayer player; private final VelocityServer server; - /** - * Constructs a new {@code KeyedCommandHandler}. - * - * @param player the player sending the command - * @param server the proxy server instance - */ public KeyedCommandHandler(ConnectedPlayer player, VelocityServer server) { super(player, server); this.player = player; @@ -125,7 +112,6 @@ public class KeyedCommandHandler extends RateLimitedCommandHandlerThe {@code KeyedPlayerChatPacket} handles player chat messages, supporting signed previews, - * message signatures, and previous message validation. It includes fields for tracking message - * signatures and handling expired messages.

      - */ public class KeyedPlayerChatPacket implements MinecraftPacket { private String message; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java index 9978243f..0bb43ec8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/keyed/KeyedPlayerCommandPacket.java @@ -35,13 +35,6 @@ import java.util.List; import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a player command packet with support for keyed commands. - * - *

      The {@code KeyedPlayerCommandPacket} handles player commands sent to the server, - * allowing for command execution based on specific keys. This packet can include additional - * information such as arguments and key-based identifiers for the command.

      - */ public class KeyedPlayerCommandPacket implements MinecraftPacket { private static final int MAX_NUM_ARGUMENTS = 8; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java index f61661e2..77df43bb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatBuilder.java @@ -25,13 +25,6 @@ import java.util.UUID; import net.kyori.adventure.identity.Identity; import net.kyori.adventure.text.Component; -/** - * A concrete implementation of {@link ChatBuilderV2} for handling legacy chat formats. - * - *

      The {@code LegacyChatBuilder} is designed to support and build chat components - * using legacy chat formatting, such as the formats used in earlier versions of Minecraft. - * It extends the functionality of {@link ChatBuilderV2} to cater to older chat systems.

      - */ public class LegacyChatBuilder extends ChatBuilderV2 { public LegacyChatBuilder(ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java index 71dc842a..b7a641ca 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatHandler.java @@ -23,13 +23,6 @@ import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.packet.chat.ChatHandler; -/** - * A handler for processing legacy chat packets, implementing {@link ChatHandler}. - * - *

      The {@code LegacyChatHandler} is responsible for handling and processing chat messages - * sent using {@link LegacyChatPacket}. This class provides the necessary logic for - * processing chat data using legacy Minecraft chat formats.

      - */ public class LegacyChatHandler implements ChatHandler { private final VelocityServer server; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java index 942dc6ca..f5bb6b4f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyChatPacket.java @@ -25,13 +25,6 @@ import io.netty.buffer.ByteBuf; import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a legacy chat packet used in older versions of Minecraft. - * - *

      The {@code LegacyChatPacket} is responsible for holding and transmitting chat messages - * in the format used by legacy versions of Minecraft. It implements {@link MinecraftPacket} - * to ensure compatibility with the packet-handling system.

      - */ public class LegacyChatPacket implements MinecraftPacket { public static final byte CHAT_TYPE = (byte) 0; @@ -52,7 +45,6 @@ public class LegacyChatPacket implements MinecraftPacket { try { return Integer.parseInt(value.trim()); } catch (final NumberFormatException e) { - // Exception has been handled } } return 100; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java index 68ff4f45..4f88ee34 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/legacy/LegacyCommandHandler.java @@ -21,27 +21,15 @@ import com.velocitypowered.api.event.command.CommandExecuteEvent; import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.packet.chat.RateLimitedCommandHandler; + import java.time.Instant; import java.util.concurrent.CompletableFuture; -/** - * A handler for processing legacy commands, implementing {@link RateLimitedCommandHandler}. - * - *

      The {@code LegacyCommandHandler} processes and handles command packets that are sent - * using {@link LegacyChatPacket}. It provides the necessary logic to support legacy - * command formats and ensure compatibility with older Minecraft versions.

      - */ public class LegacyCommandHandler extends RateLimitedCommandHandler { private final ConnectedPlayer player; private final VelocityServer server; - /** - * Constructs a new {@code LegacyCommandHandler} for handling legacy command packets. - * - * @param player the connected player issuing the command - * @param server the Velocity server instance - */ public LegacyCommandHandler(ConnectedPlayer player, VelocityServer server) { super(player, server); this.player = player; @@ -76,7 +64,6 @@ public class LegacyCommandHandler extends RateLimitedCommandHandlerThe {@code SessionChatBuilder} is designed to build chat components that are specific to - * a player's session, allowing customization and context-specific formatting of chat messages - * within the current session.

      - */ public class SessionChatBuilder extends ChatBuilderV2 { public SessionChatBuilder(ProtocolVersion version) { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java index 621564a1..74b5747f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionChatHandler.java @@ -26,17 +26,11 @@ import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.packet.chat.ChatHandler; import com.velocitypowered.proxy.protocol.packet.chat.ChatQueue; -import java.util.concurrent.CompletableFuture; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -/** - * A handler for processing session-based chat packets, implementing {@link ChatHandler}. - * - *

      The {@code SessionChatHandler} processes and handles chat messages sent during a player's - * session using {@link SessionPlayerChatPacket}. It provides the logic for handling session-specific - * chat messages, ensuring the correct context and formatting within the session.

      - */ +import java.util.concurrent.CompletableFuture; + public class SessionChatHandler implements ChatHandler { private static final Logger logger = LogManager.getLogger(SessionChatHandler.class); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java index 83d10b5d..6978f8ee 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionCommandHandler.java @@ -22,29 +22,17 @@ import com.velocitypowered.proxy.VelocityServer; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.packet.chat.ChatAcknowledgementPacket; -import com.velocitypowered.proxy.protocol.packet.chat.RateLimitedCommandHandler; import java.util.concurrent.CompletableFuture; + +import com.velocitypowered.proxy.protocol.packet.chat.RateLimitedCommandHandler; import net.kyori.adventure.text.Component; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * A handler for processing session-based commands, implementing {@link RateLimitedCommandHandler}. - * - *

      The {@code SessionCommandHandler} is responsible for handling commands that are specific - * to a player's session, using {@link SessionPlayerCommandPacket}. It provides logic to - * process commands that are tied to the context of the current session.

      - */ public class SessionCommandHandler extends RateLimitedCommandHandler { private final ConnectedPlayer player; private final VelocityServer server; - /** - * Constructs a new {@link SessionCommandHandler} for the specified player and server. - * - * @param player the connected player associated with this handler - * @param server the Velocity server instance - */ public SessionCommandHandler(ConnectedPlayer player, VelocityServer server) { super(player, server); this.player = player; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java index 4a63665c..8a00452c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerChatPacket.java @@ -25,13 +25,6 @@ import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages; import io.netty.buffer.ByteBuf; import java.time.Instant; -/** - * Represents a player chat packet specific to a session, implementing {@link MinecraftPacket}. - * - *

      The {@code SessionPlayerChatPacket} handles chat messages sent by a player during a session, - * and may include session-specific context, such as timestamps, message formatting, or other - * relevant session data.

      - */ public class SessionPlayerChatPacket implements MinecraftPacket { protected String message; @@ -107,15 +100,6 @@ public class SessionPlayerChatPacket implements MinecraftPacket { return signature; } - /** - * Creates a new {@code SessionPlayerChatPacket} with the specified last-seen messages. - * - *

      This method constructs a new {@code SessionPlayerChatPacket} instance that retains the - * current packet's properties, while updating the last seen messages.

      - * - * @param lastSeenMessages the last seen messages to associate with the new packet - * @return a new {@code SessionPlayerChatPacket} with the updated last seen messages - */ public SessionPlayerChatPacket withLastSeenMessages(LastSeenMessages lastSeenMessages) { SessionPlayerChatPacket packet = new SessionPlayerChatPacket(); packet.message = message; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java index 8a7ddd0d..f4ea3a1e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/SessionPlayerCommandPacket.java @@ -26,17 +26,11 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; -import java.time.Instant; -import java.util.List; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents a packet that handles player commands in a Minecraft session. - * - *

      This packet contains information about the player's command, timestamp, - * salt, argument signatures, and last seen messages for verification and - * processing.

      - */ +import java.time.Instant; +import java.util.List; + public class SessionPlayerCommandPacket implements MinecraftPacket { protected String command; @@ -77,8 +71,7 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { } public CommandExecuteEvent.SignedState getEventSignedState() { - return !this.argumentSignatures.isEmpty() ? CommandExecuteEvent.SignedState.SIGNED_WITH_ARGS - : CommandExecuteEvent.SignedState.SIGNED_WITHOUT_ARGS; + return !this.argumentSignatures.isEmpty() ? CommandExecuteEvent.SignedState.SIGNED_WITH_ARGS : CommandExecuteEvent.SignedState.SIGNED_WITHOUT_ARGS; } @Override @@ -88,26 +81,15 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { @Override public String toString() { - return "SessionPlayerCommand{" - + "command='" + command + '\'' - + ", timeStamp=" + timeStamp - + ", salt=" + salt - + ", argumentSignatures=" + argumentSignatures - + ", lastSeenMessages=" + lastSeenMessages - + '}'; + return "SessionPlayerCommand{" + + "command='" + command + '\'' + + ", timeStamp=" + timeStamp + + ", salt=" + salt + + ", argumentSignatures=" + argumentSignatures + + ", lastSeenMessages=" + lastSeenMessages + + '}'; } - /** - * Returns a new instance of {@code SessionPlayerCommandPacket} with the specified - * {@code LastSeenMessages}. - * - *

      If {@code lastSeenMessages} is null, it creates an {@code UnsignedPlayerCommandPacket} - * instead. Otherwise, it creates a new {@code SessionPlayerCommandPacket} with the - * provided {@code lastSeenMessages}.

      - * - * @param lastSeenMessages the last seen messages to include in the packet, may be {@code null} - * @return a new instance of {@code SessionPlayerCommandPacket} or {@code UnsignedPlayerCommandPacket} - */ public SessionPlayerCommandPacket withLastSeenMessages(@Nullable LastSeenMessages lastSeenMessages) { if (lastSeenMessages == null) { UnsignedPlayerCommandPacket packet = new UnsignedPlayerCommandPacket(); @@ -123,12 +105,6 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { return packet; } - /** - * Represents a collection of argument signatures for commands. - * - *

      This class is responsible for handling the encoding and decoding of - * argument signatures associated with a player command in a Minecraft session.

      - */ public static class ArgumentSignatures { private final List entries; @@ -137,16 +113,6 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { this.entries = List.of(); } - /** - * Constructs an {@code ArgumentSignatures} instance by decoding the signatures - * from the provided {@code ByteBuf}. - * - *

      This constructor reads the argument signatures from the buffer and ensures - * that the number of signatures does not exceed the allowed limit.

      - * - * @param buf the {@code ByteBuf} to decode the argument signatures from - * @throws QuietDecoderException if the number of argument signatures exceeds the allowed limit - */ public ArgumentSignatures(ByteBuf buf) { int size = ProtocolUtils.readVarInt(buf); if (size > 8) { @@ -164,44 +130,20 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { return this.entries.isEmpty(); } - /** - * Encodes the argument signatures into the provided {@code ByteBuf}. - * - *

      This method writes the number of argument signatures and each signature's - * details into the buffer for transmission.

      - * - * @param buf the {@code ByteBuf} to encode the argument signatures into - */ public void encode(ByteBuf buf) { ProtocolUtils.writeVarInt(buf, entries.size()); for (ArgumentSignature entry : entries) { entry.encode(buf); } } - - /** - * Returns a string representation of this {@code ArgumentSignatures} instance. - * - *

      The output includes a list of individual {@link ArgumentSignature} entries - * attached to this command packet.

      - * - * @return a human-readable string describing the argument signatures - */ @Override public String toString() { - return "ArgumentSignatures{" - + "entries=" + entries - + '}'; + return "ArgumentSignatures{" + + "entries=" + entries + + '}'; } } - /** - * Represents a single argument signature associated with a command. - * - *

      This class is responsible for handling the encoding and decoding of - * individual argument signatures, which consist of a name and a signature - * (byte array).

      - */ public static class ArgumentSignature { private final String name; @@ -219,9 +161,9 @@ public class SessionPlayerCommandPacket implements MinecraftPacket { @Override public String toString() { - return "ArgumentSignature{" - + "name='" + name + '\'' - + '}'; + return "ArgumentSignature{" + + "name='" + name + '\'' + + '}'; } } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java index 1953b07f..915f0cfb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/chat/session/UnsignedPlayerCommandPacket.java @@ -24,13 +24,6 @@ import com.velocitypowered.proxy.protocol.packet.chat.LastSeenMessages; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * Represents an unsigned player command packet, extending {@link SessionPlayerCommandPacket}. - * - *

      The {@code UnsignedPlayerCommandPacket} is used to handle player commands that are not - * signed. It inherits session-specific behavior from {@link SessionPlayerCommandPacket} - * while indicating that the command is unsigned.

      - */ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket { @Override @@ -59,8 +52,8 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket { @Override public String toString() { - return "UnsignedPlayerCommandPacket{" - + "command='" + command + '\'' - + '}'; + return "UnsignedPlayerCommandPacket{" + + "command='" + command + '\'' + + '}'; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java index 50052654..79c94b64 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ActiveFeaturesPacket.java @@ -24,13 +24,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; import net.kyori.adventure.key.Key; -/** - * The {@code ActiveFeaturesPacket} class represents a packet that communicates the currently - * active features between the client and server in the Minecraft protocol. - * - *

      This packet is used to inform the client about which features are enabled or active, - * potentially based on server configurations or gameplay states.

      - */ public class ActiveFeaturesPacket implements MinecraftPacket { private Key[] activeFeatures; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java index a9b415e9..6a3618cb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java @@ -25,47 +25,43 @@ import io.netty.buffer.ByteBuf; import java.util.HashMap; import java.util.Map; -/** - * Represents a packet sent from the server to the client, containing custom report details. - * This packet carries a map of key-value pairs, where each key and value are strings. - */ public class ClientboundCustomReportDetailsPacket implements MinecraftPacket { - private Map details; + private Map details; - public ClientboundCustomReportDetailsPacket() { - } - - public ClientboundCustomReportDetailsPacket(Map details) { - this.details = details; - } - - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - int detailsCount = ProtocolUtils.readVarInt(buf); - - this.details = new HashMap<>(detailsCount); - for (int i = 0; i < detailsCount; i++) { - details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); + public ClientboundCustomReportDetailsPacket() { } - } - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, details.size()); + public ClientboundCustomReportDetailsPacket(Map details) { + this.details = details; + } - details.forEach((key, detail) -> { - ProtocolUtils.writeString(buf, key); - ProtocolUtils.writeString(buf, detail); - }); - } + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + int detailsCount = ProtocolUtils.readVarInt(buf); - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } + this.details = new HashMap<>(detailsCount); + for (int i = 0; i < detailsCount; i++) { + details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); + } + } - public Map getDetails() { - return details; - } + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, details.size()); + + details.forEach((key, detail) -> { + ProtocolUtils.writeString(buf, key); + ProtocolUtils.writeString(buf, detail); + }); + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } + + public Map getDetails() { + return details; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java index 58b531c2..d37866d8 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java @@ -18,6 +18,7 @@ package com.velocitypowered.proxy.protocol.packet.config; import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.api.util.ServerLink; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; @@ -26,78 +27,64 @@ import io.netty.buffer.ByteBuf; import java.util.ArrayList; import java.util.List; -/** - * Represents a packet sent from the server to the client, containing server-related links. - * This packet carries a list of links (e.g., URLs or other resources) associated with the server. - */ public class ClientboundServerLinksPacket implements MinecraftPacket { - private List serverLinks; + private List serverLinks; - public ClientboundServerLinksPacket() { - } - - public ClientboundServerLinksPacket(List serverLinks) { - this.serverLinks = serverLinks; - } - - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { - int linksCount = ProtocolUtils.readVarInt(buf); - - this.serverLinks = new ArrayList<>(linksCount); - for (int i = 0; i < linksCount; i++) { - serverLinks.add(ServerLink.read(buf, version)); - } - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, serverLinks.size()); - - for (ServerLink serverLink : serverLinks) { - serverLink.write(buf); - } - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } - - public List getServerLinks() { - return serverLinks; - } - - /** - * Represents a link to a server with an ID, display name, and URL. - * - *

      This record holds the server's identification number, a display name - * encapsulated in a {@code ComponentHolder}, and the server's URL as a string.

      - * - * @param id the unique identifier for the server - * @param displayName the display name of the server, represented by a {@code ComponentHolder} - * @param url the URL of the server - */ - public record ServerLink(int id, ComponentHolder displayName, String url) { - - private static ServerLink read(ByteBuf buf, ProtocolVersion version) { - if (buf.readBoolean()) { - return new ServerLink(ProtocolUtils.readVarInt(buf), null, ProtocolUtils.readString(buf)); - } else { - return new ServerLink(-1, ComponentHolder.read(buf, version), ProtocolUtils.readString(buf)); - } + public ClientboundServerLinksPacket() { } - private void write(ByteBuf buf) { - if (id >= 0) { - buf.writeBoolean(true); - ProtocolUtils.writeVarInt(buf, id); - } else { - buf.writeBoolean(false); - displayName.write(buf); - } - ProtocolUtils.writeString(buf, url); + public ClientboundServerLinksPacket(List serverLinks) { + this.serverLinks = serverLinks; + } + + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + int linksCount = ProtocolUtils.readVarInt(buf); + + this.serverLinks = new ArrayList<>(linksCount); + for (int i = 0; i < linksCount; i++) { + serverLinks.add(ServerLink.read(buf, version)); + } + } + + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, serverLinks.size()); + + for (ServerLink serverLink : serverLinks) { + serverLink.write(buf); + } + } + + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); + } + + public List getServerLinks() { + return serverLinks; + } + + public record ServerLink(int id, ComponentHolder displayName, String url) { + + private static ServerLink read(ByteBuf buf, ProtocolVersion version) { + if (buf.readBoolean()) { + return new ServerLink(ProtocolUtils.readVarInt(buf), null, ProtocolUtils.readString(buf)); + } else { + return new ServerLink(-1, ComponentHolder.read(buf, version), ProtocolUtils.readString(buf)); + } + } + + private void write(ByteBuf buf) { + if (id >= 0) { + buf.writeBoolean(true); + ProtocolUtils.writeVarInt(buf, id); + } else { + buf.writeBoolean(false); + displayName.write(buf); + } + ProtocolUtils.writeString(buf, url); + } } - } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java index 07ca9c4b..e9811f9f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java @@ -23,12 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; -/** - * A client-to-server packet indicating the player has accepted the server's - * code of conduct during the configuration stage. - * - *

      This packet has no payload and is represented as a singleton.

      - */ public class CodeOfConductAcceptPacket implements MinecraftPacket { public static final CodeOfConductAcceptPacket INSTANCE = new CodeOfConductAcceptPacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java index 37fdd926..41433307 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductPacket.java @@ -24,14 +24,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; -/** - * A server-to-client packet containing the server's code of conduct. - * - *

      This packet is sent during the configuration stage to present the - * server-defined conduct rules to the client. The client may later - * respond with a {@link CodeOfConductAcceptPacket} to indicate - * acceptance.

      - */ public class CodeOfConductPacket extends DeferredByteBufHolder implements MinecraftPacket { public CodeOfConductPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java index 5a2afea5..20d40fd4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/FinishedUpdatePacket.java @@ -23,13 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * The {@code FinishedUpdatePacket} class represents a packet that signals the completion - * of an update process between the client and server in the Minecraft protocol. - * - *

      This packet is used to indicate that the client has finished receiving and processing - * an update, ensuring that further operations can proceed.

      - */ public class FinishedUpdatePacket implements MinecraftPacket { public static final FinishedUpdatePacket INSTANCE = new FinishedUpdatePacket(); @@ -48,7 +41,7 @@ public class FinishedUpdatePacket implements MinecraftPacket { @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java index 08e90baf..b3fb0de4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java @@ -24,74 +24,55 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; -/** - * The {@code KnownPacksPacket} class represents a packet that handles the synchronization - * of known resource packs between the client and server in the Minecraft protocol. - * - *

      This packet contains a list of {@link KnownPack} instances, each representing a resource - * pack with a namespace, identifier, and version. It allows the server to inform the client - * about available resource packs.

      - */ public class KnownPacksPacket implements MinecraftPacket { - private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64); - private static final QuietDecoderException TOO_MANY_PACKS = - new QuietDecoderException("too many known packs"); + private static final int MAX_LENGTH_PACKS = Integer.getInteger("velocity.max-known-packs", 64); + private static final QuietDecoderException TOO_MANY_PACKS = + new QuietDecoderException("too many known packs"); - private KnownPack[] packs; + private KnownPack[] packs; - @Override - public void decode(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion protocolVersion) { - final int packCount = ProtocolUtils.readVarInt(buf); - if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) { - throw TOO_MANY_PACKS; + @Override + public void decode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + final int packCount = ProtocolUtils.readVarInt(buf); + if (direction == ProtocolUtils.Direction.SERVERBOUND && packCount > MAX_LENGTH_PACKS) { + throw TOO_MANY_PACKS; + } + + final KnownPack[] packs = new KnownPack[packCount]; + + for (int i = 0; i < packCount; i++) { + packs[i] = KnownPack.read(buf); + } + + this.packs = packs; } - final KnownPack[] packs = new KnownPack[packCount]; + @Override + public void encode(ByteBuf buf, ProtocolUtils.Direction direction, + ProtocolVersion protocolVersion) { + ProtocolUtils.writeVarInt(buf, packs.length); - for (int i = 0; i < packCount; i++) { - packs[i] = KnownPack.read(buf); + for (KnownPack pack : packs) { + pack.write(buf); + } } - this.packs = packs; - } - - @Override - public void encode(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, packs.length); - - for (KnownPack pack : packs) { - pack.write(buf); - } - } - - @Override - public boolean handle(MinecraftSessionHandler handler) { - return handler.handle(this); - } - - /** - * The {@code KnownPack} record represents a known resource pack with a namespace, - * identifier, and version in the Minecraft protocol. - * - *

      It encapsulates the information needed to identify a resource pack, typically used - * for managing or synchronizing resource packs between the client and server.

      - * - * @param namespace the namespace of the resource pack (e.g., "minecraft" or a mod name) - * @param id the unique identifier of the resource pack within the namespace - * @param version the version of the resource pack - */ - public record KnownPack(String namespace, String id, String version) { - private static KnownPack read(ByteBuf buf) { - return new KnownPack(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); + @Override + public boolean handle(MinecraftSessionHandler handler) { + return handler.handle(this); } - private void write(ByteBuf buf) { - ProtocolUtils.writeString(buf, namespace); - ProtocolUtils.writeString(buf, id); - ProtocolUtils.writeString(buf, version); + public record KnownPack(String namespace, String id, String version) { + private static KnownPack read(ByteBuf buf) { + return new KnownPack(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); + } + + private void write(ByteBuf buf) { + ProtocolUtils.writeString(buf, namespace); + ProtocolUtils.writeString(buf, id); + ProtocolUtils.writeString(buf, version); + } } - } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java index e7dc200e..2d9ed230 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/RegistrySyncPacket.java @@ -25,18 +25,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import io.netty.buffer.ByteBuf; -/** - * The {@code RegistrySyncPacket} class is responsible for synchronizing registry data - * between the server and client in Minecraft. - * - *

      This packet is used to ensure that the client has the same registry information as - * the server, covering aspects like blocks, items, entities, and other game elements - * that are part of Minecraft's internal registries.

      - * - *

      It extends the {@link DeferredByteBufHolder} class to handle deferred buffering - * operations for potentially large sets of registry data, which may include - * complex serialization processes.

      - */ public class RegistrySyncPacket extends DeferredByteBufHolder implements MinecraftPacket { public RegistrySyncPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java index 8820c025..d41265ce 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/StartUpdatePacket.java @@ -23,16 +23,6 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * The {@code StartUpdatePacket} class represents a packet that signals the - * start of an update process in the Minecraft protocol. - * - *

      This packet may be used to notify the client or server that a certain update - * process, such as data synchronization or gameplay changes, is about to begin.

      - * - *

      Its specific use depends on the version and context of the update, - * typically handled in the Minecraft networking layer.

      - */ public class StartUpdatePacket implements MinecraftPacket { public static final StartUpdatePacket INSTANCE = new StartUpdatePacket(); @@ -51,7 +41,7 @@ public class StartUpdatePacket implements MinecraftPacket { @Override public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { return 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java index 5e0f9777..c0cf414e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/TagsUpdatePacket.java @@ -24,17 +24,9 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; import io.netty.buffer.ByteBuf; + import java.util.Map; -/** - * The {@code TagsUpdatePacket} class represents a packet sent to update the tags - * used by the Minecraft client. Tags are used in various parts of the game to group - * blocks, items, entities, and other objects under common categories. - * - *

      This packet is typically sent to clients when they join a server or when - * the server needs to update the list of tags for the client, ensuring that - * the client has the most up-to-date tag information.

      - */ public class TagsUpdatePacket implements MinecraftPacket { private Map> tags; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java index cad00691..d5ef296a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/legacyping/LegacyMinecraftPingVersion.java @@ -17,16 +17,6 @@ package com.velocitypowered.proxy.protocol.packet.legacyping; -/** - * The {@code LegacyMinecraftPingVersion} enum represents the various protocol versions - * used by older Minecraft clients during the server ping process. - * - *

      This enum is used to distinguish between the different legacy versions of Minecraft - * that have unique ping formats, ensuring compatibility with those older clients.

      - * - *

      Each constant in this enum corresponds to a specific version of Minecraft that - * requires a legacy server ping format.

      - */ public enum LegacyMinecraftPingVersion { MINECRAFT_1_3, MINECRAFT_1_4, diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java index d8c0e8d7..8641173e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/GenericTitlePacket.java @@ -23,21 +23,8 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; -/** - * The {@code GenericTitlePacket} class serves as the base class for all title-related packets - * in Minecraft. This class provides common functionality and properties for handling title, subtitle, - * action bar, and timing-related packets. - * - *

      Subclasses of {@code GenericTitlePacket} implement specific behavior for different types of title - * packets, such as titles, subtitles, and action bars.

      - */ public abstract class GenericTitlePacket implements MinecraftPacket { - /** - * The {@code ActionType} enum represents the different actions that can be performed with a title packet. - * Each action corresponds to a specific type of title operation, such as setting a title or subtitle, - * updating timing information, or resetting and hiding titles. - */ public enum ActionType { SET_TITLE(0), SET_SUBTITLE(1), @@ -58,6 +45,7 @@ public abstract class GenericTitlePacket implements MinecraftPacket { } } + private ActionType action; protected void setAction(ActionType action) { @@ -100,9 +88,10 @@ public abstract class GenericTitlePacket implements MinecraftPacket { throw new UnsupportedOperationException("Invalid function for this TitlePacket ActionType"); } + @Override public final void decode(ByteBuf buf, ProtocolUtils.Direction direction, - ProtocolVersion version) { + ProtocolVersion version) { throw new UnsupportedOperationException(); // encode only } @@ -114,7 +103,7 @@ public abstract class GenericTitlePacket implements MinecraftPacket { * @return GenericTitlePacket instance that follows the invoker type/version */ public static GenericTitlePacket constructTitlePacket(ActionType type, ProtocolVersion version) { - GenericTitlePacket packet; + GenericTitlePacket packet = null; if (version.noLessThan(ProtocolVersion.MINECRAFT_1_17)) { packet = switch (type) { case SET_ACTION_BAR -> new TitleActionbarPacket(); @@ -122,6 +111,7 @@ public abstract class GenericTitlePacket implements MinecraftPacket { case SET_TIMES -> new TitleTimesPacket(); case SET_TITLE -> new TitleTextPacket(); case HIDE, RESET -> new TitleClearPacket(); + default -> throw new IllegalArgumentException("Invalid ActionType"); }; } else { packet = new LegacyTitlePacket(); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java index 5b5b8b0f..ebae8a9e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/LegacyTitlePacket.java @@ -24,16 +24,6 @@ import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; -/** - * The {@code LegacyTitlePacket} class represents a packet that handles title-related functionality - * for older versions of Minecraft where title handling differs. - * - *

      This packet is used to send title and subtitle information using legacy methods for clients - * that do not support the newer title packet format.

      - * - *

      It extends the {@link GenericTitlePacket}, inheriting basic title properties but is specifically - * focused on legacy title implementations.

      - */ public class LegacyTitlePacket extends GenericTitlePacket { private @Nullable ComponentHolder component; @@ -61,10 +51,10 @@ public class LegacyTitlePacket extends GenericTitlePacket { buf.writeInt(stay); buf.writeInt(fadeOut); } - case HIDE, RESET -> { - } + case HIDE, RESET -> {} default -> throw new UnsupportedOperationException("Unknown action " + getAction()); } + } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java index 5fb3c9a8..f34983ea 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleActionbarPacket.java @@ -23,16 +23,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; -/** - * The {@code TitleActionbarPacket} class represents a packet that handles the content of an action bar - * displayed to the player in Minecraft. - * - *

      This packet is used to send the text that appears in the action bar, which is a separate text line - * displayed above the hotbar on the player's screen.

      - * - *

      It extends the {@link GenericTitlePacket}, inheriting basic title properties and focusing on - * the content of the action bar.

      - */ public class TitleActionbarPacket extends GenericTitlePacket { private ComponentHolder component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java index 077ca594..1b348969 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleClearPacket.java @@ -22,15 +22,6 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * The {@code TitleClearPacket} class represents a packet that handles the clearing or removal of a title - * from the player's screen in Minecraft. - * - *

      This packet is used to instruct the client to clear any currently displayed title and subtitle.

      - * - *

      It extends the {@link GenericTitlePacket}, inheriting basic title properties but is specifically - * focused on clearing the title display.

      - */ public class TitleClearPacket extends GenericTitlePacket { public TitleClearPacket() { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java index 3f44f3e9..0f375ae2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleSubtitlePacket.java @@ -23,15 +23,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; -/** - * The {@code TitleSubtitlePacket} class represents a packet that handles the subtitle content for a title - * displayed to the player in Minecraft. - * - *

      This packet is used to send the subtitle text that appears below the main title on the player's screen.

      - * - *

      It extends the {@link GenericTitlePacket}, inheriting basic title properties and focusing - * on the subtitle content of the title.

      - */ public class TitleSubtitlePacket extends GenericTitlePacket { private ComponentHolder component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java index 17179075..ae75f5d6 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTextPacket.java @@ -23,15 +23,6 @@ import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; -/** - * The {@code TitleTextPacket} class represents a packet that handles the text content for a title - * displayed to the player in Minecraft. - * - *

      This packet is used to send the main title text to be displayed on the player's screen.

      - * - *

      It extends the {@link GenericTitlePacket}, inheriting basic title properties and focusing - * on the specific text content of the title.

      - */ public class TitleTextPacket extends GenericTitlePacket { private ComponentHolder component; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java index 5b737af4..8764a12f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/title/TitleTimesPacket.java @@ -22,15 +22,6 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -/** - * The {@code TitleTimesPacket} class represents a packet that handles the timing settings for a title in - * Minecraft, such as fade-in, stay, and fade-out durations. - * - *

      This packet is used to set the timing properties for a title displayed to the player.

      - * - *

      It extends the {@link GenericTitlePacket} to inherit basic title properties and adds specific timing - * controls for the title display.

      - */ public class TitleTimesPacket extends GenericTitlePacket { private int fadeIn; diff --git a/proxy/src/main/resources/default-velocity.toml b/proxy/src/main/resources/default-velocity.toml index 28de5297..4d71e589 100644 --- a/proxy/src/main/resources/default-velocity.toml +++ b/proxy/src/main/resources/default-velocity.toml @@ -42,7 +42,7 @@ forwarding-secret-file = "forwarding.secret" # Announce whether or not your server supports Forge. If you run a modded server, we # suggest turning this on. -# +# # If your network runs one modpack consistently, consider using ping-passthrough = "mods" # instead for a nicer display in the server list. announce-forge = false From 747cc8984f64d07b2105136a29e4e1095ed889fe Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sun, 8 Mar 2026 20:00:28 +0000 Subject: [PATCH 26/48] Bump netty to 4.2.10.Final --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7be8d469..caa82d81 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ configurate3 = "3.7.3" configurate4 = "4.2.0" flare = "2.0.1" log4j = "2.25.3" -netty = "4.2.7.Final" +netty = "4.2.10.Final" [plugins] fill = "io.papermc.fill.gradle:1.0.10" From 0783b1d4e414660b5cde43d929e015ce2964c599 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 15 Mar 2026 08:37:14 +0100 Subject: [PATCH 27/48] Add remaining pre-sizing checks --- .../proxy/protocol/ProtocolUtils.java | 23 +++++++++++++++++- .../packet/AvailableCommandsPacket.java | 24 +++++++++---------- .../config/ClientboundServerLinksPacket.java | 4 +--- .../packet/config/KnownPacksPacket.java | 9 +++---- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index efc0ed17..898a87db 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -415,7 +415,10 @@ public enum ProtocolUtils { */ public static int[] readIntegerArray(ByteBuf buf) { int len = readVarInt(buf); - checkArgument(len >= 0, "Got a negative-length integer array (%s)", len); + checkFrame(len >= 0, "Got a negative-length integer array (%s)", len); + checkFrame(buf.isReadable(len), + "Trying to read an array that is too long (wanted %s, only have %s)", len, + buf.readableBytes()); int[] array = new int[len]; for (int i = 0; i < len; i++) { array[i] = readVarInt(buf); @@ -535,6 +538,10 @@ public enum ProtocolUtils { */ public static String[] readStringArray(ByteBuf buf) { int length = readVarInt(buf); + checkFrame(length >= 0, "Got a negative-length array (%s)", length); + checkFrame(buf.isReadable(length), + "Trying to read an array that is too long (wanted %s, only have %s)", length, + buf.readableBytes()); String[] ret = new String[length]; for (int i = 0; i < length; i++) { ret[i] = readString(buf); @@ -646,6 +653,9 @@ public enum ProtocolUtils { checkArgument(len <= FORGE_MAX_ARRAY_LENGTH, "Cannot receive array longer than %s (got %s bytes)", FORGE_MAX_ARRAY_LENGTH, len); + checkFrame(buf.isReadable(len), + "Trying to read an array that is too long (wanted %s, only have %s)", len, + buf.readableBytes()); byte[] ret = new byte[len]; buf.readBytes(ret); @@ -844,6 +854,17 @@ public enum ProtocolUtils { writeVarInt(buf, source.ordinal()); } + /** + * Returns a pre-sized list with a max initial size of {@code Short.MAX_VALUE} + * + * @param initialCapacity expected initial capacity + * @param entry type + * @return pre-sized list + */ + public static List newList(int initialCapacity) { + return new ArrayList<>(Math.min(initialCapacity, Short.MAX_VALUE)); + } + /** * Represents the direction in which a packet flows. */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java index 2746b23f..6653d763 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/AvailableCommandsPacket.java @@ -44,9 +44,9 @@ import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenCustomHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import java.util.ArrayDeque; -import java.util.Arrays; import java.util.Deque; import java.util.Iterator; +import java.util.List; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; @@ -85,14 +85,14 @@ public class AvailableCommandsPacket implements MinecraftPacket { @Override public void decode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) { int commands = ProtocolUtils.readVarInt(buf); - WireNode[] wireNodes = new WireNode[commands]; + List wireNodes = ProtocolUtils.newList(commands); for (int i = 0; i < commands; i++) { - wireNodes[i] = deserializeNode(buf, i, protocolVersion); + wireNodes.add(deserializeNode(buf, i, protocolVersion)); } // Iterate over the deserialized nodes and attempt to form a graph. We also resolve any cycles // that exist. - Queue nodeQueue = new ArrayDeque<>(Arrays.asList(wireNodes)); + Queue nodeQueue = new ArrayDeque<>(wireNodes); while (!nodeQueue.isEmpty()) { boolean cycling = false; @@ -111,7 +111,7 @@ public class AvailableCommandsPacket implements MinecraftPacket { } int rootIdx = ProtocolUtils.readVarInt(buf); - rootNode = (RootCommandNode) wireNodes[rootIdx].built; + rootNode = (RootCommandNode) wireNodes.get(rootIdx).built; } @Override @@ -245,17 +245,17 @@ public class AvailableCommandsPacket implements MinecraftPacket { this.validated = false; } - void validate(WireNode[] wireNodes) { + void validate(List wireNodes) { // Ensure all children exist. Note that we delay checking if the node has been built yet; // that needs to come after this node is built. for (int child : children) { - if (child < 0 || child >= wireNodes.length) { + if (child < 0 || child >= wireNodes.size()) { throw new IllegalStateException("Node points to non-existent index " + child); } } if (redirectTo != -1) { - if (redirectTo < 0 || redirectTo >= wireNodes.length) { + if (redirectTo < 0 || redirectTo >= wireNodes.size()) { throw new IllegalStateException("Redirect node points to non-existent index " + redirectTo); } @@ -264,7 +264,7 @@ public class AvailableCommandsPacket implements MinecraftPacket { this.validated = true; } - boolean toNode(WireNode[] wireNodes) { + boolean toNode(List wireNodes) { if (!this.validated) { this.validate(wireNodes); } @@ -280,7 +280,7 @@ public class AvailableCommandsPacket implements MinecraftPacket { // Add any redirects if (redirectTo != -1) { - WireNode redirect = wireNodes[redirectTo]; + WireNode redirect = wireNodes.get(redirectTo); if (redirect.built != null) { args.redirect(redirect.built); } else { @@ -304,7 +304,7 @@ public class AvailableCommandsPacket implements MinecraftPacket { } for (int child : children) { - if (wireNodes[child].built == null) { + if (wireNodes.get(child).built == null) { // The child is not yet deserialized. The node can't be built now. return false; } @@ -312,7 +312,7 @@ public class AvailableCommandsPacket implements MinecraftPacket { // Associate children with nodes for (int child : children) { - CommandNode childNode = wireNodes[child].built; + CommandNode childNode = wireNodes.get(child).built; if (!(childNode instanceof RootCommandNode)) { built.addChild(childNode); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java index d37866d8..e30c8a7d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundServerLinksPacket.java @@ -18,13 +18,11 @@ package com.velocitypowered.proxy.protocol.packet.config; import com.velocitypowered.api.network.ProtocolVersion; -import com.velocitypowered.api.util.ServerLink; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import io.netty.buffer.ByteBuf; -import java.util.ArrayList; import java.util.List; public class ClientboundServerLinksPacket implements MinecraftPacket { @@ -42,7 +40,7 @@ public class ClientboundServerLinksPacket implements MinecraftPacket { public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { int linksCount = ProtocolUtils.readVarInt(buf); - this.serverLinks = new ArrayList<>(linksCount); + this.serverLinks = ProtocolUtils.newList(linksCount); for (int i = 0; i < linksCount; i++) { serverLinks.add(ServerLink.read(buf, version)); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java index b3fb0de4..196e8767 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/KnownPacksPacket.java @@ -23,6 +23,7 @@ import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.util.except.QuietDecoderException; import io.netty.buffer.ByteBuf; +import java.util.List; public class KnownPacksPacket implements MinecraftPacket { @@ -30,7 +31,7 @@ public class KnownPacksPacket implements MinecraftPacket { private static final QuietDecoderException TOO_MANY_PACKS = new QuietDecoderException("too many known packs"); - private KnownPack[] packs; + private List packs; @Override public void decode(ByteBuf buf, ProtocolUtils.Direction direction, @@ -40,10 +41,10 @@ public class KnownPacksPacket implements MinecraftPacket { throw TOO_MANY_PACKS; } - final KnownPack[] packs = new KnownPack[packCount]; + final List packs = ProtocolUtils.newList(packCount); for (int i = 0; i < packCount; i++) { - packs[i] = KnownPack.read(buf); + packs.add(KnownPack.read(buf)); } this.packs = packs; @@ -52,7 +53,7 @@ public class KnownPacksPacket implements MinecraftPacket { @Override public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { - ProtocolUtils.writeVarInt(buf, packs.length); + ProtocolUtils.writeVarInt(buf, packs.size()); for (KnownPack pack : packs) { pack.write(buf); From 470cd7a9d2729e0acb95672b23aeb7282a926c22 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 15 Mar 2026 08:44:31 +0100 Subject: [PATCH 28/48] checkstyle --- .../java/com/velocitypowered/proxy/protocol/ProtocolUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 898a87db..ab7c4831 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -855,7 +855,7 @@ public enum ProtocolUtils { } /** - * Returns a pre-sized list with a max initial size of {@code Short.MAX_VALUE} + * Returns a pre-sized list with a max initial size of {@code Short.MAX_VALUE}. * * @param initialCapacity expected initial capacity * @param entry type From e8b64aa6c09edb0846dc06687307a4343637224e Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Sun, 15 Mar 2026 09:04:34 +0100 Subject: [PATCH 29/48] Add two more pre-sizing checks --- .../proxy/protocol/ProtocolUtils.java | 14 ++++++++++++++ .../protocol/packet/RemovePlayerInfoPacket.java | 3 +-- .../ClientboundCustomReportDetailsPacket.java | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index ab7c4831..21d3fb98 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -36,7 +36,9 @@ import io.netty.handler.codec.EncoderException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.UUID; import net.kyori.adventure.key.Key; import net.kyori.adventure.nbt.BinaryTag; @@ -865,6 +867,18 @@ public enum ProtocolUtils { return new ArrayList<>(Math.min(initialCapacity, Short.MAX_VALUE)); } + /** + * Returns a pre-sized map with a max initial size of {@code Short.MAX_VALUE}. + * + * @param initialCapacity expected initial capacity + * @param key type + * @param value type + * @return pre-sized map + */ + public static Map newMap(int initialCapacity) { + return new HashMap<>(Math.min(initialCapacity, Short.MAX_VALUE)); + } + /** * Represents the direction in which a packet flows. */ diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java index 90ab3871..3851d278 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/RemovePlayerInfoPacket.java @@ -17,7 +17,6 @@ package com.velocitypowered.proxy.protocol.packet; -import com.google.common.collect.Lists; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; @@ -51,7 +50,7 @@ public class RemovePlayerInfoPacket implements MinecraftPacket { public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { int length = ProtocolUtils.readVarInt(buf); - Collection profilesToRemove = Lists.newArrayListWithCapacity(length); + Collection profilesToRemove = ProtocolUtils.newList(length); for (int idx = 0; idx < length; idx++) { profilesToRemove.add(ProtocolUtils.readUuid(buf)); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java index 6a3618cb..c51c5ff2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java @@ -40,7 +40,7 @@ public class ClientboundCustomReportDetailsPacket implements MinecraftPacket { public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) { int detailsCount = ProtocolUtils.readVarInt(buf); - this.details = new HashMap<>(detailsCount); + this.details = ProtocolUtils.newMap(detailsCount); for (int i = 0; i < detailsCount; i++) { details.put(ProtocolUtils.readString(buf), ProtocolUtils.readString(buf)); } From 5017f8c9f2d5aa4ed2edda4b2bd4786280bbe009 Mon Sep 17 00:00:00 2001 From: booky Date: Wed, 18 Mar 2026 13:04:31 +0100 Subject: [PATCH 30/48] Add more protocol safeguards (#1743) * Add max length to more config phase packets * Ensure all packets during non-play state are known * Limit maximum size of play inbound packet queue Co-authored-by: Dwarslooper * Fix checkstyle --------- Co-authored-by: Dwarslooper --- .../proxy/protocol/ProtocolUtils.java | 5 +++- .../protocol/netty/MinecraftDecoder.java | 12 ++++++++++ .../netty/PlayPacketQueueInboundHandler.java | 23 +++++++++++++++++++ .../protocol/packet/ClientSettingsPacket.java | 16 ++++++++++--- .../protocol/packet/KeepAlivePacket.java | 22 ++++++++++++++++++ .../protocol/packet/PingIdentifyPacket.java | 10 ++++++++ .../protocol/packet/PluginMessagePacket.java | 12 ++++++++++ .../packet/ResourcePackResponsePacket.java | 22 +++++++++++++++++- .../ServerboundCookieResponsePacket.java | 10 ++++++++ .../ServerboundCustomClickActionPacket.java | 12 ++++++++++ .../ClientboundCustomReportDetailsPacket.java | 1 - .../config/CodeOfConductAcceptPacket.java | 5 ++++ 12 files changed, 144 insertions(+), 6 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java index 21d3fb98..826df5b3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java @@ -161,6 +161,9 @@ public enum ProtocolUtils { VAR_INT_LENGTHS[32] = 1; // Special case for the number 0. } + public static final int DEFAULT_MAX_STRING_BYTES = varIntBytes(ByteBufUtil.utf8MaxBytes(DEFAULT_MAX_STRING_SIZE)) + + ByteBufUtil.utf8MaxBytes(DEFAULT_MAX_STRING_SIZE); + private static DecoderException badVarint() { return MinecraftDecoder.DEBUG ? new CorruptedFrameException("Bad VarInt decoded") : BAD_VARINT_CACHED; @@ -886,4 +889,4 @@ public enum ProtocolUtils { SERVERBOUND, CLIENTBOUND } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java index 35ddccd5..ae84e749 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java @@ -74,6 +74,10 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter { MinecraftPacket packet = this.registry.createPacket(packetId); if (packet == null) { buf.readerIndex(originalReaderIndex); + if (this.direction == ProtocolUtils.Direction.SERVERBOUND && this.state != StateRegistry.PLAY) { + buf.release(); + throw this.handleInvalidPacketId(packetId); + } ctx.fireChannelRead(buf); } else { try { @@ -133,6 +137,14 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter { } } + private Exception handleInvalidPacketId(int packetId) { + if (DEBUG) { + return new CorruptedFrameException("Invalid packet " + getExtraConnectionDetail(packetId)); + } else { + return DECODE_FAILED; + } + } + private String getExtraConnectionDetail(int packetId) { return "Direction " + direction + " Protocol " + registry.version + " State " + state + " ID 0x" + Integer.toHexString(packetId); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java index 1affc13b..899768d2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/PlayPacketQueueInboundHandler.java @@ -21,6 +21,9 @@ import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.util.except.QuietDecoderException; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufHolder; import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.util.ReferenceCountUtil; @@ -41,8 +44,13 @@ import org.jetbrains.annotations.NotNull; */ public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler { + private static final int MAXIMUM_SIZE = Integer.getInteger("velocity.maximum-play-queue-size", 128 * 1024 * 1024); // 128MiB by default + private static final QuietDecoderException QUEUE_LIMIT_FAILED = new QuietDecoderException( + "Queue too big (greater than " + MAXIMUM_SIZE + " bytes)"); + private final StateRegistry.PacketRegistry.ProtocolRegistry registry; private final Queue queue = new ArrayDeque<>(); + private int queueSize = 0; /** * Provides registries for client & server bound packets. @@ -64,6 +72,20 @@ public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler { } } + int length = 0; + if (msg instanceof ByteBuf) { + // keep track of raw packets + length = ((ByteBuf) msg).readableBytes(); + } else if (msg instanceof ByteBufHolder) { + // keep track of bytebufs wrapped inside packets + length = ((ByteBufHolder) msg).content().readableBytes(); + } + if (this.queueSize + length > MAXIMUM_SIZE) { + ReferenceCountUtil.release(msg); + throw QUEUE_LIMIT_FAILED; + } + this.queueSize += length; + // Otherwise, queue the packet this.queue.offer(msg); } @@ -90,5 +112,6 @@ public class PlayPacketQueueInboundHandler extends ChannelDuplexHandler { ReferenceCountUtil.release(msg); } } + this.queueSize = 0; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java index 39e6fde0..b8b60a9f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientSettingsPacket.java @@ -22,8 +22,8 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import java.util.Objects; - import org.checkerframework.checker.nullness.qual.Nullable; public class ClientSettingsPacket implements MinecraftPacket { @@ -135,7 +135,7 @@ public class ClientSettingsPacket implements MinecraftPacket { return "ClientSettings{" + "locale='" + locale + '\'' + ", viewDistance=" + viewDistance + ", chatVisibility=" + chatVisibility + ", chatColors=" + chatColors + ", skinParts=" + skinParts + ", mainHand=" + mainHand + ", chatFilteringEnabled=" + textFilteringEnabled + - ", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}'; + ", clientListingAllowed=" + clientListingAllowed + ", particleStatus=" + particleStatus + '}'; } @Override @@ -206,6 +206,16 @@ public class ClientSettingsPacket implements MinecraftPacket { return handler.handle(this); } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 1 + ByteBufUtil.utf8MaxBytes(16) + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return 1 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1; + } + @Override public boolean equals(@Nullable final Object o) { if (this == o) { @@ -237,7 +247,7 @@ public class ClientSettingsPacket implements MinecraftPacket { difficulty, skinParts, mainHand, - textFilteringEnabled, + textFilteringEnabled, clientListingAllowed, particleStatus); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java index a44e50ee..932dd47a 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/KeepAlivePacket.java @@ -64,6 +64,28 @@ public class KeepAlivePacket implements MinecraftPacket { } } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + if (version.noLessThan(ProtocolVersion.MINECRAFT_1_12_2)) { + return Long.BYTES; + } else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) { + return 5; + } else { + return Integer.BYTES; + } + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + if (version.noLessThan(ProtocolVersion.MINECRAFT_1_12_2)) { + return Long.BYTES; + } else if (version.noLessThan(ProtocolVersion.MINECRAFT_1_8)) { + return 1; + } else { + return Integer.BYTES; + } + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java index 27c1351d..ed1e3feb 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PingIdentifyPacket.java @@ -42,6 +42,16 @@ public class PingIdentifyPacket implements MinecraftPacket { buf.writeInt(id); } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return Integer.BYTES; + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion version) { + return Integer.BYTES; + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java index ecf2887f..e2da28de 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java @@ -31,6 +31,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class PluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket { + private static final int MAX_PAYLOAD_SIZE = Integer.getInteger("velocity.max-plugin-message-payload-size", 32767); + private @Nullable String channel; public PluginMessagePacket() { @@ -100,6 +102,16 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return ProtocolUtils.DEFAULT_MAX_STRING_BYTES + MAX_PAYLOAD_SIZE; + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return 1 + 0 + 0; + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java index 020c3530..4d9a83d2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ResourcePackResponsePacket.java @@ -80,6 +80,26 @@ public class ResourcePackResponsePacket implements MinecraftPacket { ProtocolUtils.writeVarInt(buf, status.ordinal()); } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) { + return Long.BYTES * 2 + 1; + } else if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_9_4)) { + return ProtocolUtils.DEFAULT_MAX_STRING_BYTES + 1; + } + return 1; + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + if (version.noLessThan(ProtocolVersion.MINECRAFT_1_20_3)) { + return Long.BYTES * 2 + 1; + } else if (version.noGreaterThan(ProtocolVersion.MINECRAFT_1_9_4)) { + return 1 + 0 + 1; + } + return 1; + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); @@ -93,4 +113,4 @@ public class ResourcePackResponsePacket implements MinecraftPacket { ", status=" + status + '}'; } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java index bee12b80..0731cc2d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCookieResponsePacket.java @@ -65,6 +65,16 @@ public class ServerboundCookieResponsePacket implements MinecraftPacket { } } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return ProtocolUtils.DEFAULT_MAX_STRING_BYTES + 1 + 2 + 5120; + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return 1 + 0 + 0; + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java index 6b846c23..7b2c9256 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ServerboundCustomClickActionPacket.java @@ -27,6 +27,8 @@ import io.netty.buffer.ByteBuf; public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder implements MinecraftPacket { + private static final int MAX_TAG_SIZE = 65536; + public ServerboundCustomClickActionPacket() { super(null); } @@ -41,6 +43,16 @@ public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder im buf.writeBytes(content()); } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return ProtocolUtils.DEFAULT_MAX_STRING_BYTES + ProtocolUtils.varIntBytes(MAX_TAG_SIZE) + MAX_TAG_SIZE; + } + + @Override + public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return 1 + 0 + 1 + 0; + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java index c51c5ff2..05f535d4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/ClientboundCustomReportDetailsPacket.java @@ -22,7 +22,6 @@ import com.velocitypowered.proxy.connection.MinecraftSessionHandler; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import io.netty.buffer.ByteBuf; -import java.util.HashMap; import java.util.Map; public class ClientboundCustomReportDetailsPacket implements MinecraftPacket { diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java index e9811f9f..6cd338c4 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/config/CodeOfConductAcceptPacket.java @@ -38,6 +38,11 @@ public class CodeOfConductAcceptPacket implements MinecraftPacket { public void encode(ByteBuf buf, Direction direction, ProtocolVersion protocolVersion) { } + @Override + public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) { + return 0; + } + @Override public boolean handle(MinecraftSessionHandler handler) { return handler.handle(this); From 99bd03099689cbc9c8f92af1cba207e4348afa75 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Wed, 18 Mar 2026 19:23:01 +0100 Subject: [PATCH 31/48] Implement missing writabilityChanged() and add backlog logging with BACKPRESSURE_LOG to all writabilityChanged() implementations. (#1745) --- .../backend/ConfigSessionHandler.java | 20 +++++++++++++ .../client/ClientConfigSessionHandler.java | 29 +++++++++++++++++++ .../client/ClientPlaySessionHandler.java | 10 +++++++ 3 files changed, 59 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index 8ab38e58..e523f0f7 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -60,6 +60,7 @@ import com.velocitypowered.proxy.protocol.packet.config.TagsUpdatePacket; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; @@ -72,6 +73,9 @@ import org.apache.logging.log4j.Logger; * 1.20.2+ switching. Yes, some of this is exceptionally stupid. */ public class ConfigSessionHandler implements MinecraftSessionHandler { + private static final boolean BACKPRESSURE_LOG = + Boolean.getBoolean("velocity.log-server-backpressure"); + private static final Logger logger = LogManager.getLogger(ConfigSessionHandler.class); private final VelocityServer server; private final VelocityServerConnection serverConn; @@ -382,6 +386,22 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { serverConn.getPlayer().getConnection().write(packet); } + @Override + public void writabilityChanged() { + Channel serverChan = serverConn.ensureConnected().getChannel(); + boolean writable = serverChan.isWritable(); + + if (BACKPRESSURE_LOG) { + if (writable) { + logger.info("{} is writable, will auto-read player connection data", this.serverConn); + } else { + logger.info("{} is not writable, not auto-reading player connection data", this.serverConn); + } + } + + serverConn.getPlayer().getConnection().setAutoReading(writable); + } + private void switchFailure(Throwable cause) { logger.error("Unable to switch to new server {} for {}", serverConn.getServerInfo().getName(), serverConn.getPlayer().getUsername(), cause); 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 776f99d6..29928582 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 @@ -60,6 +60,8 @@ import org.apache.logging.log4j.Logger; * Handles the client config stage. */ public class ClientConfigSessionHandler implements MinecraftSessionHandler { + private static final boolean BACKPRESSURE_LOG = + Boolean.getBoolean("velocity.log-server-backpressure"); private static final Logger logger = LogManager.getLogger(ClientConfigSessionHandler.class); private final VelocityServer server; @@ -268,6 +270,33 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler { player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); } + @Override + public void writabilityChanged() { + final boolean writable = player.getConnection().getChannel().isWritable(); + + if (BACKPRESSURE_LOG) { + if (writable) { + logger.info("{} is writable, will auto-read backend connection data", player); + } else { + logger.info("{} is not writable, not auto-reading backend connection data", player); + } + } + + if (!writable) { + // Flush pending packets to free up memory. Schedule on a future event loop invocation + // to avoid disabling auto-read while the flush resolves backpressure. + player.getConnection().eventLoop().execute(() -> player.getConnection().flush()); + } + + final VelocityServerConnection serverConn = player.getConnectionInFlightOrConnectedServer(); + if (serverConn != null) { + final MinecraftConnection smc = serverConn.getConnection(); + if (smc != null) { + smc.setAutoReading(writable); + } + } + } + /** * Calls the {@link PlayerConfigurationEvent}. * For 1.20.5+ backends this is done when the client responds to diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index a4ddacc9..fb13271b 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -98,6 +98,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; * center that joins backend servers with players. */ public class ClientPlaySessionHandler implements MinecraftSessionHandler { + private static final boolean BACKPRESSURE_LOG = + Boolean.getBoolean("velocity.log-server-backpressure"); private static final Logger logger = LogManager.getLogger(ClientPlaySessionHandler.class); @@ -505,6 +507,14 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { public void writabilityChanged() { boolean writable = player.getConnection().getChannel().isWritable(); + if (BACKPRESSURE_LOG) { + if (writable) { + logger.info("{} is writable, will auto-read backend connection data", player); + } else { + logger.info("{} is not writable, not auto-reading backend connection data", player); + } + } + if (!writable) { // We might have packets queued from the server, so flush them now to free up memory. Make // sure to do it on a future invocation of the event loop, otherwise while the issue will From d11511c18499497e7f7186211b109ef395b44acd Mon Sep 17 00:00:00 2001 From: Aaron <71191102+RealBauHD@users.noreply.github.com> Date: Sun, 22 Mar 2026 05:14:28 +0100 Subject: [PATCH 32/48] Minecraft 26.1 (#1739) * 26.1-snapshot-10 * 26.1-snapshot-11 * 26.1-pre-1 * 26.1-pre-2 * 26.1-pre-3 * 26.1-rc-1 * 26.1-rc-2 * 26.1 --- .../api/network/ProtocolVersion.java | 3 +- .../proxy/protocol/StateRegistry.java | 99 ++++++++++++------- 2 files changed, 68 insertions(+), 34 deletions(-) diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index e803c302..3062c63c 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -94,7 +94,8 @@ public enum ProtocolVersion implements Ordered { MINECRAFT_1_21_6(771, "1.21.6"), MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"), MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"), - MINECRAFT_1_21_11(774, "1.21.11"); + MINECRAFT_1_21_11(774, "1.21.11"), + MINECRAFT_26_1(775, "26.1"); private static final int SNAPSHOT_BIT = 30; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java index 67b01087..29710876 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java @@ -46,6 +46,7 @@ import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_7_2; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_8; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9; import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_1_9_4; +import static com.velocitypowered.api.network.ProtocolVersion.MINECRAFT_26_1; import static com.velocitypowered.api.network.ProtocolVersion.MINIMUM_VERSION; import static com.velocitypowered.api.network.ProtocolVersion.SUPPORTED_VERSIONS; import static com.velocitypowered.proxy.protocol.ProtocolUtils.Direction; @@ -278,7 +279,8 @@ public enum StateRegistry { map(0x0A, MINECRAFT_1_20_2, false), map(0x0B, MINECRAFT_1_20_5, false), map(0x0D, MINECRAFT_1_21_2, false), - map(0x0E, MINECRAFT_1_21_6, false)); + map(0x0E, MINECRAFT_1_21_6, false), + map(0x0F, MINECRAFT_26_1, false)); serverbound.register( LegacyChatPacket.class, LegacyChatPacket::new, @@ -292,7 +294,8 @@ public enum StateRegistry { ChatAcknowledgementPacket::new, map(0x03, MINECRAFT_1_19_3, false), map(0x04, MINECRAFT_1_21_2, false), - map(0x05, MINECRAFT_1_21_6, false)); + map(0x05, MINECRAFT_1_21_6, false), + map(0x06, MINECRAFT_26_1, false)); serverbound.register(KeyedPlayerCommandPacket.class, KeyedPlayerCommandPacket::new, map(0x03, MINECRAFT_1_19, false), map(0x04, MINECRAFT_1_19_1, MINECRAFT_1_19_1, false)); @@ -303,18 +306,21 @@ public enum StateRegistry { map(0x04, MINECRAFT_1_19_3, false), map(0x05, MINECRAFT_1_20_5, false), map(0x06, MINECRAFT_1_21_2, false), - map(0x07, MINECRAFT_1_21_6, false)); + map(0x07, MINECRAFT_1_21_6, false), + map(0x08, MINECRAFT_26_1, false)); serverbound.register(UnsignedPlayerCommandPacket.class, UnsignedPlayerCommandPacket::new, map(0x04, MINECRAFT_1_20_5, false), map(0x05, MINECRAFT_1_21_2, false), - map(0x06, MINECRAFT_1_21_6, false)); + map(0x06, MINECRAFT_1_21_6, false), + map(0x07, MINECRAFT_26_1, false)); serverbound.register( SessionPlayerChatPacket.class, SessionPlayerChatPacket::new, map(0x05, MINECRAFT_1_19_3, false), map(0x06, MINECRAFT_1_20_5, false), map(0x07, MINECRAFT_1_21_2, false), - map(0x08, MINECRAFT_1_21_6, false)); + map(0x08, MINECRAFT_1_21_6, false), + map(0x09, MINECRAFT_26_1, false)); serverbound.register( ClientSettingsPacket.class, ClientSettingsPacket::new, @@ -330,12 +336,14 @@ public enum StateRegistry { map(0x09, MINECRAFT_1_20_2, false), map(0x0A, MINECRAFT_1_20_5, false), map(0x0C, MINECRAFT_1_21_2, false), - map(0x0D, MINECRAFT_1_21_6, false)); + map(0x0D, MINECRAFT_1_21_6, false), + map(0x0E, MINECRAFT_26_1, false)); serverbound.register( ServerboundCookieResponsePacket.class, ServerboundCookieResponsePacket::new, map(0x11, MINECRAFT_1_20_5, false), map(0x13, MINECRAFT_1_21_2, false), - map(0x14, MINECRAFT_1_21_6, false)); + map(0x14, MINECRAFT_1_21_6, false), + map(0x15, MINECRAFT_26_1, false)); serverbound.register( PluginMessagePacket.class, PluginMessagePacket::new, @@ -354,7 +362,8 @@ public enum StateRegistry { map(0x10, MINECRAFT_1_20_3, false), map(0x12, MINECRAFT_1_20_5, false), map(0x14, MINECRAFT_1_21_2, false), - map(0x15, MINECRAFT_1_21_6, false)); + map(0x15, MINECRAFT_1_21_6, false), + map(0x16, MINECRAFT_26_1, false)); serverbound.register( KeepAlivePacket.class, KeepAlivePacket::new, @@ -374,7 +383,8 @@ public enum StateRegistry { map(0x15, MINECRAFT_1_20_3, false), map(0x18, MINECRAFT_1_20_5, false), map(0x1A, MINECRAFT_1_21_2, false), - map(0x1B, MINECRAFT_1_21_6, false)); + map(0x1B, MINECRAFT_1_21_6, false), + map(0x1C, MINECRAFT_26_1, false)); serverbound.register( ResourcePackResponsePacket.class, ResourcePackResponsePacket::new, @@ -392,13 +402,15 @@ public enum StateRegistry { map(0x2B, MINECRAFT_1_20_5, false), map(0x2D, MINECRAFT_1_21_2, false), map(0x2F, MINECRAFT_1_21_4, false), - map(0x30, MINECRAFT_1_21_6, false)); + map(0x30, MINECRAFT_1_21_6, false), + map(0x31, MINECRAFT_26_1, false)); serverbound.register( FinishedUpdatePacket.class, () -> FinishedUpdatePacket.INSTANCE, map(0x0B, MINECRAFT_1_20_2, false), map(0x0C, MINECRAFT_1_20_5, false), map(0x0E, MINECRAFT_1_21_2, false), - map(0x0F, MINECRAFT_1_21_6, false)); + map(0x0F, MINECRAFT_1_21_6, false), + map(0x10, MINECRAFT_26_1, false)); clientbound.register( BossBarPacket.class, @@ -459,7 +471,8 @@ public enum StateRegistry { map(0x67, MINECRAFT_1_20_5, true), map(0x6E, MINECRAFT_1_21_2, true), map(0x6D, MINECRAFT_1_21_5, true), - map(0x72, MINECRAFT_1_21_9, true)); + map(0x72, MINECRAFT_1_21_9, true), + map(0x74, MINECRAFT_26_1, true)); clientbound.register( ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new, map(0x5F, MINECRAFT_1_19_3, true), @@ -469,7 +482,8 @@ public enum StateRegistry { map(0x6A, MINECRAFT_1_20_5, true), map(0x71, MINECRAFT_1_21_2, true), map(0x70, MINECRAFT_1_21_5, true), - map(0x75, MINECRAFT_1_21_9, true)); + map(0x75, MINECRAFT_1_21_9, true), + map(0x77, MINECRAFT_26_1, true)); clientbound.register( PluginMessagePacket.class, PluginMessagePacket::new, @@ -526,7 +540,8 @@ public enum StateRegistry { map(0x26, MINECRAFT_1_20_5, false), map(0x27, MINECRAFT_1_21_2, false), map(0x26, MINECRAFT_1_21_5, false), - map(0x2B, MINECRAFT_1_21_9, false)); + map(0x2B, MINECRAFT_1_21_9, false), + map(0x2C, MINECRAFT_26_1, false)); clientbound.register( JoinGamePacket.class, JoinGamePacket::new, @@ -546,7 +561,8 @@ public enum StateRegistry { map(0x2B, MINECRAFT_1_20_5, false), map(0x2C, MINECRAFT_1_21_2, false), map(0x2B, MINECRAFT_1_21_5, false), - map(0x30, MINECRAFT_1_21_9, false)); + map(0x30, MINECRAFT_1_21_9, false), + map(0x31, MINECRAFT_26_1, false)); clientbound.register( RespawnPacket.class, RespawnPacket::new, @@ -569,7 +585,8 @@ public enum StateRegistry { map(0x47, MINECRAFT_1_20_5, true), map(0x4C, MINECRAFT_1_21_2, true), map(0x4B, MINECRAFT_1_21_5, true), - map(0x50, MINECRAFT_1_21_9, true)); + map(0x50, MINECRAFT_1_21_9, true), + map(0x52, MINECRAFT_26_1, true)); clientbound.register( RemoveResourcePackPacket.class, RemoveResourcePackPacket::new, @@ -577,7 +594,8 @@ public enum StateRegistry { map(0x45, MINECRAFT_1_20_5, false), map(0x4A, MINECRAFT_1_21_2, false), map(0x49, MINECRAFT_1_21_5, false), - map(0x4E, MINECRAFT_1_21_9, false)); + map(0x4E, MINECRAFT_1_21_9, false), + map(0x50, MINECRAFT_26_1, false)); clientbound.register( ResourcePackRequestPacket.class, ResourcePackRequestPacket::new, @@ -600,7 +618,8 @@ public enum StateRegistry { map(0x46, MINECRAFT_1_20_5, false), map(0x4B, MINECRAFT_1_21_2, false), map(0x4A, MINECRAFT_1_21_5, false), - map(0x4F, MINECRAFT_1_21_9, false)); + map(0x4F, MINECRAFT_1_21_9, false), + map(0x51, MINECRAFT_26_1, false)); clientbound.register( HeaderAndFooterPacket.class, HeaderAndFooterPacket::new, @@ -624,7 +643,8 @@ public enum StateRegistry { map(0x6D, MINECRAFT_1_20_5, true), map(0x74, MINECRAFT_1_21_2, true), map(0x73, MINECRAFT_1_21_5, true), - map(0x78, MINECRAFT_1_21_9, true)); + map(0x78, MINECRAFT_1_21_9, true), + map(0x7A, MINECRAFT_26_1, true)); clientbound.register( LegacyTitlePacket.class, LegacyTitlePacket::new, @@ -647,7 +667,8 @@ public enum StateRegistry { map(0x63, MINECRAFT_1_20_5, true), map(0x6A, MINECRAFT_1_21_2, true), map(0x69, MINECRAFT_1_21_5, true), - map(0x6E, MINECRAFT_1_21_9, true)); + map(0x6E, MINECRAFT_1_21_9, true), + map(0x70, MINECRAFT_26_1, true)); clientbound.register( TitleTextPacket.class, TitleTextPacket::new, @@ -661,7 +682,8 @@ public enum StateRegistry { map(0x65, MINECRAFT_1_20_5, true), map(0x6C, MINECRAFT_1_21_2, true), map(0x6B, MINECRAFT_1_21_5, true), - map(0x70, MINECRAFT_1_21_9, true)); + map(0x70, MINECRAFT_1_21_9, true), + map(0x72, MINECRAFT_26_1, true)); clientbound.register( TitleActionbarPacket.class, TitleActionbarPacket::new, @@ -675,7 +697,8 @@ public enum StateRegistry { map(0x4C, MINECRAFT_1_20_5, true), map(0x51, MINECRAFT_1_21_2, true), map(0x50, MINECRAFT_1_21_5, true), - map(0x55, MINECRAFT_1_21_9, true)); + map(0x55, MINECRAFT_1_21_9, true), + map(0x57, MINECRAFT_26_1, true)); clientbound.register( TitleTimesPacket.class, TitleTimesPacket::new, @@ -689,7 +712,8 @@ public enum StateRegistry { map(0x66, MINECRAFT_1_20_5, true), map(0x6D, MINECRAFT_1_21_2, true), map(0x6C, MINECRAFT_1_21_5, true), - map(0x71, MINECRAFT_1_21_9, true)); + map(0x71, MINECRAFT_1_21_9, true), + map(0x73, MINECRAFT_26_1, true)); clientbound.register( TitleClearPacket.class, TitleClearPacket::new, @@ -720,7 +744,8 @@ public enum StateRegistry { map(0x3D, MINECRAFT_1_20_5, false), map(0x3F, MINECRAFT_1_21_2, false), map(0x3E, MINECRAFT_1_21_5, false), - map(0x43, MINECRAFT_1_21_9, false)); + map(0x43, MINECRAFT_1_21_9, false), + map(0x45, MINECRAFT_26_1, false)); clientbound.register( UpsertPlayerInfoPacket.class, UpsertPlayerInfoPacket::new, @@ -730,13 +755,15 @@ public enum StateRegistry { map(0x3E, MINECRAFT_1_20_5, false), map(0x40, MINECRAFT_1_21_2, false), map(0x3F, MINECRAFT_1_21_5, false), - map(0x44, MINECRAFT_1_21_9, false)); + map(0x44, MINECRAFT_1_21_9, false), + map(0x46, MINECRAFT_26_1, false)); clientbound.register( ClientboundStoreCookiePacket.class, ClientboundStoreCookiePacket::new, map(0x6B, MINECRAFT_1_20_5, false), map(0x72, MINECRAFT_1_21_2, false), map(0x71, MINECRAFT_1_21_5, false), - map(0x76, MINECRAFT_1_21_9, false)); + map(0x76, MINECRAFT_1_21_9, false), + map(0x78, MINECRAFT_26_1, false)); clientbound.register( SystemChatPacket.class, SystemChatPacket::new, @@ -749,7 +776,8 @@ public enum StateRegistry { map(0x6C, MINECRAFT_1_20_5, true), map(0x73, MINECRAFT_1_21_2, true), map(0x72, MINECRAFT_1_21_5, true), - map(0x77, MINECRAFT_1_21_9, true)); + map(0x77, MINECRAFT_1_21_9, true), + map(0x79, MINECRAFT_26_1, true)); clientbound.register( PlayerChatCompletionPacket.class, PlayerChatCompletionPacket::new, @@ -771,7 +799,8 @@ public enum StateRegistry { map(0x4B, MINECRAFT_1_20_5, false), map(0x50, MINECRAFT_1_21_2, false), map(0x4F, MINECRAFT_1_21_5, false), - map(0x54, MINECRAFT_1_21_9, false)); + map(0x54, MINECRAFT_1_21_9, false), + map(0x56, MINECRAFT_26_1, false)); clientbound.register( StartUpdatePacket.class, () -> StartUpdatePacket.INSTANCE, @@ -780,7 +809,8 @@ public enum StateRegistry { map(0x69, MINECRAFT_1_20_5, false), map(0x70, MINECRAFT_1_21_2, false), map(0x6F, MINECRAFT_1_21_5, false), - map(0x74, MINECRAFT_1_21_9, false)); + map(0x74, MINECRAFT_1_21_9, false), + map(0x76, MINECRAFT_26_1, false)); clientbound.register( BundleDelimiterPacket.class, () -> BundleDelimiterPacket.INSTANCE, @@ -790,19 +820,22 @@ public enum StateRegistry { TransferPacket::new, map(0x73, MINECRAFT_1_20_5, false), map(0x7A, MINECRAFT_1_21_2, false), - map(0x7F, MINECRAFT_1_21_9, false)); + map(0x7F, MINECRAFT_1_21_9, false), + map(0x81, MINECRAFT_26_1, false)); clientbound.register( ClientboundCustomReportDetailsPacket.class, ClientboundCustomReportDetailsPacket::new, map(0x7A, MINECRAFT_1_21, false), map(0x81, MINECRAFT_1_21_2, false), - map(0x86, MINECRAFT_1_21_9, false)); + map(0x86, MINECRAFT_1_21_9, false), + map(0x88, MINECRAFT_26_1, false)); clientbound.register( ClientboundServerLinksPacket.class, ClientboundServerLinksPacket::new, map(0x7B, MINECRAFT_1_21, false), map(0x82, MINECRAFT_1_21_2, false), - map(0x87, MINECRAFT_1_21_9, false)); + map(0x87, MINECRAFT_1_21_9, false), + map(0x89, MINECRAFT_26_1, false)); } }, LOGIN { @@ -831,7 +864,7 @@ public enum StateRegistry { map(0x01, MINECRAFT_1_7_2, false)); clientbound.register( ServerLoginSuccessPacket.class, ServerLoginSuccessPacket::new, - map(0x02, MINECRAFT_1_7_2, false)); + map(0x02, MINECRAFT_1_7_2, false)); clientbound.register( SetCompressionPacket.class, SetCompressionPacket::new, map(0x03, MINECRAFT_1_8, false)); From 2cf181df0c05c04b2ae07c736abfd0185efa6864 Mon Sep 17 00:00:00 2001 From: Timon Seidel Date: Tue, 31 Mar 2026 18:32:54 +0200 Subject: [PATCH 33/48] [ci skip] chore(readme): add note regarding localisation (#1759) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 5de7436f..aa6527f0 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,9 @@ and you can configure it from there. Alternatively, you can get the proxy JAR from the [downloads](https://papermc.io/downloads/velocity) page. + +# Localisation + +Translations are handled using [Crowdin](https://papermc-io.crowdin.com/velocity). +If you want to translate a language not available on Crowdin, +you might want to ask in the [Discord](https://discord.gg/papermc) about it. From ab99bde9d658fb2a270fedd0c58fc905cf1be387 Mon Sep 17 00:00:00 2001 From: Aaron <71191102+RealBauHD@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:20:30 +0200 Subject: [PATCH 34/48] Minecraft 26.1.1 (#1760) * 26.1.1-rc-1 * 26.1.1 --- .../java/com/velocitypowered/api/network/ProtocolVersion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index 3062c63c..51b2f46a 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -95,7 +95,7 @@ public enum ProtocolVersion implements Ordered { MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"), MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"), MINECRAFT_1_21_11(774, "1.21.11"), - MINECRAFT_26_1(775, "26.1"); + MINECRAFT_26_1(775, "26.1", "26.1.1"); private static final int SNAPSHOT_BIT = 30; From f6d48c90f93b3d3a0560074d2cd9b3a9be891a64 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Wed, 8 Apr 2026 20:41:09 +0100 Subject: [PATCH 35/48] reduce clientbound compression limits --- .../proxy/connection/MinecraftConnection.java | 4 +++- .../netty/MinecraftCompressDecoder.java | 23 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) 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 f7de55e0..151cbd30 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -38,6 +38,7 @@ import com.velocitypowered.proxy.connection.client.InitialLoginSessionHandler; import com.velocitypowered.proxy.connection.client.StatusSessionHandler; import com.velocitypowered.proxy.network.Connections; import com.velocitypowered.proxy.protocol.MinecraftPacket; +import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.VelocityConnectionEvent; import com.velocitypowered.proxy.protocol.netty.MinecraftCipherDecoder; @@ -544,9 +545,10 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { } else { int level = server.getConfiguration().getCompressionLevel(); VelocityCompressor compressor = Natives.compress.get().create(level); + final MinecraftDecoder minecraftDecoder = (MinecraftDecoder) channel.pipeline().get(MINECRAFT_DECODER); encoder = new MinecraftCompressorAndLengthEncoder(threshold, compressor); - decoder = new MinecraftCompressDecoder(threshold, compressor); + decoder = new MinecraftCompressDecoder(threshold, compressor, minecraftDecoder.getDirection()); channel.pipeline().remove(FRAME_ENCODER); channel.pipeline().addBefore(MINECRAFT_DECODER, COMPRESSION_DECODER, decoder); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index 1fe38e50..9bd040ef 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -33,20 +33,26 @@ import java.util.List; */ public class MinecraftCompressDecoder extends MessageToMessageDecoder { + private static final int SERVERBOUND_MAXIMUM_UNCOMPRESSED_SIZE = 2 * 1024 * 1024; // 2MiB private static final int VANILLA_MAXIMUM_UNCOMPRESSED_SIZE = 8 * 1024 * 1024; // 8MiB private static final int HARD_MAXIMUM_UNCOMPRESSED_SIZE = 128 * 1024 * 1024; // 128MiB - private static final int UNCOMPRESSED_CAP = + private static final int CLIENTBOUND_UNCOMPRESSED_CAP = Boolean.getBoolean("velocity.increased-compression-cap") ? HARD_MAXIMUM_UNCOMPRESSED_SIZE : VANILLA_MAXIMUM_UNCOMPRESSED_SIZE; + private static final int SERVERBOUND_UNCOMPRESSED_CAP = + Boolean.getBoolean("velocity.increased-compression-cap") + ? HARD_MAXIMUM_UNCOMPRESSED_SIZE : SERVERBOUND_MAXIMUM_UNCOMPRESSED_SIZE; private static final boolean SKIP_COMPRESSION_VALIDATION = Boolean.getBoolean("velocity.skip-uncompressed-packet-size-validation"); + private final ProtocolUtils.Direction direction; private int threshold; private final VelocityCompressor compressor; - public MinecraftCompressDecoder(int threshold, VelocityCompressor compressor) { + public MinecraftCompressDecoder(int threshold, VelocityCompressor compressor, ProtocolUtils.Direction direction) { this.threshold = threshold; this.compressor = compressor; + this.direction = direction; } @Override @@ -65,10 +71,15 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { checkFrame(claimedUncompressedSize >= threshold, "Uncompressed size %s is less than" + " threshold %s", claimedUncompressedSize, threshold); - checkFrame(claimedUncompressedSize <= UNCOMPRESSED_CAP, - "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, - UNCOMPRESSED_CAP); - + if (direction == ProtocolUtils.Direction.CLIENTBOUND) { + checkFrame(claimedUncompressedSize <= CLIENTBOUND_UNCOMPRESSED_CAP, + "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, + CLIENTBOUND_UNCOMPRESSED_CAP); + } else { + checkFrame(claimedUncompressedSize <= SERVERBOUND_UNCOMPRESSED_CAP, + "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, + SERVERBOUND_UNCOMPRESSED_CAP); + } ByteBuf compatibleIn = ensureCompatible(ctx.alloc(), compressor, in); ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize); try { From 0219993c8a9adc4bbfe97628a7c0dd40174927f0 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Sat, 20 Sep 2025 17:00:44 +0100 Subject: [PATCH 36/48] Add basic packet limiter --- .../proxy/config/VelocityConfiguration.java | 43 ++- .../network/ServerChannelInitializer.java | 13 + .../proxy/network/limiter/PacketLimiter.java | 32 +++ .../limiter/SimpleBytesPerSecondLimiter.java | 77 ++++++ .../netty/MinecraftVarintFrameDecoder.java | 16 ++ .../proxy/util/IntervalledCounter.java | 252 ++++++++++++++++++ .../src/main/resources/default-velocity.toml | 5 + 7 files changed, 436 insertions(+), 2 deletions(-) create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/network/limiter/PacketLimiter.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/network/limiter/SimpleBytesPerSecondLimiter.java create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/util/IntervalledCounter.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java index 8dd8d327..e198a071 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java @@ -94,6 +94,8 @@ public class VelocityConfiguration implements ProxyConfig { private @Nullable Favicon favicon; @Expose private boolean forceKeyAuthentication = true; // Added in 1.19 + @Expose + private PacketLimiterConfig packetLimiterConfig = PacketLimiterConfig.DEFAULT; private VelocityConfiguration(Servers servers, ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics) { @@ -110,7 +112,7 @@ public class VelocityConfiguration implements ProxyConfig { boolean onlineModeKickExistingPlayers, PingPassthroughMode pingPassthrough, boolean samplePlayersInPing, boolean enablePlayerAddressLogging, Servers servers, ForcedHosts forcedHosts, Advanced advanced, Query query, Metrics metrics, - boolean forceKeyAuthentication) { + boolean forceKeyAuthentication, PacketLimiterConfig packetLimiterConfig) { this.bind = bind; this.motd = motd; this.showMaxPlayers = showMaxPlayers; @@ -129,6 +131,7 @@ public class VelocityConfiguration implements ProxyConfig { this.query = query; this.metrics = metrics; this.forceKeyAuthentication = forceKeyAuthentication; + this.packetLimiterConfig = packetLimiterConfig; } /** @@ -447,6 +450,10 @@ public class VelocityConfiguration implements ProxyConfig { return advanced.isEnableReusePort(); } + public PacketLimiterConfig getPacketLimiterConfig() { + return packetLimiterConfig; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) @@ -464,6 +471,7 @@ public class VelocityConfiguration implements ProxyConfig { .add("favicon", favicon) .add("enablePlayerAddressLogging", enablePlayerAddressLogging) .add("forceKeyAuthentication", forceKeyAuthentication) + .add("packetLimiterConfig", packetLimiterConfig) .toString(); } @@ -560,6 +568,7 @@ public class VelocityConfiguration implements ProxyConfig { final boolean kickExisting = config.getOrElse("kick-existing-players", false); final boolean enablePlayerAddressLogging = config.getOrElse( "enable-player-address-logging", true); + final PacketLimiterConfig packetLimiterConfig = PacketLimiterConfig.fromConfig(config.get("packet-limiter")); // Throw an exception if the forwarding-secret file is empty and the proxy is using a // forwarding mode that requires it. @@ -587,7 +596,8 @@ public class VelocityConfiguration implements ProxyConfig { new Advanced(advancedConfig), new Query(queryConfig), new Metrics(metricsConfig), - forceKeyAuthentication + forceKeyAuthentication, + packetLimiterConfig ); } } @@ -990,4 +1000,33 @@ public class VelocityConfiguration implements ProxyConfig { return enabled; } } + + /** + * Configuration for packet limiting. + * + * @param interval the interval in seconds to measure packets over + * @param pps the maximum number of packets per second allowed + * @param bytes the maximum number of bytes per second allowed + */ + public record PacketLimiterConfig(int interval, int pps, int bytes) { + public static PacketLimiterConfig DEFAULT = new PacketLimiterConfig(7, 500, -1); + + /** + * returns a PacketLimiterConfig from a config section, or the default if the section is null. + * + * @param config the configuration object to parse + * @return the packet limiter config, or the default if {@code config} is null + */ + public static PacketLimiterConfig fromConfig(CommentedConfig config) { + if (config != null) { + return new PacketLimiterConfig( + config.getIntOrElse("interval", DEFAULT.interval()), + config.getIntOrElse("packets-per-second", DEFAULT.pps()), + config.getIntOrElse("bytes-per-second", DEFAULT.bytes()) + ); + } else { + return DEFAULT; + } + } + } } 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 0c22dcce..fae9113f 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/ServerChannelInitializer.java @@ -26,8 +26,10 @@ import static com.velocitypowered.proxy.network.Connections.MINECRAFT_ENCODER; import static com.velocitypowered.proxy.network.Connections.READ_TIMEOUT; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.config.VelocityConfiguration; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; +import com.velocitypowered.proxy.network.limiter.SimpleBytesPerSecondLimiter; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.netty.LegacyPingDecoder; @@ -72,6 +74,17 @@ public class ServerChannelInitializer extends ChannelInitializer { new HandshakeSessionHandler(connection, this.server)); ch.pipeline().addLast(Connections.HANDLER, connection); + VelocityConfiguration.PacketLimiterConfig packetLimiterConfig = + server.getConfiguration().getPacketLimiterConfig(); + int configuredInterval = packetLimiterConfig.interval(); + int configuredPacketsPerSecond = packetLimiterConfig.pps(); + int configuredBytes = packetLimiterConfig.bytes(); + + if (configuredInterval > 0 && (configuredBytes > 0 || configuredPacketsPerSecond > 0)) { + ch.pipeline().get(MinecraftVarintFrameDecoder.class).setPacketLimiter( + new SimpleBytesPerSecondLimiter(configuredPacketsPerSecond, configuredBytes, configuredInterval) + ); + } if (this.server.getConfiguration().isProxyProtocol()) { ch.pipeline().addFirst(new HAProxyMessageDecoder()); } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/limiter/PacketLimiter.java b/proxy/src/main/java/com/velocitypowered/proxy/network/limiter/PacketLimiter.java new file mode 100644 index 00000000..e63a0c8b --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/limiter/PacketLimiter.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2025 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.network.limiter; + +/** + * PacketLimiter enforces a limit on the number of bytes processed over a time window. + * Implementations should be thread-safe. + */ +public interface PacketLimiter { + /** + * Attempts to record the specified number of bytes within the current window. + * + * @param bytes the number of bytes to record + * @return true if the bytes are allowed and recorded; false if the limit would be exceeded + */ + boolean account(int bytes); +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/network/limiter/SimpleBytesPerSecondLimiter.java b/proxy/src/main/java/com/velocitypowered/proxy/network/limiter/SimpleBytesPerSecondLimiter.java new file mode 100644 index 00000000..1c6701be --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/network/limiter/SimpleBytesPerSecondLimiter.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2025 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.network.limiter; + +import com.velocitypowered.proxy.util.IntervalledCounter; +import org.jspecify.annotations.Nullable; + +/** + * A moving-window limiter over a configurable number of seconds. + * It enforces both packets-per-second and average bytes-per-second limits. + * The effective cap over the full window equals limitPerSecond * windowSeconds. + */ +public final class SimpleBytesPerSecondLimiter implements PacketLimiter { + @Nullable + private final IntervalledCounter bytesCounter; + @Nullable + private final IntervalledCounter packetsCounter; + private final int packetsPerSecond; + private final int bytesPerSecond; + + /** + * Creates a new SimpleBytesPerSecondLimiter. + * + * @param packetsPerSecond maximum average packets per second allowed (> 0) + * @param bytesPerSecond maximum average bytes per second allowed (> 0) + * @param windowSeconds number of seconds in the moving window (> 0) + */ + public SimpleBytesPerSecondLimiter(int packetsPerSecond, int bytesPerSecond, int windowSeconds) { + this.packetsPerSecond = packetsPerSecond; + if (windowSeconds <= 0) { + throw new IllegalArgumentException("windowSeconds must be > 0"); + } + this.bytesPerSecond = bytesPerSecond; + this.packetsCounter = packetsPerSecond > 0 ? new IntervalledCounter((long) (windowSeconds * 1.0e9)) : null; + this.bytesCounter = bytesPerSecond > 0 ? new IntervalledCounter((long) (windowSeconds * 1.0e9)) : null; + + } + + /** + * Records the given payload length as one packet and returns whether it is allowed. + */ + @SuppressWarnings("RedundantIfStatement") + @Override + public boolean account(int bytes) { + long currTime = System.nanoTime(); + if (packetsCounter != null) { + packetsCounter.updateAndAdd(1, currTime); + if (packetsCounter.getRate() > packetsPerSecond) { + return false; + } + } + + if (bytesCounter != null) { + bytesCounter.updateAndAdd(bytes, currTime); + if (bytesCounter.getRate() > bytesPerSecond) { + return false; + } + } + + return true; + } +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java index 71ac4fcc..96c67659 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java @@ -20,6 +20,7 @@ package com.velocitypowered.proxy.protocol.netty; import static io.netty.util.ByteProcessor.FIND_NON_NUL; import com.velocitypowered.api.network.ProtocolVersion; +import com.velocitypowered.proxy.network.limiter.PacketLimiter; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; @@ -32,6 +33,7 @@ import io.netty.handler.codec.CorruptedFrameException; import java.util.List; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jspecify.annotations.Nullable; /** * Frames Minecraft server packets which are prefixed by a 21-bit VarInt encoding. @@ -54,6 +56,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { private final ProtocolUtils.Direction direction; private final StateRegistry.PacketRegistry.ProtocolRegistry registry; private StateRegistry state; + @Nullable + private PacketLimiter packetLimiter; /** * Creates a new {@code MinecraftVarintFrameDecoder} decoding packets from the specified {@code Direction}. @@ -113,6 +117,14 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { if (in.readableBytes() < length) { in.resetReaderIndex(); } else { + // If enabled, rate-limit serverbound payload bytes based on frame length + if (packetLimiter != null) { + if (!packetLimiter.account(length)) { + throw new QuietDecoderException( + "Rate limit exceeded while processing packets for %s".formatted( + ctx.channel().remoteAddress())); + } + } out.add(in.readRetainedSlice(length)); } } @@ -265,4 +277,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { public void setState(StateRegistry stateRegistry) { this.state = stateRegistry; } + + public void setPacketLimiter(@Nullable PacketLimiter packetLimiter) { + this.packetLimiter = packetLimiter; + } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/util/IntervalledCounter.java b/proxy/src/main/java/com/velocitypowered/proxy/util/IntervalledCounter.java new file mode 100644 index 00000000..9b986dca --- /dev/null +++ b/proxy/src/main/java/com/velocitypowered/proxy/util/IntervalledCounter.java @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2025 Velocity Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.velocitypowered.proxy.util; + +/** + * IntervalledCounter maintains a rolling sum of values associated with timestamps, keeping + * only those entries that fall within a fixed time interval from the most recent timestamp. + * + *

      Time values must be provided in the same unit as {@link System#nanoTime()} (nanoseconds), + * and the configured interval is also expressed in nanoseconds. Callers are expected to + * periodically advance the counter to the current time using {@link #updateCurrentTime()} or + * {@link #updateCurrentTime(long)} to evict expired entries before adding new ones via + * {@link #addTime(long)} or {@link #addTime(long, long)}.

      + * + *

      This class is not thread-safe. If multiple threads access an instance concurrently, + * external synchronization is required.

      + */ +@SuppressWarnings("checkstyle:WhitespaceAfter") // Not our class +public final class IntervalledCounter { + + private static final int INITIAL_SIZE = 8; + + /** + * Ring buffer holding the timestamp (in nanoseconds) for each data point. + */ + protected long[] times; + /** + * Ring buffer holding the count associated with each timestamp. + */ + protected long[] counts; + /** + * The sliding window size in nanoseconds. Only entries with time >= (currentTime - interval) + * are considered part of the window. + */ + protected final long interval; + /** + * Cached lower bound of the window (in nanoseconds) after the last update. + */ + protected long minTime; + /** + * Running sum of all counts currently within the window. + */ + protected long sum; + /** + * Head index (inclusive) of the ring buffer. + */ + protected int head; // inclusive + /** + * Tail index (exclusive) of the ring buffer. + */ + protected int tail; // exclusive + + /** + * Creates a new counter with the specified interval. + * + * @param interval the window size in nanoseconds (compatible with {@link System#nanoTime()}) + */ + public IntervalledCounter(final long interval) { + this.times = new long[INITIAL_SIZE]; + this.counts = new long[INITIAL_SIZE]; + this.interval = interval; + } + + /** + * Advances the window to the current time using {@link System#nanoTime()}, evicting any + * data points that have fallen outside of the interval and updating the running sum. + */ + public void updateCurrentTime() { + this.updateCurrentTime(System.nanoTime()); + } + + /** + * Advances the window to the provided time, evicting any data points older than + * {@code currentTime - interval} and updating the running sum. + * + * @param currentTime the current time in nanoseconds (as from {@link System#nanoTime()}) + */ + public void updateCurrentTime(final long currentTime) { + long sum = this.sum; + int head = this.head; + final int tail = this.tail; + final long minTime = currentTime - this.interval; + + final int arrayLen = this.times.length; + + // guard against overflow by using subtraction + while (head != tail && this.times[head] - minTime < 0) { + sum -= this.counts[head]; + // there are two ways we can do this: + // 1. free the count when adding + // 2. free it now + // option #2 + this.counts[head] = 0; + if (++head >= arrayLen) { + head = 0; + } + } + + this.sum = sum; + this.head = head; + this.minTime = minTime; + } + + /** + * Adds a single unit at the specified timestamp, assuming the timestamp is within the current + * window. If the timestamp is older than the current window lower bound, the value is ignored. + * This method does not automatically advance the window; callers should invoke + * {@link #updateCurrentTime()} or {@link #updateCurrentTime(long)} beforehand. + * + * @param currTime the timestamp in nanoseconds + */ + public void addTime(final long currTime) { + this.addTime(currTime, 1L); + } + + /** + * Adds {@code count} units at the specified timestamp, assuming the timestamp is within the + * current window. If the timestamp is older than {@code minTime}, the value is ignored. + * This method does not automatically advance the window; callers should invoke + * {@link #updateCurrentTime()} or {@link #updateCurrentTime(long)} beforehand. + * + * @param currTime the timestamp in nanoseconds + * @param count the amount to add (non-negative) + */ + public void addTime(final long currTime, final long count) { + // guard against overflow by using subtraction + if (currTime - this.minTime < 0) { + return; + } + int nextTail = (this.tail + 1) % this.times.length; + if (nextTail == this.head) { + this.resize(); + nextTail = (this.tail + 1) % this.times.length; + } + + this.times[this.tail] = currTime; + this.counts[this.tail] += count; + this.sum += count; + this.tail = nextTail; + } + + /** + * Convenience method that advances the window to the current time and then adds {@code count} + * units at that time. + * + * @param count the amount to add (non-negative) + */ + public void updateAndAdd(final long count) { + final long currTime = System.nanoTime(); + this.updateCurrentTime(currTime); + this.addTime(currTime, count); + } + + /** + * Convenience method that advances the window to {@code currTime} and then adds {@code count} + * units at that time. + * + * @param count the amount to add (non-negative) + * @param currTime the timestamp in nanoseconds + */ + public void updateAndAdd(final long count, final long currTime) { + this.updateCurrentTime(currTime); + this.addTime(currTime, count); + } + + /** + * Doubles the capacity of the internal ring buffers, preserving the order of existing data. + */ + private void resize() { + final long[] oldElements = this.times; + final long[] oldCounts = this.counts; + final long[] newElements = new long[this.times.length * 2]; + final long[] newCounts = new long[this.times.length * 2]; + this.times = newElements; + this.counts = newCounts; + + final int head = this.head; + final int tail = this.tail; + final int size = tail >= head ? (tail - head) : (tail + (oldElements.length - head)); + this.head = 0; + this.tail = size; + + if (tail >= head) { + // sequentially ordered from [head, tail) + System.arraycopy(oldElements, head, newElements, 0, size); + System.arraycopy(oldCounts, head, newCounts, 0, size); + } else { + // ordered from [head, length) + // then followed by [0, tail) + + System.arraycopy(oldElements, head, newElements, 0, oldElements.length - head); + System.arraycopy(oldElements, 0, newElements, oldElements.length - head, tail); + + System.arraycopy(oldCounts, head, newCounts, 0, oldCounts.length - head); + System.arraycopy(oldCounts, 0, newCounts, oldCounts.length - head, tail); + } + } + + /** + * Returns the current rate in units per second based on the rolling sum and the configured + * interval. Specifically: {@code sum / (intervalSeconds)} where {@code intervalSeconds} + * equals {@code interval / 1e9}. + * + * @return the rate in units per second for the current window + */ + public double getRate() { + return (double)this.sum / ((double)this.interval * 1.0E-9); + } + + /** + * Returns the configured interval size in nanoseconds. + * + * @return the interval size in nanoseconds + */ + public long getInterval() { + return this.interval; + } + + /** + * Returns the rolling sum of all counts currently within the window. + * + * @return the rolling sum + */ + public long getSum() { + return this.sum; + } + + /** + * Returns the number of data points currently stored in the internal ring buffer. This may be + * less than or equal to the number of points added since older entries may have been evicted. + * + * @return the number of stored data points + */ + public int totalDataPoints() { + return this.tail >= this.head ? (this.tail - this.head) : (this.tail + (this.counts.length - this.head)); + } +} diff --git a/proxy/src/main/resources/default-velocity.toml b/proxy/src/main/resources/default-velocity.toml index 4d71e589..6aa5ceaa 100644 --- a/proxy/src/main/resources/default-velocity.toml +++ b/proxy/src/main/resources/default-velocity.toml @@ -74,6 +74,11 @@ sample-players-in-ping = false # If not enabled (default is true) player IP addresses will be replaced by in logs enable-player-address-logging = true +[packet-limiter] +interval = 7 +packets-per-second = 500 +bytes-per-second = -1 + [servers] # Configure your servers here. Each key represents the server's name, and the value # represents the IP address of the server to connect to. From 9890c429c68b3fe61347fbb3241eeac2f0ea20d0 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Wed, 8 Apr 2026 21:12:41 +0100 Subject: [PATCH 37/48] Add compression ratio limiter --- .../proxy/protocol/netty/MinecraftCompressDecoder.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index 9bd040ef..edd0f4c2 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -44,6 +44,7 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { Boolean.getBoolean("velocity.increased-compression-cap") ? HARD_MAXIMUM_UNCOMPRESSED_SIZE : SERVERBOUND_MAXIMUM_UNCOMPRESSED_SIZE; private static final boolean SKIP_COMPRESSION_VALIDATION = Boolean.getBoolean("velocity.skip-uncompressed-packet-size-validation"); + private static final double MAX_COMPRESSION_RATIO = Double.parseDouble(System.getProperty("velocity.max-compression-ratio", "10")); private final ProtocolUtils.Direction direction; private int threshold; @@ -68,6 +69,7 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { out.add(in.retain()); return; } + int length = in.readableBytes(); checkFrame(claimedUncompressedSize >= threshold, "Uncompressed size %s is less than" + " threshold %s", claimedUncompressedSize, threshold); @@ -79,6 +81,10 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { checkFrame(claimedUncompressedSize <= SERVERBOUND_UNCOMPRESSED_CAP, "Uncompressed size %s exceeds hard threshold of %s", claimedUncompressedSize, SERVERBOUND_UNCOMPRESSED_CAP); + double maxCompressedAllowed = length * MAX_COMPRESSION_RATIO; + checkFrame(claimedUncompressedSize <= maxCompressedAllowed, + "Uncompressed size %s exceeds ratio threshold of %s for compressed sized %s", claimedUncompressedSize, + maxCompressedAllowed, length); } ByteBuf compatibleIn = ensureCompatible(ctx.alloc(), compressor, in); ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize); From 6f01587318856e8133d871b7c42dded802b89955 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Wed, 8 Apr 2026 21:19:27 +0100 Subject: [PATCH 38/48] Appease checkstyle --- .../proxy/connection/MinecraftConnection.java | 1 - .../proxy/protocol/netty/MinecraftCompressDecoder.java | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) 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 151cbd30..c455e427 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -38,7 +38,6 @@ import com.velocitypowered.proxy.connection.client.InitialLoginSessionHandler; import com.velocitypowered.proxy.connection.client.StatusSessionHandler; import com.velocitypowered.proxy.network.Connections; import com.velocitypowered.proxy.protocol.MinecraftPacket; -import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.VelocityConnectionEvent; import com.velocitypowered.proxy.protocol.netty.MinecraftCipherDecoder; diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index edd0f4c2..2528c0fd 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -50,6 +50,13 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { private int threshold; private final VelocityCompressor compressor; + /** + * Creates a new {@code MinecraftCompressDecoder} with the specified compression {@code threshold}. + * + * @param threshold the threshold for compression. Packets with uncompressed size below this threshold will not be compressed. + * @param compressor the compressor instance to use + * @param direction the direction of the packets being decoded + */ public MinecraftCompressDecoder(int threshold, VelocityCompressor compressor, ProtocolUtils.Direction direction) { this.threshold = threshold; this.compressor = compressor; From b1a1b8bda3068307a03b114845efe4ca383ad57d Mon Sep 17 00:00:00 2001 From: Harold <55301634+ZECHEESELORD@users.noreply.github.com> Date: Wed, 8 Apr 2026 18:27:02 -0400 Subject: [PATCH 39/48] use outbound only queueing when reentering configuration (#1747) * use outbound only queueing and guard serverbound forwarding during reconfiguration --- .../proxy/connection/MinecraftConnection.java | 30 +++++++++++++++---- .../client/ClientPlaySessionHandler.java | 12 ++++++-- .../connection/client/ConnectedPlayer.java | 15 +++++++--- 3 files changed, 45 insertions(+), 12 deletions(-) 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 c455e427..8a6a22e9 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -33,6 +33,7 @@ import com.velocitypowered.natives.encryption.VelocityCipher; import com.velocitypowered.natives.encryption.VelocityCipherFactory; import com.velocitypowered.natives.util.Natives; import com.velocitypowered.proxy.VelocityServer; +import com.velocitypowered.proxy.connection.client.ConnectedPlayer; import com.velocitypowered.proxy.connection.client.HandshakeSessionHandler; import com.velocitypowered.proxy.connection.client.InitialLoginSessionHandler; import com.velocitypowered.proxy.connection.client.StatusSessionHandler; @@ -368,6 +369,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { public void setState(StateRegistry state) { ensureInEventLoop(); + final StateRegistry previousState = this.state; this.state = state; final MinecraftVarintFrameDecoder frameDecoder = this.channel.pipeline() .get(MinecraftVarintFrameDecoder.class); @@ -388,7 +390,13 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { if (state == StateRegistry.CONFIG) { // Activate the play packet queue - addPlayPacketQueueHandler(); + if (previousState == StateRegistry.PLAY + && this.pendingConfigurationSwitch + && this.association instanceof ConnectedPlayer) { + addPlayPacketQueueOutboundHandler(); + } else { + addPlayPacketQueueHandler(); + } } else { // Remove the queue if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE_OUTBOUND) != null) { @@ -404,13 +412,23 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { * Adds the play packet queue handler. */ public void addPlayPacketQueueHandler() { - if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE_OUTBOUND) == null) { - this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE_OUTBOUND, - new PlayPacketQueueOutboundHandler(this.protocolVersion, channel.pipeline().get(MinecraftEncoder.class).getDirection())); - } + addPlayPacketQueueOutboundHandler(); + if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE_INBOUND) == null) { this.channel.pipeline().addAfter(Connections.MINECRAFT_DECODER, Connections.PLAY_PACKET_QUEUE_INBOUND, - new PlayPacketQueueInboundHandler(this.protocolVersion, channel.pipeline().get(MinecraftDecoder.class).getDirection())); + new PlayPacketQueueInboundHandler(this.protocolVersion, + channel.pipeline().get(MinecraftDecoder.class).getDirection())); + } + } + + /** + * Adds only the outbound play packet queue handler. + */ + public void addPlayPacketQueueOutboundHandler() { + if (this.channel.pipeline().get(Connections.PLAY_PACKET_QUEUE_OUTBOUND) == null) { + this.channel.pipeline().addAfter(Connections.MINECRAFT_ENCODER, Connections.PLAY_PACKET_QUEUE_OUTBOUND, + new PlayPacketQueueOutboundHandler(this.protocolVersion, + channel.pipeline().get(MinecraftEncoder.class).getDirection())); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index fb13271b..a3485983 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -470,7 +470,11 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } MinecraftConnection smc = serverConnection.getConnection(); - if (smc != null && serverConnection.getPhase().consideredComplete()) { + final boolean stateAllowsForward = smc != null + && !smc.isClosed() + && serverConnection.getPhase().consideredComplete() + && smc.getState() == StateRegistry.PLAY; + if (stateAllowsForward) { if (packet instanceof PluginMessagePacket) { ((PluginMessagePacket) packet).retain(); } @@ -487,7 +491,11 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } MinecraftConnection smc = serverConnection.getConnection(); - if (smc != null && !smc.isClosed() && serverConnection.getPhase().consideredComplete()) { + final boolean stateAllowsForward = smc != null + && !smc.isClosed() + && serverConnection.getPhase().consideredComplete() + && smc.getState() == StateRegistry.PLAY; + if (stateAllowsForward) { smc.write(buf.retain()); } } 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 d6deeaef..47d59a71 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 @@ -1349,11 +1349,17 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, final Long sentTime = serverConnection.getPendingPings().remove(packet.getRandomId()); if (sentTime != null) { final MinecraftConnection smc = serverConnection.getConnection(); - if (smc != null) { + final StateRegistry clientState = connection.getState(); + final boolean stateAllowsForward = smc != null + && !smc.isClosed() + && clientState == smc.getState() + && (clientState == StateRegistry.CONFIG || clientState == StateRegistry.PLAY); + if (stateAllowsForward) { setPing(TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - sentTime)); smc.write(packet); - return true; } + // We removed this, and so this is ours + return true; } } return false; @@ -1363,7 +1369,8 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, * Switches the connection to the client into config state. */ public void switchToConfigState() { - server.getEventManager().fire(new PlayerEnterConfigurationEvent(this, getConnectionInFlightOrConnectedServer())) + final VelocityServerConnection targetServer = getConnectionInFlightOrConnectedServer(); + server.getEventManager().fire(new PlayerEnterConfigurationEvent(this, targetServer)) .completeOnTimeout(null, 5, TimeUnit.SECONDS).thenRunAsync(() -> { // if the connection was closed earlier, there is a risk that the player is no longer connected if (!connection.getChannel().isActive()) { @@ -1378,7 +1385,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player, connection.pendingConfigurationSwitch = true; 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.addPlayPacketQueueOutboundHandler(); }, connection.eventLoop()).exceptionally((ex) -> { logger.error("Error switching player connection to config state", ex); return null; From 6ce432e4aeea9eddaf7ebbc1158daefe3e53bf5b Mon Sep 17 00:00:00 2001 From: R00tB33rMan <36140389+R00tB33rMan@users.noreply.github.com> Date: Thu, 9 Apr 2026 10:50:01 -0400 Subject: [PATCH 40/48] Handle configuration/transition-phase disconnects as connection errors to prevent bricking older client versions (#1753) --- .../proxy/connection/backend/ConfigSessionHandler.java | 7 +++---- .../proxy/connection/backend/TransitionSessionHandler.java | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java index e523f0f7..8cc1bf8c 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/ConfigSessionHandler.java @@ -61,7 +61,6 @@ import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import java.io.IOException; import java.net.InetSocketAddress; import java.util.concurrent.CompletableFuture; import net.kyori.adventure.key.Key; @@ -377,8 +376,8 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { @Override public void disconnected() { - resultFuture.completeExceptionally( - new IOException("Unexpectedly disconnected from remote server")); + resultFuture.complete(ConnectionRequestResults.forDisconnect( + ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR, serverConn.getServer())); } @Override @@ -415,4 +414,4 @@ public class ConfigSessionHandler implements MinecraftSessionHandler { public enum State { START, NEGOTIATING, PLUGIN_MESSAGE_INTERRUPT, RESOURCE_PACK_INTERRUPT, COMPLETE } -} \ No newline at end of file +} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java index e713769a..cfcd8f5e 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/TransitionSessionHandler.java @@ -38,7 +38,6 @@ import com.velocitypowered.proxy.protocol.packet.DisconnectPacket; import com.velocitypowered.proxy.protocol.packet.JoinGamePacket; import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket; import com.velocitypowered.proxy.protocol.packet.PluginMessagePacket; -import java.io.IOException; import java.util.concurrent.CompletableFuture; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -213,7 +212,7 @@ public class TransitionSessionHandler implements MinecraftSessionHandler { @Override public void disconnected() { - resultFuture - .completeExceptionally(new IOException("Unexpectedly disconnected from remote server")); + resultFuture.complete(ConnectionRequestResults.forDisconnect( + ConnectionMessages.INTERNAL_SERVER_CONNECTION_ERROR, serverConn.getServer())); } } From affc1d6e08e4e324bdfe2be788dc8cc7535bca5f Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Thu, 9 Apr 2026 19:03:33 +0100 Subject: [PATCH 41/48] Extend debug logging to client play/config handlers --- .../proxy/connection/client/ClientConfigSessionHandler.java | 4 ++++ .../proxy/connection/client/ClientPlaySessionHandler.java | 4 ++++ 2 files changed, 8 insertions(+) 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 29928582..7c6032c7 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 @@ -33,6 +33,7 @@ import com.velocitypowered.proxy.connection.player.resourcepack.ResourcePackResp import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder; import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket; import com.velocitypowered.proxy.protocol.packet.KeepAlivePacket; @@ -268,6 +269,9 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler { @Override public void exception(Throwable throwable) { player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + if (MinecraftDecoder.DEBUG) { + logger.info("Exception while handling plugin message packet for {}", player, throwable); + } } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index a3485983..c03d31ae 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -41,6 +41,7 @@ import com.velocitypowered.proxy.connection.forge.legacy.LegacyForgeConstants; import com.velocitypowered.proxy.connection.player.resourcepack.ResourcePackResponseBundle; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.StateRegistry; +import com.velocitypowered.proxy.protocol.netty.MinecraftDecoder; import com.velocitypowered.proxy.protocol.packet.BossBarPacket; import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket; import com.velocitypowered.proxy.protocol.packet.JoinGamePacket; @@ -509,6 +510,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { public void exception(Throwable throwable) { player.disconnect( Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + if (MinecraftDecoder.DEBUG) { + logger.info("Exception while handling plugin message packet for {}", player, throwable); + } } @Override From e834af9cf10d6c13703cb9ff6f349e196cb3d2bd Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Thu, 9 Apr 2026 19:04:02 +0100 Subject: [PATCH 42/48] Increase max ratio Older versions of the game, and creative mode, send itemstacks to the server when dealing with itemstacks, annoying, the compression algo used is good at backreferencing, which means that compressed data can balloon pretty well. 64 should more than cover most cases of legit data, we could probably be more harsh here, but this is likely a fine balance between avoiding bombs and not erring out on legit data. --- .../proxy/protocol/netty/MinecraftCompressDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index 2528c0fd..59cb00ea 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -44,7 +44,7 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { Boolean.getBoolean("velocity.increased-compression-cap") ? HARD_MAXIMUM_UNCOMPRESSED_SIZE : SERVERBOUND_MAXIMUM_UNCOMPRESSED_SIZE; private static final boolean SKIP_COMPRESSION_VALIDATION = Boolean.getBoolean("velocity.skip-uncompressed-packet-size-validation"); - private static final double MAX_COMPRESSION_RATIO = Double.parseDouble(System.getProperty("velocity.max-compression-ratio", "10")); + private static final double MAX_COMPRESSION_RATIO = Double.parseDouble(System.getProperty("velocity.max-compression-ratio", "64")); private final ProtocolUtils.Direction direction; private int threshold; From 1a41b77ccb92e58a9c1e728c81c9e3aa3976e3e1 Mon Sep 17 00:00:00 2001 From: Aaron <71191102+RealBauHD@users.noreply.github.com> Date: Fri, 10 Apr 2026 18:01:39 +0200 Subject: [PATCH 43/48] Add 26.1.2 version string to 26.1 protocol version (#1769) --- .../java/com/velocitypowered/api/network/ProtocolVersion.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java index 51b2f46a..b166291b 100644 --- a/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java +++ b/api/src/main/java/com/velocitypowered/api/network/ProtocolVersion.java @@ -95,7 +95,7 @@ public enum ProtocolVersion implements Ordered { MINECRAFT_1_21_7(772, "1.21.7", "1.21.8"), MINECRAFT_1_21_9(773, "1.21.9", "1.21.10"), MINECRAFT_1_21_11(774, "1.21.11"), - MINECRAFT_26_1(775, "26.1", "26.1.1"); + MINECRAFT_26_1(775, "26.1", "26.1.1", "26.1.2"); private static final int SNAPSHOT_BIT = 30; From 339a4c1887ef2e8308f737d12547c13c7e63e9d9 Mon Sep 17 00:00:00 2001 From: booky Date: Sun, 12 Apr 2026 21:18:42 +0200 Subject: [PATCH 44/48] Fix some small protocol inconsistencies (#1772) --- .../proxy/connection/MinecraftConnection.java | 4 +- .../protocol/netty/MinecraftDecoder.java | 34 +++++----- .../netty/MinecraftVarintFrameDecoder.java | 65 +++++++++---------- 3 files changed, 47 insertions(+), 56 deletions(-) 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 8a6a22e9..0071716d 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftConnection.java @@ -67,7 +67,7 @@ import io.netty.util.ReferenceCountUtil; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.security.GeneralSecurityException; -import java.util.HashMap; +import java.util.EnumMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -109,7 +109,7 @@ public class MinecraftConnection extends ChannelInboundHandlerAdapter { this.server = server; this.state = StateRegistry.HANDSHAKE; - this.sessionHandlers = new HashMap<>(); + this.sessionHandlers = new EnumMap<>(StateRegistry.class); } @Override diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java index ae84e749..ce0d3426 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftDecoder.java @@ -57,7 +57,11 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { if (msg instanceof ByteBuf buf) { - tryDecode(ctx, buf); + try { + tryDecode(ctx, buf); + } finally { + buf.release(); + } } else { ctx.fireChannelRead(msg); } @@ -65,7 +69,6 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter { private void tryDecode(ChannelHandlerContext ctx, ByteBuf buf) throws Exception { if (!ctx.channel().isActive() || !buf.isReadable()) { - buf.release(); return; } @@ -75,27 +78,22 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter { if (packet == null) { buf.readerIndex(originalReaderIndex); if (this.direction == ProtocolUtils.Direction.SERVERBOUND && this.state != StateRegistry.PLAY) { - buf.release(); throw this.handleInvalidPacketId(packetId); } - ctx.fireChannelRead(buf); + ctx.fireChannelRead(buf.retain()); } else { + doLengthSanityChecks(buf, packet); + try { - doLengthSanityChecks(buf, packet); - - try { - packet.decode(buf, direction, registry.version); - } catch (Exception e) { - throw handleDecodeFailure(e, packet, packetId); - } - - if (buf.isReadable()) { - throw handleOverflow(packet, buf.readerIndex(), buf.writerIndex()); - } - ctx.fireChannelRead(packet); - } finally { - buf.release(); + packet.decode(buf, direction, registry.version); + } catch (Exception e) { + throw handleDecodeFailure(e, packet, packetId); } + + if (buf.isReadable()) { + throw handleOverflow(packet, buf.readerIndex(), buf.writerIndex()); + } + ctx.fireChannelRead(packet); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java index 96c67659..56c58619 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftVarintFrameDecoder.java @@ -94,7 +94,6 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { in.readerIndex(packetStart); // try to read the length of the packet - in.markReaderIndex(); try { int length = readRawVarInt21(in); if (packetStart == in.readerIndex()) { @@ -107,6 +106,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { if (length > 0) { if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) { if (validateServerboundHandshakePacket(in, length)) { + in.readerIndex(packetStart); return; } } @@ -115,7 +115,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { // note that zero-length packets are ignored if (length > 0) { if (in.readableBytes() < length) { - in.resetReaderIndex(); + in.readerIndex(packetStart); } else { // If enabled, rate-limit serverbound payload bytes based on frame length if (packetLimiter != null) { @@ -130,7 +130,7 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { } } catch (Exception e) { // Reset buffer to consistent state before propagating exception to prevent memory leaks - in.resetReaderIndex(); + in.readerIndex(packetStart); throw e; } } @@ -140,40 +140,33 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder { state.getProtocolRegistry(direction, ProtocolVersion.MINIMUM_VERSION); final int index = in.readerIndex(); - try { - final int packetId = readRawVarInt21(in); - // Index hasn't changed, we've read nothing - if (index == in.readerIndex()) { - in.resetReaderIndex(); - return true; - } - final int payloadLength = length - ProtocolUtils.varIntBytes(packetId); - - MinecraftPacket packet = registry.createPacket(packetId); - - // We handle every packet in this phase, if you said something we don't know, something is really wrong - if (packet == null) { - throw UNKNOWN_PACKET; - } - - // We 'technically' have the incoming bytes of a payload here, and so, these can actually parse - // the packet if needed, so, we'll take advantage of the existing methods - int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version); - int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version); - if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) { - throw handleOverflow(packet, expectedMaxLen, in.readableBytes()); - } - if (payloadLength < expectedMinLen) { - throw handleUnderflow(packet, expectedMaxLen, in.readableBytes()); - } - - in.readerIndex(index); - return false; - } catch (Exception e) { - // Reset buffer to consistent state before propagating exception to prevent memory leaks - in.readerIndex(index); - throw e; + final int packetId = readRawVarInt21(in); + // Index hasn't changed, we've read nothing + if (index == in.readerIndex()) { + return true; } + final int payloadLength = length - ProtocolUtils.varIntBytes(packetId); + + MinecraftPacket packet = registry.createPacket(packetId); + + // We handle every packet in this phase, if you said something we don't know, something is really wrong + if (packet == null) { + throw UNKNOWN_PACKET; + } + + // We 'technically' have the incoming bytes of a payload here, and so, these can actually parse + // the packet if needed, so, we'll take advantage of the existing methods + int expectedMinLen = packet.decodeExpectedMinLength(in, direction, registry.version); + int expectedMaxLen = packet.decodeExpectedMaxLength(in, direction, registry.version); + if (expectedMaxLen != -1 && payloadLength > expectedMaxLen) { + throw handleOverflow(packet, expectedMaxLen, in.readableBytes()); + } + if (payloadLength < expectedMinLen) { + throw handleUnderflow(packet, expectedMaxLen, in.readableBytes()); + } + + in.readerIndex(index); + return false; } @Override From a6d97e28adb1b0cd6464bab78ed4e2c14835868f Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Mon, 13 Apr 2026 13:39:57 +0100 Subject: [PATCH 45/48] Validate compression claim --- .../proxy/protocol/netty/MinecraftCompressDecoder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java index 59cb00ea..90b747b0 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressDecoder.java @@ -97,6 +97,8 @@ public class MinecraftCompressDecoder extends MessageToMessageDecoder { ByteBuf uncompressed = preferredBuffer(ctx.alloc(), compressor, claimedUncompressedSize); try { compressor.inflate(compatibleIn, uncompressed, claimedUncompressedSize); + checkFrame(uncompressed.writerIndex() == claimedUncompressedSize, + "Decompressed size %s does not match claimed uncompressed size %s", uncompressed.writerIndex(), claimedUncompressedSize); out.add(uncompressed); } catch (Exception e) { uncompressed.release(); From f712997dd7f243cb3a0e55ec3f6277a10b6b1d69 Mon Sep 17 00:00:00 2001 From: Shane Freeder Date: Fri, 17 Apr 2026 21:03:04 +0100 Subject: [PATCH 46/48] Seperate client/serverbound payload limits --- .../backend/BackendPlaySessionHandler.java | 8 ++++++-- .../protocol/packet/PluginMessagePacket.java | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java index 6d37520b..dfe230e3 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/BackendPlaySessionHandler.java @@ -68,6 +68,7 @@ import com.velocitypowered.proxy.protocol.packet.TransferPacket; import com.velocitypowered.proxy.protocol.packet.UpsertPlayerInfoPacket; import com.velocitypowered.proxy.protocol.packet.chat.ComponentHolder; import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket; +import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder; import com.velocitypowered.proxy.protocol.util.PluginMessageUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; @@ -91,6 +92,7 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { Boolean.getBoolean("velocity.log-server-backpressure"); private static final int MAXIMUM_PACKETS_TO_FLUSH = Integer.getInteger("velocity.max-packets-per-flush", 8192); + private static final int LARGE_PACKET_THRESHOLD = 1024 * 128; private final VelocityServer server; private final VelocityServerConnection serverConn; @@ -455,8 +457,9 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { if (packet instanceof PluginMessagePacket pluginMessage) { pluginMessage.retain(); } + boolean huge = packet instanceof DeferredByteBufHolder def && def.content().readableBytes() > LARGE_PACKET_THRESHOLD; playerConnection.delayedWrite(packet); - if (++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) { + if (huge || ++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) { playerConnection.flush(); packetsFlushed = 0; } @@ -464,8 +467,9 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler { @Override public void handleUnknown(ByteBuf buf) { + boolean huge = buf.readableBytes() > LARGE_PACKET_THRESHOLD; playerConnection.delayedWrite(buf.retain()); - if (++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) { + if (huge || ++packetsFlushed >= MAXIMUM_PACKETS_TO_FLUSH) { playerConnection.flush(); packetsFlushed = 0; } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java index e2da28de..e779ab96 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/PluginMessagePacket.java @@ -31,7 +31,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; public class PluginMessagePacket extends DeferredByteBufHolder implements MinecraftPacket { - private static final int MAX_PAYLOAD_SIZE = Integer.getInteger("velocity.max-plugin-message-payload-size", 32767); + private static final int MAX_PAYLOAD_SIZE_CLIENTBOUND = getPayloadLimit(Direction.CLIENTBOUND); + private static final int MAX_PAYLOAD_SIZE_SERVERBOUND = getPayloadLimit(Direction.SERVERBOUND); private @Nullable String channel; @@ -52,6 +53,19 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr return channel; } + private static int getPayloadLimit(Direction direction) { + if (System.getProperty("velocity.max-plugin-message-payload-size") != null) { + return Integer.getInteger("velocity.max-plugin-message-payload-size"); + } + if (direction == Direction.SERVERBOUND) { + return Integer.getInteger("velocity.max-plugin-message-payload-size.serverbound", 32767); + } else { + // This is the vanilla expected limit, a payload this large feels like a nightmare given the trust + // we give to servers... + return Integer.getInteger("velocity.max-plugin-message-payload-size.clientbound", 1048576); + } + } + public void setChannel(String channel) { this.channel = channel; } @@ -104,7 +118,8 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr @Override public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) { - return ProtocolUtils.DEFAULT_MAX_STRING_BYTES + MAX_PAYLOAD_SIZE; + return ProtocolUtils.DEFAULT_MAX_STRING_BYTES + + (direction == Direction.CLIENTBOUND ? MAX_PAYLOAD_SIZE_CLIENTBOUND : MAX_PAYLOAD_SIZE_SERVERBOUND); } @Override From ad8de4361c9d6e93b818d3381e85b14e0c90ad05 Mon Sep 17 00:00:00 2001 From: Wouter Gritter Date: Fri, 1 May 2026 20:13:51 +0200 Subject: [PATCH 47/48] Fix wrong logs in exception(Throwable) (#1784) --- .../proxy/connection/client/ClientConfigSessionHandler.java | 2 +- .../proxy/connection/client/ClientPlaySessionHandler.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) 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 7c6032c7..e4c754f9 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 @@ -270,7 +270,7 @@ public class ClientConfigSessionHandler implements MinecraftSessionHandler { public void exception(Throwable throwable) { player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); if (MinecraftDecoder.DEBUG) { - logger.info("Exception while handling plugin message packet for {}", player, throwable); + logger.info("Exception while handling packet for {}", player, throwable); } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index c03d31ae..821c0987 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -508,10 +508,9 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { @Override public void exception(Throwable throwable) { - player.disconnect( - Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); + player.disconnect(Component.translatable("velocity.error.player-connection-error", NamedTextColor.RED)); if (MinecraftDecoder.DEBUG) { - logger.info("Exception while handling plugin message packet for {}", player, throwable); + logger.info("Exception while handling packet for {}", player, throwable); } } From 9c0c9b02187c20bb767ce16ac7685580430d9b10 Mon Sep 17 00:00:00 2001 From: Aaron <71191102+RealBauHD@users.noreply.github.com> Date: Sat, 9 May 2026 09:27:52 +0200 Subject: [PATCH 48/48] fix: outdated client message (#1763) --- .../proxy/connection/client/HandshakeSessionHandler.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java index 4fb4fa1f..83919b85 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/HandshakeSessionHandler.java @@ -45,7 +45,6 @@ import java.net.InetSocketAddress; import java.util.Optional; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.minimessage.translation.Argument; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.checkerframework.checker.nullness.qual.Nullable; @@ -128,10 +127,10 @@ public class HandshakeSessionHandler implements MinecraftSessionHandler { if (!handshake.getProtocolVersion().isSupported()) { // Bump connection into correct protocol state so that we can send the disconnect packet. connection.setState(StateRegistry.LOGIN); - ic.disconnectQuietly(Component.translatable() - .key("multiplayer.disconnect.outdated_client") - .arguments(Argument.string("versions", ProtocolVersion.SUPPORTED_VERSION_STRING)) - .build()); + ic.disconnectQuietly(Component.translatable( + "multiplayer.disconnect.outdated_client", + Component.text(ProtocolVersion.SUPPORTED_VERSION_STRING) + )); return; }