, Keyed, KeyIdentifiable, Sound.Emitter {
/**
* Returns the player's current username.
@@ -383,8 +384,12 @@ public interface Player extends
/**
* {@inheritDoc}
*
- * This method is not currently implemented in Velocity
- * and will not perform any actions.
+ *
+ * @apiNote This method is not currently implemented in Velocity
+ * and will not perform any actions.
+ * @see #playSound(Sound, Sound.Emitter)
+ * @see
+ * Unsupported Adventure Operations
*/
@Override
default void playSound(@NotNull Sound sound) {
@@ -393,8 +398,11 @@ public interface Player extends
/**
* {@inheritDoc}
*
- * This method is not currently implemented in Velocity
- * and will not perform any actions.
+ * @apiNote This method is not currently implemented in Velocity
+ * and will not perform any actions.
+ * @see #playSound(Sound, Sound.Emitter)
+ * @see
+ * Unsupported Adventure Operations
*/
@Override
default void playSound(@NotNull Sound sound, double x, double y, double z) {
@@ -403,18 +411,28 @@ public interface Player extends
/**
* {@inheritDoc}
*
- * This method is not currently implemented in Velocity
- * and will not perform any actions.
+ * Note: Due to MC-146721, stereo sounds are always played globally in 1.14+.
+ *
+ *
Note: Due to MC-138832, the volume and pitch are ignored when using this method in 1.14 to 1.16.5.
+ *
+ * @param sound the sound to play
+ * @param emitter the emitter of the sound; may be another player of this player's server
+ * @since 3.4.0
+ * @sinceMinecraft 1.19.3
+ * @apiNote This method is currently only implemented for players on 1.19.3+
+ * and requires a present {@link #getCurrentServer} for the emitting player as well as this player.
*/
@Override
- default void playSound(@NotNull Sound sound, Sound.Emitter emitter) {
+ default void playSound(@NotNull Sound sound, @NotNull Sound.Emitter emitter) {
}
/**
* {@inheritDoc}
*
- * This method is not currently implemented in Velocity
- * and will not perform any actions.
+ * @param stop the sound and/or a sound source, to stop
+ * @since 3.4.0
+ * @sinceMinecraft 1.19.3
+ * @apiNote This method is currently only implemented for players on 1.19.3+.
*/
@Override
default void stopSound(@NotNull SoundStop stop) {
@@ -425,11 +443,40 @@ public interface Player extends
*
* This method is not currently implemented in Velocity
* and will not perform any actions.
+ *
+ * @see
+ * Unsupported Adventure Operations
*/
@Override
default void openBook(@NotNull Book book) {
}
+ /**
+ * {@inheritDoc}
+ *
+ * This method is not currently implemented in Velocity
+ * and will not perform any actions.
+ *
+ * @see
+ * Unsupported Adventure Operations
+ */
+ @Override
+ default void showDialog(@NotNull DialogLike dialog) {
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * This method is not currently implemented in Velocity
+ * and will not perform any actions.
+ *
+ * @see
+ * Unsupported Adventure Operations
+ */
+ @Override
+ default void closeDialog() {
+ }
+
/**
* Transfers a Player to a host.
*
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java
index 94620218..d1101d6a 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/MinecraftSessionHandler.java
@@ -23,6 +23,8 @@ import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
+import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
+import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
import com.velocitypowered.proxy.protocol.packet.DialogClearPacket;
import com.velocitypowered.proxy.protocol.packet.DialogShowPacket;
@@ -390,4 +392,11 @@ public interface MinecraftSessionHandler {
return false;
}
+ default boolean handle(ClientboundSoundEntityPacket packet) {
+ return false;
+ }
+
+ default boolean handle(ClientboundStopSoundPacket packet) {
+ return false;
+ }
}
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 af3f8179..71ebd7bc 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
@@ -53,6 +53,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
+import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.jetbrains.annotations.NotNull;
@@ -70,6 +71,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
private boolean gracefulDisconnect = false;
private BackendConnectionPhase connectionPhase = BackendConnectionPhases.UNKNOWN;
private final Map pendingPings = new HashMap<>();
+ private @MonotonicNonNull Integer entityId;
/**
* Initializes a new server connection.
@@ -324,6 +326,14 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation,
return pendingPings;
}
+ public Integer getEntityId() {
+ return entityId;
+ }
+
+ public void setEntityId(Integer entityId) {
+ this.entityId = entityId;
+ }
+
/**
* Ensures that this server connection remains "active": the connection is established and not
* closed, the player is still connected to the server, and the player still remains online.
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 4b658cd6..254842cf 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
@@ -575,6 +575,8 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
}
}
+ destination.setEntityId(joinGame.getEntityId()); // used for sound api
+
// Remove previous boss bars. These don't get cleared when sending JoinGame, thus the need to
// track them.
for (UUID serverBossBar : serverBossBars) {
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 6d32535f..44fe95c5 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
@@ -73,6 +73,8 @@ import com.velocitypowered.proxy.protocol.netty.MinecraftEncoder;
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
+import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
+import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
import com.velocitypowered.proxy.protocol.packet.DisconnectPacket;
import com.velocitypowered.proxy.protocol.packet.HeaderAndFooterPacket;
@@ -127,6 +129,8 @@ import net.kyori.adventure.pointer.PointersSupplier;
import net.kyori.adventure.resource.ResourcePackInfoLike;
import net.kyori.adventure.resource.ResourcePackRequest;
import net.kyori.adventure.resource.ResourcePackRequestLike;
+import net.kyori.adventure.sound.Sound;
+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;
@@ -1042,6 +1046,50 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
this.clientBrand = clientBrand;
}
+ @Override
+ public void playSound(@NotNull Sound sound, @NotNull Sound.Emitter emitter) {
+ Preconditions.checkNotNull(sound, "sound");
+ Preconditions.checkNotNull(emitter, "emitter");
+ VelocityServerConnection soundTargetServerConn = getConnectedServer();
+ if (getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_19_3)
+ || connection.getState() != StateRegistry.PLAY
+ || soundTargetServerConn == null
+ || (sound.source() == Sound.Source.UI
+ && getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_5))) {
+ return;
+ }
+
+ VelocityServerConnection soundEmitterServerConn;
+ if (emitter == Sound.Emitter.self()) {
+ soundEmitterServerConn = soundTargetServerConn;
+ } else if (emitter instanceof ConnectedPlayer player) {
+ if ((soundEmitterServerConn = player.getConnectedServer()) == null) {
+ return;
+ }
+
+ if (!soundEmitterServerConn.getServer().equals(soundTargetServerConn.getServer())) {
+ return;
+ }
+ } else {
+ return;
+ }
+
+ connection.write(new ClientboundSoundEntityPacket(sound, null, soundEmitterServerConn.getEntityId()));
+ }
+
+ @Override
+ public void stopSound(@NotNull SoundStop stop) {
+ Preconditions.checkNotNull(stop, "stop");
+ if (getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_19_3)
+ || connection.getState() != StateRegistry.PLAY
+ || (stop.source() == Sound.Source.UI
+ && getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_21_5))) {
+ return;
+ }
+
+ connection.write(new ClientboundStopSoundPacket(stop));
+ }
+
@Override
public void transferToHost(final InetSocketAddress address) {
Preconditions.checkNotNull(address);
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 5b54e0f0..f0d1d63b 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
@@ -44,6 +44,7 @@ import net.kyori.adventure.nbt.BinaryTagIO;
import net.kyori.adventure.nbt.BinaryTagType;
import net.kyori.adventure.nbt.BinaryTagTypes;
import net.kyori.adventure.nbt.CompoundBinaryTag;
+import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.json.JSONOptions;
import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer;
@@ -316,6 +317,16 @@ public enum ProtocolUtils {
writeString(buf, key.asString());
}
+ /**
+ * Writes the key to the buffer, dropping the "minecraft:" namespace when present.
+ *
+ * @param buf the buffer to write to
+ * @param key the key to write
+ */
+ public static void writeMinimalKey(ByteBuf buf, Key key) {
+ writeString(buf, key.asMinimalString());
+ }
+
/**
* Reads a standard Mojang Text namespaced:key array from the buffer.
*
@@ -781,6 +792,40 @@ public enum ProtocolUtils {
return new IdentifiedKeyImpl(revision, key, expiry, signature);
}
+ /**
+ * Reads a {@link Sound.Source} from the buffer.
+ *
+ * @param buf the buffer
+ * @param version the protocol version
+ * @return the sound source
+ */
+ public static Sound.Source readSoundSource(ByteBuf buf, ProtocolVersion version) {
+ int ordinal = readVarInt(buf);
+
+ if (version.lessThan(ProtocolVersion.MINECRAFT_1_21_5)
+ && ordinal == Sound.Source.UI.ordinal()) {
+ throw new UnsupportedOperationException("UI sound-source is only supported in 1.21.5+");
+ }
+
+ return Sound.Source.values()[ordinal];
+ }
+
+ /**
+ * Writes a {@link Sound.Source} to the buffer.
+ *
+ * @param buf the buffer
+ * @param version the protocol version
+ * @param source the sound source to write
+ */
+ public static void writeSoundSource(ByteBuf buf, ProtocolVersion version, Sound.Source source) {
+ if (version.lessThan(ProtocolVersion.MINECRAFT_1_21_5)
+ && source == Sound.Source.UI) {
+ throw new UnsupportedOperationException("UI sound-source is only supported in 1.21.5+");
+ }
+
+ writeVarInt(buf, source.ordinal());
+ }
+
/**
* Represents the direction in which a packet flows.
*/
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 42d60029..67b01087 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/StateRegistry.java
@@ -59,6 +59,8 @@ import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
import com.velocitypowered.proxy.protocol.packet.BundleDelimiterPacket;
import com.velocitypowered.proxy.protocol.packet.ClientSettingsPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundCookieRequestPacket;
+import com.velocitypowered.proxy.protocol.packet.ClientboundSoundEntityPacket;
+import com.velocitypowered.proxy.protocol.packet.ClientboundStopSoundPacket;
import com.velocitypowered.proxy.protocol.packet.ClientboundStoreCookiePacket;
import com.velocitypowered.proxy.protocol.packet.DialogClearPacket;
import com.velocitypowered.proxy.protocol.packet.DialogShowPacket;
@@ -448,6 +450,26 @@ public enum StateRegistry {
ClientboundCookieRequestPacket.class, ClientboundCookieRequestPacket::new,
map(0x16, MINECRAFT_1_20_5, false),
map(0x15, MINECRAFT_1_21_5, false));
+ clientbound.register(
+ ClientboundSoundEntityPacket.class, ClientboundSoundEntityPacket::new,
+ map(0x5D, MINECRAFT_1_19_3, true),
+ map(0x61, MINECRAFT_1_19_4, true),
+ map(0x63, MINECRAFT_1_20_2, true),
+ map(0x65, MINECRAFT_1_20_3, true),
+ 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));
+ clientbound.register(
+ ClientboundStopSoundPacket.class, ClientboundStopSoundPacket::new,
+ map(0x5F, MINECRAFT_1_19_3, true),
+ map(0x63, MINECRAFT_1_19_4, true),
+ map(0x66, MINECRAFT_1_20_2, true),
+ map(0x68, MINECRAFT_1_20_3, true),
+ 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));
clientbound.register(
PluginMessagePacket.class,
PluginMessagePacket::new,
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
new file mode 100644
index 00000000..459f1430
--- /dev/null
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundSoundEntityPacket.java
@@ -0,0 +1,101 @@
+/*
+ * 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.protocol.packet;
+
+import com.velocitypowered.api.network.ProtocolVersion;
+import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
+import com.velocitypowered.proxy.protocol.MinecraftPacket;
+import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import io.netty.buffer.ByteBuf;
+import net.kyori.adventure.sound.Sound;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Random;
+
+public class ClientboundSoundEntityPacket implements MinecraftPacket {
+
+ private static final Random SEEDS_RANDOM = new Random();
+
+ private Sound sound;
+ private @Nullable Float fixedRange;
+ private int emitterEntityId;
+
+ public ClientboundSoundEntityPacket() {}
+
+ public ClientboundSoundEntityPacket(Sound sound, @Nullable Float fixedRange, int emitterEntityId) {
+ this.sound = sound;
+ this.fixedRange = fixedRange;
+ this.emitterEntityId = emitterEntityId;
+ }
+
+ @Override
+ public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
+ throw new UnsupportedOperationException("Decode is not implemented");
+ }
+
+ @Override
+ public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
+ ProtocolUtils.writeVarInt(buf, 0); // version-dependent, hardcoded sound ID
+
+ ProtocolUtils.writeMinimalKey(buf, sound.name());
+
+ buf.writeBoolean(fixedRange != null);
+ if (fixedRange != null)
+ buf.writeFloat(fixedRange);
+
+ ProtocolUtils.writeSoundSource(buf, protocolVersion, sound.source());
+
+ ProtocolUtils.writeVarInt(buf, emitterEntityId);
+
+ buf.writeFloat(sound.volume());
+
+ buf.writeFloat(sound.pitch());
+
+ buf.writeLong(sound.seed().orElse(SEEDS_RANDOM.nextLong()));
+ }
+
+ @Override
+ public boolean handle(MinecraftSessionHandler handler) {
+ return handler.handle(this);
+ }
+
+ public Sound getSound() {
+ return sound;
+ }
+
+ public void setSound(Sound sound) {
+ this.sound = sound;
+ }
+
+ public @Nullable Float getFixedRange() {
+ return fixedRange;
+ }
+
+ public void setFixedRange(@Nullable Float fixedRange) {
+ this.fixedRange = fixedRange;
+ }
+
+ public int getEmitterEntityId() {
+ return emitterEntityId;
+ }
+
+ public void setEmitterEntityId(int emitterEntityId) {
+ this.emitterEntityId = emitterEntityId;
+ }
+
+}
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
new file mode 100644
index 00000000..3e085d38
--- /dev/null
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/ClientboundStopSoundPacket.java
@@ -0,0 +1,109 @@
+/*
+ * 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.protocol.packet;
+
+import com.velocitypowered.api.network.ProtocolVersion;
+import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
+import com.velocitypowered.proxy.protocol.MinecraftPacket;
+import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import io.netty.buffer.ByteBuf;
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.sound.Sound;
+import net.kyori.adventure.sound.SoundStop;
+
+import javax.annotation.Nullable;
+
+public class ClientboundStopSoundPacket implements MinecraftPacket {
+
+ private @Nullable Sound.Source source;
+ private @Nullable Key soundName;
+
+ public ClientboundStopSoundPacket() {}
+
+ public ClientboundStopSoundPacket(SoundStop soundStop) {
+ this(soundStop.source(), soundStop.sound());
+ }
+
+ public ClientboundStopSoundPacket(@Nullable Sound.Source source, @Nullable Key soundName) {
+ this.source = source;
+ this.soundName = soundName;
+ }
+
+ @Override
+ public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
+ int flagsBitmask = buf.readByte();
+
+ if ((flagsBitmask & 1) != 0) {
+ source = ProtocolUtils.readSoundSource(buf, protocolVersion);
+ } else {
+ source = null;
+ }
+
+ if ((flagsBitmask & 2) != 0) {
+ soundName = ProtocolUtils.readKey(buf);
+ } else {
+ soundName = null;
+ }
+ }
+
+ @Override
+ public void encode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
+ int flagsBitmask = 0;
+ if (source != null && soundName == null) {
+ flagsBitmask |= 1;
+ } else if (soundName != null && source == null) {
+ flagsBitmask |= 2;
+ } else if (source != null /*&& sound != null*/) {
+ flagsBitmask |= 3;
+ }
+
+ buf.writeByte(flagsBitmask);
+
+ if (source != null) {
+ ProtocolUtils.writeSoundSource(buf, protocolVersion, source);
+ }
+
+ if (soundName != null) {
+ ProtocolUtils.writeMinimalKey(buf, soundName);
+ }
+ }
+
+ @Override
+ public boolean handle(MinecraftSessionHandler handler) {
+ return handler.handle(this);
+ }
+
+ @Nullable
+ public Sound.Source getSource() {
+ return source;
+ }
+
+ public void setSource(@Nullable Sound.Source source) {
+ this.source = source;
+ }
+
+ @Nullable
+ public Key getSoundName() {
+ return soundName;
+ }
+
+ public void setSoundName(@Nullable Key soundName) {
+ this.soundName = soundName;
+ }
+
+}
From b1dd26fbc4ffdc1a6d9c8281cee2165107e66f14 Mon Sep 17 00:00:00 2001
From: Aaron <71191102+RealBauHD@users.noreply.github.com>
Date: Tue, 7 Oct 2025 16:40:25 +0200
Subject: [PATCH 21/36] 1.21.10 (#1658)
---
.../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 916e3db5..f2a629b1 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,7 @@ 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");
+ MINECRAFT_1_21_9(773, "1.21.9", "1.21.10");
private static final int SNAPSHOT_BIT = 30;
From d266059abe6b2b150b2084dc72ab44317387bca1 Mon Sep 17 00:00:00 2001
From: Cedric
Date: Fri, 10 Oct 2025 10:40:10 +0200
Subject: [PATCH 22/36] Update adventure to version 4.25.0 (#1660)
---
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 c44264fa..726a1ec0 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.24.0"
-adventure-text-serializer-json-legacy-impl = "net.kyori:adventure-text-serializer-json-legacy-impl:4.24.0"
+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-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 806b386cdb8da23051a9679682ed6a76370b9818 Mon Sep 17 00:00:00 2001
From: Ross <32296125+Rossterd@users.noreply.github.com>
Date: Sun, 12 Oct 2025 04:11:44 +0200
Subject: [PATCH 23/36] Fix command suggestion offset (#1662)
---
.../client/ClientPlaySessionHandler.java | 34 +++++++++++++------
1 file changed, 23 insertions(+), 11 deletions(-)
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 254842cf..bccd8375 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
@@ -696,22 +696,34 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
return;
}
- List offers = new ArrayList<>();
- for (Suggestion suggestion : suggestions.getList()) {
- String offer = suggestion.getText();
- ComponentHolder tooltip = null;
- if (suggestion.getTooltip() instanceof ComponentLike componentLike) {
- tooltip = new ComponentHolder(player.getProtocolVersion(), componentLike.asComponent());
- } else if (suggestion.getTooltip() != null) {
- tooltip = new ComponentHolder(player.getProtocolVersion(), Component.text(suggestion.getTooltip().getString()));
+ int startPos = -1;
+ for (var suggestion : suggestions.getList()) {
+ if (startPos == -1 || startPos > suggestion.getRange().getStart()) {
+ startPos = suggestion.getRange().getStart();
}
- offers.add(new Offer(offer, tooltip));
}
- int startPos = packet.getCommand().lastIndexOf(' ') + 1;
+
if (startPos > 0) {
+ List offers = new ArrayList<>();
+ for (Suggestion suggestion : suggestions.getList()) {
+ String offer;
+ if (suggestion.getRange().getStart() == startPos) {
+ offer = suggestion.getText();
+ } else {
+ offer = command.substring(startPos, suggestion.getRange().getStart()) + suggestion.getText();
+ }
+ ComponentHolder tooltip = null;
+ if (suggestion.getTooltip() instanceof ComponentLike componentLike) {
+ tooltip = new ComponentHolder(player.getProtocolVersion(), componentLike.asComponent());
+ } else if (suggestion.getTooltip() != null) {
+ tooltip = new ComponentHolder(player.getProtocolVersion(), Component.text(suggestion.getTooltip().getString()));
+ }
+ offers.add(new Offer(offer, tooltip));
+ }
+
TabCompleteResponsePacket resp = new TabCompleteResponsePacket();
resp.setTransactionId(packet.getTransactionId());
- resp.setStart(startPos);
+ resp.setStart(startPos + 1);
resp.setLength(packet.getCommand().length() - startPos);
resp.getOffers().addAll(offers);
player.getConnection().write(resp);
From 5753548b44193d2b72a4b70d3f12b7f21d6c1d1d Mon Sep 17 00:00:00 2001
From: Ross <32296125+Rossterd@users.noreply.github.com>
Date: Mon, 13 Oct 2025 21:41:33 +0200
Subject: [PATCH 24/36] Fix SimpleCommand suggestion offset (#1664)
* Fix command suggestion offset
* fix length error
* add test
* checkstyle
---------
Co-authored-by: Ross <2086824-trashp@users.noreply.gitlab.com>
---
.../registrar/InvocableCommandRegistrar.java | 8 ++++--
.../client/ClientPlaySessionHandler.java | 2 +-
.../command/SuggestionsProviderTests.java | 25 +++++++++++++++++++
3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java b/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java
index 380f45e3..847d67d1 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/command/registrar/InvocableCommandRegistrar.java
@@ -103,13 +103,17 @@ abstract class InvocableCommandRegistrar,
.requiresWithContext((context, reader) -> requirement.test(context))
.executes(callback)
.suggests((context, builder) -> {
+ // Offset the suggestion to the last space seperated word
+ int lastSpace = builder.getRemaining().lastIndexOf(' ') + 1;
+ final var offsetBuilder = builder.createOffset(builder.getStart() + lastSpace);
+
final I invocation = invocationFactory.create(context);
return command.suggestAsync(invocation).thenApply(suggestions -> {
for (String value : suggestions) {
Preconditions.checkNotNull(value, "suggestion");
- builder.suggest(value);
+ offsetBuilder.suggest(value);
}
- return builder.build();
+ return offsetBuilder.build();
});
})
.build();
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 bccd8375..288315d7 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
@@ -724,7 +724,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
TabCompleteResponsePacket resp = new TabCompleteResponsePacket();
resp.setTransactionId(packet.getTransactionId());
resp.setStart(startPos + 1);
- resp.setLength(packet.getCommand().length() - startPos);
+ resp.setLength(packet.getCommand().length() - startPos - 1);
resp.getOffers().addAll(offers);
player.getConnection().write(resp);
}
diff --git a/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java b/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java
index 9fe86335..fa282f71 100644
--- a/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java
+++ b/proxy/src/test/java/com/velocitypowered/proxy/command/SuggestionsProviderTests.java
@@ -18,14 +18,17 @@
package com.velocitypowered.proxy.command;
import static com.mojang.brigadier.arguments.StringArgumentType.word;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import com.google.common.collect.ImmutableList;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
+import com.mojang.brigadier.suggestion.Suggestions;
import com.velocitypowered.api.command.Command;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.command.RawCommand;
+import com.velocitypowered.api.command.SimpleCommand;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.Test;
@@ -286,4 +289,26 @@ public class SuggestionsProviderTests extends CommandTestSuite {
return ImmutableList.of();
}
}
+
+ @Test
+ void testSuggestionOffset() {
+ final var meta = manager.metaBuilder("offset").build();
+ manager.register(meta, new SimpleCommand() {
+ @Override
+ public void execute(final Invocation invocation) {
+ fail();
+ }
+
+ @Override
+ public List suggest(final Invocation invocation) {
+ return List.of("bump");
+ }
+ });
+
+ assertSuggestions("offset bu", "bump");
+ for (int i = 10; i < 20; i++) {
+ final Suggestions suggestions = manager.offerBrigadierSuggestions(source, "offset " + "bump ".repeat(i)).join();
+ assertEquals(7 + 5 * i, suggestions.getList().get(0).getRange().getStart());
+ }
+ }
}
From 1140fc65baddc41723e71977aeafe224d6b14c42 Mon Sep 17 00:00:00 2001
From: Emil <12966472+Emilxyz@users.noreply.github.com>
Date: Tue, 14 Oct 2025 20:10:57 +0200
Subject: [PATCH 25/36] fix: Enable EMIT_CLICK_URL_HTTPS on component
serializers (#1665)
---
.../com/velocitypowered/proxy/protocol/ProtocolUtils.java | 8 ++++++++
1 file changed, 8 insertions(+)
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 f0d1d63b..0be9065a 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
@@ -62,6 +62,8 @@ public enum ProtocolUtils {
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
.options(
OptionSchema.globalSchema().stateBuilder()
+ // general options
+ .value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
// before 1.16
.value(JSONOptions.EMIT_RGB, Boolean.FALSE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.VALUE_FIELD)
@@ -80,6 +82,8 @@ public enum ProtocolUtils {
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
.options(
OptionSchema.globalSchema().stateBuilder()
+ // general options
+ .value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
// after 1.16
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
@@ -99,6 +103,8 @@ public enum ProtocolUtils {
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
.options(
OptionSchema.globalSchema().stateBuilder()
+ // general options
+ .value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
// after 1.16
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE)
@@ -118,6 +124,8 @@ public enum ProtocolUtils {
.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get())
.options(
OptionSchema.globalSchema().stateBuilder()
+ // general options
+ .value(JSONOptions.EMIT_CLICK_URL_HTTPS, Boolean.TRUE)
// after 1.16
.value(JSONOptions.EMIT_RGB, Boolean.TRUE)
.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.SNAKE_CASE)
From 4cd3b6869729484887b4fa58b7a6c3b007710a10 Mon Sep 17 00:00:00 2001
From: okx-code
Date: Fri, 17 Oct 2025 05:12:57 +0100
Subject: [PATCH 26/36] Fix players disconnecting when updating boss bars
(#1656)
* Fix 1.20.2+ clients disconnecting when updating boss bars
On 1.20.2, the Minecraft client started clearing boss bars after the login packet, which meant that the ProxyServer#showBossbar API would result in the player getting kicked if the boss bar they were previously shown was updated after switching servers.
Therefore, I have added BossBarManager which drops boss bar packets once the client enters the configure phase to ensure that they do not disconnect, and then re-adds the boss bar once the client enters the login phase.
This ensures that clients do not receive boss bar updates for boss bars that they don't exist and causing them to disconnect. I have also taken care to ensure that this logic only applies on 1.20.2 and up, as it is not necessary for older clients.
---------
Co-authored-by: Adrian Gonzales
---
.../VelocityBossBarImplementation.java | 22 ++++--
.../backend/BackendPlaySessionHandler.java | 12 +--
.../client/ClientPlaySessionHandler.java | 27 ++++---
.../connection/client/ConnectedPlayer.java | 7 ++
.../player/bossbar/BossBarManager.java | 79 +++++++++++++++++++
5 files changed, 125 insertions(+), 22 deletions(-)
create mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/player/bossbar/BossBarManager.java
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/adventure/VelocityBossBarImplementation.java b/proxy/src/main/java/com/velocitypowered/proxy/adventure/VelocityBossBarImplementation.java
index 9dec3309..e2451188 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/adventure/VelocityBossBarImplementation.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/adventure/VelocityBossBarImplementation.java
@@ -53,15 +53,23 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
viewer.getProtocolVersion(),
viewer.translateMessage(this.bar.name())
);
- viewer.getConnection().write(BossBarPacket.createAddPacket(this.id, this.bar, name));
+ viewer.getBossBarManager().writeUpdate(this, BossBarPacket.createAddPacket(this.id, this.bar, name));
return true;
}
return false;
}
+ public void createDirect(final ConnectedPlayer viewer) {
+ final ComponentHolder name = new ComponentHolder(
+ viewer.getProtocolVersion(),
+ viewer.translateMessage(this.bar.name())
+ );
+ viewer.getConnection().write(BossBarPacket.createAddPacket(this.id, this.bar, name));
+ }
+
public boolean viewerRemove(final ConnectedPlayer viewer) {
if (this.viewers.remove(viewer)) {
- viewer.getConnection().write(BossBarPacket.createRemovePacket(this.id, this.bar));
+ viewer.getBossBarManager().remove(this, BossBarPacket.createRemovePacket(this.id, this.bar));
return true;
}
return false;
@@ -84,7 +92,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
this.bar,
new ComponentHolder(viewer.getProtocolVersion(), translated)
);
- viewer.getConnection().write(packet);
+ viewer.getBossBarManager().writeUpdate(this, packet);
}
}
@@ -96,7 +104,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
) {
final BossBarPacket packet = BossBarPacket.createUpdateProgressPacket(this.id, this.bar);
for (final ConnectedPlayer viewer : this.viewers) {
- viewer.getConnection().write(packet);
+ viewer.getBossBarManager().writeUpdate(this, packet);
}
}
@@ -108,7 +116,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
) {
final BossBarPacket packet = BossBarPacket.createUpdateStylePacket(this.id, this.bar);
for (final ConnectedPlayer viewer : this.viewers) {
- viewer.getConnection().write(packet);
+ viewer.getBossBarManager().writeUpdate(this, packet);
}
}
@@ -120,7 +128,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
) {
final BossBarPacket packet = BossBarPacket.createUpdateStylePacket(this.id, this.bar);
for (final ConnectedPlayer viewer : this.viewers) {
- viewer.getConnection().write(packet);
+ viewer.getBossBarManager().writeUpdate(this, packet);
}
}
@@ -132,7 +140,7 @@ public final class VelocityBossBarImplementation implements BossBar.Listener,
) {
final BossBarPacket packet = BossBarPacket.createUpdatePropertiesPacket(this.id, this.bar);
for (final ConnectedPlayer viewer : this.viewers) {
- viewer.getConnection().write(packet);
+ viewer.getBossBarManager().writeUpdate(this, packet);
}
}
}
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 eb9c9bca..ed30057a 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
@@ -177,10 +177,12 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
@Override
public boolean handle(BossBarPacket packet) {
- if (packet.getAction() == BossBarPacket.ADD) {
- playerSessionHandler.getServerBossBars().add(packet.getUuid());
- } else if (packet.getAction() == BossBarPacket.REMOVE) {
- playerSessionHandler.getServerBossBars().remove(packet.getUuid());
+ if (serverConn.getPlayer().getProtocolVersion().lessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
+ if (packet.getAction() == BossBarPacket.ADD) {
+ playerSessionHandler.getServerBossBars().add(packet.getUuid());
+ } else if (packet.getAction() == BossBarPacket.REMOVE) {
+ playerSessionHandler.getServerBossBars().remove(packet.getUuid());
+ }
}
return false; // forward
}
@@ -516,4 +518,4 @@ public class BackendPlaySessionHandler implements MinecraftSessionHandler {
playerConnection.setAutoReading(writable);
}
-}
\ No newline at end of file
+}
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 288315d7..17eb708b 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
@@ -535,9 +535,13 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
// Config state clears everything in the client. No need to clear later.
spawned = false;
- serverBossBars.clear();
player.clearPlayerListHeaderAndFooterSilent();
player.getTabList().clearAllSilent();
+ if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
+ player.getBossBarManager().dropPackets();
+ } else {
+ serverBossBars.clear();
+ }
}
player.switchToConfigState();
@@ -576,16 +580,19 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler {
}
destination.setEntityId(joinGame.getEntityId()); // used for sound api
-
- // Remove previous boss bars. These don't get cleared when sending JoinGame, thus the need to
- // track them.
- for (UUID serverBossBar : serverBossBars) {
- BossBarPacket deletePacket = new BossBarPacket();
- deletePacket.setUuid(serverBossBar);
- deletePacket.setAction(BossBarPacket.REMOVE);
- player.getConnection().delayedWrite(deletePacket);
+ if (player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20_2)) {
+ player.getBossBarManager().sendBossBars();
+ } else {
+ // Remove previous boss bars. These don't get cleared when sending JoinGame (up until 1.20.2),
+ // thus the need to track them.
+ for (UUID serverBossBar : serverBossBars) {
+ BossBarPacket deletePacket = new BossBarPacket();
+ deletePacket.setUuid(serverBossBar);
+ deletePacket.setAction(BossBarPacket.REMOVE);
+ player.getConnection().delayedWrite(deletePacket);
+ }
+ serverBossBars.clear();
}
- serverBossBars.clear();
// Tell the server about the proxy's plugin message channels.
ProtocolVersion serverVersion = serverMc.getProtocolVersion();
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 44fe95c5..17f4fb5c 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
@@ -62,6 +62,7 @@ import com.velocitypowered.proxy.adventure.VelocityBossBarImplementation;
import com.velocitypowered.proxy.connection.MinecraftConnection;
import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation;
import com.velocitypowered.proxy.connection.backend.VelocityServerConnection;
+import com.velocitypowered.proxy.connection.player.bossbar.BossBarManager;
import com.velocitypowered.proxy.connection.player.bundle.BundleDelimiterHandler;
import com.velocitypowered.proxy.connection.player.resourcepack.VelocityResourcePackInfo;
import com.velocitypowered.proxy.connection.player.resourcepack.handler.ResourcePackHandler;
@@ -201,6 +202,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
private @Nullable ClientSettingsPacket clientSettingsPacket;
private volatile ChatQueue chatQueue;
private final ChatBuilderFactory chatBuilderFactory;
+ private final BossBarManager bossBarManager;
ConnectedPlayer(VelocityServer server, GameProfile profile, MinecraftConnection connection,
@Nullable InetSocketAddress virtualHost, @Nullable String rawVirtualHost, boolean onlineMode,
@@ -227,6 +229,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
this.chatQueue = new ChatQueue(this);
this.chatBuilderFactory = new ChatBuilderFactory(this.getProtocolVersion());
this.resourcePackHandler = ResourcePackHandler.create(this, server);
+ this.bossBarManager = new BossBarManager(this);
}
/**
@@ -1431,6 +1434,10 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
return handshakeIntent;
}
+ public BossBarManager getBossBarManager() {
+ return bossBarManager;
+ }
+
private final class ConnectionRequestBuilderImpl implements ConnectionRequestBuilder {
private final RegisteredServer toConnect;
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/player/bossbar/BossBarManager.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/bossbar/BossBarManager.java
new file mode 100644
index 00000000..03ff4f7f
--- /dev/null
+++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/player/bossbar/BossBarManager.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2019-2023 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.connection.player.bossbar;
+
+import com.velocitypowered.proxy.adventure.VelocityBossBarImplementation;
+import com.velocitypowered.proxy.connection.client.ConnectedPlayer;
+import com.velocitypowered.proxy.protocol.packet.BossBarPacket;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Handles dropping and resending boss bar packets on versions 1.20.2 and newer because the client now
+ * deletes all boss bars during the login phase, and sending update packets would cause the client to be disconnected.
+ */
+public final class BossBarManager {
+
+ private final ConnectedPlayer player;
+ private final Set bossBars = new HashSet<>();
+
+ private boolean dropPackets = false;
+
+ public BossBarManager(ConnectedPlayer player) {
+ this.player = player;
+ }
+
+ /**
+ * Records the specified boss bar to be re-sent when a player changes server, and sends the update packet
+ * if the client is able to receive it and not be disconnected.
+ */
+ public synchronized void writeUpdate(VelocityBossBarImplementation bar, BossBarPacket packet) {
+ this.bossBars.add(bar);
+ if (!this.dropPackets) {
+ this.player.getConnection().write(packet);
+ }
+ }
+
+ /**
+ * Removes the specified boss bar from the player to ensure it is not re-sent.
+ */
+ public synchronized void remove(VelocityBossBarImplementation bar, BossBarPacket packet) {
+ this.bossBars.remove(bar);
+ if (!this.dropPackets) {
+ this.player.getConnection().write(packet);
+ }
+ }
+
+ /**
+ * Re-creates the boss bars the player can see with any updates that may have occurred in the meantime,
+ * and allows update packets for those boss bars to be sent.
+ */
+ public synchronized void sendBossBars() {
+ for (VelocityBossBarImplementation bossBar : bossBars) {
+ bossBar.createDirect(player);
+ }
+ this.dropPackets = false;
+ }
+
+ /**
+ * Prevents the player from receiving boss bar update packets while logging in to a new server.
+ */
+ public synchronized void dropPackets() {
+ this.dropPackets = true;
+ }
+}
From 70c3eabdb1459419cb7e7187cd0a741cdefaa66a Mon Sep 17 00:00:00 2001
From: Andrew Steinborn
Date: Sat, 18 Oct 2025 16:15:22 -0400
Subject: [PATCH 27/36] Minor optimizations for
`MinecraftCompressorAndLengthEncoder` and friends
No need to bounce around changing the writer index, we can just set the value directly.
Also pull out the handshake checks into a separate function, to improve inlining.
---
.../proxy/protocol/ProtocolUtils.java | 13 ++--
.../MinecraftCompressorAndLengthEncoder.java | 9 +--
.../netty/MinecraftVarintFrameDecoder.java | 69 ++++++++++---------
.../proxy/protocol/ProtocolUtilsTest.java | 3 +-
4 files changed, 48 insertions(+), 46 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 0be9065a..6e8ba6ac 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
@@ -150,7 +150,7 @@ public enum ProtocolUtils {
BinaryTagTypes.COMPOUND, BinaryTagTypes.INT_ARRAY, BinaryTagTypes.LONG_ARRAY};
private static final QuietDecoderException BAD_VARINT_CACHED =
new QuietDecoderException("Bad VarInt decoded");
- private static final int[] VAR_INT_LENGTHS = new int[65];
+ private static final int[] VAR_INT_LENGTHS = new int[33];
static {
for (int i = 0; i <= 32; ++i) {
@@ -250,16 +250,15 @@ public enum ProtocolUtils {
}
/**
- * Writes the specified {@code value} as a 21-bit Minecraft VarInt to the specified {@code buf}.
+ * Directly encodes a 21-bit Minecraft VarInt, ready to be written with {@link ByteBuf#writeMedium(int)}.
* The upper 11 bits will be discarded.
*
- * @param buf the buffer to read from
- * @param value the integer to write
+ * @param value the value to encode
+ * @return the encoded value
*/
- public static void write21BitVarInt(ByteBuf buf, int value) {
+ public static int encode21BitVarInt(int value) {
// See https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
- int w = (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
- buf.writeMedium(w);
+ return (value & 0x7F | 0x80) << 16 | ((value >>> 7) & 0x7F | 0x80) << 8 | (value >>> 14);
}
public static String readString(ByteBuf buf) {
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressorAndLengthEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressorAndLengthEncoder.java
index 90952a72..990d1732 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressorAndLengthEncoder.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftCompressorAndLengthEncoder.java
@@ -46,7 +46,7 @@ public class MinecraftCompressorAndLengthEncoder extends MessageToByteEncoder 0) {
if (state == StateRegistry.HANDSHAKE && direction == ProtocolUtils.Direction.SERVERBOUND) {
- StateRegistry.PacketRegistry.ProtocolRegistry registry =
- 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();
+ if (validateServerboundHandshakePacket(in, length)) {
return;
}
- 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.expectedMinLength(in, direction, registry.version);
- int expectedMaxLen = packet.expectedMaxLength(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);
}
}
@@ -139,6 +109,41 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
}
}
+ private boolean validateServerboundHandshakePacket(ByteBuf in, int length) throws Exception {
+ StateRegistry.PacketRegistry.ProtocolRegistry registry =
+ 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);
+
+ 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.expectedMinLength(in, direction, registry.version);
+ int expectedMaxLen = packet.expectedMaxLength(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
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (MinecraftDecoder.DEBUG) {
diff --git a/proxy/src/test/java/com/velocitypowered/proxy/protocol/ProtocolUtilsTest.java b/proxy/src/test/java/com/velocitypowered/proxy/protocol/ProtocolUtilsTest.java
index 1ed59cd8..ccd9cb7a 100644
--- a/proxy/src/test/java/com/velocitypowered/proxy/protocol/ProtocolUtilsTest.java
+++ b/proxy/src/test/java/com/velocitypowered/proxy/protocol/ProtocolUtilsTest.java
@@ -17,6 +17,7 @@
package com.velocitypowered.proxy.protocol;
+import static com.velocitypowered.proxy.protocol.ProtocolUtils.encode21BitVarInt;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -83,7 +84,7 @@ public class ProtocolUtilsTest {
private void writeReadTest3Bytes(ByteBuf buf, int test) {
buf.clear();
- ProtocolUtils.write21BitVarInt(buf, test);
+ buf.writeMedium(encode21BitVarInt(test));
assertEquals(test, ProtocolUtils.readVarInt(buf));
}
From 38a0a7ed27230dceb33f3c241e740a91ae73d328 Mon Sep 17 00:00:00 2001
From: Shane Freeder
Date: Sat, 18 Oct 2025 21:22:26 +0100
Subject: [PATCH 28/36] use correct string length for newer MC versions (Fixes
#1629) (#1668)
---
.../packet/chat/session/SessionPlayerCommandPacket.java | 3 ++-
.../packet/chat/session/UnsignedPlayerCommandPacket.java | 2 +-
2 files changed, 3 insertions(+), 2 deletions(-)
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 993587dc..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
@@ -41,7 +41,8 @@ public class SessionPlayerCommandPacket implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
- this.command = ProtocolUtils.readString(buf, 256);
+ int cap = protocolVersion.lessThan(ProtocolVersion.MINECRAFT_1_20_5) ? 256 : ProtocolUtils.DEFAULT_MAX_STRING_SIZE;
+ this.command = ProtocolUtils.readString(buf, cap);
this.timeStamp = Instant.ofEpochMilli(buf.readLong());
this.salt = buf.readLong();
this.argumentSignatures = new ArgumentSignatures(buf);
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 cb5ac3c4..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
@@ -28,7 +28,7 @@ public class UnsignedPlayerCommandPacket extends SessionPlayerCommandPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction, ProtocolVersion protocolVersion) {
- this.command = ProtocolUtils.readString(buf, 256);
+ this.command = ProtocolUtils.readString(buf, ProtocolUtils.DEFAULT_MAX_STRING_SIZE);
}
@Override
From 13a1c93ea6e4816f489b6dbdf7b2cb94e64f6b2c Mon Sep 17 00:00:00 2001
From: Andrew Steinborn
Date: Sat, 18 Oct 2025 16:22:27 -0400
Subject: [PATCH 29/36] Bump Netty to 4.2.7.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 726a1ec0..d0bb2c84 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -3,7 +3,7 @@ configurate3 = "3.7.3"
configurate4 = "4.1.2"
flare = "2.0.1"
log4j = "2.24.3"
-netty = "4.2.5.Final"
+netty = "4.2.7.Final"
[plugins]
fill = "io.papermc.fill.gradle:1.0.3"
From 498a38cf74de86fccecf4fe715983d2036c3024e Mon Sep 17 00:00:00 2001
From: Andrew Steinborn
Date: Sat, 18 Oct 2025 16:40:54 -0400
Subject: [PATCH 30/36] Re-enable adaptive allocator
Recent Netty versions have improved the adaptive allocator, and we shouldn't be seeing the OOM issues others were noticing before. Let's re-enable it.
As for the buffer resizing issue, the upstream issue netty/netty#14912 is long fixed. I think we *should* pre-allocate the buffers beforehand much more aggressively, but that has to be future work.
---
proxy/src/main/java/com/velocitypowered/proxy/Velocity.java | 5 -----
1 file changed, 5 deletions(-)
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/Velocity.java b/proxy/src/main/java/com/velocitypowered/proxy/Velocity.java
index a6fc850b..0ec8622d 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/Velocity.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/Velocity.java
@@ -47,11 +47,6 @@ public class Velocity {
System.setProperty("io.netty.native.workdir", System.getProperty("velocity.natives-tmpdir"));
}
- // Restore allocator used before Netty 4.2 due to oom issues with the adaptive allocator
- if (System.getProperty("io.netty.allocator.type") == null) {
- System.setProperty("io.netty.allocator.type", "pooled");
- }
-
// Disable the resource leak detector by default as it reduces performance. Allow the user to
// override this if desired.
if (!VelocityProperties.hasProperty("io.netty.leakDetection.level")) {
From d2c13c2a4c509ca208d5f8bb6840ee1556163786 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn
Date: Sat, 18 Oct 2025 17:36:39 -0400
Subject: [PATCH 31/36] Provide encode buffer hint
---
.../proxy/protocol/MinecraftPacket.java | 9 +++++--
.../proxy/protocol/ProtocolUtils.java | 11 +++++++++
.../protocol/netty/MinecraftDecoder.java | 4 ++--
.../protocol/netty/MinecraftEncoder.java | 13 ++++++++++
.../netty/MinecraftVarintFrameDecoder.java | 4 ++--
.../packet/AvailableCommandsPacket.java | 8 +++++++
.../packet/EncryptionResponsePacket.java | 6 ++---
.../protocol/packet/HandshakePacket.java | 12 ++++++++--
.../packet/LoginAcknowledgedPacket.java | 2 +-
.../packet/LoginPluginMessagePacket.java | 6 +++++
.../packet/LoginPluginResponsePacket.java | 6 +++++
.../protocol/packet/PluginMessagePacket.java | 6 +++++
.../protocol/packet/ServerDataPacket.java | 6 +++++
.../protocol/packet/ServerLoginPacket.java | 2 +-
.../packet/ServerLoginSuccessPacket.java | 8 +++++++
.../ServerboundCustomClickActionPacket.java | 5 ++++
.../protocol/packet/StatusPingPacket.java | 4 ++--
.../protocol/packet/StatusRequestPacket.java | 2 +-
.../protocol/packet/StatusResponsePacket.java | 6 +++++
.../packet/UpsertPlayerInfoPacket.java | 24 +++++++------------
.../packet/config/CodeOfConductPacket.java | 5 ++++
.../packet/config/FinishedUpdatePacket.java | 2 +-
.../packet/config/RegistrySyncPacket.java | 6 +++++
.../packet/config/StartUpdatePacket.java | 2 +-
.../packet/config/TagsUpdatePacket.java | 19 +++++++++++++++
25 files changed, 145 insertions(+), 33 deletions(-)
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/MinecraftPacket.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/MinecraftPacket.java
index e54ee770..1722f42b 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/MinecraftPacket.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/MinecraftPacket.java
@@ -32,13 +32,18 @@ public interface MinecraftPacket {
boolean handle(MinecraftSessionHandler handler);
- default int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ default int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) {
return -1;
}
- default int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ default int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) {
return 0;
}
+
+ default int encodeSizeHint(ProtocolUtils.Direction direction,
+ ProtocolVersion version) {
+ return -1;
+ }
}
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 6e8ba6ac..efc0ed17 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java
@@ -292,6 +292,17 @@ public enum ProtocolUtils {
return str;
}
+ /**
+ * Determines the size of the written {@code str} if encoded as a VarInt-prefixed UTF-8 string.
+ *
+ * @param str the string to write
+ * @return the encoded size
+ */
+ public static int stringSizeHint(CharSequence str) {
+ int size = ByteBufUtil.utf8Bytes(str);
+ return varIntBytes(size) + size;
+ }
+
/**
* Writes the specified {@code str} to the {@code buf} with a VarInt prefix.
*
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 5389de73..35ddccd5 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
@@ -96,8 +96,8 @@ public class MinecraftDecoder extends ChannelInboundHandlerAdapter {
}
private void doLengthSanityChecks(ByteBuf buf, MinecraftPacket packet) throws Exception {
- int expectedMinLen = packet.expectedMinLength(buf, direction, registry.version);
- int expectedMaxLen = packet.expectedMaxLength(buf, direction, registry.version);
+ int expectedMinLen = packet.decodeExpectedMinLength(buf, direction, registry.version);
+ int expectedMaxLen = packet.decodeExpectedMaxLength(buf, direction, registry.version);
if (expectedMaxLen != -1 && buf.readableBytes() > expectedMaxLen) {
throw handleOverflow(packet, expectedMaxLen, buf.readableBytes());
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java
index 7133f1d2..4af366ce 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/netty/MinecraftEncoder.java
@@ -54,6 +54,19 @@ public class MinecraftEncoder extends MessageToByteEncoder {
msg.encode(out, direction, registry.version);
}
+ @Override
+ protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, MinecraftPacket msg,
+ boolean preferDirect) throws Exception {
+ int hint = msg.encodeSizeHint(direction, registry.version);
+ if (hint < 0) {
+ return super.allocateBuffer(ctx, msg, preferDirect);
+ }
+
+ int packetId = this.registry.getPacketId(msg);
+ int totalHint = ProtocolUtils.varIntBytes(packetId) + hint;
+ return preferDirect ? ctx.alloc().ioBuffer(totalHint) : ctx.alloc().heapBuffer(totalHint);
+ }
+
public void setProtocolVersion(final ProtocolVersion protocolVersion) {
this.registry = state.getProtocolRegistry(direction, protocolVersion);
}
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 1301ed5b..7d4d8d6d 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
@@ -131,8 +131,8 @@ public class MinecraftVarintFrameDecoder extends ByteToMessageDecoder {
// 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.expectedMinLength(in, direction, registry.version);
- int expectedMaxLen = packet.expectedMaxLength(in, direction, registry.version);
+ 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());
}
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 08fe23b2..d3fc3a82 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
@@ -362,4 +362,12 @@ public class AvailableCommandsPacket implements MinecraftPacket {
return builder.buildFuture();
}
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ // This is a very complex packet to encode. Paper 1.21.10 + Velocity with Spark has a size of
+ // 30,334, but this is likely on the lower side. We'll use 128KiB as a more realistically-sized
+ // amount.
+ return 128 * 1024;
+ }
}
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 d6591e7b..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
@@ -107,7 +107,7 @@ public class EncryptionResponsePacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
+ public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
// It turns out these come out to the same length, whether we're talking >=1.8 or not.
// The length prefix always winds up being 2 bytes.
int base = 256 + 2 + 2;
@@ -123,8 +123,8 @@ public class EncryptionResponsePacket implements MinecraftPacket {
}
@Override
- public int expectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
- int base = expectedMaxLength(buf, direction, version);
+ public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
+ int base = decodeExpectedMaxLength(buf, direction, version);
if (version.noLessThan(ProtocolVersion.MINECRAFT_1_19)) {
// These are "optional"
base -= 128 + 8;
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 9eb7a93e..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
@@ -24,6 +24,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import io.netty.buffer.ByteBuf;
public class HandshakePacket implements MinecraftPacket {
@@ -108,14 +109,21 @@ public class HandshakePacket implements MinecraftPacket {
}
@Override
- public int expectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ public int decodeExpectedMinLength(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) {
return 7;
}
@Override
- public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) {
return 9 + (MAXIMUM_HOSTNAME_LENGTH * 3);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ // We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
+ // sizes of this packet.
+ return 4 * 1024;
+ }
}
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 dad9e08d..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
@@ -36,7 +36,7 @@ public class LoginAcknowledgedPacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
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 682785eb..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
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -86,4 +87,9 @@ public class LoginPluginMessagePacket extends DeferredByteBufHolder implements M
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return content().readableBytes();
+ }
}
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 dee33c13..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
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
@@ -88,4 +89,9 @@ public class LoginPluginResponsePacket extends DeferredByteBufHolder implements
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return content().readableBytes();
+ }
}
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 d78ed833..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
@@ -23,6 +23,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@@ -143,4 +144,9 @@ public class PluginMessagePacket extends DeferredByteBufHolder implements Minecr
public PluginMessagePacket touch(Object hint) {
return (PluginMessagePacket) super.touch(hint);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return content().readableBytes();
+ }
}
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 610462a9..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
@@ -22,6 +22,7 @@ import com.velocitypowered.api.util.Favicon;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
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;
@@ -121,4 +122,9 @@ public class ServerDataPacket implements MinecraftPacket {
public void setSecureChatEnforced(boolean secureChatEnforced) {
this.secureChatEnforced = secureChatEnforced;
}
+
+ @Override
+ 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 74eabb5c..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
@@ -150,7 +150,7 @@ public class ServerLoginPacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
+ public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
// Accommodate the rare (but likely malicious) use of UTF-8 usernames, since it is technically
// legal on the protocol level.
int base = 1 + (16 * 3);
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 1e70568f..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
@@ -23,6 +23,7 @@ import com.velocitypowered.api.util.UuidUtils;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.util.VelocityProperties;
import io.netty.buffer.ByteBuf;
import java.util.List;
@@ -132,4 +133,11 @@ public class ServerLoginSuccessPacket implements MinecraftPacket {
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ // We could compute an exact size, but 4KiB ought to be enough to encode all reasonable
+ // sizes of this packet.
+ return 4 * 1024;
+ }
}
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 2092b260..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
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
import io.netty.buffer.ByteBuf;
@@ -45,4 +46,8 @@ public class ServerboundCustomClickActionPacket extends DeferredByteBufHolder im
return handler.handle(this);
}
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return content().readableBytes();
+ }
}
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 15999e61..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
@@ -44,12 +44,12 @@ public class StatusPingPacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
+ public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return 8;
}
@Override
- public int expectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
+ public int decodeExpectedMinLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return 8;
}
}
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 46dc0401..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
@@ -53,7 +53,7 @@ public class StatusRequestPacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
+ public int decodeExpectedMaxLength(ByteBuf buf, Direction direction, ProtocolVersion version) {
return 0;
}
}
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 8591fa03..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
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
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 org.checkerframework.checker.nullness.qual.Nullable;
@@ -66,4 +67,9 @@ public class StatusResponsePacket implements MinecraftPacket {
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return ProtocolUtils.stringSizeHint(this.status);
+ }
}
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 35bf4a96..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
@@ -36,6 +36,8 @@ import org.jetbrains.annotations.Nullable;
public class UpsertPlayerInfoPacket implements MinecraftPacket {
+ private static final Action[] ALL_ACTIONS = Action.class.getEnumConstants();
+
private final EnumSet actions;
private final List entries;
@@ -85,14 +87,13 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
@Override
public void decode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) {
- Action[] actions = Action.class.getEnumConstants();
- byte[] bytes = new byte[-Math.floorDiv(-actions.length, 8)];
+ byte[] bytes = new byte[-Math.floorDiv(-ALL_ACTIONS.length, 8)];
buf.readBytes(bytes);
BitSet actionSet = BitSet.valueOf(bytes);
- for (int idx = 0; idx < actions.length; idx++) {
+ for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
if (actionSet.get(idx)) {
- addAction(actions[idx]);
+ addAction(ALL_ACTIONS[idx]);
}
}
@@ -109,14 +110,13 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
@Override
public void encode(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion protocolVersion) {
- Action[] actions = Action.class.getEnumConstants();
- BitSet set = new BitSet(actions.length);
- for (int idx = 0; idx < actions.length; idx++) {
- set.set(idx, this.actions.contains(actions[idx]));
+ BitSet set = new BitSet(ALL_ACTIONS.length);
+ for (int idx = 0; idx < ALL_ACTIONS.length; idx++) {
+ set.set(idx, this.actions.contains(ALL_ACTIONS[idx]));
}
byte[] bytes = set.toByteArray();
- buf.writeBytes(Arrays.copyOf(bytes, -Math.floorDiv(-actions.length, 8)));
+ buf.writeBytes(Arrays.copyOf(bytes, -Math.floorDiv(-ALL_ACTIONS.length, 8)));
ProtocolUtils.writeVarInt(buf, this.entries.size());
for (Entry entry : this.entries) {
@@ -133,12 +133,6 @@ public class UpsertPlayerInfoPacket implements MinecraftPacket {
return handler.handle(this);
}
- public BitSet readFixedBitSet(ByteBuf buf, int param0) {
- byte[] var0 = new byte[-Math.floorDiv(-param0, 8)];
- buf.readBytes(var0);
- return BitSet.valueOf(var0);
- }
-
public enum Action {
ADD_PLAYER((ignored, buf, info) -> { // read
info.profile = new GameProfile(
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 44adb743..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
@@ -44,4 +44,9 @@ public class CodeOfConductPacket extends DeferredByteBufHolder implements Minecr
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return content().readableBytes();
+ }
}
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 b4d93ec4..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
@@ -40,7 +40,7 @@ public class FinishedUpdatePacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
ProtocolVersion version) {
return 0;
}
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 ef0ee47a..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
@@ -21,6 +21,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
+import com.velocitypowered.proxy.protocol.ProtocolUtils.Direction;
import com.velocitypowered.proxy.protocol.util.DeferredByteBufHolder;
import io.netty.buffer.ByteBuf;
@@ -47,4 +48,9 @@ public class RegistrySyncPacket extends DeferredByteBufHolder implements Minecra
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ return content().readableBytes();
+ }
}
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 8d4585d8..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
@@ -40,7 +40,7 @@ public class StartUpdatePacket implements MinecraftPacket {
}
@Override
- public int expectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
+ public int decodeExpectedMaxLength(ByteBuf buf, ProtocolUtils.Direction direction,
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 6d462fb2..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
@@ -22,6 +22,7 @@ import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
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;
@@ -79,4 +80,22 @@ public class TagsUpdatePacket implements MinecraftPacket {
public boolean handle(MinecraftSessionHandler handler) {
return handler.handle(this);
}
+
+ @Override
+ public int encodeSizeHint(Direction direction, ProtocolVersion version) {
+ int size = ProtocolUtils.varIntBytes(tags.size());
+ for (Map.Entry> entry : tags.entrySet()) {
+ size += ProtocolUtils.stringSizeHint(entry.getKey());
+ size += ProtocolUtils.varIntBytes(entry.getValue().size());
+ for (Map.Entry innerEntry : entry.getValue().entrySet()) {
+ size += ProtocolUtils.stringSizeHint(innerEntry.getKey());
+ size += ProtocolUtils.varIntBytes(innerEntry.getValue().length);
+ for (int innerEntryValue : innerEntry.getValue()) {
+ size += ProtocolUtils.varIntBytes(innerEntryValue);
+ }
+ }
+ }
+
+ return size;
+ }
}
From 67b988e6d24338e716de1b87584d06af75d974b8 Mon Sep 17 00:00:00 2001
From: Andrew Steinborn
Date: Sat, 18 Oct 2025 18:58:21 -0400
Subject: [PATCH 32/36] Update all localizations to use the current year
---
.../com/velocitypowered/proxy/l10n/messages_ar_SA.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_bg_BG.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_cs_CZ.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_da_DK.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_de_DE.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_es_ES.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_et_EE.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_fi_FI.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_fr_FR.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_he_IL.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_hu_HU.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_it_IT.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_ja_JP.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_ko_KR.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_nb_NO.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_nl_NL.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_nn_NO.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_pl_PL.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_pt_BR.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_ro_RO.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_ru_RU.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_sk_SK.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_sq_AL.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_sr_CS.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_sr_Latn.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_sv_SE.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_tl_PH.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_tr_TR.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_uk_UA.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_vi_VN.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_zh_CN.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_zh_HK.properties | 2 +-
.../com/velocitypowered/proxy/l10n/messages_zh_TW.properties | 2 +-
33 files changed, 33 insertions(+), 33 deletions(-)
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 103ae08a..8f79f570 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=هناك {0} لاعبين متصلون با
velocity.command.glist-view-all=لعرض اللاعبين على جميع السيرفرات استخدم /glist all
velocity.command.reload-success=تم إعادة تحميل إعدادات Velocity بنجاح.
velocity.command.reload-failure=فشلت إعادة تحميل إعدادات Velocity. تفقد الـconsole للمزيد من التفاصيل.
-velocity.command.version-copyright=حقوق الطبع والنشر 2018-2023 {0}. {1} مرخصة بموجب شروط الإصدار الثالث لرخصة GNU العامة (GPLv3).
+velocity.command.version-copyright=حقوق الطبع والنشر 2018-{2} {0}. {1} مرخصة بموجب شروط الإصدار الثالث لرخصة GNU العامة (GPLv3).
velocity.command.no-plugins=لا توجد إضافات مثبتة على Velocity.
velocity.command.plugins-list=الإضافات\: {0}
velocity.command.plugin-tooltip-website=موقعها\: {0}
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 b5a12e46..c554fa3d 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} играчи са свързани къ
velocity.command.glist-view-all=За да видите всички играчи, разпределени по сървъри, използвайте /glist all.
velocity.command.reload-success=Настройките на Velocity бяха презаредени успешно.
velocity.command.reload-failure=Не успяхме да презаредим настройките на Velocity. Моля, проверете конзолата за повече информация.
-velocity.command.version-copyright=Авторско право 2018-2023 {0}. {1} е лицензиран под условията на GNU General Public License v3.
+velocity.command.version-copyright=Авторско право 2018-{2} {0}. {1} е лицензиран под условията на GNU General Public License v3.
velocity.command.no-plugins=За момента няма инсталирани добавки.
velocity.command.plugins-list=Добавки\: {0}
velocity.command.plugin-tooltip-website=Уебсайт\: {0}
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 99d4f38a..980e4591 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=Počet hráčů připojených k tomuto prox
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-2023 {0}. {1} je licencovaný pod podmínkami GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 c593076e..1a82cbdf 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spillere er i øjeblikket forbundet til
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-2023 {0}. {1} er licenseret under betingelserne i GNU General Public License v3.
+velocity.command.version-copyright=Ophavsret 2018-{2} {0}. {1} 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}
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 f2d6872a..4de00f9e 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} Spieler sind derzeit mit dem Proxy verb
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-2023 {0}. {1} ist lizenziert unter den Bedingungen der GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 a99efb44..0d484bc9 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} 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-2023 {0}. {1} está licenciado bajo los términos de la Licencia Pública General de GNU v3.
+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.no-plugins=Actualmente no hay plugins instalados.
velocity.command.plugins-list=Complementos\: {0}
velocity.command.plugin-tooltip-website=Página web\: {0}
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 246419b9..0e4ea63d 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} players are currently connected to the
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-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 84b6d593..39c8f374 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} pelaajaa on tällä hetkellä yhdistän
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-2023 {0}. {1} on lisensoitu GNU General Public License v3\:n ehtojen mukaisesti.
+velocity.command.version-copyright=Tekijänoikeus 2018-{2} {0}. {1} 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}
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 da990209..64fa63ee 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} joueurs sont actuellement connectés au
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-2023 {0}. {1} est sous la licence GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 3b0b8c69..85cd9f99 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} שחקנים מחוברים כעת ל-
velocity.command.glist-view-all=כדי להציג את כל השחקנים בשרתים, השתמש ב- glist all/.
velocity.command.reload-success=תצורת Velocity נטענה מחדש בהצלחה.
velocity.command.reload-failure=אין אפשרות לטעון מחדש את תצורת ה- Velocity שלך. עיין בקונסולה לקבלת פרטים נוספים.
-velocity.command.version-copyright=זכויות יוצרים 2018-2023 {0}. {1} מורשה על פי תנאי v3 הרישיון הציבורי הכללי של GNU.
+velocity.command.version-copyright=זכויות יוצרים 2018-{2} {0}. {1} מורשה על פי תנאי v3 הרישיון הציבורי הכללי של GNU.
velocity.command.no-plugins=לא מותקנים כעת תוספים.
velocity.command.plugins-list=תוספים\: {0}
velocity.command.plugin-tooltip-website=אתר אינטרנט\: {0}
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 e5cb5b1c..b43f69b5 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} játékos van jelenleg csatlakozva a pr
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-2023 {0}. {1} licenszelve van a GNU General Public License v3 alatt.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 0c72f5e1..d2a79886 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} giocatori sono attualmente connessi al
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-2023 {0}. {1} è concesso in licenza secondo i termini della GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} è 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}
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 a16b0605..235de499 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} 人が現在プロキシに接続して
velocity.command.glist-view-all=サーバー上のすべてのプレイヤーを表示するには、/glist allを使用してください。
velocity.command.reload-success=Velocityの設定が再読み込みされました。
velocity.command.reload-failure=Velocityの設定を再読み込みできません。詳細はコンソールで確認してください。
-velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} は、GNU General Public License v3に基づいてライセンスされています。
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} は、GNU General Public License v3に基づいてライセンスされています。
velocity.command.no-plugins=現在インストールされているプラグインはありません。
velocity.command.plugins-list=プラグイン\: {0}
velocity.command.plugin-tooltip-website=ウェブサイト\: {0}
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 b4bbf4c8..e7e528cc 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=플레이어 {0}명이 현재 프록시에
velocity.command.glist-view-all=서버에 있는 모든 플레이어를 보려면, /glist all을 사용하세요.
velocity.command.reload-success=Velocity 설정을 성공적으로 다시 불러왔습니다.
velocity.command.reload-failure=Velocity 설정을 다시 불러올 수 없습니다. 자세한 내용은 콘솔을 확인하세요.
-velocity.command.version-copyright=Copyright 2018-2023 {0}. {1}은(는) GNU General Public License v3 라이센스의 약관을 따릅니다.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1}은(는) GNU General Public License v3 라이센스의 약관을 따릅니다.
velocity.command.no-plugins=설치된 플러그인이 없습니다.
velocity.command.plugins-list=플러그인\: {0}
velocity.command.plugin-tooltip-website=웹사이트\: {0}
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 ef7794e5..05a17545 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spillere er for øyeblikket tilkoblet d
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-2023 {0}. {1} er lisensiert under betingelsene av GNU General Public License v3.
+velocity.command.version-copyright=Opphavsrett 2018-{2} {0}. {1} 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}
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 44d12b08..cbb5f6b8 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spelers zijn momenteel verbonden met de
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-2023 {0}. {1} is gelicentieerd onder de voorwaarden van de GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 eb6bfa38..b23ce960 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spelare er for augneblinken tilkopla de
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-2023 {0}. {1} er lisensiert under vilkåra av GNU General Public License v3.
+velocity.command.version-copyright=Opphavsrett 2018-{2} {0}. {1} 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}
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 c3e2cfcf..02a90f87 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=Z tym proxy jest obecnie połączonych {0}
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-2023 {0}. {1} jest objęty licencją na warunkach GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 5a915a8d..e0708942 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} jogadores estão atualmente conectados
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-2023 {0}. {1} está licenciado sobre os termos da Licença Pública Geral GNU v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 8f28b91b..ea0d4609 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} players are currently connected to the
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-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 a2a7afb9..5e5be8e6 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} игрок(а, ов) подключен
velocity.command.glist-view-all=Чтобы просмотреть всех игроков на серверах, используйте /glist all.
velocity.command.reload-success=Конфигурация Velocity успешно перезагружена.
velocity.command.reload-failure=Не удалось перезагрузить конфигурацию Velocity. Проверьте консоль для получения более подробной информации.
-velocity.command.version-copyright=Copyright 2018-2023 {0}. {1} лицензирована на условиях GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} лицензирована на условиях GNU General Public License v3.
velocity.command.no-plugins=Ни одного плагина не установлено.
velocity.command.plugins-list=Плагины\: {0}
velocity.command.plugin-tooltip-website=Веб-сайт\: {0}
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 f7a89585..04e75974 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} hráčov je pripojených na tento proxy
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-2023 {0}. {1} je licencovaný pod podmienkami GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 64e6b2b1..711b8e84 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} lojtarët janë aktualisht të lidhur m
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-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 6313a69b..006a3037 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
@@ -46,7 +46,7 @@ velocity.command.glist-player-plural={0} 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-2023 {0}. {1} je licenciran pod uslovima licence GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 313aa913..6106bb7b 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} 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-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 fca663fa..973506eb 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} spelare är just nu ansluten till proxy
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-2023 {0}. {1} är licensierad enligt villkoren i GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} ä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}
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 a9e5c15b..ec4cc9d2 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} 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-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 5ae8c98d..3c255d93 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=Şu anda sunucuya toplam {0} 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-2023 {0}. {1}, GNU General Public License v3 adı altında lisanslanmıştır.
+velocity.command.version-copyright=Talif hakkı 2018-{2} {0}. {1}, 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}
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 18be5e9c..2400bd29 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} гравець(ця, ців) приєд
velocity.command.glist-view-all=Щоб переглянути всіх гравців на серверах, використовуйте /glist all.
velocity.command.reload-success=Конфігурація Velocity успішно перезавантажена.
velocity.command.reload-failure=Не вдалося перезантажити конфігурацію Velocity. Перевірте консоль для подробиць.
-velocity.command.version-copyright=Авторське право 2018-2023 {0}. {1} ліцензовано на умовах GNU General Public License v3.
+velocity.command.version-copyright=Авторське право 2018-{2} {0}. {1} ліцензовано на умовах GNU General Public License v3.
velocity.command.no-plugins=Плагіни відсутні.
velocity.command.plugins-list=Плагіни\: {0}
velocity.command.plugin-tooltip-website=Веб-сайт\: {0}
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 7e46f191..5450e21e 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural={0} người chơi hiện đang kết nối
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-2023 {0}. {1} is licensed under the terms of the GNU General Public License v3.
+velocity.command.version-copyright=Copyright 2018-{2} {0}. {1} 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}
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 f26dea88..4b3b07d3 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=共有 {0} 名玩家已连接至此代理
velocity.command.glist-view-all=使用 /glist all 命令来查看所有服务器的全部玩家列表。
velocity.command.reload-success=Velocity 配置已成功重载。
velocity.command.reload-failure=无法重载 Velocity 配置,请查看控制台了解详情。
-velocity.command.version-copyright=Copyright 2018-2023 {0}。{1} 以 GNU 通用公共许可证第三版授权。
+velocity.command.version-copyright=Copyright 2018-{2} {0}。{1} 以 GNU 通用公共许可证第三版授权。
velocity.command.no-plugins=当前没有安装任何插件。
velocity.command.plugins-list=插件:{0}
velocity.command.plugin-tooltip-website=网站:{0}
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 dc58d3f8..37468347 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=共有 {0} 個玩家已連接至此代理
velocity.command.glist-view-all=使用 /glist all 命令來查看所有伺服器的玩家列表。
velocity.command.reload-success=Velocity 配置重新加載完成。
velocity.command.reload-failure=無法重新加載 Velocity 配置,請查看控制台了解詳情。
-velocity.command.version-copyright=Copyright 2018-2023 {0} ( {1} 的授權條款爲: GNU 通用公共授權條款第三版)
+velocity.command.version-copyright=Copyright 2018-{2} {0} ( {1} 的授權條款爲: GNU 通用公共授權條款第三版)
velocity.command.no-plugins=目前未有安裝任何 Velocity 插件。
velocity.command.plugins-list=插件: {0}
velocity.command.plugin-tooltip-website=網站: {0}
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 49ed3916..b7fe1b5b 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
@@ -48,7 +48,7 @@ velocity.command.glist-player-plural=共有 {0} 名玩家已連線至此代理
velocity.command.glist-view-all=使用 /glist all 命令來查看所有伺服器的全部玩家列表。
velocity.command.reload-success=Velocity 配置已成功重載。
velocity.command.reload-failure=無法重載 Velocity 配置,請查看控制台了解詳情。
-velocity.command.version-copyright=Copyright 2018-2023 {0}。{1} 以 GNU 通用公共許可證第三版授權。
+velocity.command.version-copyright=Copyright 2018-{2} {0}。{1} 以 GNU 通用公共許可證第三版授權。
velocity.command.no-plugins=當前沒有安裝任何插件。
velocity.command.plugins-list=插件:{0}
velocity.command.plugin-tooltip-website=網站:{0}
From 02cf349075d49509ec0d06951bfe0f90d07ad947 Mon Sep 17 00:00:00 2001
From: Adrian <68704415+4drian3d@users.noreply.github.com>
Date: Sun, 19 Oct 2025 09:43:40 -0500
Subject: [PATCH 33/36] Fixed disconnecting players in the middle of a backend
server reconfiguration (#1669)
---
.../backend/ConfigSessionHandler.java | 8 +++++-
.../backend/LoginSessionHandler.java | 2 +-
.../connection/client/ConnectedPlayer.java | 27 +++++++++----------
3 files changed, 21 insertions(+), 16 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 90bb1a30..8ab38e58 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
@@ -257,7 +257,13 @@ public class ConfigSessionHandler implements MinecraftSessionHandler {
@Override
public boolean handle(DisconnectPacket packet) {
serverConn.disconnect();
- resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
+ // If the player receives a DisconnectPacket without a connection to a server in progress,
+ // it means that the backend server has kicked the player during reconfiguration
+ if (serverConn.getPlayer().getConnectionInFlight() != null) {
+ resultFuture.complete(ConnectionRequestResults.forDisconnect(packet, serverConn.getServer()));
+ } else {
+ serverConn.getPlayer().handleConnectionException(serverConn.getServer(), packet, true);
+ }
return true;
}
diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java
index 612e9c25..14884af4 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/LoginSessionHandler.java
@@ -165,7 +165,7 @@ public class LoginSessionHandler implements MinecraftSessionHandler {
}
if (player.getConnection().getActiveSessionHandler() instanceof ClientPlaySessionHandler clientPlaySessionHandler) {
smc.setAutoReading(false);
- clientPlaySessionHandler.doSwitch().thenAcceptAsync((unused) -> smc.setAutoReading(true), smc.eventLoop());
+ clientPlaySessionHandler.doSwitch().thenRunAsync(() -> smc.setAutoReading(true), smc.eventLoop());
} else {
// Initial login - the player is already in configuration state.
server.getEventManager().fireAndForget(new PlayerEnteredConfigurationEvent(player, serverConn));
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 17f4fb5c..0807789f 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
@@ -817,9 +817,7 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
createConnectionRequest(res.getServer(), previousConnection).connect()
.whenCompleteAsync((status, throwable) -> {
if (throwable != null) {
- handleConnectionException(
- status != null ? status.getAttemptedConnection() : res.getServer(), throwable,
- true);
+ handleConnectionException(res.getServer(), throwable, true);
return;
}
@@ -1497,7 +1495,16 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
VelocityServerConnection con =
new VelocityServerConnection(vrs, previousServer, ConnectedPlayer.this, server);
connectionInFlight = con;
- return con.connect().whenCompleteAsync((result, exception) -> this.resetIfInFlightIs(con),
+
+ return con.connect().whenCompleteAsync((result, exception) -> {
+ if (result != null && !result.isSuccessful() && !result.isSafe()) {
+ handleConnectionException(result.getAttemptedConnection(),
+ // The only way for the reason to be null is if the result is safe
+ DisconnectPacket.create(result.getReasonComponent().orElseThrow(),
+ getProtocolVersion(), connection.getState()), false);
+ }
+ this.resetIfInFlightIs(con);
+ },
connection.eventLoop());
}, connection.eventLoop());
});
@@ -1511,22 +1518,14 @@ public class ConnectedPlayer implements MinecraftConnectionAssociation, Player,
@Override
public CompletableFuture connect() {
- return this.internalConnect().whenCompleteAsync((status, throwable) -> {
- if (status != null && !status.isSuccessful()) {
- if (!status.isSafe()) {
- handleConnectionException(status.getAttemptedConnection(), throwable, false);
- }
- }
- }, connection.eventLoop()).thenApply(x -> x);
+ return this.internalConnect().thenApply(x -> x);
}
@Override
public CompletableFuture connectWithIndication() {
return internalConnect().whenCompleteAsync((status, throwable) -> {
if (throwable != null) {
- // TODO: The exception handling from this is not very good. Find a better way.
- handleConnectionException(status != null ? status.getAttemptedConnection() : toConnect,
- throwable, true);
+ handleConnectionException(toConnect, throwable, true);
return;
}
From 7412aca81c80c5639e863c2884d232b25316c137 Mon Sep 17 00:00:00 2001
From: Adrian <68704415+4drian3d@users.noreply.github.com>
Date: Mon, 20 Oct 2025 19:51:47 -0500
Subject: [PATCH 34/36] Fixed sending ServerData packets if the description
component from the backend server is null (#1673)
---
api/build.gradle.kts | 2 +-
.../api/proxy/server/ServerPing.java | 19 +++++++++++--------
.../util/ServerListPingHandler.java | 8 ++++++++
.../protocol/packet/chat/ComponentHolder.java | 4 ++--
4 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/api/build.gradle.kts b/api/build.gradle.kts
index a4cbd741..b96208c1 100644
--- a/api/build.gradle.kts
+++ b/api/build.gradle.kts
@@ -70,7 +70,7 @@ tasks {
"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}/",
- "https://javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/${libs.caffeine.get().version}/",
+ "https://www.javadocs.dev/com.github.ben-manes.caffeine/caffeine/${libs.caffeine.get().version}/",
)
o.tags(
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 4d906b7b..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
@@ -19,7 +19,9 @@ import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
-import org.checkerframework.checker.nullness.qual.Nullable;
+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.
@@ -28,7 +30,7 @@ public final class ServerPing {
private final Version version;
private final @Nullable Players players;
- private final net.kyori.adventure.text.Component description;
+ private final @Nullable Component description;
private final @Nullable Favicon favicon;
private final @Nullable ModInfo modinfo;
@@ -47,8 +49,8 @@ public final class ServerPing {
* @param modinfo the mods this server runs
*/
public ServerPing(Version version, @Nullable Players players,
- net.kyori.adventure.text.Component description, @Nullable Favicon favicon,
- @Nullable ModInfo modinfo) {
+ Component description, @Nullable Favicon favicon,
+ @Nullable ModInfo modinfo) {
this.version = Preconditions.checkNotNull(version, "version");
this.players = players;
this.description = Preconditions.checkNotNull(description, "description");
@@ -64,7 +66,8 @@ public final class ServerPing {
return Optional.ofNullable(players);
}
- public net.kyori.adventure.text.Component getDescriptionComponent() {
+ @Nullable
+ public Component getDescriptionComponent() {
return description;
}
@@ -151,7 +154,7 @@ public final class ServerPing {
private final List samplePlayers = new ArrayList<>();
private String modType = "FML";
private final List mods = new ArrayList<>();
- private net.kyori.adventure.text.Component description;
+ private Component description;
private @Nullable Favicon favicon;
private boolean nullOutPlayers;
private boolean nullOutModinfo;
@@ -299,7 +302,7 @@ public final class ServerPing {
* @param description Component to use as the description.
* @return this builder, for chaining
*/
- public Builder description(net.kyori.adventure.text.Component description) {
+ public Builder description(Component description) {
this.description = Preconditions.checkNotNull(description, "description");
return this;
}
@@ -359,7 +362,7 @@ public final class ServerPing {
return samplePlayers;
}
- public Optional getDescriptionComponent() {
+ public Optional getDescriptionComponent() {
return Optional.ofNullable(description);
}
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 d1f2b0db..7740139c 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
@@ -36,6 +36,7 @@ import java.util.Locale;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
+import net.kyori.adventure.text.Component;
/**
* Common utilities for handling server list ping results.
@@ -107,6 +108,13 @@ public class ServerListPingHandler {
if (response == fallback) {
continue;
}
+
+ if (response.getDescriptionComponent() == null) {
+ return response.asBuilder()
+ .description(Component.empty())
+ .build();
+ }
+
return response;
}
return fallback;
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 22b49621..01f36d0e 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
@@ -87,7 +87,7 @@ public class ComponentHolder {
} catch (Exception ex) {
logger.error(
"Error converting binary component to JSON component! "
- + "Binary: " + binaryTag + " JSON: " + json, ex);
+ + "Binary: " + binaryTag + " JSON: " + json, ex);
throw ex;
}
}
@@ -112,7 +112,7 @@ public class ComponentHolder {
public static BinaryTag serialize(JsonElement json) {
if (json instanceof JsonPrimitive jsonPrimitive) {
- if (jsonPrimitive.isNumber()) {
+ if (jsonPrimitive.isNumber()) {
Number number = json.getAsNumber();
if (number instanceof Byte) {
From f75b512837b51a68b5c6cafaf63dbdaefedc284a Mon Sep 17 00:00:00 2001
From: Dylan Sperrer
Date: Tue, 21 Oct 2025 11:45:04 -0600
Subject: [PATCH 35/36] Moved pre-1.19.1 command argument validation so it
prints the faulty identifier (#1675)
---
.../packet/brigadier/ArgumentPropertyRegistry.java | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
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 197fddf3..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,6 +45,8 @@ 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;
@@ -87,9 +89,6 @@ public class ArgumentPropertyRegistry {
ArgumentIdentifier identifier = readIdentifier(buf, protocolVersion);
ArgumentPropertySerializer> serializer = byIdentifier.get(identifier);
- if (serializer == null) {
- throw new IllegalArgumentException("Argument type identifier " + identifier + " unknown.");
- }
Object result = serializer.deserialize(buf, protocolVersion);
if (result instanceof ArgumentType) {
@@ -156,7 +155,7 @@ public class ArgumentPropertyRegistry {
* @param protocolVersion the protocol version to use
* @return the identifier read from the buffer
*/
- public static ArgumentIdentifier readIdentifier(ByteBuf buf, ProtocolVersion protocolVersion) {
+ public static @NotNull ArgumentIdentifier readIdentifier(ByteBuf buf, ProtocolVersion protocolVersion) {
if (protocolVersion.noLessThan(MINECRAFT_1_19)) {
int id = ProtocolUtils.readVarInt(buf);
for (ArgumentIdentifier i : byIdentifier.keySet()) {
@@ -173,8 +172,8 @@ public class ArgumentPropertyRegistry {
return i;
}
}
+ throw new IllegalArgumentException("Argument type identifier " + identifier + " unknown.");
}
- return null;
}
static {
From b6b6b20fe97cd9cb0d6b4e817d3e7db72aca2d8d Mon Sep 17 00:00:00 2001
From: Adrian <68704415+4drian3d@users.noreply.github.com>
Date: Thu, 23 Oct 2025 11:13:36 -0500
Subject: [PATCH 36/36] Generate a new forwarding secret file if the file is
deleted (#1671)
* Generate a new forwarding secret file if the file is deleted
This allows to generate a new forwarding secret simply by deleting the file if required.
The file will only be generated if the forwarding secret is not configured through a system property
resolves #1670
* Add file creation message
---
.../proxy/config/VelocityConfiguration.java | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
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 dfd007ac..6f0fb61c 100644
--- a/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java
+++ b/proxy/src/main/java/com/velocitypowered/proxy/config/VelocityConfiguration.java
@@ -515,7 +515,7 @@ public class VelocityConfiguration implements ProxyConfig {
String forwardingSecretString = System.getenv().getOrDefault(
"VELOCITY_FORWARDING_SECRET", "");
- if (forwardingSecretString.isEmpty()) {
+ if (forwardingSecretString.isBlank()) {
final String forwardSecretFile = config.get("forwarding-secret-file");
final Path secretPath = forwardSecretFile == null
? defaultForwardingSecretPath
@@ -528,7 +528,11 @@ public class VelocityConfiguration implements ProxyConfig {
"The file " + forwardSecretFile + " is not a valid file or it is a directory.");
}
} else {
- throw new RuntimeException("The forwarding-secret-file does not exist.");
+ Files.createFile(secretPath);
+ Files.writeString(secretPath, forwardingSecretString = generateRandomString(12),
+ StandardCharsets.UTF_8);
+ logger.info("The forwarding-secret-file does not exist. A new file has been created at {}",
+ forwardSecretFile);
}
}
final byte[] forwardingSecret = forwardingSecretString.getBytes(StandardCharsets.UTF_8);